diff --git a/docs/developers/devex/appfile.md b/docs/developers/devex/appfile.md index e44f26dc2..397f81763 100644 --- a/docs/developers/devex/appfile.md +++ b/docs/developers/devex/appfile.md @@ -8,8 +8,7 @@ In this tutorial, we will build and deploy an example NodeJS app under [examples ## Prerequisites - [docker](https://docs.docker.com/get-docker/) installed on the host -- [vela](../../install.md) installed -- [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) installed +- [vela](../../install.md) installed and configured ## 1. Download test app code @@ -24,9 +23,10 @@ The example contains NodeJS app code, Dockerfile to build the app. ## 2. Deploy app in one command -[vela.yaml](../../../examples/testapp/vela.yaml) is an appfile format supported by Vela. +In the directory there is a [vela.yaml](../../../examples/testapp/vela.yaml) which follows Appfile format supported by Vela. +We are going to use it to build and deploy the app. -You need to change this line to the image that you can push to on your host: +ATTENTION: change the image field in vela.yaml to something you can push to on your host: > Or you may try the local kind cluster option which will be introduced in the following section. @@ -34,28 +34,94 @@ You need to change this line to the image that you can push to on your host: image: oamdev/testapp:v1 ``` -Deploy vela.yaml: +Run the following command: ```console $ vela up +Parsing vela.yaml ... +Loading templates ... + +Building service (express-server)... +Sending build context to Docker daemon 71.68kB +Step 1/10 : FROM mhart/alpine-node:12 + ---> 9d88359808c3 +... + +pushing image (oamdev/testapp:v1)... +... + +Rendering configs for service (express-server)... +writing deploy config to (.vela/deploy.yaml) + +Applying deploy configs ... + +Checking if app has been deployed... +app has not been deployed, creating a new deployment... +app has been deployed 🚀🚀🚀 + Port forward: vela port-forward testapp + SSH: vela exec testapp + Logging: vela logs testapp ``` -Now the app has been rendered and deployed. - -## 3. Check rendered manifests and deployment - -By default, Vela renders the final manifests in `.vela/deploy.yaml`: - -```console -$ cat .vela/deploy.yaml -``` +Now the app deployment has been rendered and run. Check the status of the application deployment: ```console -$ vela app status testapp +$ vela svc status express-server [0:06:32] +Showing status of service(type: webservice) express-server deployed in Environment default +Service express-server Status: HEALTHY Ready: 1/1 + scaler: replica=1 + scaler: replica=1 -$ vela svc status express-server +Last Deployment: + Created at: 2020-10-30 00:06:10 -0700 PDT + Updated at: 2020-10-30T00:06:10-07:00 +``` + +## 3. Check rendered manifests + +By default, Vela renders the final manifests in `.vela/deploy.yaml`: + +```yaml +apiVersion: core.oam.dev/v1alpha2 +kind: ApplicationConfiguration +metadata: + name: testapp + namespace: default +spec: + components: + - componentName: express-server + traits: + - trait: + apiVersion: core.oam.dev/v1alpha2 + kind: ManualScalerTrait + ... + - trait: + apiVersion: standard.oam.dev/v1alpha1 + kind: Route + ... +--- +apiVersion: core.oam.dev/v1alpha2 +kind: Component +metadata: + name: express-server + namespace: default +spec: + workload: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: express-server + ... +--- +apiVersion: core.oam.dev/v1alpha2 +kind: HealthScope +metadata: + name: testapp-default-health + namespace: default +spec: + ... ``` ## [Optional] Configure "task" workload type diff --git a/examples/testapp/vela.yaml b/examples/testapp/vela.yaml index c1f380af0..8fcde5a15 100644 --- a/examples/testapp/vela.yaml +++ b/examples/testapp/vela.yaml @@ -13,8 +13,8 @@ services: context: . # Uncomment the following to push to local kind cluster - # push: - # local: kind + push: + local: kind # type: webservice (default) | worker | task diff --git a/pkg/appfile/appfile.go b/pkg/appfile/appfile.go index b94a24e3f..d832b7921 100644 --- a/pkg/appfile/appfile.go +++ b/pkg/appfile/appfile.go @@ -5,9 +5,12 @@ import ( "io/ioutil" "time" + "github.com/crossplane/crossplane-runtime/apis/core/v1alpha1" "github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2" + "github.com/crossplane/oam-kubernetes-runtime/pkg/oam" "github.com/ghodss/yaml" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "github.com/oam-dev/kubevela/pkg/appfile/template" cmdutil "github.com/oam-dev/kubevela/pkg/commands/util" @@ -57,18 +60,18 @@ func LoadFromFile(filename string) (*AppFile, error) { // BuildOAM renders Appfile into AppConfig, Components. It also builds images for services if defined. func (app *AppFile) BuildOAM(ns string, io cmdutil.IOStreams, tm template.Manager, slience bool) ( - []*v1alpha2.Component, *v1alpha2.ApplicationConfiguration, error) { + []*v1alpha2.Component, *v1alpha2.ApplicationConfiguration, []oam.Object, error) { return app.buildOAM(ns, io, true, tm, slience) } // RenderOAM renders Appfile into AppConfig, Components. func (app *AppFile) RenderOAM(ns string, io cmdutil.IOStreams, tm template.Manager, slience bool) ( - []*v1alpha2.Component, *v1alpha2.ApplicationConfiguration, error) { + []*v1alpha2.Component, *v1alpha2.ApplicationConfiguration, []oam.Object, error) { return app.buildOAM(ns, io, false, tm, slience) } func (app *AppFile) buildOAM(ns string, io cmdutil.IOStreams, buildImage bool, tm template.Manager, slience bool) ( - []*v1alpha2.Component, *v1alpha2.ApplicationConfiguration, error) { + []*v1alpha2.Component, *v1alpha2.ApplicationConfiguration, []oam.Object, error) { appConfig := &v1alpha2.ApplicationConfiguration{ ObjectMeta: metav1.ObjectMeta{ @@ -88,12 +91,12 @@ func (app *AppFile) buildOAM(ns string, io cmdutil.IOStreams, buildImage bool, t if b := svc.GetBuild(); b != nil { if image == "" { - return nil, nil, ErrImageNotDefined + return nil, nil, nil, ErrImageNotDefined } if buildImage { io.Infof("\nBuilding service (%s)...\n", sname) if err := b.BuildImage(io, image); err != nil { - return nil, nil, err + return nil, nil, nil, err } } } @@ -102,11 +105,53 @@ func (app *AppFile) buildOAM(ns string, io cmdutil.IOStreams, buildImage bool, t } acComp, comp, err := svc.RenderService(tm, sname, ns, app.configGetter) if err != nil { - return nil, nil, err + return nil, nil, nil, err } appConfig.Spec.Components = append(appConfig.Spec.Components, *acComp) comps = append(comps, comp) } - return comps, appConfig, nil + addWorkloadTypeLabel(comps, app.Services) + health := addHealthScope(appConfig) + return comps, appConfig, []oam.Object{health}, nil +} + +func addWorkloadTypeLabel(comps []*v1alpha2.Component, services map[string]Service) { + for _, comp := range comps { + workloadType := services[comp.Name].GetType() + workloadObject := comp.Spec.Workload.Object.(*unstructured.Unstructured) + labels := workloadObject.GetLabels() + if labels == nil { + labels = map[string]string{oam.WorkloadTypeLabel: workloadType} + } else { + labels[oam.WorkloadTypeLabel] = workloadType + } + workloadObject.SetLabels(labels) + } +} + +func addHealthScope(appConfig *v1alpha2.ApplicationConfiguration) *v1alpha2.HealthScope { + health := &v1alpha2.HealthScope{ + TypeMeta: metav1.TypeMeta{ + APIVersion: v1alpha2.HealthScopeGroupVersionKind.GroupVersion().String(), + Kind: v1alpha2.HealthScopeKind, + }, + } + health.Name = FormatDefaultHealthScopeName(appConfig.Name) + health.Namespace = appConfig.Namespace + health.Spec.WorkloadReferences = make([]v1alpha1.TypedReference, 0) + for i := range appConfig.Spec.Components { + // TODO(wonderflow): Temporarily we add health scope here, should change to use scope framework + appConfig.Spec.Components[i].Scopes = append(appConfig.Spec.Components[i].Scopes, v1alpha2.ComponentScope{ + ScopeReference: v1alpha1.TypedReference{ + APIVersion: v1alpha2.SchemeGroupVersion.String(), + Kind: v1alpha2.HealthScopeKind, + Name: health.Name, + }, + }) + } + return health +} +func FormatDefaultHealthScopeName(appName string) string { + return appName + "-default-health" } diff --git a/pkg/appfile/appfile_test.go b/pkg/appfile/appfile_test.go index 4ccbb3d4e..7725b5829 100644 --- a/pkg/appfile/appfile_test.go +++ b/pkg/appfile/appfile_test.go @@ -4,10 +4,12 @@ import ( "os" "testing" + "github.com/crossplane/crossplane-runtime/apis/core/v1alpha1" "github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2" "github.com/ghodss/yaml" "github.com/stretchr/testify/assert" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" @@ -162,6 +164,13 @@ outputs: ingress: { Spec: v1alpha2.ApplicationConfigurationSpec{ Components: []v1alpha2.ApplicationConfigurationComponent{{ ComponentName: "express-server", + Scopes: []v1alpha2.ComponentScope{{ + ScopeReference: v1alpha1.TypedReference{ + APIVersion: "core.oam.dev/v1alpha2", + Kind: "HealthScope", + Name: "myapp-default-health", + }, + }}, Traits: []v1alpha2.ComponentTrait{{ Trait: runtime.RawExtension{ Object: &unstructured.Unstructured{ @@ -220,6 +229,13 @@ outputs: ingress: { ac2.Spec.Components = append(ac2.Spec.Components, v1alpha2.ApplicationConfigurationComponent{ ComponentName: "mongodb", Traits: []v1alpha2.ComponentTrait{}, + Scopes: []v1alpha2.ComponentScope{{ + ScopeReference: v1alpha1.TypedReference{ + APIVersion: "core.oam.dev/v1alpha2", + Kind: "HealthScope", + Name: "myapp-default-health", + }, + }}, }) comp1 := &v1alpha2.Component{ @@ -233,7 +249,12 @@ outputs: ingress: { Object: map[string]interface{}{ "apiVersion": "test.oam.dev/v1", "kind": "WebService", - "metadata": map[string]interface{}{"name": "express-server"}, + "metadata": map[string]interface{}{ + "name": "express-server", + "labels": map[string]interface{}{ + "workload.oam.dev/type": "webservice", + }, + }, "spec": map[string]interface{}{ "image": "oamdev/testapp:v1", "command": []interface{}{"node", "server.js"}, @@ -255,7 +276,12 @@ outputs: ingress: { Object: map[string]interface{}{ "apiVersion": "test.oam.dev/v1", "kind": "Worker", - "metadata": map[string]interface{}{"name": "mongodb"}, + "metadata": map[string]interface{}{ + "name": "mongodb", + "labels": map[string]interface{}{ + "workload.oam.dev/type": "backend", + }, + }, "spec": map[string]interface{}{ "image": "bitnami/mongodb:3.6.20", "command": []interface{}{"mongodb"}, @@ -281,6 +307,8 @@ outputs: ingress: { fakeConfigData, "spec", "env"); err != nil { t.Fatal(err) } + compWithConfig.Spec.Workload.Object.(*unstructured.Unstructured).SetLabels( + map[string]string{"workload.oam.dev/type": "withconfig"}) type args struct { appfileData string @@ -377,7 +405,7 @@ outputs: ingress: { } } - comps, ac, err := app.RenderOAM("default", io, tm, false) + comps, ac, _, err := app.RenderOAM("default", io, tm, false) if err != nil { assert.Equal(t, c.want.err, err) return @@ -416,3 +444,45 @@ outputs: ingress: { }) } } + +func TestAddWorkloadTypeLabel(t *testing.T) { + tests := map[string]struct { + comps []*v1alpha2.Component + services map[string]Service + expect []*v1alpha2.Component + }{ + "empty case": { + comps: []*v1alpha2.Component{}, + services: map[string]Service{}, + expect: []*v1alpha2.Component{}, + }, + "add type to labels normal case": { + comps: []*v1alpha2.Component{ + { + ObjectMeta: v1.ObjectMeta{Name: "mycomp"}, + Spec: v1alpha2.ComponentSpec{Workload: runtime.RawExtension{Object: &unstructured.Unstructured{Object: map[string]interface{}{}}}}, + }, + }, + services: map[string]Service{ + "mycomp": {"type": "kubewatch"}, + }, + expect: []*v1alpha2.Component{ + { + ObjectMeta: v1.ObjectMeta{Name: "mycomp"}, + Spec: v1alpha2.ComponentSpec{ + Workload: runtime.RawExtension{ + Object: &unstructured.Unstructured{Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "labels": map[string]interface{}{ + "workload.oam.dev/type": "kubewatch", + }}}}}, + }, + }, + }, + }, + } + for key, ca := range tests { + addWorkloadTypeLabel(ca.comps, ca.services) + assert.Equal(t, ca.expect, ca.comps, key) + } +} diff --git a/pkg/application/app.go b/pkg/application/app.go index e9cfdd0b5..aea53e159 100644 --- a/pkg/application/app.go +++ b/pkg/application/app.go @@ -11,11 +11,9 @@ import ( "strings" "time" - "github.com/crossplane/crossplane-runtime/apis/core/v1alpha1" "github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2" "github.com/crossplane/oam-kubernetes-runtime/pkg/oam" "github.com/ghodss/yaml" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "github.com/oam-dev/kubevela/api/types" "github.com/oam-dev/kubevela/pkg/appfile" @@ -222,51 +220,13 @@ func (app *Application) GetTraitsByType(componentName, traitType string) (map[st return t.(map[string]interface{}), nil } -func FormatDefaultHealthScopeName(appName string) string { - return appName + "-default-health" -} - // TODO(wonderflow) add scope support here func (app *Application) OAM(env *types.EnvMeta, io cmdutil.IOStreams, slience bool) ([]*v1alpha2.Component, *v1alpha2.ApplicationConfiguration, []oam.Object, error) { - comps, appConfig, err := app.RenderOAM(env.Namespace, io, app.tm, slience) + comps, appConfig, scopes, err := app.RenderOAM(env.Namespace, io, app.tm, slience) if err != nil { return nil, nil, nil, err } - addWorkloadTypeLabel(comps, app.Services) - health := addHealthScope(appConfig) - return comps, appConfig, []oam.Object{health}, nil -} - -func addWorkloadTypeLabel(comps []*v1alpha2.Component, services map[string]appfile.Service) { - for _, comp := range comps { - workloadType := services[comp.Name].GetType() - workloadObject := comp.Spec.Workload.Object.(*unstructured.Unstructured) - labels := workloadObject.GetLabels() - if labels == nil { - labels = map[string]string{oam.WorkloadTypeLabel: workloadType} - } else { - labels[oam.WorkloadTypeLabel] = workloadType - } - workloadObject.SetLabels(labels) - } -} - -func addHealthScope(appConfig *v1alpha2.ApplicationConfiguration) *v1alpha2.HealthScope { - health := &v1alpha2.HealthScope{} - health.Name = FormatDefaultHealthScopeName(appConfig.Name) - health.Namespace = appConfig.Namespace - health.Spec.WorkloadReferences = make([]v1alpha1.TypedReference, 0) - for i := range appConfig.Spec.Components { - // TODO(wonderflow): Temporarily we add health scope here, should change to use scope framework - appConfig.Spec.Components[i].Scopes = append(appConfig.Spec.Components[i].Scopes, v1alpha2.ComponentScope{ - ScopeReference: v1alpha1.TypedReference{ - APIVersion: v1alpha2.SchemeGroupVersion.String(), - Kind: v1alpha2.HealthScopeKind, - Name: health.Name, - }, - }) - } - return health + return comps, appConfig, scopes, nil } func getApplicationDir(envName string) (string, error) { diff --git a/pkg/application/app_test.go b/pkg/application/app_test.go index ea1faa669..b5e33dcd5 100644 --- a/pkg/application/app_test.go +++ b/pkg/application/app_test.go @@ -5,13 +5,6 @@ import ( "fmt" "testing" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" - - "github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2" - "github.com/oam-dev/kubevela/pkg/appfile" - "github.com/ghodss/yaml" "github.com/stretchr/testify/assert" @@ -143,45 +136,3 @@ services: assert.Equal(t, c.ExpTraits, traits, caseName) } } - -func TestAddWorkloadTypeLabel(t *testing.T) { - tests := map[string]struct { - comps []*v1alpha2.Component - services map[string]appfile.Service - expect []*v1alpha2.Component - }{ - "empty case": { - comps: []*v1alpha2.Component{}, - services: map[string]appfile.Service{}, - expect: []*v1alpha2.Component{}, - }, - "add type to labels normal case": { - comps: []*v1alpha2.Component{ - { - ObjectMeta: v1.ObjectMeta{Name: "mycomp"}, - Spec: v1alpha2.ComponentSpec{Workload: runtime.RawExtension{Object: &unstructured.Unstructured{Object: map[string]interface{}{}}}}, - }, - }, - services: map[string]appfile.Service{ - "mycomp": {"type": "kubewatch"}, - }, - expect: []*v1alpha2.Component{ - { - ObjectMeta: v1.ObjectMeta{Name: "mycomp"}, - Spec: v1alpha2.ComponentSpec{ - Workload: runtime.RawExtension{ - Object: &unstructured.Unstructured{Object: map[string]interface{}{ - "metadata": map[string]interface{}{ - "labels": map[string]interface{}{ - "workload.oam.dev/type": "kubewatch", - }}}}}, - }, - }, - }, - }, - } - for key, ca := range tests { - addWorkloadTypeLabel(ca.comps, ca.services) - assert.Equal(t, ca.expect, ca.comps, key) - } -} diff --git a/pkg/commands/status.go b/pkg/commands/status.go index 1a6eb96a9..d4bd967f1 100644 --- a/pkg/commands/status.go +++ b/pkg/commands/status.go @@ -21,6 +21,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "github.com/oam-dev/kubevela/api/types" + "github.com/oam-dev/kubevela/pkg/appfile" "github.com/oam-dev/kubevela/pkg/application" cmdutil "github.com/oam-dev/kubevela/pkg/commands/util" oam2 "github.com/oam-dev/kubevela/pkg/oam" @@ -73,7 +74,7 @@ const ( const ( ErrNotLoadAppConfig = "cannot load the application" - ErrFmtNotInitialized = "initializing service: %s failed" + ErrFmtNotInitialized = "service: %s not ready" ErrServiceNotFound = "service %s not found in app" ) @@ -195,7 +196,7 @@ func printAppStatus(ctx context.Context, c client.Client, ioStreams cmdutil.IOSt func getWorkloadHealthConditions(ctx context.Context, c client.Client, app *application.Application, ns string) (map[string]*WorkloadHealthCondition, error) { hs := &v1alpha2.HealthScope{} // only use default health scope - hsName := application.FormatDefaultHealthScopeName(app.Name) + hsName := appfile.FormatDefaultHealthScopeName(app.Name) if err := c.Get(ctx, client.ObjectKey{Namespace: ns, Name: hsName}, hs); err != nil { return nil, err } diff --git a/pkg/commands/up.go b/pkg/commands/up.go index 63db29ebf..a9285f7db 100644 --- a/pkg/commands/up.go +++ b/pkg/commands/up.go @@ -9,12 +9,12 @@ import ( "path/filepath" "github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2" - "github.com/ghodss/yaml" - "github.com/kyokomi/emoji" + "github.com/crossplane/oam-kubernetes-runtime/pkg/oam" "github.com/pkg/errors" "github.com/spf13/cobra" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + k8sjson "k8s.io/apimachinery/pkg/runtime/serializer/json" apitypes "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" @@ -27,7 +27,6 @@ import ( var ( appFilePath string - emojiRocket = emoji.Sprint(":rocket") ) func NewUpCommand(c types.Args, ioStream cmdutil.IOStreams) *cobra.Command { @@ -93,36 +92,43 @@ func (o *appfileOptions) Run(filePath string) error { return err } - comps, appConfig, err := app.BuildOAM(o.Env.Namespace, o.IO, tm, false) + comps, appConfig, scopes, err := app.BuildOAM(o.Env.Namespace, o.IO, tm, false) if err != nil { return err } - var cfg bytes.Buffer + var w bytes.Buffer + enc := k8sjson.NewYAMLSerializer(k8sjson.DefaultMetaFactory, nil, nil) appConfig.TypeMeta = metav1.TypeMeta{ APIVersion: v1alpha2.ApplicationConfigurationGroupVersionKind.GroupVersion().String(), Kind: v1alpha2.ApplicationConfigurationKind, } - b, err := yaml.Marshal(appConfig) + err = enc.Encode(appConfig, &w) if err != nil { - return fmt.Errorf("marshal AppConfig failed: %w", err) + return fmt.Errorf("yaml encode AppConfig failed: %w", err) } - cfg.Write(b) - cfg.WriteByte('\n') + w.WriteByte('\n') for _, comp := range comps { - cfg.WriteString("---\n") + w.WriteString("---\n") comp.TypeMeta = metav1.TypeMeta{ APIVersion: v1alpha2.ComponentGroupVersionKind.GroupVersion().String(), Kind: v1alpha2.ComponentKind, } - b, err := yaml.Marshal(comp) + err = enc.Encode(comp, &w) if err != nil { - return fmt.Errorf("marshal service (%s) failed: %w", comp.Name, err) + return fmt.Errorf("yaml encode service (%s) failed: %w", comp.Name, err) } - cfg.Write(b) - cfg.WriteByte('\n') + w.WriteByte('\n') + } + for _, scope := range scopes { + w.WriteString("---\n") + err = enc.Encode(scope, &w) + if err != nil { + return fmt.Errorf("yaml encode scope (%s) failed: %w", scope.GetName(), err) + } + w.WriteByte('\n') } deployFilePath := ".vela/deploy.yaml" @@ -130,7 +136,7 @@ func (o *appfileOptions) Run(filePath string) error { if err := os.MkdirAll(filepath.Dir(deployFilePath), 0700); err != nil { return err } - if err := ioutil.WriteFile(deployFilePath, cfg.Bytes(), 0600); err != nil { + if err := ioutil.WriteFile(deployFilePath, w.Bytes(), 0600); err != nil { return errors.Wrap(err, "write deploy config manifests failed") } @@ -139,7 +145,7 @@ func (o *appfileOptions) Run(filePath string) error { } o.IO.Infof("\nApplying deploy configs ...\n") - return o.ApplyAppConfig(appConfig, comps) + return o.ApplyAppConfig(appConfig, comps, scopes) } func (o *appfileOptions) saveToAppDir(f *appfile.AppFile) error { @@ -152,7 +158,7 @@ func (o *appfileOptions) saveToAppDir(f *appfile.AppFile) error { // - for create, it displays app status along with information of url, metrics, ssh, logging. // - for update, it rolls out a canary deployment and prints its information. User can verify the canary deployment. // This will wait for user approval. If approved, it continues upgrading the whole; otherwise, it would rollback. -func (o *appfileOptions) ApplyAppConfig(ac *v1alpha2.ApplicationConfiguration, comps []*v1alpha2.Component) error { +func (o *appfileOptions) ApplyAppConfig(ac *v1alpha2.ApplicationConfiguration, comps []*v1alpha2.Component, scopes []oam.Object) error { key := apitypes.NamespacedName{ Namespace: ac.Namespace, Name: ac.Name, @@ -168,25 +174,30 @@ func (o *appfileOptions) ApplyAppConfig(ac *v1alpha2.ApplicationConfiguration, c default: return err } - if err := o.apply(ac, comps); err != nil { + if err := o.apply(ac, comps, scopes); err != nil { return err } o.info(ac.Name) return nil } -func (o *appfileOptions) apply(ac *v1alpha2.ApplicationConfiguration, comps []*v1alpha2.Component) error { +func (o *appfileOptions) apply(ac *v1alpha2.ApplicationConfiguration, comps []*v1alpha2.Component, scopes []oam.Object) error { for _, comp := range comps { if err := application.CreateOrUpdateComponent(context.TODO(), o.Kubecli, comp); err != nil { return err } } + + if err := application.CreateScopes(context.TODO(), o.Kubecli, scopes); err != nil { + return err + } return application.CreateOrUpdateAppConfig(context.TODO(), o.Kubecli, ac) } func (o *appfileOptions) info(appName string) { - o.IO.Infof("app has been deployed %s%s%s\n", emojiRocket, emojiRocket, emojiRocket) - o.IO.Infof("\tPort forward: vela port-forward %s \n", appName) + o.IO.Infof("app has been deployed 🚀🚀🚀\n") + o.IO.Infof("\tPort forward: vela port-forward %s\n", appName) o.IO.Infof("\tSSH: vela exec %s\n", appName) o.IO.Infof("\tLogging: vela logs %s\n", appName) + // TODO: print status } diff --git a/pkg/oam/application.go b/pkg/oam/application.go index a15d5f060..fb8604d74 100644 --- a/pkg/oam/application.go +++ b/pkg/oam/application.go @@ -7,6 +7,7 @@ import ( "sort" "github.com/oam-dev/kubevela/api/types" + "github.com/oam-dev/kubevela/pkg/appfile" "github.com/oam-dev/kubevela/pkg/application" cmdutil "github.com/oam-dev/kubevela/pkg/commands/util" "github.com/oam-dev/kubevela/pkg/server/apis" @@ -182,7 +183,7 @@ func (o *DeleteOptions) DeleteApp() (string, error) { return "", fmt.Errorf("delete application err %s", err) } var healthScope corev1alpha2.HealthScope - healthScope.Name = application.FormatDefaultHealthScopeName(o.AppName) + healthScope.Name = appfile.FormatDefaultHealthScopeName(o.AppName) healthScope.Namespace = o.Env.Namespace err = o.Client.Delete(ctx, &healthScope) if err != nil && !apierrors.IsNotFound(err) {