diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a0ebeab77..23e51475b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,12 +5,10 @@ contributing to `kubevela` or build a PoC (Proof of Concept). ## Prerequisites -1. Golang version 1.12+ -2. Kubernetes version v1.15+ with `~/.kube/config` configured. -3. OAM Kubernetes Runtime installed. -4. Kustomize version 3.8+ -5. ginkgo 1.14.0+ (just for [E2E test](https://github.com/oam-dev/kubevela/blob/master/DEVELOPMENT.md#e2e-test)) -6. golangci-lint 1.31.0+, it will install automatically if you run `make`, you can [install it manually](https://golangci-lint.run/usage/install/#local-installation) if the installation is too slow. +1. Golang version 1.13+ +2. Kubernetes version v1.16+ with `~/.kube/config` configured. +3. ginkgo 1.14.0+ (just for [E2E test](https://github.com/oam-dev/kubevela/blob/master/DEVELOPMENT.md#e2e-test)) +4. golangci-lint 1.31.0+, it will install automatically if you run `make`, you can [install it manually](https://golangci-lint.run/usage/install/#local-installation) if the installation is too slow. ## Build * Clone this project @@ -19,96 +17,89 @@ contributing to `kubevela` or build a PoC (Proof of Concept). git clone git@github.com:oam-dev/kubevela.git ``` -* Install Template CRD into your cluster +* Build Vela CLI ```shell script -make install +make ``` -* Install template object +* Configure vela to PATH + +after build, make will create `vela` binary to `bin/`, Set this path to PATH. ```shell script -kubectl apply -f config/samples/ +export PATH=$PATH:/your/path/to/project/kubevela/bin ``` -## Develop & Debug -If you change Template CRD, remember to rerun `make install`. - -Use the following command to develop and debug. +* Install Vela Core ```shell script -$ cd cmd/vela -$ go run main.go COMMAND [FLAG] +vela install ``` +## Use + +* Create ENV + +```shell script +vela env init myenv --namespace myenv --email my@email.com --domain kubevela.io +``` + +* Create Component + For example, use the following command to create and run an application. + ```shell script -$ go run main.go run containerized app2057 nginx:1.9.4 -Creating AppConfig app2057 +$ vela comp run mycomp -t webservice --image crccheck/hello-world --port 8000 +Creating AppConfig appcomp SUCCEED - -$ kubectl get oam -NAME WORKLOAD-KIND -component.core.oam.dev/app2057 ContainerizedWorkload - -NAME AGE -containerizedworkload.core.oam.dev/poc 53m - -NAME AGE -applicationconfiguration.core.oam.dev/app2057 69s - -NAME DEFINITION-NAME -traitdefinition.core.oam.dev/simplerollouttraits.extend.oam.dev simplerollouttraits.extend.oam.dev - -NAME DEFINITION-NAME -workloaddefinition.core.oam.dev/containerizedworkloads.core.oam.dev containerizedworkloads.core.oam.dev -workloaddefinition.core.oam.dev/deployments.apps deployments.apps -workloaddefinition.core.oam.dev/statefulsets.apps statefulsets.apps ``` -## E2E test -``` -$ make e2e-test -Running Suite: Trait Suite -========================== -Random Seed: 1596559178 -Will run 5 of 5 specs +* Add Trait -Trait env init - should print env initiation successful message - kubevela/e2e/commonContext.go:14 -Create env succeed, current env is default -• ------------------------------- -Trait env set - should show env set message - kubevela/e2e/commonContext.go:40 -Set env succeed, current env is default -• ------------------------------- -Trait run - should print successful creation information - kubevela/e2e/commonContext.go:76 -Creating AppConfig app-trait-basic -SUCCEED -• ------------------------------- -Trait kubevela attach trait - should print successful attached information - kubevela/e2e/trait/trait_test.go:24 -Applying trait for app +```shell script +$ vela route mycomp +Adding route for app abc Succeeded! -• ------------------------------- -Trait delete - should print successful deletion information - kubevela/e2e/commonContext.go:85 -Deleting AppConfig "app-trait-basic" -DELETE SUCCEED -• -Ran 5 of 5 Specs in 9.717 seconds -SUCCESS! -- 5 Passed | 0 Failed | 0 Pending | 0 Skipped -PASS +``` + +* Check Status + +``` +$ vela comp status abc +Showing status of Component abc deployed in Environment t2 +Component Status: + Name: abc Containerized(type) UNKNOWN APIVersion standard.oam.dev/v1alpha1 Kind Containerized workload is unknown for HealthScope + Traits + └─Trait/route + +Last Deployment: + Created at: 2020-09-18 18:47:09 +0800 CST + Updated at: 2020-09-18T18:47:16+08:00 +``` + +* Delete App + +```shell script +$ vela app ls +abc + +$ vela app delete abc +Deleting Application "abc" +delete apps succeed abc from t2 +``` + +## Tests + +### Unit test + +```shell script +make test +``` + +### E2E test +``` +make e2e-test ``` ## Make a pull request diff --git a/README.md b/README.md index 5c2bfdda1..ef5712741 100644 --- a/README.md +++ b/README.md @@ -29,38 +29,54 @@ This command will install vela core controller into your K8s cluster, along with ## Demos -#### Check workloads - -``` -$ vela workloads - NAME DEFINITION - backend containerizeds.standard.oam.dev - task jobs - webservice containerizeds.standard.oam.dev -``` - -#### workload run +* Create ENV + ```shell script -$ vela comp run -t webservice app123 -p 80 --image nginx:1.9.4 -Creating AppConfig app123 +vela env init myenv --namespace myenv --email my@email.com --domain kubevela.io +``` + +* Create Component + +For example, use the following command to create and run an application. + +```shell script +$ vela comp run mycomp -t webservice --image crccheck/hello-world --port 8000 +Creating AppConfig appcomp SUCCEED - -$ vela comp status app123 - -$ vela comp ls -NAME APP WORKLOAD TRAITS STATUS CREATED-TIME -app123 app123 deployment Deployed 2020-08-27 10:56:41 +0800 CST ``` -#### app +* Add Trait + +```shell script +$ vela route mycomp +Adding route for app abc +Succeeded! +``` + +* Check Status ``` +$ vela comp status abc +Showing status of Component abc deployed in Environment t2 +Component Status: + Name: abc Containerized(type) UNKNOWN APIVersion standard.oam.dev/v1alpha1 Kind Containerized workload is unknown for HealthScope + Traits + └─Trait/route + +Last Deployment: + Created at: 2020-09-18 18:47:09 +0800 CST + Updated at: 2020-09-18T18:47:16+08:00 +``` + +* Delete App + +```shell script $ vela app ls -app123 +abc -$ vela app delete app123 -Deleting AppConfig "app123" -DELETE SUCCEED +$ vela app delete abc +Deleting Application "abc" +delete apps succeed abc from t2 ``` #### Auto-Completion diff --git a/api/types/types.go b/api/types/types.go index 5264aabe3..45544a083 100644 --- a/api/types/types.go +++ b/api/types/types.go @@ -27,8 +27,13 @@ const ( type EnvMeta struct { Name string `json:"name"` - Current string `json:"current,omitempty"` Namespace string `json:"namespace"` + Email string `json:"email,omitempty"` + Domain string `json:"domain,omitempty"` + + // Below are not arguments, should be auto-generated + Issuer string `json:"issuer"` + Current string `json:"current,omitempty"` } const ( diff --git a/charts/vela-core/templates/routetrait.yaml b/charts/vela-core/templates/routetrait.yaml new file mode 100644 index 000000000..f1879f352 --- /dev/null +++ b/charts/vela-core/templates/routetrait.yaml @@ -0,0 +1,37 @@ +apiVersion: core.oam.dev/v1alpha2 +kind: TraitDefinition +metadata: + name: routes.standard.oam.dev + annotations: + definition.oam.dev/apiVersion: standard.oam.dev/v1alpha1 + definition.oam.dev/kind: Route +spec: + appliesToWorkloads: + - core.oam.dev/v1alpha2.ContainerizedWorkload + - standard.oam.dev/v1alpha1.Containerized + - deployments.apps + workloadRefPath: spec.workloadRef + definitionRef: + name: routes.standard.oam.dev + extension: + template: | + #Template: { + apiVersion: "standard.oam.dev/v1alpha1" + kind: "Route" + spec: { + host: route.domain + path: route.path + tls: { + issuerName: route.issuer + } + backend: { + port: route.port + } + } + } + route: { + domain: *"" | string + path: *"" | string + port: *443 | int + issuer: *"" | string + } diff --git a/cmd/vela/main.go b/cmd/vela/main.go index 4de7d54ad..3b99d8d4f 100644 --- a/cmd/vela/main.go +++ b/cmd/vela/main.go @@ -17,6 +17,7 @@ import ( "github.com/crossplane/oam-kubernetes-runtime/apis/core" "github.com/gosuri/uitable" + certmanager "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha2" "github.com/spf13/cobra" k8sruntime "k8s.io/apimachinery/pkg/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" @@ -34,7 +35,7 @@ var chartTGZSource string func init() { _ = clientgoscheme.AddToScheme(scheme) - + _ = certmanager.AddToScheme(scheme) _ = core.AddToScheme(scheme) // +kubebuilder:scaffold:scheme } diff --git a/config/samples/issuer.yaml b/config/samples/issuer.yaml new file mode 100644 index 000000000..5d8fae714 --- /dev/null +++ b/config/samples/issuer.yaml @@ -0,0 +1,19 @@ +apiVersion: cert-manager.io/v1alpha2 +kind: Issuer +metadata: + name: letsencrypt-prod +spec: + acme: + # You must replace this email address with your own. + # Let's Encrypt will use this to contact you about expiring + # certificates, and issues related to your account. + email: wonderflow@icloud.com + server: https://acme-v02.api.letsencrypt.org/directory + privateKeySecretRef: + # Secret resource that will be used to store the account's private key. + name: example-issuer-account-key + # Add a single challenge solver, HTTP01 using nginx + solvers: + - http01: + ingress: + class: nginx \ No newline at end of file diff --git a/config/samples/traits/route.yaml b/config/samples/traits/route.yaml index df4843893..f1879f352 100644 --- a/config/samples/traits/route.yaml +++ b/config/samples/traits/route.yaml @@ -21,13 +21,17 @@ spec: spec: { host: route.domain path: route.path + tls: { + issuerName: route.issuer + } backend: { port: route.port } } } route: { - domain: string + domain: *"" | string path: *"" | string port: *443 | int + issuer: *"" | string } diff --git a/e2e/commonContext.go b/e2e/commonContext.go index 0c725dbf7..312dd92cd 100644 --- a/e2e/commonContext.go +++ b/e2e/commonContext.go @@ -58,7 +58,7 @@ var ( cli := fmt.Sprintf("vela env init %s --namespace %s", envName, envName) output, err := Exec(cli) gomega.Expect(err).NotTo(gomega.HaveOccurred()) - expectedOutput := fmt.Sprintf("Create env succeed, current env is %s", envName) + expectedOutput := fmt.Sprintf("ENV %s CREATED,", envName) gomega.Expect(output).To(gomega.ContainSubstring(expectedOutput)) }) }) @@ -214,7 +214,7 @@ var ( err = json.Unmarshal(result, &r) gomega.Expect(err).NotTo(gomega.HaveOccurred()) gomega.Expect(http.StatusOK).Should(gomega.Equal(r.Code)) - gomega.Expect(r.Data.(string)).To(gomega.ContainSubstring("Create env succeed")) + gomega.Expect(r.Data.(string)).To(gomega.ContainSubstring("CREATED")) }) }) } diff --git a/pkg/application/app.go b/pkg/application/app.go index 2ca15b459..aaa512f7a 100644 --- a/pkg/application/app.go +++ b/pkg/application/app.go @@ -320,7 +320,7 @@ func EvalToObject(capName string, data map[string]interface{}) (*unstructured.Un return u, nil } -func (app *Application) GetComponentTraits(componentName string) ([]v1alpha2.ComponentTrait, error) { +func (app *Application) GetComponentTraits(componentName string, env *types.EnvMeta) ([]v1alpha2.ComponentTrait, error) { var traits []v1alpha2.ComponentTrait rawTraits, err := app.GetTraits(componentName) if err != nil { @@ -338,6 +338,14 @@ func (app *Application) GetComponentTraits(componentName string) ([]v1alpha2.Com return traits, nil } +func (app *Application) VelaCoreInjection(obj *unstructured.Unstructured, env *types.EnvMeta, traitType string) { + switch traitType { + case "route": + + } + +} + func FormatDefaultHealthScopeName(appName string) string { return appName + "-default-health" } @@ -387,7 +395,7 @@ func (app *Application) OAM(env *types.EnvMeta) ([]v1alpha2.Component, v1alpha2. }}) //TODO(wonderflow): handle component data input/output here - compTraits, err := app.GetComponentTraits(name) + compTraits, err := app.GetComponentTraits(name, env) if err != nil { return nil, v1alpha2.ApplicationConfiguration{}, nil, err } diff --git a/pkg/commands/env.go b/pkg/commands/env.go index a0fd3c804..8d3dd1233 100644 --- a/pkg/commands/env.go +++ b/pkg/commands/env.go @@ -57,7 +57,7 @@ func NewEnvInitCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command DisableFlagsInUseLine: true, Short: "Create environments", Long: "Create environment and set the currently using environment", - Example: `vela env init test --namespace test`, + Example: `vela env init test --namespace test --email my@email.com`, RunE: func(cmd *cobra.Command, args []string) error { newClient, err := client.New(c.Config, client.Options{Scheme: c.Schema}) if err != nil { @@ -71,6 +71,8 @@ func NewEnvInitCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command } cmd.SetOut(ioStreams.Out) cmd.Flags().StringVar(&envArgs.Namespace, "namespace", "default", "specify K8s namespace for env") + cmd.Flags().StringVar(&envArgs.Email, "email", "", "specify email for production TLS Certificate notification") + cmd.Flags().StringVar(&envArgs.Domain, "domain", "", "specify domain your applications") return cmd } @@ -94,7 +96,6 @@ func NewEnvDeleteCommand(ioStreams cmdutil.IOStreams) *cobra.Command { } func NewEnvSetCommand(ioStreams cmdutil.IOStreams) *cobra.Command { - ctx := context.Background() cmd := &cobra.Command{ Use: "set", Aliases: []string{"sw"}, @@ -103,7 +104,7 @@ func NewEnvSetCommand(ioStreams cmdutil.IOStreams) *cobra.Command { Long: "Set an environment as the current using one", Example: `vela env set test`, RunE: func(cmd *cobra.Command, args []string) error { - return SetEnv(ctx, args, ioStreams) + return SetEnv(args, ioStreams) }, Annotations: map[string]string{ types.TagCommandType: types.TypeStart, @@ -149,8 +150,8 @@ func CreateOrUpdateEnv(ctx context.Context, c client.Client, envArgs *types.EnvM return fmt.Errorf("you must specify env name for vela env init command") } envName := args[0] - namespace := envArgs.Namespace - msg, err := oam.CreateOrUpdateEnv(ctx, c, envName, namespace) + envArgs.Name = envName + msg, err := oam.CreateOrUpdateEnv(ctx, c, envName, envArgs) if err != nil { return err } @@ -158,7 +159,7 @@ func CreateOrUpdateEnv(ctx context.Context, c client.Client, envArgs *types.EnvM return nil } -func SetEnv(ctx context.Context, args []string, ioStreams cmdutil.IOStreams) error { +func SetEnv(args []string, ioStreams cmdutil.IOStreams) error { if len(args) < 1 { return fmt.Errorf("you must specify env name for vela env command") } diff --git a/pkg/commands/env_test.go b/pkg/commands/env_test.go index bafb1e783..2ca974ebc 100644 --- a/pkg/commands/env_test.go +++ b/pkg/commands/env_test.go @@ -77,7 +77,7 @@ func TestENV(t *testing.T) { assert.Error(t, err) // set as default env - err = SetEnv(ctx, []string{"default"}, ioStream) + err = SetEnv([]string{"default"}, ioStream) assert.NoError(t, err) // check env set success @@ -93,10 +93,10 @@ func TestENV(t *testing.T) { assert.NoError(t, err) // can not set as a non-exist env - err = SetEnv(ctx, []string{"env1"}, ioStream) + err = SetEnv([]string{"env1"}, ioStream) assert.Error(t, err) // set success - err = SetEnv(ctx, []string{"default"}, ioStream) + err = SetEnv([]string{"default"}, ioStream) assert.NoError(t, err) } diff --git a/pkg/commands/trait.go b/pkg/commands/trait.go index 231a1741e..ee5cceea9 100644 --- a/pkg/commands/trait.go +++ b/pkg/commands/trait.go @@ -44,7 +44,7 @@ func AddTraitCommands(parentCmd *cobra.Command, c types.Args, ioStreams cmdutil. Long: "Attach " + name + " trait to an app", Example: "vela " + name + " frontend", RunE: func(cmd *cobra.Command, args []string) error { - o := &commandOptions{IOStreams: ioStreams} + o := &commandOptions{IOStreams: ioStreams, traitType: name} o.Template = tmp newClient, err := client.New(c.Config, client.Options{Scheme: c.Schema}) if err != nil { @@ -103,7 +103,9 @@ func (o *commandOptions) AddOrUpdateTrait(cmd *cobra.Command, args []string) err if err = o.Prepare(cmd, args); err != nil { return err } - if o.app, err = oam.AddOrUpdateTrait(o.Env.Name, o.appName, o.workloadName, cmd.Flags(), o.Template); err != nil { + flags := cmd.Flags() + + if o.app, err = oam.AddOrUpdateTrait(o.Env, o.appName, o.workloadName, flags, o.Template); err != nil { return err } return nil @@ -138,6 +140,7 @@ func (o *commandOptions) Run(ctx context.Context, cmd *cobra.Command) error { if err != nil { return err } + o.Info(msg) return nil } diff --git a/pkg/controller/v1alpha1/routes/route_controller.go b/pkg/controller/v1alpha1/routes/route_controller.go index 3b28d7af4..7b82b6266 100644 --- a/pkg/controller/v1alpha1/routes/route_controller.go +++ b/pkg/controller/v1alpha1/routes/route_controller.go @@ -201,7 +201,7 @@ func (r *Reconciler) createService(ctx context.Context, mLog logr.Logger, worklo }, }, Spec: corev1.ServiceSpec{ - Type: corev1.ServiceTypeLoadBalancer, + Type: corev1.ServiceTypeClusterIP, }, } // assign selector diff --git a/pkg/oam/env.go b/pkg/oam/env.go index fb52e279e..3e0163dd8 100644 --- a/pkg/oam/env.go +++ b/pkg/oam/env.go @@ -9,6 +9,9 @@ import ( "os" "path/filepath" + "github.com/jetstack/cert-manager/pkg/apis/acme/v1alpha2" + certmanager "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha2" + v1 "github.com/jetstack/cert-manager/pkg/apis/meta/v1" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -36,15 +39,40 @@ func GetEnvByName(name string) (*types.EnvMeta, error) { //Create or update env. //If it does not exist, create it and set to the new env. //If it exists, update it and set to the new env. -func CreateOrUpdateEnv(ctx context.Context, c client.Client, envName string, namespace string) (string, error) { +func CreateOrUpdateEnv(ctx context.Context, c client.Client, envName string, envArgs *types.EnvMeta) (string, error) { var message = "" - var envArgs = types.EnvMeta{ - Name: envName, - Namespace: namespace, - } + // Create Namespace if err := c.Create(ctx, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: envArgs.Namespace}}); err != nil && !apierrors.IsAlreadyExists(err) { return message, err } + + // Create Issuer For SSL + if envArgs.Email != "" { + issuerName := "oam-env-" + envArgs.Name + if err := c.Create(ctx, &certmanager.Issuer{ + ObjectMeta: metav1.ObjectMeta{Name: issuerName, Namespace: envArgs.Namespace}, + Spec: certmanager.IssuerSpec{ + IssuerConfig: certmanager.IssuerConfig{ + ACME: &v1alpha2.ACMEIssuer{ + Email: envArgs.Email, + Server: "https://acme-v02.api.letsencrypt.org/directory", + PrivateKey: v1.SecretKeySelector{ + LocalObjectReference: v1.LocalObjectReference{Name: "oam-env-" + envArgs.Name + ".key"}, + }, + Solvers: []v1alpha2.ACMEChallengeSolver{{ + HTTP01: &v1alpha2.ACMEChallengeSolverHTTP01{ + Ingress: &v1alpha2.ACMEChallengeSolverHTTP01Ingress{Class: GetStringPointer("nginx")}, + }, + }}, + }, + }, + }, + }); err != nil && !apierrors.IsAlreadyExists(err) { + return message, err + } + envArgs.Issuer = issuerName + } + data, err := json.Marshal(envArgs) if err != nil { return message, err @@ -67,42 +95,22 @@ func CreateOrUpdateEnv(ctx context.Context, c client.Client, envName string, nam if err = ioutil.WriteFile(curEnvPath, []byte(envName), 0644); err != nil { return message, err } - message = fmt.Sprintf("Create env succeed, current env is " + envName + " namespace is " + envArgs.Namespace + ", use --namespace= to specify namespace with env init") + message = fmt.Sprintf("ENV %s CREATED, Namespace: %s, Email: %s.", envName, envArgs.Namespace, envArgs.Email) return message, nil } -//Create env. If env already exists, return error -func CreateEnv(ctx context.Context, c client.Client, envName string, namespace string) (string, error) { - var message = "" - var envArgs = types.EnvMeta{ - Name: envName, - Namespace: namespace, - } - data, err := json.Marshal(envArgs) - if err != nil { - return message, err - } - _, err = GetEnvByName(envName) +func GetStringPointer(v string) *string { + return &v +} + +// CreateEnv will only create. If env already exists, return error +func CreateEnv(ctx context.Context, c client.Client, envName string, envArgs *types.EnvMeta) (string, error) { + _, err := GetEnvByName(envName) if err == nil { - message = fmt.Sprintf("Env %s already exist", envName) + message := fmt.Sprintf("Env %s already exist", envName) return message, errors.New(message) } - if err := c.Create(ctx, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: envArgs.Namespace}}); err != nil && !apierrors.IsAlreadyExists(err) { - return message, err - } - envdir, err := system.GetEnvDir() - if err != nil { - return message, err - } - subEnvDir := filepath.Join(envdir, envName) - if _, err := system.CreateIfNotExist(subEnvDir); err != nil { - return "", nil - } - if err = ioutil.WriteFile(filepath.Join(subEnvDir, system.EnvConfigName), data, 0644); err != nil { - return message, err - } - message = "Create env succeed" - return message, err + return CreateOrUpdateEnv(ctx, c, envName, envArgs) } //Update Env, if env does not exist, return error diff --git a/pkg/oam/trait.go b/pkg/oam/trait.go index 84d798b67..0eae8013e 100644 --- a/pkg/oam/trait.go +++ b/pkg/oam/trait.go @@ -148,12 +148,47 @@ func SimplifyCapabilityStruct(capabilityList []types.Capability) []apis.TraitMet return traitList } +func ValidateAndMutateForCore(traitType, workloadName string, flags *pflag.FlagSet, env *types.EnvMeta) error { + switch traitType { + case "route": + domain, _ := flags.GetString("domain") + if domain == "" { + if env.Domain == "" { + return fmt.Errorf("--domain is required if not set in env") + } + if strings.HasPrefix(env.Domain, "https://") { + env.Domain = strings.TrimPrefix(env.Domain, "https://") + } + if strings.HasPrefix(env.Domain, "http://") { + env.Domain = strings.TrimPrefix(env.Domain, "http://") + } + if err := flags.Set("domain", workloadName+"."+env.Domain); err != nil { + return fmt.Errorf("set flag for vela-core trait('route') err %v, please make sure your template is right", err) + } + } + issuer, _ := flags.GetString("issuer") + if issuer == "" { + if env.Issuer == "" { + return fmt.Errorf("--issuer is required, you can also set email in env and let it generate automatically") + } + if err := flags.Set("issuer", env.Issuer); err != nil { + return fmt.Errorf("set flag for vela-core trait('route') err %v, please make sure your template is right", err) + } + } + } + return nil +} + //AddOrUpdateTrait attach trait to workload -func AddOrUpdateTrait(envName string, appName string, workloadName string, flagSet *pflag.FlagSet, template types.Capability) (*application.Application, error) { +func AddOrUpdateTrait(env *types.EnvMeta, appName string, workloadName string, flagSet *pflag.FlagSet, template types.Capability) (*application.Application, error) { + err := ValidateAndMutateForCore(template.Name, workloadName, flagSet, env) + if err != nil { + return nil, err + } if appName == "" { appName = workloadName } - app, err := application.Load(envName, appName) + app, err := application.Load(env.Name, appName) if err != nil { return app, err } @@ -181,7 +216,7 @@ func AddOrUpdateTrait(envName string, appName string, workloadName string, flagS if err = app.SetTrait(workloadName, traitAlias, traitData); err != nil { return app, err } - return app, app.Save(envName) + return app, app.Save(env.Name) } func AttachTrait(c *gin.Context, body apis.TraitBody) (string, error) { @@ -204,12 +239,13 @@ func AttachTrait(c *gin.Context, body apis.TraitBody) (string, error) { if err != nil { return "", err } - appObj, err = AddOrUpdateTrait(body.EnvName, body.AppGroup, body.WorkloadName, fs, template) + // Run step + env, err := GetEnvByName(body.EnvName) if err != nil { return "", err } - // Run step - env, err := GetEnvByName(body.EnvName) + + appObj, err = AddOrUpdateTrait(env, body.AppGroup, body.WorkloadName, fs, template) if err != nil { return "", err } diff --git a/pkg/server/apis/types.go b/pkg/server/apis/types.go index 876acb41e..dc851c8e2 100644 --- a/pkg/server/apis/types.go +++ b/pkg/server/apis/types.go @@ -10,6 +10,8 @@ import ( type Environment struct { EnvName string `json:"envName" binding:"required,min=1,max=32"` Namespace string `json:"namespace" binding:"required,min=1,max=32"` + Email string `json:"email"` + Domain string `json:"domain"` Current string `json:"current,omitempty"` } diff --git a/pkg/server/handler/envHandlers.go b/pkg/server/handler/envHandlers.go index f387cce27..5718fb39d 100644 --- a/pkg/server/handler/envHandlers.go +++ b/pkg/server/handler/envHandlers.go @@ -2,6 +2,7 @@ package handler import ( "github.com/gin-gonic/gin" + "github.com/oam-dev/kubevela/api/types" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -23,9 +24,16 @@ func CreateEnv(c *gin.Context) { if namespace == "" { namespace = "default" } + ctx := util.GetContext(c) kubeClient := c.MustGet("KubeClient") - message, err := oam.CreateEnv(ctx, kubeClient.(client.Client), name, namespace) + message, err := oam.CreateEnv(ctx, kubeClient.(client.Client), name, &types.EnvMeta{ + Name: name, + Current: environment.Current, + Namespace: namespace, + Email: environment.Email, + Domain: environment.Domain, + }) util.AssembleResponse(c, message, err) } diff --git a/vela-templates/route.cue b/vela-templates/route.cue index 433a15638..22ad4fb44 100644 --- a/vela-templates/route.cue +++ b/vela-templates/route.cue @@ -4,13 +4,17 @@ spec: { host: route.domain path: route.path + tls: { + issuerName: route.issuer + } backend: { port: route.port } } } route: { - domain: string + domain: *"" | string path: *"" | string port: *443 | int + issuer: *"" | string }