From 728ebb33b23c2daf6173fc471cc550d244cb8b72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A9=E5=85=83?= Date: Fri, 31 Jul 2020 19:25:57 +0800 Subject: [PATCH] refactor rudr run to rudr :run --- .github/workflows/go.yml | 12 +- {pkg/cmd/util => api/types}/template_types.go | 27 +-- api/types/types.go | 10 + api/v1alpha2/groupversion_info.go | 36 ---- cmd/rudrx/main.go | 10 +- .../containerizedworkload_definition.yaml | 1 - .../workloads/deployment_definition.yaml | 1 - go.mod | 1 + go.sum | 1 + pkg/cmd/bind.go | 12 +- pkg/cmd/fixtures_test.go | 57 +++-- pkg/cmd/init.go | 33 ++- pkg/cmd/run.go | 204 ------------------ pkg/cmd/util/helpers.go | 14 +- pkg/cmd/workload/run.go | 134 ++++++++++++ pkg/cmd/{ => workload}/run_test.go | 2 +- pkg/plugins/cluster.go | 68 ++++++ pkg/plugins/cluster_test.go | 109 ++++++++++ pkg/plugins/local.go | 61 ++++++ pkg/plugins/local_test.go | 125 +++++++++++ pkg/plugins/suit_test.go | 122 +++++++++++ pkg/plugins/testdata/traitDef.yaml | 18 ++ pkg/plugins/testdata/workloadDef.yaml | 18 ++ 23 files changed, 747 insertions(+), 329 deletions(-) rename {pkg/cmd/util => api/types}/template_types.go (66%) create mode 100644 api/types/types.go delete mode 100644 api/v1alpha2/groupversion_info.go delete mode 100644 pkg/cmd/run.go create mode 100644 pkg/cmd/workload/run.go rename pkg/cmd/{ => workload}/run_test.go (99%) create mode 100644 pkg/plugins/cluster.go create mode 100644 pkg/plugins/cluster_test.go create mode 100644 pkg/plugins/local.go create mode 100644 pkg/plugins/local_test.go create mode 100644 pkg/plugins/suit_test.go create mode 100644 pkg/plugins/testdata/traitDef.yaml create mode 100644 pkg/plugins/testdata/workloadDef.yaml diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 8d6325f08..ca4589ac0 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -24,12 +24,6 @@ jobs: run: | go get -v -t -d ./... - - name: Run Make - run: make - - - name: Run Make test - run: make test - - name: Install ginkgo run: | sudo apt-get update @@ -40,6 +34,12 @@ jobs: with: version: "v0.7.0" + - name: Run Make + run: make + + - name: Run Make test + run: make test + - name: Run e2e tests run: | make e2e-setup diff --git a/pkg/cmd/util/template_types.go b/api/types/template_types.go similarity index 66% rename from pkg/cmd/util/template_types.go rename to api/types/template_types.go index 3eac20818..458080b45 100644 --- a/pkg/cmd/util/template_types.go +++ b/api/types/template_types.go @@ -14,30 +14,31 @@ See the License for the specific language governing permissions and limitations under the License. */ -package util +package types import ( "encoding/json" "fmt" "k8s.io/apimachinery/pkg/runtime" - - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) -// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! -// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. - -// TemplateSpec defines the desired state of Template +// Template defines the content of a plugin type Template struct { - // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - // Important: Run "make" to regenerate code after modifying this file - Alias string `json:"alias,omitempty"` - Object unstructured.Unstructured `json:"object,omitempty"` - LastCommandParam string `json:"lastCommandParam,omitempty"` - Parameters []Parameter `json:"parameters,omitempty"` + Name string `json:"name"` + Type DefinitionType `json:"type"` + Alias string `json:"alias,omitempty"` + Object map[string]interface{} `json:"object,omitempty"` + Parameters []Parameter `json:"parameters,omitempty"` } +type DefinitionType string + +const ( + TypeWorkload DefinitionType = "workload" + TypeTrait DefinitionType = "trait" +) + type Parameter struct { Name string `json:"name"` Short string `json:"short,omitempty"` diff --git a/api/types/types.go b/api/types/types.go new file mode 100644 index 000000000..6fbfd1c13 --- /dev/null +++ b/api/types/types.go @@ -0,0 +1,10 @@ +package types + +const ( + DefaultOAMNS = "oam-system" + DefaultOAMReleaseName = "core-runtime" + DefaultOAMChartName = "crossplane-master/oam-kubernetes-runtime" + DefaultOAMRepoName = "crossplane-master" + DefaultOAMRepoUrl = "https://charts.crossplane.io/master" + DefaultOAMVersion = ">0.0.0-0" +) diff --git a/api/v1alpha2/groupversion_info.go b/api/v1alpha2/groupversion_info.go deleted file mode 100644 index 7a87c1ae8..000000000 --- a/api/v1alpha2/groupversion_info.go +++ /dev/null @@ -1,36 +0,0 @@ -/* - - -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 v1alpha2 contains API Schema definitions for the core.oam.dev v1alpha2 API group -// +kubebuilder:object:generate=true -// +groupName=admin.oam.dev -package v1alpha2 - -import ( - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/controller-runtime/pkg/scheme" -) - -var ( - // GroupVersion is group version used to register these objects - GroupVersion = schema.GroupVersion{Group: "admin.oam.dev", Version: "v1alpha2"} - - // SchemeBuilder is used to add go types to the GroupVersionKind scheme - SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} - - // AddToScheme adds the types in this group-version to the given scheme. - AddToScheme = SchemeBuilder.AddToScheme -) diff --git a/cmd/rudrx/main.go b/cmd/rudrx/main.go index 6b3d9f84b..ed224641a 100644 --- a/cmd/rudrx/main.go +++ b/cmd/rudrx/main.go @@ -7,6 +7,8 @@ import ( "runtime" "time" + "github.com/cloud-native-application/rudrx/pkg/cmd/workload" + "github.com/crossplane/oam-kubernetes-runtime/apis/core" "github.com/spf13/cobra" k8sruntime "k8s.io/apimachinery/pkg/runtime" @@ -14,7 +16,6 @@ import ( clientgoscheme "k8s.io/client-go/kubernetes/scheme" "sigs.k8s.io/controller-runtime/pkg/client" - coreoamdevv1alpha2 "github.com/cloud-native-application/rudrx/api/v1alpha2" "github.com/cloud-native-application/rudrx/pkg/cmd" cmdutil "github.com/cloud-native-application/rudrx/pkg/cmd/util" "github.com/cloud-native-application/rudrx/pkg/utils/logs" @@ -38,8 +39,6 @@ var ( func init() { _ = clientgoscheme.AddToScheme(scheme) - _ = coreoamdevv1alpha2.AddToScheme(scheme) - _ = core.AddToScheme(scheme) // +kubebuilder:scaffold:scheme } @@ -82,7 +81,6 @@ func newCommand() *cobra.Command { } cmds.AddCommand( - cmd.NewRunCommand(f, client, ioStream, os.Args[1:]), cmd.NewTraitsCommand(f, client, ioStream, []string{}), cmd.NewWorkloadsCommand(f, client, ioStream, os.Args[1:]), cmd.NewBindCommand(f, client, ioStream, []string{}), @@ -95,6 +93,10 @@ func newCommand() *cobra.Command { cmd.NewEnvCommand(f, ioStream), NewVersionCommand(), ) + if err = workload.AddPlugins(cmds, client, ioStream); err != nil { + fmt.Println("Add plugins from workloadDefinition err", err) + os.Exit(1) + } return cmds } diff --git a/config/samples/workloads/containerizedworkload_definition.yaml b/config/samples/workloads/containerizedworkload_definition.yaml index 41f0ccf12..974a2f831 100644 --- a/config/samples/workloads/containerizedworkload_definition.yaml +++ b/config/samples/workloads/containerizedworkload_definition.yaml @@ -25,7 +25,6 @@ spec: - containerPort: 6379 protocol: TCP name: tbd # TODO(zzxwill) A temporary workaround for ContainerizedWorkload - lastCommandParam: image parameters: - name: image short: i diff --git a/config/samples/workloads/deployment_definition.yaml b/config/samples/workloads/deployment_definition.yaml index 540d0990f..42f6980dd 100644 --- a/config/samples/workloads/deployment_definition.yaml +++ b/config/samples/workloads/deployment_definition.yaml @@ -20,7 +20,6 @@ spec: - containerPort: 6379 protocol: TCP name: tbd # TODO(zzxwill) A temporary workaround for ContainerizedWorkload - lastCommandParam: image parameters: - name: image short: i diff --git a/go.mod b/go.mod index 2bfb0e936..029e66db9 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.13 require ( github.com/crossplane/crossplane-runtime v0.8.0 github.com/crossplane/oam-kubernetes-runtime v0.0.8 + github.com/ghodss/yaml v1.0.0 github.com/go-logr/logr v0.1.0 github.com/gosuri/uitable v0.0.4 github.com/onsi/ginkgo v1.11.0 diff --git a/go.sum b/go.sum index fb52d6c57..c6ec01653 100644 --- a/go.sum +++ b/go.sum @@ -185,6 +185,7 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/gertd/go-pluralize v0.1.7 h1:RgvJTJ5W7olOoAks97BOwOlekBFsLEyh00W48Z6ZEZY= github.com/gertd/go-pluralize v0.1.7/go.mod h1:O4eNeeIf91MHh1GJ2I47DNtaesm66NYvjYgAahcqSDQ= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= diff --git a/pkg/cmd/bind.go b/pkg/cmd/bind.go index b8b7572ff..516ade154 100644 --- a/pkg/cmd/bind.go +++ b/pkg/cmd/bind.go @@ -8,6 +8,8 @@ import ( "strconv" "strings" + "github.com/cloud-native-application/rudrx/api/types" + cmdutil "github.com/cloud-native-application/rudrx/pkg/cmd/util" "github.com/crossplane/crossplane-runtime/pkg/fieldpath" corev1alpha2 "github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2" @@ -18,7 +20,7 @@ import ( type commandOptions struct { Env *EnvMeta - Template cmdutil.Template + Template types.Template Component corev1alpha2.Component AppConfig corev1alpha2.ApplicationConfiguration Client client.Client @@ -62,8 +64,8 @@ func NewBindCommand(f cmdutil.Factory, c client.Client, ioStreams cmdutil.IOStre } for _, t := range traitDefinitions.Items { - var traitTemplate cmdutil.Template - traitTemplate, err := cmdutil.ConvertTemplateJson2Object(t.Spec.Extension) + var traitTemplate types.Template + traitTemplate, err := types.ConvertTemplateJson2Object(t.Spec.Extension) if err != nil { fmt.Printf("extract template from traitDefinition %v err: %v, ignore it\n", t.Name, err) continue @@ -142,13 +144,13 @@ func (o *commandOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [] cmdutil.PrintErrorMessage(errMsg, 1) } - traitTemplate, err := cmdutil.ConvertTemplateJson2Object(traitDefinition.Spec.Extension) + traitTemplate, err := types.ConvertTemplateJson2Object(traitDefinition.Spec.Extension) if err != nil { return fmt.Errorf("attaching the trait hit an issue: %s", err) } - pvd := fieldpath.Pave(traitTemplate.Object.Object) + pvd := fieldpath.Pave(traitTemplate.Object) for _, v := range traitTemplate.Parameters { flagSet := cmd.Flag(v.Name) for _, path := range v.FieldPaths { diff --git a/pkg/cmd/fixtures_test.go b/pkg/cmd/fixtures_test.go index e23b12a54..aafe0cdf4 100644 --- a/pkg/cmd/fixtures_test.go +++ b/pkg/cmd/fixtures_test.go @@ -1,13 +1,11 @@ package cmd import ( - "github.com/cloud-native-application/rudrx/pkg/cmd/util" + "github.com/cloud-native-application/rudrx/api/types" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" - "github.com/cloud-native-application/rudrx/api/v1alpha2" "github.com/crossplane/oam-kubernetes-runtime/apis/core" corev1alpha2 "github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2" ) @@ -18,37 +16,33 @@ var ( func init() { _ = clientgoscheme.AddToScheme(scheme) - _ = v1alpha2.AddToScheme(scheme) _ = core.AddToScheme(scheme) // +kubebuilder:scaffold:scheme } // used in testing var ( - workloadTemplateExample = &util.Template{ + workloadTemplateExample = &types.Template{ - Object: unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "core.oam.dev/v1alpha2", - "kind": "ContainerizedWorkload", - "metadata": map[string]interface{}{ - "name": "pod", - }, - "spec": map[string]interface{}{ - "containers": "", - }, + Object: map[string]interface{}{ + "apiVersion": "core.oam.dev/v1alpha2", + "kind": "ContainerizedWorkload", + "metadata": map[string]interface{}{ + "name": "pod", + }, + "spec": map[string]interface{}{ + "containers": "", }, }, - LastCommandParam: "image", - Parameters: []util.Parameter{ - util.Parameter{ + Parameters: []types.Parameter{ + types.Parameter{ Name: "image", Short: "i", Required: true, Type: "string", FieldPaths: []string{"spec.containers[0].image"}, }, - util.Parameter{ + types.Parameter{ Name: "port", Short: "p", Required: false, @@ -58,22 +52,21 @@ var ( }, } - traitTemplateExample = &util.Template{ + traitTemplateExample = &types.Template{ - Object: unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "core.oam.dev/v1alpha2", - "kind": "ManualScalerTrait", - "metadata": map[string]interface{}{ - "name": "pod", - }, - "spec": map[string]interface{}{ - "replicaCount": "2", - }, + Object: map[string]interface{}{ + "apiVersion": "core.oam.dev/v1alpha2", + "kind": "ManualScalerTrait", + "metadata": map[string]interface{}{ + "name": "pod", + }, + "spec": map[string]interface{}{ + "replicaCount": "2", }, }, - Parameters: []util.Parameter{ - util.Parameter{ + + Parameters: []types.Parameter{ + types.Parameter{ Name: "replicaCount", Short: "i", Required: true, diff --git a/pkg/cmd/init.go b/pkg/cmd/init.go index 64660c55e..eceee450d 100644 --- a/pkg/cmd/init.go +++ b/pkg/cmd/init.go @@ -6,6 +6,8 @@ import ( "io" "os" + "github.com/cloud-native-application/rudrx/api/types" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -50,15 +52,6 @@ type initCmd struct { version string } -const ( - DefaultOAMNS = "oam-system" - DefaultOAMReleaseName = "core-runtime" - DefaultOAMChartName = "crossplane-master/oam-kubernetes-runtime" - DefaultOAMRepoName = "crossplane-master" - DefaultOAMRepoUrl = "https://charts.crossplane.io/master" - DefaultOAMVersion = ">0.0.0-0" -) - var ( defaultObject = []interface{}{ &oamv1.WorkloadDefinition{}, @@ -92,7 +85,7 @@ func NewInitCommand(f cmdutil.Factory, c client.Client, ioStreams cmdutil.IOStre Long: initDesc, RunE: func(cmd *cobra.Command, args []string) error { i.client = c - i.namespace = DefaultOAMNS + i.namespace = types.DefaultOAMNS return i.run(ioStreams) }, } @@ -109,8 +102,8 @@ func (i *initCmd) run(ioStreams cmdutil.IOStreams) error { return fmt.Errorf("could not get kubernetes client: %s", err) } - if !cmdutil.IsNamespaceExist(i.client, DefaultOAMNS) { - if err := cmdutil.NewNamespace(i.client, DefaultOAMNS); err != nil { + if !cmdutil.IsNamespaceExist(i.client, types.DefaultOAMNS) { + if err := cmdutil.NewNamespace(i.client, types.DefaultOAMNS); err != nil { return err } } @@ -143,8 +136,8 @@ func (i *initCmd) IsOamRuntimeExist() bool { func InstallOamRuntime(ioStreams cmdutil.IOStreams, version string) error { - if !IsHelmRepositoryExist(DefaultOAMRepoName, DefaultOAMRepoUrl) { - err := AddHelmRepository(DefaultOAMRepoName, DefaultOAMRepoUrl, + if !IsHelmRepositoryExist(types.DefaultOAMRepoName, types.DefaultOAMRepoUrl) { + err := AddHelmRepository(types.DefaultOAMRepoName, types.DefaultOAMRepoUrl, "", "", "", "", "", false, ioStreams.Out) if err != nil { return err @@ -156,7 +149,7 @@ func InstallOamRuntime(ioStreams cmdutil.IOStreams, version string) error { return err } - chartRequested, err := GetChart(chartClient, DefaultOAMChartName) + chartRequested, err := GetChart(chartClient, types.DefaultOAMChartName) if err != nil { return err } @@ -174,8 +167,8 @@ func NewHelmInstall(version string, ioStreams cmdutil.IOStreams) (*action.Instal actionConfig := new(action.Configuration) if err := actionConfig.Init( - kube.GetConfig(cmdutil.GetKubeConfig(), "", DefaultOAMNS), - DefaultOAMNS, + kube.GetConfig(cmdutil.GetKubeConfig(), "", types.DefaultOAMNS), + types.DefaultOAMNS, os.Getenv("HELM_DRIVER"), ioStreams.Infof, ); err != nil { @@ -183,14 +176,14 @@ func NewHelmInstall(version string, ioStreams cmdutil.IOStreams) (*action.Instal } client := action.NewInstall(actionConfig) - client.Namespace = DefaultOAMNS - client.ReleaseName = DefaultOAMReleaseName + client.Namespace = types.DefaultOAMNS + client.ReleaseName = types.DefaultOAMReleaseName if len(version) > 0 { client.Version = version return client, nil } - client.Version = DefaultOAMVersion + client.Version = types.DefaultOAMVersion return client, nil } diff --git a/pkg/cmd/run.go b/pkg/cmd/run.go deleted file mode 100644 index f3895c43a..000000000 --- a/pkg/cmd/run.go +++ /dev/null @@ -1,204 +0,0 @@ -package cmd - -import ( - "context" - "errors" - "fmt" - "strconv" - "strings" - - "github.com/crossplane/crossplane-runtime/pkg/fieldpath" - corev1alpha2 "github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2" - "github.com/spf13/cobra" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "sigs.k8s.io/controller-runtime/pkg/client" - - cmdutil "github.com/cloud-native-application/rudrx/pkg/cmd/util" -) - -type runOptions struct { - Template cmdutil.Template - Env *EnvMeta - Component corev1alpha2.Component - AppConfig corev1alpha2.ApplicationConfiguration - client client.Client - cmdutil.IOStreams -} - -func newRunOptions(ioStreams cmdutil.IOStreams) *runOptions { - return &runOptions{IOStreams: ioStreams} -} - -// NewRunCommand init new command -func NewRunCommand(f cmdutil.Factory, c client.Client, ioStreams cmdutil.IOStreams, args []string) *cobra.Command { - cmd := newRunCommand() - // flags pass to new command directly - cmd.DisableFlagParsing = true - cmd.SetArgs(args) - cmd.SetOut(ioStreams.Out) - - cmd.RunE = func(cmd *cobra.Command, args []string) error { - return runSubRunCommand(cmd, f, c, ioStreams, args) - } - return cmd -} - -// runSubRunCommand is init a new command and run independent -func runSubRunCommand(parentCmd *cobra.Command, f cmdutil.Factory, c client.Client, ioStreams cmdutil.IOStreams, args []string) error { - ctx := context.Background() - workloadNames := []string{} - o := newRunOptions(ioStreams) - o.client = c - o.Env, _ = GetEnv() - - // init fake command and pass args to fake command - // flags and subcommand append to fake comand and parent command - // run fake command only, show tips in parent command only - fakeCommand := newRunCommand() - fakeCommand.SilenceUsage = true - fakeCommand.SilenceErrors = true - fakeCommand.DisableAutoGenTag = true - fakeCommand.DisableFlagsInUseLine = true - fakeCommand.DisableSuggestions = true - - // set args from parent - if len(args) > 0 { - fakeCommand.SetArgs(args) - } else { - fakeCommand.SetArgs([]string{}) - } - fakeCommand.SetOut(o.Out) - fakeCommand.RunE = func(cmd *cobra.Command, args []string) error { - return errors.New("You must specify a workload, like " + strings.Join(workloadNames, ", ") + - "\nSee 'rudr run -h' for help and examples") - } - fakeCommand.PersistentFlags().StringP("namespace", "n", "default", "namespace for apps") - parentCmd.PersistentFlags().StringP("namespace", "n", "default", "namespace for apps") - - var workloadDefs corev1alpha2.WorkloadDefinitionList - err := c.List(ctx, &workloadDefs) - if err != nil { - return fmt.Errorf("listing Workload definition hit an issue: %s", err) - } - - for _, wd := range workloadDefs.Items { - var tmp cmdutil.Template - tmp, err := cmdutil.ConvertTemplateJson2Object(wd.Spec.Extension) - if err != nil { - fmt.Printf("extract template from traitDefinition %v err: %v, ignore it\n", wd.Name, err) - continue - } - name := tmp.Alias - workloadNames = append(workloadNames, name) - - subcmd := &cobra.Command{ - Use: name + " [args]", - DisableFlagsInUseLine: true, - Short: "Run " + name + " workloads", - Long: "Run " + name + " workloads", - RunE: func(cmd *cobra.Command, args []string) error { - if err := o.Complete(f, cmd, args, ctx); err != nil { - return err - } - return o.Run(f, cmd) - }, - } - subcmd.SetOut(o.Out) - for _, v := range tmp.Parameters { - if tmp.LastCommandParam != v.Name { - subcmd.PersistentFlags().StringP(v.Name, v.Short, v.Default, v.Usage) - } - } - - // Comment this line as template content will get mixed when there are more than two WorkloadDefinitions - // tmp.DeepCopyInto(&o.Template) - o.Template = tmp - fakeCommand.AddCommand(subcmd) - parentCmd.AddCommand(subcmd) - } - - return fakeCommand.Execute() -} - -func (o *runOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string, ctx context.Context) error { - - argsLength := len(args) - lastCommandParam := o.Template.LastCommandParam - - if argsLength < 1 { - return errors.New("must specify name for workload") - } else if argsLength >= 1 { - workloadName := args[0] - - switch { - case argsLength < 2 && lastCommandParam != "": - // TODO(zzxwill): Could not determine whether the argument is the workload name or image name if without image tag - return fmt.Errorf("You must specify `%s` as the last command.\nSee 'rudr run -h' for help and examples", - lastCommandParam) - case argsLength == 2: - workloadTemplate := o.Template - pvd := fieldpath.Pave(workloadTemplate.Object.Object) - for _, v := range workloadTemplate.Parameters { - lastCommandValue := args[argsLength-1] - var paraV string - if v.Name == lastCommandParam { - paraV = lastCommandValue - } else { - flagSet := cmd.Flag(v.Name) - paraV = flagSet.Value.String() - } - - if paraV == "" { - return fmt.Errorf("Flag `%s` is NOT set, please check and try again. \nSee 'rudr run -h' for help and examples", v.Name) - } - - for _, path := range v.FieldPaths { - if v.Type == "int" { - portValue, _ := strconv.ParseFloat(paraV, 64) - pvd.SetNumber(path, portValue) - break - } - pvd.SetString(path, paraV) - } - } - - pvd.SetString("metadata.name", strings.ToLower(workloadName)) - namespace := o.Env.Namespace - o.Component.Spec.Workload.Object = &unstructured.Unstructured{Object: pvd.UnstructuredContent()} - o.Component.Name = args[0] - o.Component.Namespace = namespace - o.AppConfig.Name = args[0] - o.AppConfig.Namespace = namespace - o.AppConfig.Spec.Components = append(o.AppConfig.Spec.Components, corev1alpha2.ApplicationConfigurationComponent{ComponentName: args[0]}) - - case argsLength > 2: - return fmt.Errorf("there are more commands than needed, please try again") - } - } - return nil -} - -func (o *runOptions) Run(f cmdutil.Factory, cmd *cobra.Command) error { - o.Infof("Creating AppConfig %s\n", o.AppConfig.Name) - err := o.client.Create(context.Background(), &o.Component) - if err != nil { - return fmt.Errorf("create component err: %s", err) - } - err = o.client.Create(context.Background(), &o.AppConfig) - if err != nil { - return fmt.Errorf("create appconfig err %s", err) - } - o.Info("SUCCEED") - return nil -} - -func newRunCommand() *cobra.Command { - return &cobra.Command{ - Use: "run [WORKLOAD_KIND] [args]", - DisableFlagsInUseLine: true, - Short: "Run OAM workloads", - Long: "Create and Run one Workload one AppConfig OAM APP", - Example: ` - rudr run containerized frontend -p 80 oam-dev/demo:v1 -`} -} diff --git a/pkg/cmd/util/helpers.go b/pkg/cmd/util/helpers.go index 1ea3e5675..ddb48d27c 100644 --- a/pkg/cmd/util/helpers.go +++ b/pkg/cmd/util/helpers.go @@ -5,6 +5,8 @@ import ( "os" "strings" + "github.com/cloud-native-application/rudrx/api/types" + v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" corev1alpha2 "github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2" @@ -172,7 +174,7 @@ func GetTraitDefinitionByAlias(ctx context.Context, c client.Client, traitAlias err := c.List(ctx, &traitDefinitionList) if err == nil { for _, t := range traitDefinitionList.Items { - template, err := ConvertTemplateJson2Object(t.Spec.Extension) + template, err := types.ConvertTemplateJson2Object(t.Spec.Extension) if err == nil && strings.EqualFold(template.Alias, traitAlias) { traitDefinition = t break @@ -190,14 +192,14 @@ func GetTraitNameAliasKind(ctx context.Context, c client.Client, namespace strin t, err := GetTraitDefinitionByName(ctx, c, namespace, name) if err == nil { - template, err := ConvertTemplateJson2Object(t.Spec.Extension) + template, err := types.ConvertTemplateJson2Object(t.Spec.Extension) if err == nil { tName, tAlias = t.Name, template.Alias } } else { t, err := GetTraitDefinitionByAlias(ctx, c, name) if err == nil { - template, err := ConvertTemplateJson2Object(t.Spec.Extension) + template, err := types.ConvertTemplateJson2Object(t.Spec.Extension) if err == nil { tName, tAlias = t.Name, template.Alias } @@ -230,15 +232,15 @@ func GetWorkloadNameAliasKind(ctx context.Context, c client.Client, namespace st w, err := GetWorkloadDefinitionByName(ctx, c, namespace, workloadName) if err == nil { // workloadName is complete name - var workloadTemplate Template - workloadTemplate, err := ConvertTemplateJson2Object(w.Spec.Extension) + var workloadTemplate types.Template + workloadTemplate, err := types.ConvertTemplateJson2Object(w.Spec.Extension) if err == nil { name, alias = w.Name, workloadTemplate.Alias } } else { // workloadName is alias or kind w, err := GetWorkloadDefinitionByAlias(ctx, c, name) if err == nil { - workloadTemplate, err := ConvertTemplateJson2Object(w.Spec.Extension) + workloadTemplate, err := types.ConvertTemplateJson2Object(w.Spec.Extension) if err == nil { name, alias, kind = w.Name, workloadTemplate.Alias, w.Kind } diff --git a/pkg/cmd/workload/run.go b/pkg/cmd/workload/run.go new file mode 100644 index 000000000..88658e211 --- /dev/null +++ b/pkg/cmd/workload/run.go @@ -0,0 +1,134 @@ +package workload + +import ( + "context" + "errors" + "fmt" + "strconv" + "strings" + + "github.com/cloud-native-application/rudrx/api/types" + + "github.com/cloud-native-application/rudrx/pkg/plugins" + + "github.com/cloud-native-application/rudrx/pkg/cmd" + + "github.com/crossplane/crossplane-runtime/pkg/fieldpath" + corev1alpha2 "github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2" + "github.com/spf13/cobra" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "sigs.k8s.io/controller-runtime/pkg/client" + + cmdutil "github.com/cloud-native-application/rudrx/pkg/cmd/util" +) + +type runOptions struct { + Template types.Template + Env *cmd.EnvMeta + Component corev1alpha2.Component + AppConfig corev1alpha2.ApplicationConfiguration + client client.Client + cmdutil.IOStreams +} + +func newRunOptions(ioStreams cmdutil.IOStreams) *runOptions { + return &runOptions{IOStreams: ioStreams} +} + +func AddPlugins(parentCmd *cobra.Command, c client.Client, ioStreams cmdutil.IOStreams) error { + templates, err := plugins.GetWorkloadsFromCluster(context.TODO(), types.DefaultOAMNS, c) + if err != nil { + return err + } + + for _, tmp := range templates { + var name string + if tmp.Alias != "" { + name = tmp.Alias + } + o := newRunOptions(ioStreams) + o.client = c + o.Env, _ = cmd.GetEnv() + pluginCmd := &cobra.Command{ + Use: name + ":run [args]", + DisableFlagsInUseLine: true, + Short: "Run " + name + " workloads", + Long: "Run " + name + " workloads", + RunE: func(cmd *cobra.Command, args []string) error { + if err := o.Complete(cmd, args, context.TODO()); err != nil { + return err + } + return o.Run(cmd) + }, + } + pluginCmd.SetOut(o.Out) + for _, v := range tmp.Parameters { + pluginCmd.Flags().StringP(v.Name, v.Short, v.Default, v.Usage) + if v.Required { + pluginCmd.MarkFlagRequired(v.Name) + } + } + + o.Template = tmp + parentCmd.AddCommand(pluginCmd) + } + return nil +} + +func (o *runOptions) Complete(cmd *cobra.Command, args []string, ctx context.Context) error { + + argsLength := len(args) + + if argsLength < 1 { + return errors.New("must specify name for workload") + } + + workloadName := args[0] + + workloadTemplate := o.Template + pvd := fieldpath.Pave(workloadTemplate.Object) + for _, v := range workloadTemplate.Parameters { + var paraV string + + flagSet := cmd.Flag(v.Name) + paraV = flagSet.Value.String() + + if paraV == "" { + continue + } + + for _, path := range v.FieldPaths { + if v.Type == "int" { + portValue, _ := strconv.ParseFloat(paraV, 64) + pvd.SetNumber(path, portValue) + break + } + pvd.SetString(path, paraV) + } + } + + pvd.SetString("metadata.name", strings.ToLower(workloadName)) + namespace := o.Env.Namespace + o.Component.Spec.Workload.Object = &unstructured.Unstructured{Object: pvd.UnstructuredContent()} + o.Component.Name = args[0] + o.Component.Namespace = namespace + o.AppConfig.Name = args[0] + o.AppConfig.Namespace = namespace + o.AppConfig.Spec.Components = append(o.AppConfig.Spec.Components, corev1alpha2.ApplicationConfigurationComponent{ComponentName: args[0]}) + + return nil +} + +func (o *runOptions) Run(cmd *cobra.Command) error { + o.Infof("Creating AppConfig %s\n", o.AppConfig.Name) + err := o.client.Create(context.Background(), &o.Component) + if err != nil { + return fmt.Errorf("create component err: %s", err) + } + err = o.client.Create(context.Background(), &o.AppConfig) + if err != nil { + return fmt.Errorf("create appconfig err %s", err) + } + o.Info("SUCCEED") + return nil +} diff --git a/pkg/cmd/run_test.go b/pkg/cmd/workload/run_test.go similarity index 99% rename from pkg/cmd/run_test.go rename to pkg/cmd/workload/run_test.go index 921b088e4..49cf921af 100644 --- a/pkg/cmd/run_test.go +++ b/pkg/cmd/workload/run_test.go @@ -1,4 +1,4 @@ -package cmd +package workload /* func TestNewRunCommand(t *testing.T) { diff --git a/pkg/plugins/cluster.go b/pkg/plugins/cluster.go new file mode 100644 index 000000000..0e62b2969 --- /dev/null +++ b/pkg/plugins/cluster.go @@ -0,0 +1,68 @@ +package plugins + +import ( + "context" + "fmt" + + "github.com/cloud-native-application/rudrx/api/types" + + corev1alpha2 "github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func GetTemplatesFromCluster(ctx context.Context, namespace string, c client.Client) ([]types.Template, error) { + workloads, err := GetWorkloadsFromCluster(ctx, namespace, c) + if err != nil { + return nil, err + } + traits, err := GetTraitsFromCluster(ctx, namespace, c) + if err != nil { + return nil, err + } + workloads = append(workloads, traits...) + return workloads, nil +} + +func GetWorkloadsFromCluster(ctx context.Context, namespace string, c client.Client) ([]types.Template, error) { + var templates []types.Template + var workloadDefs corev1alpha2.WorkloadDefinitionList + err := c.List(ctx, &workloadDefs, &client.ListOptions{Namespace: namespace}) + if err != nil { + return nil, fmt.Errorf("list WorkloadDefinition err: %s", err) + } + + for _, wd := range workloadDefs.Items { + var tmp types.Template + tmp, err := types.ConvertTemplateJson2Object(wd.Spec.Extension) + if err != nil { + fmt.Printf("extract template from workloadDefinition %v err: %v, ignore it\n", wd.Name, err) + continue + } + tmp.Type = types.TypeWorkload + tmp.Name = wd.Name + templates = append(templates, tmp) + } + return templates, nil +} + +func GetTraitsFromCluster(ctx context.Context, namespace string, c client.Client) ([]types.Template, error) { + var templates []types.Template + var traitDefs corev1alpha2.TraitDefinitionList + err := c.List(ctx, &traitDefs, &client.ListOptions{Namespace: namespace}) + if err != nil { + return nil, fmt.Errorf("list TraitDefinition err: %s", err) + } + + for _, td := range traitDefs.Items { + var tmp types.Template + tmp, err := types.ConvertTemplateJson2Object(td.Spec.Extension) + if err != nil { + fmt.Printf("extract template from workloadDefinition %v err: %v, ignore it\n", td.Name, err) + continue + } + tmp.Type = types.TypeTrait + tmp.Name = td.Name + templates = append(templates, tmp) + } + return templates, nil +} diff --git a/pkg/plugins/cluster_test.go b/pkg/plugins/cluster_test.go new file mode 100644 index 000000000..c8865c6db --- /dev/null +++ b/pkg/plugins/cluster_test.go @@ -0,0 +1,109 @@ +package plugins + +import ( + "context" + "fmt" + "io/ioutil" + + "github.com/cloud-native-application/rudrx/api/types" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/ghodss/yaml" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + corev1 "k8s.io/api/core/v1" + logf "sigs.k8s.io/controller-runtime/pkg/log" + + "github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2" + "github.com/crossplane/oam-kubernetes-runtime/pkg/oam/util" +) + +var _ = Describe("DefinitionFiles", func() { + ctx := context.Background() + route := types.Template{ + Name: "routes.extend.oam.dev", + Type: types.TypeTrait, + Alias: "route", + Object: map[string]interface{}{ + "apiVersion": "extend.oam.dev/v1alpha2", + "kind": "Route", + }, + Parameters: []types.Parameter{ + { + Name: "domain", + Short: "d", + Required: true, + FieldPaths: []string{"spec.domain"}, + }, + }, + } + deployment := types.Template{ + Name: "deployments.testapps", + Type: types.TypeWorkload, + Alias: "deployment", + Object: map[string]interface{}{ + "apiVersion": "core.oam.dev/v1alpha2", + "kind": "Deployment", + }, + Parameters: []types.Parameter{ + { + Name: "image", + Short: "i", + Required: true, + FieldPaths: []string{"spec.containers[0].image"}, + }, + }, + } + + BeforeEach(func() { + Expect(k8sClient.Create(ctx, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: DefinitionNamespace}})).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{})) + + traitdata, err := ioutil.ReadFile("testdata/traitDef.yaml") + Expect(err).Should(BeNil()) + var td v1alpha2.TraitDefinition + Expect(yaml.Unmarshal(traitdata, &td)).Should(BeNil()) + + td.Namespace = DefinitionNamespace + logf.Log.Info("Creating trait definition", "data", td) + Expect(k8sClient.Create(ctx, &td)).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{})) + + workloaddata, err := ioutil.ReadFile("testdata/workloadDef.yaml") + Expect(err).Should(BeNil()) + var wd v1alpha2.WorkloadDefinition + Expect(yaml.Unmarshal(workloaddata, &wd)).Should(BeNil()) + + wd.Namespace = DefinitionNamespace + logf.Log.Info("Creating workload definition", "data", wd) + Expect(k8sClient.Create(ctx, &wd)).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{})) + + }) + + // Notice!! Definition Object is Cluster Scope object + // which means objects created in other DefinitionNamespace will also affect here. + It("gettrait", func() { + traitDefs, err := GetTraitsFromCluster(context.Background(), DefinitionNamespace, k8sClient) + Expect(err).Should(BeNil()) + logf.Log.Info(fmt.Sprintf("Getting trait definitions %v", traitDefs)) + + Expect(traitDefs).Should(Equal([]types.Template{route})) + }) + // Notice!! Definition Object is Cluster Scope object + // which means objects created in other DefinitionNamespace will also affect here. + It("getworkload", func() { + workloadDefs, err := GetWorkloadsFromCluster(context.Background(), DefinitionNamespace, k8sClient) + Expect(err).Should(BeNil()) + logf.Log.Info(fmt.Sprintf("Getting workload definitions %v", workloadDefs)) + + Expect(workloadDefs).Should(Equal([]types.Template{deployment})) + }) + It("getall", func() { + alldef, err := GetTemplatesFromCluster(context.Background(), DefinitionNamespace, k8sClient) + Expect(err).Should(BeNil()) + logf.Log.Info(fmt.Sprintf("Getting all definitions %v", alldef)) + + Expect(alldef).Should(Equal([]types.Template{deployment, route})) + }) +}) diff --git a/pkg/plugins/local.go b/pkg/plugins/local.go new file mode 100644 index 000000000..5b184bfbd --- /dev/null +++ b/pkg/plugins/local.go @@ -0,0 +1,61 @@ +package plugins + +import ( + "encoding/json" + "io/ioutil" + "path/filepath" + + "github.com/cloud-native-application/rudrx/api/types" +) + +func GetDefFromLocal(dir string, defType types.DefinitionType) ([]types.Template, error) { + temps, err := LoadTempFromLocal(dir) + if err != nil { + return nil, err + } + var defs []types.Template + for _, t := range temps { + if t.Type != defType { + continue + } + defs = append(defs, t) + } + return defs, nil +} + +func SinkTemp2Local(templates []types.Template, dir string) error { + for _, tmp := range templates { + data, err := json.Marshal(tmp) + if err != nil { + return err + } + err = ioutil.WriteFile(filepath.Join(dir, tmp.Name), data, 0644) + if err != nil { + return err + } + } + return nil +} + +func LoadTempFromLocal(dir string) ([]types.Template, error) { + var tmps []types.Template + files, err := ioutil.ReadDir(dir) + if err != nil { + return nil, err + } + for _, f := range files { + if f.IsDir() { + continue + } + data, err := ioutil.ReadFile(filepath.Join(dir, f.Name())) + if err != nil { + return nil, err + } + var tmp types.Template + if err = json.Unmarshal(data, &tmp); err != nil { + return nil, err + } + tmps = append(tmps, tmp) + } + return tmps, nil +} diff --git a/pkg/plugins/local_test.go b/pkg/plugins/local_test.go new file mode 100644 index 000000000..d4e9373b9 --- /dev/null +++ b/pkg/plugins/local_test.go @@ -0,0 +1,125 @@ +package plugins + +import ( + "os" + "testing" + + "github.com/cloud-native-application/rudrx/api/types" + + "github.com/stretchr/testify/assert" +) + +func TestLocalSink(t *testing.T) { + deployment := types.Template{ + Name: "deployment", + Type: types.TypeWorkload, + Alias: "deployment", + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + }, + Parameters: []types.Parameter{ + { + Name: "image", + Short: "i", + Required: true, + FieldPaths: []string{"spec.containers[0].image"}, + }, + }, + } + statefulset := types.Template{ + Name: "statefulset", + Type: types.TypeWorkload, + Alias: "stateful", + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Statefulset", + }, + Parameters: []types.Parameter{ + { + Name: "image", + Short: "i", + Required: true, + FieldPaths: []string{"spec.containers[0].image"}, + }, + }, + } + route := types.Template{ + Name: "route", + Type: types.TypeTrait, + Alias: "route", + Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Route", + }, + Parameters: []types.Parameter{ + { + Name: "domain", + Short: "d", + Required: true, + FieldPaths: []string{"spec.domain"}, + }, + }, + } + + cases := map[string]struct { + dir string + tmps []types.Template + Type types.DefinitionType + expDef []types.Template + }{ + "Test No Templates": { + dir: "rudrx-test1", + tmps: nil, + }, + "Test Only Workload": { + dir: "rudrx-test2", + tmps: []types.Template{deployment, statefulset}, + Type: types.TypeWorkload, + expDef: []types.Template{deployment, statefulset}, + }, + "Test Only Trait": { + dir: "rudrx-test3", + tmps: []types.Template{route}, + Type: types.TypeTrait, + expDef: []types.Template{route}, + }, + "Test Only Workload But want trait": { + dir: "rudrx-test3", + tmps: []types.Template{deployment, statefulset}, + Type: types.TypeTrait, + expDef: nil, + }, + "Test Both have Workload and trait But want Workload": { + dir: "rudrx-test4", + tmps: []types.Template{deployment, route, statefulset}, + Type: types.TypeWorkload, + expDef: []types.Template{deployment, statefulset}, + }, + "Test Both have Workload and trait But want Trait": { + dir: "rudrx-test5", + tmps: []types.Template{deployment, route, statefulset}, + Type: types.TypeTrait, + expDef: []types.Template{route}, + }, + } + for name, c := range cases { + testInDir(t, name, c.dir, c.tmps, c.expDef, c.Type) + } +} + +func testInDir(t *testing.T, casename, dir string, tmps, defexp []types.Template, Type types.DefinitionType) { + err := os.MkdirAll(dir, 0755) + assert.NoError(t, err, casename) + defer os.RemoveAll(dir) + err = SinkTemp2Local(tmps, dir) + assert.NoError(t, err, casename) + gottmps, err := LoadTempFromLocal(dir) + assert.NoError(t, err, casename) + assert.Equal(t, tmps, gottmps, casename) + if Type != "" { + gotDef, err := GetDefFromLocal(dir, Type) + assert.NoError(t, err, casename) + assert.Equal(t, defexp, gotDef, casename) + } +} diff --git a/pkg/plugins/suit_test.go b/pkg/plugins/suit_test.go new file mode 100644 index 000000000..6943fdb16 --- /dev/null +++ b/pkg/plugins/suit_test.go @@ -0,0 +1,122 @@ +package plugins + +import ( + "context" + "path/filepath" + "testing" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + + "github.com/crossplane/oam-kubernetes-runtime/pkg/oam/util" + + corev1alpha2 "github.com/crossplane/oam-kubernetes-runtime/apis/core" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" + "sigs.k8s.io/controller-runtime/pkg/envtest/printer" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + // +kubebuilder:scaffold:imports +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +var cfg *rest.Config +var k8sClient client.Client +var testEnv *envtest.Environment + +func TestAPIs(t *testing.T) { + RegisterFailHandler(Fail) + + RunSpecsWithDefaultAndCustomReporters(t, + "CLI Suite", + []Reporter{printer.NewlineReporter{}}) +} + +var _ = BeforeSuite(func(done Done) { + logf.SetLogger(zap.LoggerTo(GinkgoWriter, true)) + + By("bootstrapping test environment") + useExistCluster := true + testEnv = &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")}, + UseExistingCluster: &useExistCluster, + } + + var err error + cfg, err = testEnv.Start() + Expect(err).ToNot(HaveOccurred()) + Expect(cfg).ToNot(BeNil()) + scheme := runtime.NewScheme() + Expect(corev1alpha2.AddToScheme(scheme)).NotTo(HaveOccurred()) + Expect(clientgoscheme.AddToScheme(scheme)).NotTo(HaveOccurred()) + Expect(v1beta1.AddToScheme(scheme)).NotTo(HaveOccurred()) + + k8sClient, err = client.New(cfg, client.Options{Scheme: scheme}) + Expect(err).ToNot(HaveOccurred()) + Expect(k8sClient).ToNot(BeNil()) + + crd := v1beta1.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: "traitdefinitions.core.oam.dev", + }, + Spec: v1beta1.CustomResourceDefinitionSpec{ + Group: "core.oam.dev", + Names: v1beta1.CustomResourceDefinitionNames{ + Kind: "TraitDefinition", + ListKind: "TraitDefinitionList", + Plural: "traitdefinitions", + Singular: "traitdefinition", + }, + Versions: []v1beta1.CustomResourceDefinitionVersion{ + { + Name: "v1alpha2", + Served: true, + Storage: true, + }, + }, + }, + } + Expect(k8sClient.Create(context.Background(), &crd)).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{})) + + crd = v1beta1.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: "workloaddefinitions.core.oam.dev", + }, + Spec: v1beta1.CustomResourceDefinitionSpec{ + Group: "core.oam.dev", + Names: v1beta1.CustomResourceDefinitionNames{ + Kind: "WorkloadDefinition", + ListKind: "WorkloadDefinitionList", + Plural: "workloaddefinitions", + Singular: "workloaddefinition", + }, + Versions: []v1beta1.CustomResourceDefinitionVersion{ + { + Name: "v1alpha2", + Served: true, + Storage: true, + }, + }, + }, + } + Expect(k8sClient.Create(context.Background(), &crd)).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{})) + close(done) +}, 60) + +var DefinitionNamespace = "testdef" +var _ = AfterSuite(func() { + By("tearing down the test environment") + k8sClient.Delete(context.Background(), &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: DefinitionNamespace}}) + + err := testEnv.Stop() + Expect(err).ToNot(HaveOccurred()) +}) diff --git a/pkg/plugins/testdata/traitDef.yaml b/pkg/plugins/testdata/traitDef.yaml new file mode 100644 index 000000000..febb7f65c --- /dev/null +++ b/pkg/plugins/testdata/traitDef.yaml @@ -0,0 +1,18 @@ +apiVersion: core.oam.dev/v1alpha2 +kind: TraitDefinition +metadata: + name: routes.extend.oam.dev +spec: + definitionRef: + name: routes.extend.oam.dev + extension: + alias: route + object: + apiVersion: extend.oam.dev/v1alpha2 + kind: Route + parameters: + - name: domain + required: true + short: d + fieldPaths: + - "spec.domain" diff --git a/pkg/plugins/testdata/workloadDef.yaml b/pkg/plugins/testdata/workloadDef.yaml new file mode 100644 index 000000000..839025546 --- /dev/null +++ b/pkg/plugins/testdata/workloadDef.yaml @@ -0,0 +1,18 @@ +apiVersion: core.oam.dev/v1alpha2 +kind: WorkloadDefinition +metadata: + name: deployments.testapps +spec: + definitionRef: + name: deployments.testapps + extension: + alias: deployment + object: + apiVersion: core.oam.dev/v1alpha2 + kind: Deployment + parameters: + - name: image + short: i + required: true + fieldPaths: + - "spec.containers[0].image" \ No newline at end of file