mirror of
https://github.com/kubevela/kubevela.git
synced 2026-05-14 13:26:44 +00:00
Feat: add RBAC support (#3493)
* Feat: add the rbac data model Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: add some api about the project Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: add CRUD about the project and the project user Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: add CRUD about the role and perm check filter function Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: update swagger config Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: add default roles and perm policies Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: add perm check filter for all webservice Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: change the method that find project name Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: query applications and envs by user perm Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: support get login user info Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: change default permissions Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: change PermPolicy to Permission Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: add some unit test and fix the e2e test error Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: change some comment word Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: e2e api path error Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
This commit is contained in:
@@ -1,17 +1,17 @@
|
||||
/*
|
||||
Copyright 2022 The KubeVela Authors.
|
||||
Copyright 2022 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package sync
|
||||
@@ -20,138 +20,14 @@ import (
|
||||
"context"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha1"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/model"
|
||||
"github.com/oam-dev/kubevela/pkg/multicluster"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/sync/convert"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/workflow/step"
|
||||
)
|
||||
|
||||
// ConvertFromCRComponent concerts Application CR Component object into velaux data store component
|
||||
func ConvertFromCRComponent(appPrimaryKey string, component common.ApplicationComponent) (model.ApplicationComponent, error) {
|
||||
bc := model.ApplicationComponent{
|
||||
AppPrimaryKey: appPrimaryKey,
|
||||
Name: component.Name,
|
||||
Type: component.Type,
|
||||
ExternalRevision: component.ExternalRevision,
|
||||
DependsOn: component.DependsOn,
|
||||
Inputs: component.Inputs,
|
||||
Outputs: component.Outputs,
|
||||
Scopes: component.Scopes,
|
||||
Creator: model.AutoGenComp,
|
||||
}
|
||||
if component.Properties != nil {
|
||||
properties, err := model.NewJSONStruct(component.Properties)
|
||||
if err != nil {
|
||||
return bc, err
|
||||
}
|
||||
bc.Properties = properties
|
||||
}
|
||||
for _, trait := range component.Traits {
|
||||
properties, err := model.NewJSONStruct(trait.Properties)
|
||||
if err != nil {
|
||||
return bc, err
|
||||
}
|
||||
bc.Traits = append(bc.Traits, model.ApplicationTrait{CreateTime: time.Now(), UpdateTime: time.Now(), Properties: properties, Type: trait.Type, Alias: trait.Type, Description: "auto gen"})
|
||||
}
|
||||
return bc, nil
|
||||
}
|
||||
|
||||
// ConvertFromCRPolicy converts Application CR Policy object into velaux data store policy
|
||||
func ConvertFromCRPolicy(appPrimaryKey string, policyCR v1beta1.AppPolicy, creator string) (model.ApplicationPolicy, error) {
|
||||
plc := model.ApplicationPolicy{
|
||||
AppPrimaryKey: appPrimaryKey,
|
||||
Name: policyCR.Name,
|
||||
Type: policyCR.Type,
|
||||
Creator: creator,
|
||||
}
|
||||
if policyCR.Properties != nil {
|
||||
properties, err := model.NewJSONStruct(policyCR.Properties)
|
||||
if err != nil {
|
||||
return plc, err
|
||||
}
|
||||
plc.Properties = properties
|
||||
}
|
||||
return plc, nil
|
||||
}
|
||||
|
||||
// ConvertFromCRWorkflow converts Application CR Workflow section into velaux data store workflow
|
||||
func ConvertFromCRWorkflow(ctx context.Context, cli client.Client, appPrimaryKey string, app *v1beta1.Application) (model.Workflow, []v1beta1.WorkflowStep, error) {
|
||||
dataWf := model.Workflow{
|
||||
AppPrimaryKey: appPrimaryKey,
|
||||
// every namespace has a synced env
|
||||
EnvName: model.AutoGenEnvNamePrefix + app.Namespace,
|
||||
// every application has a synced workflow
|
||||
Name: model.AutoGenWorkflowNamePrefix + appPrimaryKey,
|
||||
Alias: model.AutoGenWorkflowNamePrefix + app.Name,
|
||||
Description: model.AutoGenDesc,
|
||||
}
|
||||
if app.Spec.Workflow == nil {
|
||||
return dataWf, nil, nil
|
||||
}
|
||||
var steps []v1beta1.WorkflowStep
|
||||
if app.Spec.Workflow.Ref != "" {
|
||||
dataWf.Name = app.Spec.Workflow.Ref
|
||||
wf := &v1alpha1.Workflow{}
|
||||
if err := cli.Get(ctx, types.NamespacedName{Namespace: app.GetNamespace(), Name: app.Spec.Workflow.Ref}, wf); err != nil {
|
||||
return dataWf, nil, err
|
||||
}
|
||||
steps = step.ConvertSteps(wf.Steps)
|
||||
} else {
|
||||
steps = app.Spec.Workflow.Steps
|
||||
}
|
||||
for _, s := range steps {
|
||||
if s.Properties == nil {
|
||||
continue
|
||||
}
|
||||
properties, err := model.NewJSONStruct(s.Properties)
|
||||
if err != nil {
|
||||
return dataWf, nil, err
|
||||
}
|
||||
dataWf.Steps = append(dataWf.Steps, model.WorkflowStep{
|
||||
Name: s.Name,
|
||||
Type: s.Type,
|
||||
Inputs: s.Inputs,
|
||||
Outputs: s.Outputs,
|
||||
DependsOn: s.DependsOn,
|
||||
Properties: properties,
|
||||
})
|
||||
}
|
||||
return dataWf, steps, nil
|
||||
}
|
||||
|
||||
// ConvertFromCRTargets converts deployed Cluster/Namespace from Application CR Status into velaux data store
|
||||
func ConvertFromCRTargets(targetApp *v1beta1.Application) []*model.Target {
|
||||
var targets []*model.Target
|
||||
nc := make(map[string]struct{})
|
||||
for _, v := range targetApp.Status.AppliedResources {
|
||||
var cluster = v.Cluster
|
||||
if cluster == "" {
|
||||
cluster = multicluster.ClusterLocalName
|
||||
}
|
||||
name := model.AutoGenTargetNamePrefix + cluster + "-" + v.Namespace
|
||||
if _, ok := nc[name]; ok {
|
||||
continue
|
||||
}
|
||||
nc[name] = struct{}{}
|
||||
targets = append(targets, &model.Target{
|
||||
Name: name,
|
||||
Cluster: &model.ClusterTarget{
|
||||
ClusterName: cluster,
|
||||
Namespace: v.Namespace,
|
||||
},
|
||||
})
|
||||
}
|
||||
return targets
|
||||
}
|
||||
|
||||
// ConvertApp2DatastoreApp will convert Application CR to datastore application related resources
|
||||
func (c *CR2UX) ConvertApp2DatastoreApp(ctx context.Context, targetApp *v1beta1.Application) (*model.DataStoreApp, error) {
|
||||
cli := c.cli
|
||||
@@ -193,7 +69,7 @@ func (c *CR2UX) ConvertApp2DatastoreApp(ctx context.Context, targetApp *v1beta1.
|
||||
|
||||
// 2. convert component and trait
|
||||
for _, cmp := range targetApp.Spec.Components {
|
||||
compModel, err := ConvertFromCRComponent(appMeta.PrimaryKey(), cmp)
|
||||
compModel, err := convert.FromCRComponent(appMeta.PrimaryKey(), cmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -201,7 +77,7 @@ func (c *CR2UX) ConvertApp2DatastoreApp(ctx context.Context, targetApp *v1beta1.
|
||||
}
|
||||
|
||||
// 3. convert workflow
|
||||
wf, steps, err := ConvertFromCRWorkflow(ctx, cli, appMeta.PrimaryKey(), targetApp)
|
||||
wf, steps, err := convert.FromCRWorkflow(ctx, cli, appMeta.PrimaryKey(), targetApp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -217,7 +93,7 @@ func (c *CR2UX) ConvertApp2DatastoreApp(ctx context.Context, targetApp *v1beta1.
|
||||
return nil, err
|
||||
}
|
||||
for _, plc := range outsidePLC {
|
||||
plcModel, err := ConvertFromCRPolicy(appMeta.PrimaryKey(), plc, model.AutoGenRefPolicy)
|
||||
plcModel, err := convert.FromCRPolicy(appMeta.PrimaryKey(), plc, model.AutoGenRefPolicy)
|
||||
if _, ok := innerPlc[plc.Name]; ok {
|
||||
plcModel.Creator = model.AutoGenPolicy
|
||||
}
|
||||
|
||||
150
pkg/apiserver/sync/convert/convert.go
Normal file
150
pkg/apiserver/sync/convert/convert.go
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
Copyright 2022 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package convert
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha1"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/model"
|
||||
"github.com/oam-dev/kubevela/pkg/multicluster"
|
||||
"github.com/oam-dev/kubevela/pkg/workflow/step"
|
||||
)
|
||||
|
||||
// FromCRComponent concerts Application CR Component object into velaux data store component
|
||||
func FromCRComponent(appPrimaryKey string, component common.ApplicationComponent) (model.ApplicationComponent, error) {
|
||||
bc := model.ApplicationComponent{
|
||||
AppPrimaryKey: appPrimaryKey,
|
||||
Name: component.Name,
|
||||
Type: component.Type,
|
||||
ExternalRevision: component.ExternalRevision,
|
||||
DependsOn: component.DependsOn,
|
||||
Inputs: component.Inputs,
|
||||
Outputs: component.Outputs,
|
||||
Scopes: component.Scopes,
|
||||
Creator: model.AutoGenComp,
|
||||
}
|
||||
if component.Properties != nil {
|
||||
properties, err := model.NewJSONStruct(component.Properties)
|
||||
if err != nil {
|
||||
return bc, err
|
||||
}
|
||||
bc.Properties = properties
|
||||
}
|
||||
for _, trait := range component.Traits {
|
||||
properties, err := model.NewJSONStruct(trait.Properties)
|
||||
if err != nil {
|
||||
return bc, err
|
||||
}
|
||||
bc.Traits = append(bc.Traits, model.ApplicationTrait{CreateTime: time.Now(), UpdateTime: time.Now(), Properties: properties, Type: trait.Type, Alias: trait.Type, Description: "auto gen"})
|
||||
}
|
||||
return bc, nil
|
||||
}
|
||||
|
||||
// FromCRPolicy converts Application CR Policy object into velaux data store policy
|
||||
func FromCRPolicy(appPrimaryKey string, policyCR v1beta1.AppPolicy, creator string) (model.ApplicationPolicy, error) {
|
||||
plc := model.ApplicationPolicy{
|
||||
AppPrimaryKey: appPrimaryKey,
|
||||
Name: policyCR.Name,
|
||||
Type: policyCR.Type,
|
||||
Creator: creator,
|
||||
}
|
||||
if policyCR.Properties != nil {
|
||||
properties, err := model.NewJSONStruct(policyCR.Properties)
|
||||
if err != nil {
|
||||
return plc, err
|
||||
}
|
||||
plc.Properties = properties
|
||||
}
|
||||
return plc, nil
|
||||
}
|
||||
|
||||
// FromCRWorkflow converts Application CR Workflow section into velaux data store workflow
|
||||
func FromCRWorkflow(ctx context.Context, cli client.Client, appPrimaryKey string, app *v1beta1.Application) (model.Workflow, []v1beta1.WorkflowStep, error) {
|
||||
dataWf := model.Workflow{
|
||||
AppPrimaryKey: appPrimaryKey,
|
||||
// every namespace has a synced env
|
||||
EnvName: model.AutoGenEnvNamePrefix + app.Namespace,
|
||||
// every application has a synced workflow
|
||||
Name: model.AutoGenWorkflowNamePrefix + appPrimaryKey,
|
||||
Alias: model.AutoGenWorkflowNamePrefix + app.Name,
|
||||
Description: model.AutoGenDesc,
|
||||
}
|
||||
if app.Spec.Workflow == nil {
|
||||
return dataWf, nil, nil
|
||||
}
|
||||
var steps []v1beta1.WorkflowStep
|
||||
if app.Spec.Workflow.Ref != "" {
|
||||
dataWf.Name = app.Spec.Workflow.Ref
|
||||
wf := &v1alpha1.Workflow{}
|
||||
if err := cli.Get(ctx, types.NamespacedName{Namespace: app.GetNamespace(), Name: app.Spec.Workflow.Ref}, wf); err != nil {
|
||||
return dataWf, nil, err
|
||||
}
|
||||
steps = step.ConvertSteps(wf.Steps)
|
||||
} else {
|
||||
steps = app.Spec.Workflow.Steps
|
||||
}
|
||||
for _, s := range steps {
|
||||
if s.Properties == nil {
|
||||
continue
|
||||
}
|
||||
properties, err := model.NewJSONStruct(s.Properties)
|
||||
if err != nil {
|
||||
return dataWf, nil, err
|
||||
}
|
||||
dataWf.Steps = append(dataWf.Steps, model.WorkflowStep{
|
||||
Name: s.Name,
|
||||
Type: s.Type,
|
||||
Inputs: s.Inputs,
|
||||
Outputs: s.Outputs,
|
||||
DependsOn: s.DependsOn,
|
||||
Properties: properties,
|
||||
})
|
||||
}
|
||||
return dataWf, steps, nil
|
||||
}
|
||||
|
||||
// FromCRTargets converts deployed Cluster/Namespace from Application CR Status into velaux data store
|
||||
func FromCRTargets(targetApp *v1beta1.Application) []*model.Target {
|
||||
var targets []*model.Target
|
||||
nc := make(map[string]struct{})
|
||||
for _, v := range targetApp.Status.AppliedResources {
|
||||
var cluster = v.Cluster
|
||||
if cluster == "" {
|
||||
cluster = multicluster.ClusterLocalName
|
||||
}
|
||||
name := model.AutoGenTargetNamePrefix + cluster + "-" + v.Namespace
|
||||
if _, ok := nc[name]; ok {
|
||||
continue
|
||||
}
|
||||
nc[name] = struct{}{}
|
||||
targets = append(targets, &model.Target{
|
||||
Name: name,
|
||||
Cluster: &model.ClusterTarget{
|
||||
ClusterName: cluster,
|
||||
Namespace: v.Namespace,
|
||||
},
|
||||
})
|
||||
}
|
||||
return targets
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/datastore"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/log"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/model"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/rest/usecase"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
)
|
||||
|
||||
@@ -79,9 +80,10 @@ func (c *CR2UX) getApp(ctx context.Context, name, namespace string) (*model.Appl
|
||||
|
||||
// CR2UX provides the Add/Update/Delete method
|
||||
type CR2UX struct {
|
||||
ds datastore.DataStore
|
||||
cli client.Client
|
||||
cache sync.Map
|
||||
ds datastore.DataStore
|
||||
cli client.Client
|
||||
cache sync.Map
|
||||
usecases map[string]interface{}
|
||||
}
|
||||
|
||||
func formatAppComposedName(name, namespace string) string {
|
||||
@@ -106,8 +108,11 @@ func (c *CR2UX) AddOrUpdate(ctx context.Context, targetApp *v1beta1.Application)
|
||||
log.Logger.Errorf("Convert App to data store err %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err = StoreProject(ctx, dsApp.AppMeta.Project, ds); err != nil {
|
||||
pu, ok := c.usecases["project"].(usecase.ProjectUsecase)
|
||||
if !ok {
|
||||
log.Logger.Warnf("not provide project usecase instance")
|
||||
}
|
||||
if err = StoreProject(ctx, dsApp.AppMeta.Project, ds, pu); err != nil {
|
||||
log.Logger.Errorf("get or create project for sync process err %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -24,11 +24,13 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/datastore"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/log"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/model"
|
||||
v1 "github.com/oam-dev/kubevela/pkg/apiserver/rest/apis/v1"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/rest/usecase"
|
||||
"github.com/oam-dev/kubevela/pkg/utils"
|
||||
)
|
||||
|
||||
// StoreProject will create project for synced application
|
||||
func StoreProject(ctx context.Context, name string, ds datastore.DataStore) error {
|
||||
func StoreProject(ctx context.Context, name string, ds datastore.DataStore, projectUsecase usecase.ProjectUsecase) error {
|
||||
err := ds.Get(ctx, &model.Project{Name: name})
|
||||
if err == nil {
|
||||
// it means the record already exists, don't need to add anything
|
||||
@@ -38,12 +40,15 @@ func StoreProject(ctx context.Context, name string, ds datastore.DataStore) erro
|
||||
// other database error, return it
|
||||
return err
|
||||
}
|
||||
proj := &model.Project{
|
||||
Name: name,
|
||||
Description: model.AutoGenProj,
|
||||
Alias: strings.Title(name),
|
||||
if projectUsecase != nil {
|
||||
_, err := projectUsecase.CreateProject(ctx, v1.CreateProjectRequest{
|
||||
Name: name,
|
||||
Alias: strings.Title(name),
|
||||
Owner: model.DefaultAdminUserName,
|
||||
Description: model.AutoGenProj})
|
||||
return err
|
||||
}
|
||||
return ds.Add(ctx, proj)
|
||||
return nil
|
||||
}
|
||||
|
||||
// StoreAppMeta will sync application metadata from CR to datastore
|
||||
|
||||
@@ -37,7 +37,7 @@ import (
|
||||
)
|
||||
|
||||
// Start prepares watchers and run their controllers, then waits for process termination signals
|
||||
func Start(ctx context.Context, ds datastore.DataStore, cfg *rest.Config) {
|
||||
func Start(ctx context.Context, ds datastore.DataStore, cfg *rest.Config, usecases map[string]interface{}) {
|
||||
k8sClient, err := clients.GetKubeClient()
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
@@ -50,10 +50,10 @@ func Start(ctx context.Context, ds datastore.DataStore, cfg *rest.Config) {
|
||||
|
||||
f := dynamicinformer.NewFilteredDynamicSharedInformerFactory(dynamicClient, 0, v1.NamespaceAll, nil)
|
||||
|
||||
startAppSyncing(ctx, f, ds, k8sClient)
|
||||
startAppSyncing(ctx, f, ds, k8sClient, usecases)
|
||||
}
|
||||
|
||||
func startAppSyncing(ctx context.Context, factory dynamicinformer.DynamicSharedInformerFactory, ds datastore.DataStore, cli client.Client) {
|
||||
func startAppSyncing(ctx context.Context, factory dynamicinformer.DynamicSharedInformerFactory, ds datastore.DataStore, cli client.Client, usecases map[string]interface{}) {
|
||||
var err error
|
||||
informer := factory.ForResource(v1beta1.SchemeGroupVersion.WithResource("applications")).Informer()
|
||||
getApp := func(obj interface{}) *v1beta1.Application {
|
||||
@@ -62,10 +62,14 @@ func startAppSyncing(ctx context.Context, factory dynamicinformer.DynamicSharedI
|
||||
_ = json.Unmarshal(bs, app)
|
||||
return app
|
||||
}
|
||||
if usecases == nil {
|
||||
usecases = make(map[string]interface{})
|
||||
}
|
||||
cu := &CR2UX{
|
||||
ds: ds,
|
||||
cli: cli,
|
||||
cache: sync.Map{},
|
||||
ds: ds,
|
||||
cli: cli,
|
||||
cache: sync.Map{},
|
||||
usecases: usecases,
|
||||
}
|
||||
if err = cu.initCache(ctx); err != nil {
|
||||
klog.Fatal("sync app init err", err)
|
||||
|
||||
@@ -61,7 +61,7 @@ var _ = Describe("Test Worker CR sync to datastore", func() {
|
||||
By("Start syncing")
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
go Start(ctx, ds, cfg)
|
||||
go Start(ctx, ds, cfg, nil)
|
||||
|
||||
By("create test app1 and check the syncing results")
|
||||
app1 := &v1beta1.Application{}
|
||||
|
||||
Reference in New Issue
Block a user