mirror of
https://github.com/kubevela/kubevela.git
synced 2026-08-27 16:17:34 +00:00
@@ -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 <port>
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
+52
-7
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-42
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
+32
-21
@@ -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 <port>\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
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user