Compare commits

...

5 Commits

Author SHA1 Message Date
qiaozp
93faf41ac4 Fix: Align -n command argument (backport #2719) (#2753)
* Fix: Align -n command argument (#2719)

* add namespace flag

fix

fix test

fix tests

* try test

* try test

* fix tests

(cherry picked from commit b38aa1cdf0)

* revert

* fix

* fix test
2021-11-20 12:28:52 +08:00
github-actions[bot]
1d7ace119d Chore(deps): Bump github.com/containerd/containerd from 1.4.11 to 1.4.12 (#2745)
Bumps [github.com/containerd/containerd](https://github.com/containerd/containerd) from 1.4.11 to 1.4.12.
- [Release notes](https://github.com/containerd/containerd/releases)
- [Changelog](https://github.com/containerd/containerd/blob/main/RELEASES.md)
- [Commits](https://github.com/containerd/containerd/compare/v1.4.11...v1.4.12)

---
updated-dependencies:
- dependency-name: github.com/containerd/containerd
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
(cherry picked from commit 13ed9be6a9)

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-19 11:13:57 +08:00
github-actions[bot]
44bdf033ad [Backport release-1.1] Fix: observability installation (#2735)
* fix observability installation

(cherry picked from commit 32646ea3b6)

* fix nil pointer

(cherry picked from commit 29564fe264)

* fix nil pointer

(cherry picked from commit 716d869dc5)

* remove asset, build in trait

(cherry picked from commit acbeeb16e1)

Co-authored-by: qiaozp <chivalry.pp@gmail.com>
2021-11-18 16:09:35 +08:00
github-actions[bot]
69008da5e8 fix istio (#2736)
(cherry picked from commit 4521a66d19)

Co-authored-by: qiaozp <chivalry.pp@gmail.com>
2021-11-18 14:16:13 +08:00
github-actions[bot]
514ef7ff03 Fix: fix workflowstep depends-on-app (#2725)
(cherry picked from commit b161c247d9)

Co-authored-by: yangsoon <songyang.song@alibaba-inc.com>
2021-11-16 22:50:49 +08:00
48 changed files with 769 additions and 901 deletions

View File

@@ -8,7 +8,7 @@ data:
addons.oam.dev/description: istio Controller is a Kubernetes Controller for manage
traffic.
name: istio
namespace: istio-system
namespace: vela-system
spec:
components:
- name: ns-istio-system

View File

@@ -10,106 +10,13 @@ data:
namespace: vela-system
spec:
components:
- name: ns-observability
properties:
apiVersion: v1
kind: Namespace
metadata:
name: observability
type: raw
- name: import-grafana-dashboard-traitdef
properties:
apiVersion: core.oam.dev/v1beta1
kind: TraitDefinition
metadata:
annotations:
definition.oam.dev/description: Import dashboards to Grafana
name: import-grafana-dashboard
namespace: vela-system
spec:
schematic:
cue:
template: "outputs: registerdatasource: {\n\tapiVersion: \"grafana.extension.oam.dev/v1alpha1\"\n\tkind:
\ \"ImportDashboard\"\n\tspec: {\n\t\tgrafana: {\n\t\t\tservice:
\ parameter.grafanaServiceName\n\t\t\tnamespace: parameter.grafanaServiceNamespace\n\t\t\tcredentialSecret:
\ parameter.credentialSecret\n\t\t\tcredentialSecretNamespace:
parameter.credentialSecretNamespace\n\t\t}\n\t\turls: parameter.urls\n\t}\n}\nparameter:
{\n\tgrafanaServiceName: string\n\tgrafanaServiceNamespace: *\"default\"
| string\n\tcredentialSecret: string\n\tcredentialSecretNamespace:
*\"default\" | string\n\turls: [...string]\n}\n"
type: raw
- name: pure-ingress-traitdef
properties:
apiVersion: core.oam.dev/v1beta1
kind: TraitDefinition
metadata:
annotations:
definition.oam.dev/description: Enable public web traffic for the component
without creating a Service.
name: pure-ingress
namespace: vela-system
spec:
schematic:
cue:
template: "\noutputs: ingress: {\n\tapiVersion: \"networking.k8s.io/v1beta1\"\n\tkind:
\ \"Ingress\"\n\tmetadata:\n\t\tname: context.name\n\tspec: {\n\t\trules:
[{\n\t\t\thost: parameter.domain\n\t\t\thttp: {\n\t\t\t\tpaths: [\n\t\t\t\t\tfor
k, v in parameter.http {\n\t\t\t\t\t\tpath: k\n\t\t\t\t\t\tbackend:
{\n\t\t\t\t\t\t\tserviceName: context.name\n\t\t\t\t\t\t\tservicePort:
v\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t]\n\t\t\t}\n\t\t}]\n\t}\n}\n\nparameter:
{\n\t// +usage=Specify the domain you want to expose\n\tdomain: string\n\n\t//
+usage=Specify the mapping relationship between the http path and the
workload port\n\thttp: [string]: int\n}\n"
status:
customStatus: |-
let igs = context.outputs.ingress.status.loadBalancer.ingress
if igs == _|_ {
message: "No loadBalancer found, visiting by using 'vela port-forward " + context.appName + " --route'\n"
}
if len(igs) > 0 {
if igs[0].ip != _|_ {
message: "Visiting URL: " + context.outputs.ingress.spec.rules[0].host + ", IP: " + igs[0].ip
}
if igs[0].ip == _|_ {
message: "Visiting URL: " + context.outputs.ingress.spec.rules[0].host
}
}
healthPolicy: |
isHealth: len(context.outputs.ingress.status.loadBalancer.ingress) > 0
type: raw
- name: register-grafana-datasource-traitdef
properties:
apiVersion: core.oam.dev/v1beta1
kind: TraitDefinition
metadata:
annotations:
definition.oam.dev/description: Add a datasource to Grafana
name: register-grafana-datasource
namespace: vela-system
spec:
schematic:
cue:
template: "outputs: registerdatasource: {\n\tapiVersion: \"grafana.extension.oam.dev/v1alpha1\"\n\tkind:
\ \"DatasourceRegistration\"\n\tspec: {\n\t\tgrafana: {\n\t\t\tservice:
\ parameter.grafanaServiceName\n\t\t\tnamespace: parameter.grafanaServiceNamespace\n\t\t\tcredentialSecret:
\ parameter.credentialSecret\n\t\t\tcredentialSecretNamespace:
parameter.credentialSecretNamespace\n\t\t}\n\t\tdatasource: {\n\t\t\tname:
\ parameter.name\n\t\t\ttype: parameter.type\n\t\t\taccess:
\ parameter.access\n\t\t\tservice: parameter.service\n\t\t\tnamespace:
parameter.namespace\n\t\t}\n\t}\n}\n\nparameter: {\n\tgrafanaServiceName:
\ string\n\tgrafanaServiceNamespace: *\"default\" | string\n\tcredentialSecret:
\ string\n\tcredentialSecretNamespace: string\n\tname: string\n\ttype:
\ string\n\taccess: *\"proxy\"
| string\n\tservice: string\n\tnamespace: *\"default\"
| string\n}\n"
type: raw
- name: grafana-registration
properties:
chart: ./chart
git:
branch: master
repoType: git
targetNamespace: observability
targetNamespace: vela-system
url: https://github.com/oam-dev/grafana-registration
values:
replicaCount: 1
@@ -119,7 +26,7 @@ data:
chart: grafana
releaseName: grafana
repoType: helm
targetNamespace: observability
targetNamespace: vela-system
url: https://charts.kubevela.net/addons
version: 6.14.1
traits:
@@ -130,9 +37,9 @@ data:
type: pure-ingress
- properties:
credentialSecret: grafana
credentialSecretNamespace: observability
credentialSecretNamespace: vela-system
grafanaServiceName: grafana
grafanaServiceNamespace: observability
grafanaServiceNamespace: vela-system
urls:
- https://charts.kubevela.net/addons/dashboards/kubevela_core_logging.json
- https://charts.kubevela.net/addons/dashboards/kubevela_core_monitoring.json
@@ -145,18 +52,18 @@ data:
chart: loki-stack
releaseName: loki
repoType: helm
targetNamespace: observability
targetNamespace: vela-system
url: https://charts.kubevela.net/addons
version: 2.4.1
traits:
- properties:
access: proxy
credentialSecret: grafana
credentialSecretNamespace: observability
credentialSecretNamespace: vela-system
grafanaServiceName: grafana
grafanaServiceNamespace: observability
grafanaServiceNamespace: vela-system
name: loki
namespace: observability
namespace: vela-system
service: loki
type: loki
type: register-grafana-datasource
@@ -166,7 +73,7 @@ data:
chart: prometheus
releaseName: prometheus
repoType: helm
targetNamespace: observability
targetNamespace: vela-system
url: https://charts.kubevela.net/addons
values:
alertmanager:
@@ -184,11 +91,11 @@ data:
- properties:
access: proxy
credentialSecret: grafana
credentialSecretNamespace: observability
credentialSecretNamespace: vela-system
grafanaServiceName: grafana
grafanaServiceNamespace: observability
grafanaServiceNamespace: vela-system
name: prometheus
namespace: observability
namespace: vela-system
service: prometheus-server
type: prometheus
type: register-grafana-datasource
@@ -197,7 +104,7 @@ data:
properties:
chart: kube-state-metrics
repoType: helm
targetNamespace: observability
targetNamespace: vela-system
url: https://charts.kubevela.net/addons
values:
image:
@@ -212,22 +119,6 @@ data:
name: fluxcd
namespace: vela-system
type: depends-on-app
- name: apply-ns
properties:
component: ns-observability
type: apply-component
- name: apply-trait-1
properties:
component: import-grafana-dashboard-traitdef
type: apply-component
- name: apply-trait-2
properties:
component: pure-ingress-traitdef
type: apply-component
- name: apply-trait-3
properties:
component: register-grafana-datasource-traitdef
type: apply-component
- name: apply-resources
type: apply-remaining
status:

View File

@@ -27,7 +27,7 @@ spec:
}
}
load: op.#Steps & {
if dependsOn.err != _|_ && dependsOn.value == _|_ {
if dependsOn.err != _|_ {
configMap: op.#Read & {
value: {
apiVersion: "v1"
@@ -37,18 +37,17 @@ spec:
namespace: parameter.namespace
}
}
}
apply: op.#Apply & {
value: {
yaml.Unmarshal(configMap.value.data[parameter.name])
}
}
} @step(1)
template: configMap.value.data["application"]
apply: op.#Apply & {
value: yaml.Unmarshal(template)
} @step(2)
wait: op.#ConditionalWait & {
continue: load.apply.value.status.status == "running"
}
continue: apply.value.status.status == "running"
} @step(3)
}
if dependsOn.value != _|_ {
if dependsOn.err == _|_ {
wait: op.#ConditionalWait & {
continue: dependsOn.value.status.status == "running"
}

View File

@@ -0,0 +1,39 @@
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
# Definition source cue file: vela-templates/definitions/internal/import-grafana-dashboard.cue
apiVersion: core.oam.dev/v1beta1
kind: TraitDefinition
metadata:
annotations:
definition.oam.dev/description: Import dashboards to Grafana
name: import-grafana-dashboard
namespace: {{.Values.systemDefinitionNamespace}}
spec:
appliesToWorkloads: []
conflictsWith: []
podDisruptive: false
schematic:
cue:
template: |
outputs: registerdatasource: {
apiVersion: "grafana.extension.oam.dev/v1alpha1"
kind: "ImportDashboard"
spec: {
grafana: {
service: parameter.grafanaServiceName
namespace: parameter.grafanaServiceNamespace
credentialSecret: parameter.credentialSecret
credentialSecretNamespace: parameter.credentialSecretNamespace
}
urls: parameter.urls
}
}
parameter: {
grafanaServiceName: string
grafanaServiceNamespace: *"default" | string
credentialSecret: string
credentialSecretNamespace: *"default" | string
urls: [...string]
}
workloadRefPath: ""

View File

@@ -0,0 +1,56 @@
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
# Definition source cue file: vela-templates/definitions/internal/pure-ingress.cue
apiVersion: core.oam.dev/v1beta1
kind: TraitDefinition
metadata:
annotations:
definition.oam.dev/description: Enable public web traffic for the component without creating a Service.
name: pure-ingress
namespace: {{.Values.systemDefinitionNamespace}}
spec:
appliesToWorkloads: []
conflictsWith: []
podDisruptive: false
schematic:
cue:
template: |
outputs: ingress: {
apiVersion: "networking.k8s.io/v1beta1"
kind: "Ingress"
metadata: name: context.name
spec: rules: [{
host: parameter.domain
http: paths: [
for k, v in parameter.http {
path: k
backend: {
serviceName: context.name
servicePort: v
}
},
]
}]
}
parameter: {
// +usage=Specify the domain you want to expose
domain: string
// +usage=Specify the mapping relationship between the http path and the workload port
http: [string]: int
}
status:
customStatus: |-
let igs = context.outputs.ingress.status.loadBalancer.ingress
if igs == _|_ {
message: "No loadBalancer found, visiting by using 'vela port-forward " + context.appName + " --route'\n"
}
if len(igs) > 0 {
if igs[0].ip != _|_ {
message: "Visiting URL: " + context.outputs.ingress.spec.rules[0].host + ", IP: " + igs[0].ip
}
if igs[0].ip == _|_ {
message: "Visiting URL: " + context.outputs.ingress.spec.rules[0].host
}
}
workloadRefPath: ""

View File

@@ -0,0 +1,48 @@
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
# Definition source cue file: vela-templates/definitions/internal/register-grafana-datasource.cue
apiVersion: core.oam.dev/v1beta1
kind: TraitDefinition
metadata:
annotations:
definition.oam.dev/description: Add a datasource to Grafana
name: register-grafana-datasource
namespace: {{.Values.systemDefinitionNamespace}}
spec:
appliesToWorkloads: []
conflictsWith: []
podDisruptive: false
schematic:
cue:
template: |
outputs: registerdatasource: {
apiVersion: "grafana.extension.oam.dev/v1alpha1"
kind: "DatasourceRegistration"
spec: {
grafana: {
service: parameter.grafanaServiceName
namespace: parameter.grafanaServiceNamespace
credentialSecret: parameter.credentialSecret
credentialSecretNamespace: parameter.credentialSecretNamespace
}
datasource: {
name: parameter.name
type: parameter.type
access: parameter.access
service: parameter.service
namespace: parameter.namespace
}
}
}
parameter: {
grafanaServiceName: string
grafanaServiceNamespace: *"default" | string
credentialSecret: string
credentialSecretNamespace: string
name: string
type: string
access: *"proxy" | string
service: string
namespace: *"default" | string
}
workloadRefPath: ""

View File

@@ -27,7 +27,7 @@ spec:
}
}
load: op.#Steps & {
if dependsOn.err != _|_ && dependsOn.value == _|_ {
if dependsOn.err != _|_ {
configMap: op.#Read & {
value: {
apiVersion: "v1"
@@ -37,18 +37,17 @@ spec:
namespace: parameter.namespace
}
}
}
apply: op.#Apply & {
value: {
yaml.Unmarshal(configMap.value.data[parameter.name])
}
}
} @step(1)
template: configMap.value.data["application"]
apply: op.#Apply & {
value: yaml.Unmarshal(template)
} @step(2)
wait: op.#ConditionalWait & {
continue: load.apply.value.status.status == "running"
}
continue: apply.value.status.status == "running"
} @step(3)
}
if dependsOn.value != _|_ {
if dependsOn.err == _|_ {
wait: op.#ConditionalWait & {
continue: dependsOn.value.status.status == "running"
}

View File

@@ -0,0 +1,39 @@
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
# Definition source cue file: vela-templates/definitions/internal/import-grafana-dashboard.cue
apiVersion: core.oam.dev/v1beta1
kind: TraitDefinition
metadata:
annotations:
definition.oam.dev/description: Import dashboards to Grafana
name: import-grafana-dashboard
namespace: {{.Values.systemDefinitionNamespace}}
spec:
appliesToWorkloads: []
conflictsWith: []
podDisruptive: false
schematic:
cue:
template: |
outputs: registerdatasource: {
apiVersion: "grafana.extension.oam.dev/v1alpha1"
kind: "ImportDashboard"
spec: {
grafana: {
service: parameter.grafanaServiceName
namespace: parameter.grafanaServiceNamespace
credentialSecret: parameter.credentialSecret
credentialSecretNamespace: parameter.credentialSecretNamespace
}
urls: parameter.urls
}
}
parameter: {
grafanaServiceName: string
grafanaServiceNamespace: *"default" | string
credentialSecret: string
credentialSecretNamespace: *"default" | string
urls: [...string]
}
workloadRefPath: ""

View File

@@ -0,0 +1,56 @@
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
# Definition source cue file: vela-templates/definitions/internal/pure-ingress.cue
apiVersion: core.oam.dev/v1beta1
kind: TraitDefinition
metadata:
annotations:
definition.oam.dev/description: Enable public web traffic for the component without creating a Service.
name: pure-ingress
namespace: {{.Values.systemDefinitionNamespace}}
spec:
appliesToWorkloads: []
conflictsWith: []
podDisruptive: false
schematic:
cue:
template: |
outputs: ingress: {
apiVersion: "networking.k8s.io/v1beta1"
kind: "Ingress"
metadata: name: context.name
spec: rules: [{
host: parameter.domain
http: paths: [
for k, v in parameter.http {
path: k
backend: {
serviceName: context.name
servicePort: v
}
},
]
}]
}
parameter: {
// +usage=Specify the domain you want to expose
domain: string
// +usage=Specify the mapping relationship between the http path and the workload port
http: [string]: int
}
status:
customStatus: |-
let igs = context.outputs.ingress.status.loadBalancer.ingress
if igs == _|_ {
message: "No loadBalancer found, visiting by using 'vela port-forward " + context.appName + " --route'\n"
}
if len(igs) > 0 {
if igs[0].ip != _|_ {
message: "Visiting URL: " + context.outputs.ingress.spec.rules[0].host + ", IP: " + igs[0].ip
}
if igs[0].ip == _|_ {
message: "Visiting URL: " + context.outputs.ingress.spec.rules[0].host
}
}
workloadRefPath: ""

View File

@@ -0,0 +1,48 @@
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
# Definition source cue file: vela-templates/definitions/internal/register-grafana-datasource.cue
apiVersion: core.oam.dev/v1beta1
kind: TraitDefinition
metadata:
annotations:
definition.oam.dev/description: Add a datasource to Grafana
name: register-grafana-datasource
namespace: {{.Values.systemDefinitionNamespace}}
spec:
appliesToWorkloads: []
conflictsWith: []
podDisruptive: false
schematic:
cue:
template: |
outputs: registerdatasource: {
apiVersion: "grafana.extension.oam.dev/v1alpha1"
kind: "DatasourceRegistration"
spec: {
grafana: {
service: parameter.grafanaServiceName
namespace: parameter.grafanaServiceNamespace
credentialSecret: parameter.credentialSecret
credentialSecretNamespace: parameter.credentialSecretNamespace
}
datasource: {
name: parameter.name
type: parameter.type
access: parameter.access
service: parameter.service
namespace: parameter.namespace
}
}
}
parameter: {
grafanaServiceName: string
grafanaServiceNamespace: *"default" | string
credentialSecret: string
credentialSecretNamespace: string
name: string
type: string
access: *"proxy" | string
service: string
namespace: *"default" | string
}
workloadRefPath: ""

View File

@@ -1,4 +1,4 @@
This repo is the source artifacts for addon `observability`.
- All .cue files are source artifacts from definition of [observability-asset](../../../vela-templates/addons/observability-asset).
- `initializer-observability.yaml` will help developer [observability](../../../vela-templates/addons/observability).
- All files in definitions are source artifacts which is now built-in in `vela-core` helm chart.
- `application-observability.yaml` will help developer [observability](../../../vela-templates/addons/observability).

View File

@@ -1,21 +0,0 @@
outputs: registerdatasource: {
apiVersion: "grafana.extension.oam.dev/v1alpha1"
kind: "ImportDashboard"
spec: {
grafana: {
service: parameter.grafanaServiceName
namespace: parameter.grafanaServiceNamespace
credentialSecret: parameter.credentialSecret
credentialSecretNamespace: parameter.credentialSecretNamespace
}
urls: parameter.urls
}
}
parameter: {
grafanaServiceName: string
grafanaServiceNamespace: *"default" | string
credentialSecret: string
credentialSecretNamespace: *"default" | string
urls: [...string]
}

View File

@@ -1,31 +0,0 @@
outputs: registerdatasource: {
apiVersion: "grafana.extension.oam.dev/v1alpha1"
kind: "DatasourceRegistration"
spec: {
grafana: {
service: parameter.grafanaServiceName
namespace: parameter.grafanaServiceNamespace
credentialSecret: parameter.credentialSecret
credentialSecretNamespace: parameter.credentialSecretNamespace
}
datasource: {
name: parameter.name
type: parameter.type
access: parameter.access
service: parameter.service
namespace: parameter.namespace
}
}
}
parameter: {
grafanaServiceName: string
grafanaServiceNamespace: *"default" | string
credentialSecret: string
credentialSecretNamespace: string
name: string
type: string
access: *"proxy" | string
service: string
namespace: *"default" | string
}

View File

@@ -88,9 +88,8 @@ var ApplicationStatusDeeplyContext = func(context string, applicationName, workl
}, 180*time.Second, 1*time.Second).Should(gomega.BeTrue())
cli := fmt.Sprintf("vela status %s", applicationName)
output, err := e2e.LongTimeExec(cli, 120*time.Second)
_, err = e2e.LongTimeExec(cli, 120*time.Second)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
gomega.Expect(output).To(gomega.ContainSubstring("Checking health status"))
// TODO(zzxwill) need to check workloadType after app status is refined
})
})

12
e2e/application/vela.yaml Normal file
View File

@@ -0,0 +1,12 @@
createTime: "0001-01-01T00:00:00Z"
name: initmyapp
services:
mysvc:
addRevisionLabel: false
cpu: "0.5"
image: nginx:latest
imagePullPolicy: Always
memory: 200M
port: 80
type: webservice
updateTime: "0001-01-01T00:00:00Z"

View File

@@ -127,7 +127,7 @@ var (
cli := fmt.Sprintf("vela delete %s", applicationName)
output, err := Exec(cli)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
gomega.Expect(output).To(gomega.ContainSubstring("deleted from env"))
gomega.Expect(output).To(gomega.ContainSubstring("already deleted"))
})
})
}

2
go.mod
View File

@@ -10,7 +10,7 @@ require (
github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869
github.com/briandowns/spinner v1.11.1
github.com/containerd/containerd v1.4.11
github.com/containerd/containerd v1.4.12
github.com/coreos/prometheus-operator v0.41.1
github.com/crossplane/crossplane-runtime v0.14.1-0.20210722005935-0b469fcc77cd
github.com/davecgh/go-spew v1.1.1

4
go.sum
View File

@@ -310,8 +310,8 @@ github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on
github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ=
github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.4.4/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.4.11 h1:QCGOUN+i70jEEL/A6JVIbhy4f4fanzAzSR4kNG7SlcE=
github.com/containerd/containerd v1.4.11/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.4.12 h1:V+SHzYmhng/iju6M5nFrpTTusrhidoxKTwdwLw+u4c4=
github.com/containerd/containerd v1.4.12/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7 h1:6ejg6Lkk8dskcM7wQ28gONkukbQkM4qpj4RnYbpFzrI=
github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y=

View File

@@ -31,7 +31,6 @@ import (
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha2"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/builtin"
"github.com/oam-dev/kubevela/pkg/oam"
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
@@ -142,7 +141,7 @@ func (app *AppFile) ExecuteAppfileTasks(io cmdutil.IOStreams) error {
}
// BuildOAMApplication renders Appfile into Application, Scopes and other K8s Resources.
func (app *AppFile) BuildOAMApplication(env *types.EnvMeta, io cmdutil.IOStreams, tm template.Manager, silence bool) (*v1beta1.Application, []oam.Object, error) {
func (app *AppFile) BuildOAMApplication(namespace string, io cmdutil.IOStreams, tm template.Manager, silence bool) (*v1beta1.Application, []oam.Object, error) {
if err := app.ExecuteAppfileTasks(io); err != nil {
if strings.Contains(err.Error(), "'image' : not found") {
return nil, nil, ErrImageNotDefined
@@ -152,7 +151,7 @@ func (app *AppFile) BuildOAMApplication(env *types.EnvMeta, io cmdutil.IOStreams
// auxiliaryObjects currently include OAM Scope Custom Resources and ConfigMaps
var auxiliaryObjects []oam.Object
servApp := new(v1beta1.Application)
servApp.SetNamespace(env.Namespace)
servApp.SetNamespace(namespace)
servApp.SetName(app.Name)
servApp.Spec.Components = []common.ApplicationComponent{}
if !silence {

View File

@@ -132,7 +132,7 @@ func TestBuildOAMApplication2(t *testing.T) {
for _, tcase := range testCases {
tcase.expectApp.Namespace = expectNs
o, _, err := tcase.appFile.BuildOAMApplication(&types.EnvMeta{Namespace: expectNs}, cmdutil.IOStreams{
o, _, err := tcase.appFile.BuildOAMApplication(expectNs, cmdutil.IOStreams{
In: os.Stdin,
Out: os.Stdout,
}, tm, false)
@@ -378,7 +378,7 @@ outputs: ingress: {
}
}
application, objects, err := app.BuildOAMApplication(&types.EnvMeta{Namespace: "default"}, io, tm, false)
application, objects, err := app.BuildOAMApplication("default", io, tm, false)
if c.want.err != nil {
assert.Equal(t, c.want.err, err)
return

View File

@@ -24,6 +24,10 @@ import (
"text/template"
"time"
yaml2 "k8s.io/apimachinery/pkg/util/yaml"
"github.com/oam-dev/kubevela/pkg/oam/util"
common2 "github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/Masterminds/sprig"
@@ -31,20 +35,15 @@ import (
"github.com/pkg/errors"
"github.com/spf13/cobra"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer/yaml"
types2 "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/dynamic"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/oam"
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
"github.com/oam-dev/kubevela/pkg/utils/apply"
"github.com/oam-dev/kubevela/pkg/utils/common"
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
@@ -53,6 +52,9 @@ import (
const (
// DescAnnotation records the description of addon
DescAnnotation = "addons.oam.dev/description"
// DependsOnWorkFlowStepName is workflow step name which is used to check dependsOn app
DependsOnWorkFlowStepName = "depends-on-app"
)
var statusUninstalled = "uninstalled"
@@ -333,25 +335,10 @@ type Addon struct {
data string
// Args is map for renderInitializer
Args map[string]string
application *unstructured.Unstructured
gvk *schema.GroupVersionKind
application *v1beta1.Application
}
func (a *Addon) getGVK() (*schema.GroupVersionKind, error) {
if a.gvk == nil {
if a.application == nil {
_, err := a.renderApplication()
if err != nil {
return nil, err
}
}
gvk := schema.FromAPIVersionAndKind(a.application.GetAPIVersion(), a.application.GetKind())
a.gvk = &gvk
}
return a.gvk, nil
}
func (a *Addon) renderApplication() (*unstructured.Unstructured, error) {
func (a *Addon) renderApplication() (*v1beta1.Application, error) {
if a.Args == nil {
a.Args = map[string]string{}
}
@@ -364,14 +351,10 @@ func (a *Addon) renderApplication() (*unstructured.Unstructured, error) {
if err != nil {
return nil, errors.Wrap(err, "application template render fail")
}
dec := yaml.NewDecodingSerializer(unstructured.UnstructuredJSONScheme)
obj := &unstructured.Unstructured{}
_, gvk, err := dec.Decode(buf.Bytes(), nil, obj)
err = yaml2.NewYAMLOrJSONDecoder(&buf, buf.Len()).Decode(&a.application)
if err != nil {
return nil, err
}
a.application = obj
a.gvk = gvk
return a.application, nil
}
@@ -382,6 +365,10 @@ func (a *Addon) enable() error {
if err != nil {
return err
}
err = a.installDependsOn()
if err != nil {
return errors.Wrap(err, "Error occurs when install dependent addon")
}
err = applicator.Apply(ctx, obj)
if err != nil {
return errors.Wrapf(err, "Error occurs when apply addon application: %s\n", a.name)
@@ -393,7 +380,7 @@ func (a *Addon) enable() error {
return nil
}
func waitApplicationRunning(obj *unstructured.Unstructured) error {
func waitApplicationRunning(obj *v1beta1.Application) error {
ctx := context.Background()
period := 20 * time.Second
timeout := 10 * time.Minute
@@ -412,40 +399,12 @@ func waitApplicationRunning(obj *unstructured.Unstructured) error {
})
}
func (a *Addon) disable() error {
dynamicClient, err := dynamic.NewForConfig(clientArgs.Config)
if err != nil {
return err
}
mapper, err := discoverymapper.New(clientArgs.Config)
if err != nil {
return err
}
obj, err := a.renderApplication()
if err != nil {
return err
}
gvk, err := a.getGVK()
if err != nil {
return err
}
mapping, err := mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
if err != nil {
return err
}
var resourceREST dynamic.ResourceInterface
if mapping.Scope.Name() == meta.RESTScopeNameNamespace {
// namespaced resources should specify the namespace
resourceREST = dynamicClient.Resource(mapping.Resource).Namespace(obj.GetNamespace())
} else {
// for cluster-wide resources
resourceREST = dynamicClient.Resource(mapping.Resource)
}
deletePolicy := metav1.DeletePropagationForeground
deleteOptions := metav1.DeleteOptions{
PropagationPolicy: &deletePolicy,
}
fmt.Println("Deleting all resources...")
err = resourceREST.Delete(context.TODO(), obj.GetName(), deleteOptions)
err = clt.Delete(context.TODO(), obj, client.PropagationPolicy(metav1.DeletePropagationForeground))
if err != nil {
return err
}
@@ -468,6 +427,37 @@ func (a *Addon) setArgs(args map[string]string) {
a.Args = args
}
func (a *Addon) installDependsOn() error {
if a.application.Spec.Workflow == nil || a.application.Spec.Workflow.Steps == nil {
return nil
}
repo, err := NewAddonRepo()
if err != nil {
return err
}
for _, step := range a.application.Spec.Workflow.Steps {
if step.Type == DependsOnWorkFlowStepName {
props, err := util.RawExtension2Map(step.Properties)
if err != nil {
return err
}
dependsOnAddonName, _ := props["name"].(string)
fmt.Printf("Installing dependent addon: %s\n", dependsOnAddonName)
addon, err := repo.getAddon(dependsOnAddonName)
if err != nil {
return err
}
if addon.getStatus() != statusInstalled {
err = addon.enable()
if err != nil {
return err
}
}
}
}
return nil
}
// TransAddonName will turn addon's name from xxx/yyy to xxx-yyy
func TransAddonName(name string) string {
return strings.ReplaceAll(name, "/", "-")

View File

@@ -16,9 +16,53 @@ limitations under the License.
package cli
import (
"github.com/spf13/cobra"
"github.com/oam-dev/kubevela/pkg/utils/common"
)
// constants used in `svc` command
const (
App = "app"
Service = "svc"
Namespace = "namespace"
// FlagDescription command flag to specify the description of the definition
FlagDescription = "desc"
// FlagDryRun command flag to disable actual changes and only display intend changes
FlagDryRun = "dry-run"
// FlagTemplateYAML command flag to specify which existing template YAML file to use
FlagTemplateYAML = "template-yaml"
// FlagOutput command flag to specify which file to save
FlagOutput = "output"
// FlagMessage command flag to specify which file to save
FlagMessage = "message"
// FlagType command flag to specify which definition type to use
FlagType = "type"
// FlagNamespace command flag to specify which namespace to use
FlagNamespace = "namespace"
// FlagInteractive command flag to specify the use of interactive process
FlagInteractive = "interactive"
)
func addNamespaceArg(cmd *cobra.Command) {
cmd.Flags().StringP(Namespace, "n", "", "specify the namespace to use")
}
// GetFlagNamespaceOrEnv will get env and namespace flag, namespace flag takes the priority
func GetFlagNamespaceOrEnv(cmd *cobra.Command, args common.Args) (string, error) {
namespace, err := cmd.Flags().GetString(Namespace)
if err != nil {
return "", err
}
if namespace != "" {
return namespace, nil
}
velaEnv, err := GetFlagEnvOrCurrent(cmd, args)
if err != nil {
return "", err
}
return velaEnv.Namespace, nil
}

View File

@@ -47,22 +47,6 @@ import (
)
const (
// FlagDescription command flag to specify the description of the definition
FlagDescription = "desc"
// FlagDryRun command flag to disable actual changes and only display intend changes
FlagDryRun = "dry-run"
// FlagTemplateYAML command flag to specify which existing template YAML file to use
FlagTemplateYAML = "template-yaml"
// FlagOutput command flag to specify which file to save
FlagOutput = "output"
// FlagMessage command flag to specify which file to save
FlagMessage = "message"
// FlagType command flag to specify which definition type to use
FlagType = "type"
// FlagNamespace command flag to specify which namespace to use
FlagNamespace = "namespace"
// FlagInteractive command flag to specify the use of interactive process
FlagInteractive = "interactive"
// HelmChartNamespacePlaceholder is used as a placeholder for rendering definitions into helm chart format
HelmChartNamespacePlaceholder = "###HELM_NAMESPACE###"
// HelmChartFormatEnvName is the name of the environment variable to enable render helm chart format YAML
@@ -315,7 +299,7 @@ func NewDefinitionGetCommand(c common.Args) *cobra.Command {
}
namespace, err := cmd.Flags().GetString(FlagNamespace)
if err != nil {
return errors.Wrapf(err, "failed to get `%s`", FlagNamespace)
return errors.Wrapf(err, "failed to get `%s`", Namespace)
}
k8sClient, err := c.GetClient()
if err != nil {
@@ -336,7 +320,7 @@ func NewDefinitionGetCommand(c common.Args) *cobra.Command {
},
}
cmd.Flags().StringP(FlagType, "t", "", "Specify which definition type to get. If empty, all types will be searched. Valid types: "+strings.Join(common2.ValidDefinitionTypes(), ", "))
cmd.Flags().StringP(FlagNamespace, "n", "", "Specify which namespace to get. If empty, all namespaces will be searched.")
cmd.Flags().StringP(Namespace, "n", "", "Specify which namespace to get. If empty, all namespaces will be searched.")
return cmd
}
@@ -358,7 +342,7 @@ func NewDefinitionListCommand(c common.Args) *cobra.Command {
}
namespace, err := cmd.Flags().GetString(FlagNamespace)
if err != nil {
return errors.Wrapf(err, "failed to get `%s`", FlagNamespace)
return errors.Wrapf(err, "failed to get `%s`", Namespace)
}
k8sClient, err := c.GetClient()
if err != nil {
@@ -386,7 +370,7 @@ func NewDefinitionListCommand(c common.Args) *cobra.Command {
},
}
cmd.Flags().StringP(FlagType, "t", "", "Specify which definition type to list. If empty, all types will be searched. Valid types: "+strings.Join(common2.ValidDefinitionTypes(), ", "))
cmd.Flags().StringP(FlagNamespace, "n", "", "Specify which namespace to list. If empty, all namespaces will be searched.")
cmd.Flags().StringP(Namespace, "n", "", "Specify which namespace to list. If empty, all namespaces will be searched.")
return cmd
}
@@ -409,7 +393,7 @@ func NewDefinitionEditCommand(c common.Args) *cobra.Command {
}
namespace, err := cmd.Flags().GetString(FlagNamespace)
if err != nil {
return errors.Wrapf(err, "failed to get `%s`", FlagNamespace)
return errors.Wrapf(err, "failed to get `%s`", Namespace)
}
k8sClient, err := c.GetClient()
if err != nil {
@@ -470,7 +454,7 @@ func NewDefinitionEditCommand(c common.Args) *cobra.Command {
},
}
cmd.Flags().StringP(FlagType, "t", "", "Specify which definition type to get. If empty, all types will be searched. Valid types: "+strings.Join(common2.ValidDefinitionTypes(), ", "))
cmd.Flags().StringP(FlagNamespace, "n", "", "Specify which namespace to get. If empty, all namespaces will be searched.")
cmd.Flags().StringP(Namespace, "n", "", "Specify which namespace to get. If empty, all namespaces will be searched.")
return cmd
}
@@ -606,7 +590,7 @@ func NewDefinitionApplyCommand(c common.Args) *cobra.Command {
}
namespace, err := cmd.Flags().GetString(FlagNamespace)
if err != nil {
return errors.Wrapf(err, "failed to get `%s`", FlagNamespace)
return errors.Wrapf(err, "failed to get `%s`", Namespace)
}
k8sClient, err := c.GetClient()
if err != nil {
@@ -660,7 +644,7 @@ func NewDefinitionApplyCommand(c common.Args) *cobra.Command {
},
}
cmd.Flags().BoolP(FlagDryRun, "", false, "only build definition from CUE into CRB object without applying it to kubernetes clusters")
cmd.Flags().StringP(FlagNamespace, "n", "vela-system", "Specify which namespace to apply.")
cmd.Flags().StringP(Namespace, "n", "vela-system", "Specify which namespace to apply.")
return cmd
}
@@ -680,7 +664,7 @@ func NewDefinitionDelCommand(c common.Args) *cobra.Command {
}
namespace, err := cmd.Flags().GetString(FlagNamespace)
if err != nil {
return errors.Wrapf(err, "failed to get `%s`", FlagNamespace)
return errors.Wrapf(err, "failed to get `%s`", Namespace)
}
k8sClient, err := c.GetClient()
if err != nil {
@@ -725,7 +709,7 @@ func NewDefinitionDelCommand(c common.Args) *cobra.Command {
},
}
cmd.Flags().StringP(FlagType, "t", "", "Specify the definition type of target. Valid types: "+strings.Join(common2.ValidDefinitionTypes(), ", "))
cmd.Flags().StringP(FlagNamespace, "n", "", "Specify which namespace the definition locates.")
cmd.Flags().StringP(Namespace, "n", "", "Specify which namespace the definition locates.")
return cmd
}

View File

@@ -46,17 +46,18 @@ func NewDeleteCommand(c common2.Args, ioStreams cmdutil.IOStreams) *cobra.Comman
cmd.SetOut(ioStreams.Out)
cmd.RunE = func(cmd *cobra.Command, args []string) error {
namespace, err := GetFlagNamespaceOrEnv(cmd, c)
if err != nil {
return err
}
newClient, err := c.GetClient()
if err != nil {
return err
}
o := &common.DeleteOptions{
C: c,
}
o.Client = newClient
o.Env, err = GetFlagEnvOrCurrent(cmd, c)
if err != nil {
return err
C: c,
Namespace: namespace,
Client: newClient,
}
if len(args) < 1 {
return errors.New("must specify name for the app")
@@ -89,5 +90,6 @@ func NewDeleteCommand(c common2.Args, ioStreams cmdutil.IOStreams) *cobra.Comman
return nil
}
cmd.PersistentFlags().StringP(Service, "", "", "delete only the specified service in this app")
addNamespaceArg(cmd)
return cmd
}

View File

@@ -72,11 +72,11 @@ func NewDryRunCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Command
return c.SetConfig()
},
RunE: func(cmd *cobra.Command, args []string) error {
velaEnv, err := GetFlagEnvOrCurrent(cmd, c)
namespace, err := GetFlagNamespaceOrEnv(cmd, c)
if err != nil {
return err
}
buff, err := DryRunApplication(o, c, velaEnv.Namespace)
buff, err := DryRunApplication(o, c, namespace)
if err != nil {
return err
}
@@ -87,6 +87,7 @@ func NewDryRunCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Command
cmd.Flags().StringVarP(&o.ApplicationFile, "file", "f", "./app.yaml", "application file name")
cmd.Flags().StringVarP(&o.DefinitionFile, "definition", "d", "", "specify a definition file or directory, it will only be used in dry-run rather than applied to K8s cluster")
addNamespaceArg(cmd)
cmd.SetOut(ioStreams.Out)
return cmd
}

View File

@@ -134,6 +134,7 @@ func NewExecCommand(c common.Args, ioStreams util.IOStreams) *cobra.Command {
cmd.Flags().Duration(podRunningTimeoutFlag, defaultPodExecTimeout,
"The length of time (like 5s, 2m, or 3h, higher than zero) to wait until at least one pod is running",
)
cmd.Flags().StringP(Namespace, "n", "", "Specify which namespace to get. If empty, uses namespace in env.")
return cmd
}
@@ -143,12 +144,18 @@ func (o *VelaExecOptions) Init(ctx context.Context, c *cobra.Command, argsIn []s
o.Cmd = c
o.Args = argsIn
env, err := GetFlagEnvOrCurrent(o.Cmd, o.VelaC)
namespace, err := c.Flags().GetString(Namespace)
if err != nil {
return err
return errors.Wrapf(err, "failed to get `%s`", FlagNamespace)
}
o.Env = env
app, err := appfile.LoadApplication(env.Namespace, o.Args[0], o.VelaC)
if namespace == "" {
env, err := GetFlagEnvOrCurrent(o.Cmd, o.VelaC)
if err != nil {
return err
}
namespace = env.Namespace
}
app, err := appfile.LoadApplication(namespace, o.Args[0], o.VelaC)
if err != nil {
return err
}

View File

@@ -37,15 +37,14 @@ func NewExportCommand(c common2.Args, ioStream cmdutil.IOStreams) *cobra.Command
types.TagCommandType: types.TypeStart,
},
RunE: func(cmd *cobra.Command, args []string) error {
velaEnv, err := GetFlagEnvOrCurrent(cmd, c)
namespace, err := GetFlagNamespaceOrEnv(cmd, c)
if err != nil {
return err
}
o := &common.AppfileOptions{
IO: ioStream,
Env: velaEnv,
IO: ioStream,
}
_, data, err := o.Export(*appFilePath, velaEnv.Namespace, true, c)
_, data, err := o.Export(*appFilePath, namespace, true, c)
if err != nil {
return err
}
@@ -55,6 +54,7 @@ func NewExportCommand(c common2.Args, ioStream cmdutil.IOStreams) *cobra.Command
}
cmd.SetOut(ioStream.Out)
addNamespaceArg(cmd)
cmd.Flags().StringVarP(appFilePath, "file", "f", "", "specify file path for appfile")
return cmd
}

View File

@@ -26,15 +26,15 @@ import (
"cuelang.org/go/cue"
"github.com/AlecAivazis/survey/v2"
"github.com/fatih/color"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
v1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
"github.com/oam-dev/kubevela/apis/types"
common2 "github.com/oam-dev/kubevela/pkg/utils/common"
"github.com/oam-dev/kubevela/pkg/utils/env"
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
"github.com/oam-dev/kubevela/references/appfile"
"github.com/oam-dev/kubevela/references/appfile/api"
@@ -45,8 +45,8 @@ import (
type appInitOptions struct {
client client.Client
cmdutil.IOStreams
Env *types.EnvMeta
c common2.Args
Namespace string
c common2.Args
app *api.Application
appName string
@@ -68,15 +68,17 @@ func NewInitCommand(c common2.Args, ioStreams cmdutil.IOStreams) *cobra.Command
return c.SetConfig()
},
RunE: func(cmd *cobra.Command, args []string) error {
var err error
o.Namespace, err = GetFlagNamespaceOrEnv(cmd, c)
if err != nil {
return err
}
newClient, err := c.GetClient()
if err != nil {
return err
}
o.client = newClient
o.Env, err = GetFlagEnvOrCurrent(cmd, c)
if err != nil {
return err
}
o.IOStreams.Info("Welcome to use KubeVela CLI! Please describe your application.")
o.IOStreams.Info()
if err = o.CheckEnv(); err != nil {
@@ -108,24 +110,25 @@ func NewInitCommand(c common2.Args, ioStreams cmdutil.IOStreams) *cobra.Command
}
ctx := context.Background()
err = common.BuildRun(ctx, o.app, o.client, o.Env, o.IOStreams)
err = common.BuildRun(ctx, o.app, o.client, o.Namespace, o.IOStreams)
if err != nil {
return err
}
deployStatus, err := printTrackingDeployStatus(c, o.IOStreams, o.appName, o.Env)
deployStatus, err := printTrackingDeployStatus(c, o.IOStreams, o.appName, o.Namespace)
if err != nil {
return err
}
if deployStatus != compStatusDeployed {
return nil
}
return printAppStatus(context.Background(), newClient, ioStreams, o.appName, o.Env, cmd, c)
return printAppStatus(context.Background(), newClient, ioStreams, o.appName, o.Namespace, cmd, c)
},
Annotations: map[string]string{
types.TagCommandType: types.TypeStart,
},
}
cmd.Flags().BoolVar(&o.renderOnly, "render-only", false, "Rendering vela.yaml in current dir and do not deploy")
addNamespaceArg(cmd)
cmd.SetOut(ioStreams.Out)
return cmd
}
@@ -144,11 +147,22 @@ func (o *appInitOptions) Naming() error {
// CheckEnv checks environment, e.g., domain and email.
func (o *appInitOptions) CheckEnv() error {
if o.Env.Namespace == "" {
o.Env.Namespace = "default"
if o.Namespace == "" {
o.Namespace = "default"
}
if err := env.CreateEnv(o.Env.Name, o.Env); err != nil {
return errors.Wrap(err, "app init create namespace err")
var ns v1.Namespace
ctx := context.Background()
err := o.client.Get(ctx, client.ObjectKey{
Name: o.Namespace,
}, &ns)
if apierrors.IsNotFound(err) {
ns.Name = o.Namespace
err = o.client.Create(ctx, &ns)
if err != nil {
return err
}
} else if err != nil {
return err
}
return nil
}
@@ -181,7 +195,7 @@ func formatAndGetUsage(p *types.Parameter) string {
// Workload asks user to choose workload type from installed workloads
func (o *appInitOptions) Workload() error {
workloads, err := plugins.LoadInstalledCapabilityWithType(o.Env.Namespace, o.c, types.TypeComponentDefinition)
workloads, err := plugins.LoadInstalledCapabilityWithType(o.Namespace, o.c, types.TypeComponentDefinition)
if err != nil {
return err
}
@@ -303,7 +317,7 @@ func (o *appInitOptions) Workload() error {
// other type not supported
}
}
o.app, err = common.BaseComplete(o.Env, o.c, o.workloadName, o.appName, fs, o.workloadType)
o.app, err = common.BaseComplete(o.Namespace, o.c, o.workloadName, o.appName, fs, o.workloadType)
return err
}

View File

@@ -73,11 +73,11 @@ func NewLiveDiffCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Comma
return c.SetConfig()
},
RunE: func(cmd *cobra.Command, args []string) error {
velaEnv, err := GetFlagEnvOrCurrent(cmd, c)
namespace, err := GetFlagNamespaceOrEnv(cmd, c)
if err != nil {
return err
}
buff, err := LiveDiffApplication(o, c, velaEnv.Namespace)
buff, err := LiveDiffApplication(o, c, namespace)
if err != nil {
return err
}
@@ -90,6 +90,7 @@ func NewLiveDiffCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Comma
cmd.Flags().StringVarP(&o.DefinitionFile, "definition", "d", "", "specify a file or directory containing capability definitions, they will only be used in dry-run rather than applied to K8s cluster")
cmd.Flags().StringVarP(&o.Revision, "Revision", "r", "", "specify an application Revision name, by default, it will compare with the latest Revision")
cmd.Flags().IntVarP(&o.Context, "context", "c", -1, "output number lines of context around changes, by default show all unchanged lines")
addNamespaceArg(cmd)
cmd.SetOut(ioStreams.Out)
return cmd
}

View File

@@ -44,28 +44,21 @@ func NewListCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
return c.SetConfig()
},
RunE: func(cmd *cobra.Command, args []string) error {
env, err := GetFlagEnvOrCurrent(cmd, c)
if err != nil {
return err
}
newClient, err := c.GetClient()
if err != nil {
return err
}
namespace, err := cmd.Flags().GetString(Namespace)
namespace, err := GetFlagNamespaceOrEnv(cmd, c)
if err != nil {
return err
}
if namespace == "" {
namespace = env.Namespace
}
return printApplicationList(ctx, newClient, namespace, ioStreams)
},
Annotations: map[string]string{
types.TagCommandType: types.TypeApp,
},
}
cmd.PersistentFlags().StringP(Namespace, "n", "", "specify the namespace the application want to list, default is the current env namespace")
addNamespaceArg(cmd)
return cmd
}

View File

@@ -58,10 +58,6 @@ func newTrackingSpinnerWithDelay(suffix string, interval time.Duration) *spinner
spinner.WithSuffix(suffixColor.Sprintf(" %s", suffix)))
}
func newTrackingSpinner(suffix string) *spinner.Spinner {
return newTrackingSpinnerWithDelay(suffix, 500*time.Millisecond)
}
func applySpinnerNewSuffix(s *spinner.Spinner, suffix string) {
suffixColor := color.New(color.Bold, color.FgGreen)
s.Suffix = suffixColor.Sprintf(" %s", suffix)

View File

@@ -74,14 +74,14 @@ func NewCapabilityShowCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra
}
ctx := context.Background()
capabilityName := args[0]
velaEnv, err := GetFlagEnvOrCurrent(cmd, c)
namespace, err := GetFlagNamespaceOrEnv(cmd, c)
if err != nil {
return err
}
if webSite {
return startReferenceDocsSite(ctx, velaEnv.Namespace, c, ioStreams, capabilityName)
return startReferenceDocsSite(ctx, namespace, c, ioStreams, capabilityName)
}
return ShowReferenceConsole(ctx, c, ioStreams, capabilityName, velaEnv.Namespace)
return ShowReferenceConsole(ctx, c, ioStreams, capabilityName, namespace)
},
Annotations: map[string]string{
types.TagCommandType: types.TypeStart,
@@ -89,6 +89,7 @@ func NewCapabilityShowCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra
}
cmd.Flags().BoolVarP(&webSite, "web", "", false, " start web doc site")
addNamespaceArg(cmd)
cmd.SetOut(ioStreams.Out)
return cmd
}

View File

@@ -18,7 +18,6 @@ package cli
import (
"context"
"fmt"
"os"
"strings"
"time"
@@ -32,11 +31,9 @@ import (
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha2"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/oam/util"
"github.com/oam-dev/kubevela/pkg/utils/common"
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
"github.com/oam-dev/kubevela/references/appfile"
"github.com/oam-dev/kubevela/references/appfile/api"
)
// HealthStatus represents health status strings.
@@ -70,22 +67,17 @@ const (
compStatusDeploying CompStatus = iota
compStatusDeployFail
compStatusDeployed
compStatusHealthChecking
compStatusHealthCheckDone
compStatusUnknown
)
// Error msg used in `status` command
const (
ErrNotLoadAppConfig = "cannot load the application"
ErrFmtNotInitialized = "service: %s not ready"
ErrServiceNotFound = "service %s not found in app"
ErrNotLoadAppConfig = "cannot load the application"
)
const (
trackingInterval time.Duration = 1 * time.Second
deployTimeout time.Duration = 10 * time.Second
healthCheckBufferTime time.Duration = 120 * time.Second
trackingInterval time.Duration = 1 * time.Second
deployTimeout time.Duration = 10 * time.Second
)
// NewAppStatusCommand creates `status` command for showing status
@@ -100,38 +92,37 @@ func NewAppStatusCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Comm
return c.SetConfig()
},
RunE: func(cmd *cobra.Command, args []string) error {
namespace, err := GetFlagNamespaceOrEnv(cmd, c)
if err != nil {
return err
}
argsLength := len(args)
if argsLength == 0 {
ioStreams.Errorf("Hint: please specify an application")
os.Exit(1)
}
appName := args[0]
env, err := GetFlagEnvOrCurrent(cmd, c)
if err != nil {
ioStreams.Errorf("Error: failed to get Env: %s", err)
return err
}
newClient, err := c.GetClient()
if err != nil {
return err
}
return printAppStatus(ctx, newClient, ioStreams, appName, env, cmd, c)
return printAppStatus(ctx, newClient, ioStreams, appName, namespace, cmd, c)
},
Annotations: map[string]string{
types.TagCommandType: types.TypeApp,
},
}
cmd.Flags().StringP("svc", "s", "", "service name")
addNamespaceArg(cmd)
cmd.SetOut(ioStreams.Out)
return cmd
}
func printAppStatus(ctx context.Context, c client.Client, ioStreams cmdutil.IOStreams, appName string, env *types.EnvMeta, cmd *cobra.Command, velaC common.Args) error {
app, err := appfile.LoadApplication(env.Namespace, appName, velaC)
func printAppStatus(_ context.Context, c client.Client, ioStreams cmdutil.IOStreams, appName string, namespace string, cmd *cobra.Command, velaC common.Args) error {
app, err := appfile.LoadApplication(namespace, appName, velaC)
if err != nil {
return err
}
namespace := env.Namespace
cmd.Printf("About:\n\n")
table := newUITable()
@@ -141,7 +132,7 @@ func printAppStatus(ctx context.Context, c client.Client, ioStreams cmdutil.IOSt
cmd.Printf("%s\n\n", table.String())
cmd.Printf("Services:\n\n")
return loopCheckStatus(ctx, c, ioStreams, appName, env)
return loopCheckStatus(c, ioStreams, appName, namespace)
}
func loadRemoteApplication(c client.Client, ns string, name string) (*v1beta1.Application, error) {
@@ -153,35 +144,41 @@ func loadRemoteApplication(c client.Client, ns string, name string) (*v1beta1.Ap
return app, err
}
func loopCheckStatus(ctx context.Context, c client.Client, ioStreams cmdutil.IOStreams, appName string, env *types.EnvMeta) error {
remoteApp, err := loadRemoteApplication(c, env.Namespace, appName)
func getComponentType(app *v1beta1.Application, name string) string {
for _, c := range app.Spec.Components {
if c.Name == name {
return c.Type
}
}
return "webservice"
}
func loopCheckStatus(c client.Client, ioStreams cmdutil.IOStreams, appName string, namespace string) error {
remoteApp, err := loadRemoteApplication(c, namespace, appName)
if err != nil {
return err
}
for _, comp := range remoteApp.Spec.Components {
for _, comp := range remoteApp.Status.Services {
compName := comp.Name
healthStatus, healthInfo, err := healthCheckLoop(ctx, c, compName, appName, env)
if err != nil {
ioStreams.Info(healthInfo)
return err
ioStreams.Infof(white.Sprintf(" - Name: %s Env: %s\n", compName, comp.Env))
ioStreams.Infof(" Type: %s\n", getComponentType(remoteApp, compName))
healthColor := getHealthStatusColor(comp.Healthy)
healthInfo := strings.ReplaceAll(comp.Message, "\n", "\n\t") // format healthInfo output
healthstats := "healthy"
if !comp.Healthy {
healthstats = "unhealthy"
}
ioStreams.Infof(white.Sprintf(" - Name: %s\n", compName))
ioStreams.Infof(" Type: %s\n", comp.Type)
healthColor := getHealthStatusColor(healthStatus)
healthInfo = strings.ReplaceAll(healthInfo, "\n", "\n\t") // format healthInfo output
ioStreams.Infof(" %s %s\n", healthColor.Sprint(healthStatus), healthColor.Sprint(healthInfo))
ioStreams.Infof(" %s %s\n", healthColor.Sprint(healthstats), healthColor.Sprint(healthInfo))
// load it again after health check
remoteApp, err = loadRemoteApplication(c, env.Namespace, appName)
remoteApp, err = loadRemoteApplication(c, namespace, appName)
if err != nil {
return err
}
// workload Must found
ioStreams.Infof(" Traits:\n")
workloadStatus, _ := getWorkloadStatusFromApp(remoteApp, compName)
for _, tr := range workloadStatus.Traits {
for _, tr := range comp.Traits {
if tr.Message != "" {
if tr.Healthy {
ioStreams.Infof(" - %s%s: %s", emojiSucceed, white.Sprint(tr.Type), tr.Message)
@@ -190,58 +187,20 @@ func loopCheckStatus(ctx context.Context, c client.Client, ioStreams cmdutil.IOS
}
continue
}
var message string
for _, v := range comp.Traits {
if v.Type == tr.Type {
traitData, _ := util.RawExtension2Map(v.Properties)
for k, v := range traitData {
message += fmt.Sprintf("%v=%v\n\t\t", k, v)
}
break
}
}
ioStreams.Infof(" - %s%s: %s", emojiSucceed, white.Sprint(tr.Type), message)
}
ioStreams.Info("")
ioStreams.Infof(" Last Deployment:\n")
ioStreams.Infof(" Created at: %v\n", remoteApp.CreationTimestamp)
}
return nil
}
func healthCheckLoop(ctx context.Context, c client.Client, compName, appName string, env *types.EnvMeta) (HealthStatus, string, error) {
// Health Check Loop For Workload
var healthInfo string
var healthStatus HealthStatus
var err error
sHealthCheck := newTrackingSpinner("Checking health status ...")
sHealthCheck.Start()
defer sHealthCheck.Stop()
HealthCheckLoop:
for {
time.Sleep(trackingInterval)
var healthcheckStatus CompStatus
healthcheckStatus, healthStatus, healthInfo, err = trackHealthCheckingStatus(ctx, c, compName, appName, env)
if err != nil {
healthInfo = red.Sprintf("Health checking failed!")
return "", healthInfo, err
}
if healthcheckStatus == compStatusHealthCheckDone {
break HealthCheckLoop
}
}
return healthStatus, healthInfo, nil
}
func printTrackingDeployStatus(c common.Args, ioStreams cmdutil.IOStreams, appName string, env *types.EnvMeta) (CompStatus, error) {
func printTrackingDeployStatus(c common.Args, ioStreams cmdutil.IOStreams, appName string, namespace string) (CompStatus, error) {
sDeploy := newTrackingSpinnerWithDelay("Checking Status ...", trackingInterval)
sDeploy.Start()
defer sDeploy.Stop()
TrackDeployLoop:
for {
time.Sleep(trackingInterval)
deployStatus, failMsg, err := TrackDeployStatus(c, appName, env)
deployStatus, failMsg, err := TrackDeployStatus(c, appName, namespace)
if err != nil {
return compStatusUnknown, err
}
@@ -263,8 +222,8 @@ TrackDeployLoop:
}
// TrackDeployStatus will only check AppConfig is deployed successfully,
func TrackDeployStatus(c common.Args, appName string, env *types.EnvMeta) (CompStatus, string, error) {
appObj, err := appfile.LoadApplication(env.Namespace, appName, c)
func TrackDeployStatus(c common.Args, appName string, namespace string) (CompStatus, string, error) {
appObj, err := appfile.LoadApplication(namespace, appName, c)
if err != nil {
return compStatusUnknown, "", err
}
@@ -289,86 +248,9 @@ func TrackDeployStatus(c common.Args, appName string, env *types.EnvMeta) (CompS
return compStatusDeploying, "", nil
}
// trackHealthCheckingStatus will check health status from health scope
func trackHealthCheckingStatus(ctx context.Context, c client.Client, compName, appName string, env *types.EnvMeta) (CompStatus, HealthStatus, string, error) {
app, err := loadRemoteApplication(c, env.Namespace, appName)
if err != nil {
return compStatusUnknown, HealthStatusNotDiagnosed, "", err
func getHealthStatusColor(s bool) *color.Color {
if s {
return green
}
if len(app.Status.Conditions) < 1 {
// still reconciling
return compStatusUnknown, HealthStatusUnknown, "", nil
}
// check whether referenced a HealthScope
var healthScopeName string
for _, v := range app.Spec.Components {
if len(v.Scopes) > 0 {
healthScopeName = v.Scopes[api.DefaultHealthScopeKey]
}
}
var healthStatus HealthStatus
if healthScopeName != "" {
var healthScope v1alpha2.HealthScope
if err = c.Get(ctx, client.ObjectKey{Namespace: env.Namespace, Name: healthScopeName}, &healthScope); err != nil {
return compStatusUnknown, HealthStatusUnknown, "", err
}
var wlhc *v1alpha2.WorkloadHealthCondition
for _, v := range healthScope.Status.WorkloadHealthConditions {
if v.ComponentName == compName {
wlhc = v
}
}
if wlhc == nil {
cTime := app.GetCreationTimestamp()
if time.Since(cTime.Time) <= deployTimeout {
return compStatusHealthChecking, HealthStatusUnknown, "", nil
}
if len(healthScope.Spec.AppRefs) == 0 && len(healthScope.Spec.WorkloadReferences) == 0 {
return compStatusHealthCheckDone, HealthStatusHealthy, "no workload or app found in health scope", nil
}
return compStatusUnknown, HealthStatusUnknown, "", fmt.Errorf("cannot get health condition from the health scope: %s", healthScope.Name)
}
healthStatus = wlhc.HealthStatus
if healthStatus == HealthStatusHealthy {
return compStatusHealthCheckDone, healthStatus, wlhc.Diagnosis, nil
}
if healthStatus == HealthStatusUnhealthy {
cTime := app.GetCreationTimestamp()
if time.Since(cTime.Time) <= healthCheckBufferTime {
return compStatusHealthChecking, HealthStatusUnknown, "", nil
}
return compStatusHealthCheckDone, healthStatus, wlhc.Diagnosis, nil
}
}
return compStatusHealthCheckDone, HealthStatusNotDiagnosed, "", nil
}
func getWorkloadStatusFromApp(app *v1beta1.Application, compName string) (commontypes.ApplicationComponentStatus, bool) {
foundWlStatus := false
wlStatus := commontypes.ApplicationComponentStatus{}
if app == nil {
return wlStatus, foundWlStatus
}
for _, v := range app.Status.Services {
if v.Name == compName {
wlStatus = v
foundWlStatus = true
break
}
}
return wlStatus, foundWlStatus
}
func getHealthStatusColor(s HealthStatus) *color.Color {
var c *color.Color
switch s {
case HealthStatusHealthy:
c = green
case HealthStatusUnknown, HealthStatusNotDiagnosed:
c = yellow
default:
c = red
}
return c
return yellow
}

View File

@@ -46,7 +46,7 @@ func NewUpCommand(c common2.Args, ioStream cmdutil.IOStreams) *cobra.Command {
return c.SetConfig()
},
RunE: func(cmd *cobra.Command, args []string) error {
velaEnv, err := GetFlagEnvOrCurrent(cmd, c)
namespace, err := GetFlagNamespaceOrEnv(cmd, c)
if err != nil {
return err
}
@@ -70,16 +70,17 @@ func NewUpCommand(c common2.Args, ioStream cmdutil.IOStreams) *cobra.Command {
}
} else {
o := &common.AppfileOptions{
Kubecli: kubecli,
IO: ioStream,
Env: velaEnv,
Kubecli: kubecli,
IO: ioStream,
Namespace: namespace,
}
return o.Run(*appFilePath, velaEnv.Namespace, c)
return o.Run(*appFilePath, o.Namespace, c)
}
return nil
},
}
cmd.SetOut(ioStream.Out)
cmd.Flags().StringVarP(appFilePath, "file", "f", "", "specify file path for appfile")
addNamespaceArg(cmd)
return cmd
}

View File

@@ -25,7 +25,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/apis/types"
common2 "github.com/oam-dev/kubevela/pkg/utils/common"
"github.com/oam-dev/kubevela/pkg/utils/util"
"github.com/oam-dev/kubevela/references/common"
@@ -33,13 +32,10 @@ import (
func TestUp(t *testing.T) {
ioStream := util.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr}
env := types.EnvMeta{
Name: "up",
Namespace: "env-up",
}
namespace := "up-ns"
o := common.AppfileOptions{
IO: ioStream,
Env: &env,
IO: ioStream,
Namespace: namespace,
}
app := &v1beta1.Application{}
app.Name = "app-up"

View File

@@ -60,17 +60,10 @@ func NewWorkflowSuspendCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra
if len(args) < 1 {
return fmt.Errorf("must specify application name")
}
namespace, err := cmd.Flags().GetString(FlagNamespace)
namespace, err := GetFlagNamespaceOrEnv(cmd, c)
if err != nil {
return err
}
if namespace == "" {
env, err := GetFlagEnvOrCurrent(cmd, c)
if err != nil {
return err
}
namespace = env.Namespace
}
app, err := appfile.LoadApplication(namespace, args[0], c)
if err != nil {
return err
@@ -93,7 +86,7 @@ func NewWorkflowSuspendCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra
return nil
},
}
cmd.Flags().StringP(FlagNamespace, "n", "", "Specify which namespace to get. If empty, uses namespace in env.")
addNamespaceArg(cmd)
return cmd
}
@@ -108,17 +101,10 @@ func NewWorkflowResumeCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.
if len(args) < 1 {
return fmt.Errorf("must specify application name")
}
namespace, err := cmd.Flags().GetString(FlagNamespace)
namespace, err := GetFlagNamespaceOrEnv(cmd, c)
if err != nil {
return err
}
if namespace == "" {
env, err := GetFlagEnvOrCurrent(cmd, c)
if err != nil {
return err
}
namespace = env.Namespace
}
app, err := appfile.LoadApplication(namespace, args[0], c)
if err != nil {
return err
@@ -151,7 +137,7 @@ func NewWorkflowResumeCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.
return nil
},
}
cmd.Flags().StringP(FlagNamespace, "n", "", "Specify which namespace to get. If empty, uses namespace in env.")
addNamespaceArg(cmd)
return cmd
}
@@ -166,17 +152,10 @@ func NewWorkflowTerminateCommand(c common.Args, ioStream cmdutil.IOStreams) *cob
if len(args) < 1 {
return fmt.Errorf("must specify application name")
}
namespace, err := cmd.Flags().GetString(FlagNamespace)
namespace, err := GetFlagNamespaceOrEnv(cmd, c)
if err != nil {
return err
}
if namespace == "" {
env, err := GetFlagEnvOrCurrent(cmd, c)
if err != nil {
return err
}
namespace = env.Namespace
}
app, err := appfile.LoadApplication(namespace, args[0], c)
if err != nil {
return err
@@ -199,7 +178,7 @@ func NewWorkflowTerminateCommand(c common.Args, ioStream cmdutil.IOStreams) *cob
return nil
},
}
cmd.Flags().StringP(FlagNamespace, "n", "", "Specify which namespace to get. If empty, uses namespace in env.")
addNamespaceArg(cmd)
return cmd
}
@@ -214,17 +193,10 @@ func NewWorkflowRestartCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra
if len(args) < 1 {
return fmt.Errorf("must specify application name")
}
namespace, err := cmd.Flags().GetString(FlagNamespace)
namespace, err := GetFlagNamespaceOrEnv(cmd, c)
if err != nil {
return err
}
if namespace == "" {
env, err := GetFlagEnvOrCurrent(cmd, c)
if err != nil {
return err
}
namespace = env.Namespace
}
app, err := appfile.LoadApplication(namespace, args[0], c)
if err != nil {
return err
@@ -247,7 +219,7 @@ func NewWorkflowRestartCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra
return nil
},
}
cmd.Flags().StringP(FlagNamespace, "n", "", "Specify which namespace to get. If empty, uses namespace in env.")
addNamespaceArg(cmd)
return cmd
}

View File

@@ -38,17 +38,18 @@ func NewWorkloadsCommand(c common2.Args, ioStreams cmdutil.IOStreams) *cobra.Com
return c.SetConfig()
},
RunE: func(cmd *cobra.Command, args []string) error {
env, err := GetFlagEnvOrCurrent(cmd, c)
namespace, err := GetFlagNamespaceOrEnv(cmd, c)
if err != nil {
return err
}
return printWorkloadList(env.Namespace, c, ioStreams)
return printWorkloadList(namespace, c, ioStreams)
},
Annotations: map[string]string{
types.TagCommandType: types.TypeCap,
},
}
cmd.SetOut(ioStreams.Out)
addNamespaceArg(cmd)
return cmd
}

View File

@@ -63,9 +63,9 @@ type applicationMetaList []apis.ApplicationMeta
// AppfileOptions is some configuration that modify options for an Appfile
type AppfileOptions struct {
Kubecli client.Client
IO cmdutil.IOStreams
Env *types.EnvMeta
Kubecli client.Client
IO cmdutil.IOStreams
Namespace string
}
// BuildResult is the export struct from AppFile yaml or AppFile object
@@ -105,11 +105,11 @@ type Option struct {
// DeleteOptions is options for delete
type DeleteOptions struct {
AppName string
CompName string
Client client.Client
Env *types.EnvMeta
C common.Args
Namespace string
AppName string
CompName string
Client client.Client
C common.Args
}
// ListApplications lists all applications
@@ -211,7 +211,7 @@ func RetrieveApplicationStatusByName(ctx context.Context, c client.Reader, appli
func (o *DeleteOptions) DeleteApp() (string, error) {
ctx := context.Background()
var app = new(corev1beta1.Application)
err := o.Client.Get(ctx, client.ObjectKey{Name: o.AppName, Namespace: o.Env.Namespace}, app)
err := o.Client.Get(ctx, client.ObjectKey{Name: o.AppName, Namespace: o.Namespace}, app)
if err != nil {
if apierrors.IsNotFound(err) {
return fmt.Sprintf("app \"%s\" already deleted", o.AppName), nil
@@ -228,7 +228,7 @@ func (o *DeleteOptions) DeleteApp() (string, error) {
healthScopeName, ok := cmp.Scopes[api.DefaultHealthScopeKey]
if ok {
var healthScope corev1alpha2.HealthScope
if err := o.Client.Get(ctx, client.ObjectKey{Namespace: o.Env.Namespace, Name: healthScopeName}, &healthScope); err != nil {
if err := o.Client.Get(ctx, client.ObjectKey{Namespace: o.Namespace, Name: healthScopeName}, &healthScope); err != nil {
if apierrors.IsNotFound(err) {
continue
}
@@ -239,7 +239,7 @@ func (o *DeleteOptions) DeleteApp() (string, error) {
}
}
}
return fmt.Sprintf("app \"%s\" deleted from env \"%s\"", o.AppName, o.Env.Name), nil
return fmt.Sprintf("app \"%s\" already deleted from namespace \"%s\"", o.AppName, o.Namespace), nil
}
// DeleteComponent will delete one component including server side.
@@ -248,7 +248,7 @@ func (o *DeleteOptions) DeleteComponent(io cmdutil.IOStreams) (string, error) {
if o.AppName == "" {
return "", errors.New("app name is required")
}
app, err := appfile.LoadApplication(o.Env.Namespace, o.AppName, o.C)
app, err := appfile.LoadApplication(o.Namespace, o.AppName, o.C)
if err != nil {
return "", err
}
@@ -371,7 +371,7 @@ func (o *AppfileOptions) ExportFromAppFile(app *api.AppFile, namespace string, q
appHandler := appfile.NewApplication(app, tm)
// new
retApplication, scopes, err := appHandler.BuildOAMApplication(o.Env, o.IO, appHandler.Tm, quiet)
retApplication, scopes, err := appHandler.BuildOAMApplication(o.Namespace, o.IO, appHandler.Tm, quiet)
if err != nil {
return nil, nil, err
}
@@ -441,7 +441,7 @@ func (o *AppfileOptions) Run(filePath, namespace string, c common.Args) error {
// BaseAppFileRun starts an application according to Appfile
func (o *AppfileOptions) BaseAppFileRun(result *BuildResult, args common.Args) error {
kubernetesComponent, err := appfile.ApplyTerraform(result.application, o.Kubecli, o.IO, o.Env.Namespace, args)
kubernetesComponent, err := appfile.ApplyTerraform(result.application, o.Kubecli, o.IO, o.Namespace, args)
if err != nil {
return err
}

View File

@@ -21,15 +21,14 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/utils/util"
"github.com/oam-dev/kubevela/references/appfile"
"github.com/oam-dev/kubevela/references/appfile/api"
)
// BuildRun will build application and deploy from Appfile
func BuildRun(ctx context.Context, app *api.Application, client client.Client, env *types.EnvMeta, io util.IOStreams) error {
o, scopes, err := app.BuildOAMApplication(env, io, app.Tm, true)
func BuildRun(ctx context.Context, app *api.Application, client client.Client, namespace string, io util.IOStreams) error {
o, scopes, err := app.BuildOAMApplication(namespace, io, app.Tm, true)
if err != nil {
return err
}

View File

@@ -25,28 +25,14 @@ import (
"cuelang.org/go/cue"
"github.com/spf13/pflag"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/utils/util"
"github.com/oam-dev/kubevela/references/appfile"
"github.com/oam-dev/kubevela/references/appfile/api"
"github.com/oam-dev/kubevela/references/plugins"
)
// RunOptions include all options for run
type RunOptions struct {
Env *types.EnvMeta
WorkloadName string
KubeClient client.Client
App *api.Application
AppName string
Staging bool
util.IOStreams
}
// InitApplication will load Application from cluster
func InitApplication(env *types.EnvMeta, c common.Args, workloadName string, appGroup string) (*api.Application, error) {
func InitApplication(namespace string, c common.Args, workloadName string, appGroup string) (*api.Application, error) {
var appName string
if appGroup != "" {
appName = appGroup
@@ -56,7 +42,7 @@ func InitApplication(env *types.EnvMeta, c common.Args, workloadName string, app
// TODO(wonderflow): we should load the existing application from cluster and convert to appfile
// app, err := appfile.LoadApplication(env.Namespace, appName, c)
// compatible application not found
app, err := appfile.NewEmptyApplication(env.Namespace, c)
app, err := appfile.NewEmptyApplication(namespace, c)
if err != nil {
return nil, err
}
@@ -66,8 +52,8 @@ func InitApplication(env *types.EnvMeta, c common.Args, workloadName string, app
}
// BaseComplete will construct an Application from cli parameters.
func BaseComplete(env *types.EnvMeta, c common.Args, workloadName string, appName string, flagSet *pflag.FlagSet, workloadType string) (*api.Application, error) {
app, err := InitApplication(env, c, workloadName, appName)
func BaseComplete(namespace string, c common.Args, workloadName string, appName string, flagSet *pflag.FlagSet, workloadType string) (*api.Application, error) {
app, err := InitApplication(namespace, c, workloadName, appName)
if err != nil {
return nil, err
}
@@ -79,7 +65,7 @@ func BaseComplete(env *types.EnvMeta, c common.Args, workloadName string, appNam
// Not exist
tp = workloadType
}
template, err := plugins.LoadCapabilityByName(tp, env.Namespace, c)
template, err := plugins.LoadCapabilityByName(tp, namespace, c)
if err != nil {
return nil, err
}

View File

@@ -5,7 +5,7 @@ metadata:
addons.oam.dev/description: istio Controller is a Kubernetes Controller for manage
traffic.
name: istio
namespace: istio-system
namespace: vela-system
spec:
components:
- name: ns-istio-system

View File

@@ -7,106 +7,13 @@ metadata:
namespace: vela-system
spec:
components:
- name: ns-observability
properties:
apiVersion: v1
kind: Namespace
metadata:
name: observability
type: raw
- name: import-grafana-dashboard-traitdef
properties:
apiVersion: core.oam.dev/v1beta1
kind: TraitDefinition
metadata:
annotations:
definition.oam.dev/description: Import dashboards to Grafana
name: import-grafana-dashboard
namespace: vela-system
spec:
schematic:
cue:
template: "outputs: registerdatasource: {\n\tapiVersion: \"grafana.extension.oam.dev/v1alpha1\"\n\tkind:
\ \"ImportDashboard\"\n\tspec: {\n\t\tgrafana: {\n\t\t\tservice:
\ parameter.grafanaServiceName\n\t\t\tnamespace: parameter.grafanaServiceNamespace\n\t\t\tcredentialSecret:
\ parameter.credentialSecret\n\t\t\tcredentialSecretNamespace:
parameter.credentialSecretNamespace\n\t\t}\n\t\turls: parameter.urls\n\t}\n}\nparameter:
{\n\tgrafanaServiceName: string\n\tgrafanaServiceNamespace: *\"default\"
| string\n\tcredentialSecret: string\n\tcredentialSecretNamespace:
*\"default\" | string\n\turls: [...string]\n}\n"
type: raw
- name: pure-ingress-traitdef
properties:
apiVersion: core.oam.dev/v1beta1
kind: TraitDefinition
metadata:
annotations:
definition.oam.dev/description: Enable public web traffic for the component
without creating a Service.
name: pure-ingress
namespace: vela-system
spec:
schematic:
cue:
template: "\noutputs: ingress: {\n\tapiVersion: \"networking.k8s.io/v1beta1\"\n\tkind:
\ \"Ingress\"\n\tmetadata:\n\t\tname: context.name\n\tspec: {\n\t\trules:
[{\n\t\t\thost: parameter.domain\n\t\t\thttp: {\n\t\t\t\tpaths: [\n\t\t\t\t\tfor
k, v in parameter.http {\n\t\t\t\t\t\tpath: k\n\t\t\t\t\t\tbackend:
{\n\t\t\t\t\t\t\tserviceName: context.name\n\t\t\t\t\t\t\tservicePort:
v\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t]\n\t\t\t}\n\t\t}]\n\t}\n}\n\nparameter:
{\n\t// +usage=Specify the domain you want to expose\n\tdomain: string\n\n\t//
+usage=Specify the mapping relationship between the http path and the
workload port\n\thttp: [string]: int\n}\n"
status:
customStatus: |-
let igs = context.outputs.ingress.status.loadBalancer.ingress
if igs == _|_ {
message: "No loadBalancer found, visiting by using 'vela port-forward " + context.appName + " --route'\n"
}
if len(igs) > 0 {
if igs[0].ip != _|_ {
message: "Visiting URL: " + context.outputs.ingress.spec.rules[0].host + ", IP: " + igs[0].ip
}
if igs[0].ip == _|_ {
message: "Visiting URL: " + context.outputs.ingress.spec.rules[0].host
}
}
healthPolicy: |
isHealth: len(context.outputs.ingress.status.loadBalancer.ingress) > 0
type: raw
- name: register-grafana-datasource-traitdef
properties:
apiVersion: core.oam.dev/v1beta1
kind: TraitDefinition
metadata:
annotations:
definition.oam.dev/description: Add a datasource to Grafana
name: register-grafana-datasource
namespace: vela-system
spec:
schematic:
cue:
template: "outputs: registerdatasource: {\n\tapiVersion: \"grafana.extension.oam.dev/v1alpha1\"\n\tkind:
\ \"DatasourceRegistration\"\n\tspec: {\n\t\tgrafana: {\n\t\t\tservice:
\ parameter.grafanaServiceName\n\t\t\tnamespace: parameter.grafanaServiceNamespace\n\t\t\tcredentialSecret:
\ parameter.credentialSecret\n\t\t\tcredentialSecretNamespace:
parameter.credentialSecretNamespace\n\t\t}\n\t\tdatasource: {\n\t\t\tname:
\ parameter.name\n\t\t\ttype: parameter.type\n\t\t\taccess:
\ parameter.access\n\t\t\tservice: parameter.service\n\t\t\tnamespace:
parameter.namespace\n\t\t}\n\t}\n}\n\nparameter: {\n\tgrafanaServiceName:
\ string\n\tgrafanaServiceNamespace: *\"default\" | string\n\tcredentialSecret:
\ string\n\tcredentialSecretNamespace: string\n\tname: string\n\ttype:
\ string\n\taccess: *\"proxy\"
| string\n\tservice: string\n\tnamespace: *\"default\"
| string\n}\n"
type: raw
- name: grafana-registration
properties:
chart: ./chart
git:
branch: master
repoType: git
targetNamespace: observability
targetNamespace: vela-system
url: https://github.com/oam-dev/grafana-registration
values:
replicaCount: 1
@@ -116,7 +23,7 @@ spec:
chart: grafana
releaseName: grafana
repoType: helm
targetNamespace: observability
targetNamespace: vela-system
url: https://charts.kubevela.net/addons
version: 6.14.1
traits:
@@ -127,9 +34,9 @@ spec:
type: pure-ingress
- properties:
credentialSecret: grafana
credentialSecretNamespace: observability
credentialSecretNamespace: vela-system
grafanaServiceName: grafana
grafanaServiceNamespace: observability
grafanaServiceNamespace: vela-system
urls:
- https://charts.kubevela.net/addons/dashboards/kubevela_core_logging.json
- https://charts.kubevela.net/addons/dashboards/kubevela_core_monitoring.json
@@ -142,18 +49,18 @@ spec:
chart: loki-stack
releaseName: loki
repoType: helm
targetNamespace: observability
targetNamespace: vela-system
url: https://charts.kubevela.net/addons
version: 2.4.1
traits:
- properties:
access: proxy
credentialSecret: grafana
credentialSecretNamespace: observability
credentialSecretNamespace: vela-system
grafanaServiceName: grafana
grafanaServiceNamespace: observability
grafanaServiceNamespace: vela-system
name: loki
namespace: observability
namespace: vela-system
service: loki
type: loki
type: register-grafana-datasource
@@ -163,7 +70,7 @@ spec:
chart: prometheus
releaseName: prometheus
repoType: helm
targetNamespace: observability
targetNamespace: vela-system
url: https://charts.kubevela.net/addons
values:
alertmanager:
@@ -181,11 +88,11 @@ spec:
- properties:
access: proxy
credentialSecret: grafana
credentialSecretNamespace: observability
credentialSecretNamespace: vela-system
grafanaServiceName: grafana
grafanaServiceNamespace: observability
grafanaServiceNamespace: vela-system
name: prometheus
namespace: observability
namespace: vela-system
service: prometheus-server
type: prometheus
type: register-grafana-datasource
@@ -194,7 +101,7 @@ spec:
properties:
chart: kube-state-metrics
repoType: helm
targetNamespace: observability
targetNamespace: vela-system
url: https://charts.kubevela.net/addons
values:
image:
@@ -209,22 +116,6 @@ spec:
name: fluxcd
namespace: vela-system
type: depends-on-app
- name: apply-ns
properties:
component: ns-observability
type: apply-component
- name: apply-trait-1
properties:
component: import-grafana-dashboard-traitdef
type: apply-component
- name: apply-trait-2
properties:
component: pure-ingress-traitdef
type: apply-component
- name: apply-trait-3
properties:
component: register-grafana-datasource-traitdef
type: apply-component
- name: apply-resources
type: apply-remaining
status:

View File

@@ -4,7 +4,7 @@ metadata:
annotations:
addons.oam.dev/description: "istio Controller is a Kubernetes Controller for manage traffic."
name: istio
namespace: istio-system
namespace: vela-system
spec:
workflow:
steps:

View File

@@ -13,173 +13,9 @@ spec:
properties:
name: fluxcd
namespace: vela-system
- name: apply-ns
type: apply-component
properties:
component: ns-observability
- name: apply-trait-1
type: apply-component
properties:
component: import-grafana-dashboard-traitdef
- name: apply-trait-2
type: apply-component
properties:
component: pure-ingress-traitdef
- name: apply-trait-3
type: apply-component
properties:
component: register-grafana-datasource-traitdef
- name: apply-resources
type: apply-remaining
components:
- name: ns-observability
type: raw
properties:
apiVersion: v1
kind: Namespace
metadata:
name: observability
- name: import-grafana-dashboard-traitdef
type: raw
properties:
apiVersion: core.oam.dev/v1beta1
kind: TraitDefinition
metadata:
annotations:
definition.oam.dev/description: "Import dashboards to Grafana"
name: import-grafana-dashboard
namespace: vela-system
spec:
schematic:
cue:
template: |
outputs: registerdatasource: {
apiVersion: "grafana.extension.oam.dev/v1alpha1"
kind: "ImportDashboard"
spec: {
grafana: {
service: parameter.grafanaServiceName
namespace: parameter.grafanaServiceNamespace
credentialSecret: parameter.credentialSecret
credentialSecretNamespace: parameter.credentialSecretNamespace
}
urls: parameter.urls
}
}
parameter: {
grafanaServiceName: string
grafanaServiceNamespace: *"default" | string
credentialSecret: string
credentialSecretNamespace: *"default" | string
urls: [...string]
}
- name: pure-ingress-traitdef
type: raw
properties:
apiVersion: core.oam.dev/v1beta1
kind: TraitDefinition
metadata:
annotations:
definition.oam.dev/description: "Enable public web traffic for the component without creating a Service."
name: pure-ingress
namespace: vela-system
spec:
status:
customStatus: |-
let igs = context.outputs.ingress.status.loadBalancer.ingress
if igs == _|_ {
message: "No loadBalancer found, visiting by using 'vela port-forward " + context.appName + " --route'\n"
}
if len(igs) > 0 {
if igs[0].ip != _|_ {
message: "Visiting URL: " + context.outputs.ingress.spec.rules[0].host + ", IP: " + igs[0].ip
}
if igs[0].ip == _|_ {
message: "Visiting URL: " + context.outputs.ingress.spec.rules[0].host
}
}
healthPolicy: |
isHealth: len(context.outputs.ingress.status.loadBalancer.ingress) > 0
schematic:
cue:
template: |
outputs: ingress: {
apiVersion: "networking.k8s.io/v1beta1"
kind: "Ingress"
metadata:
name: context.name
spec: {
rules: [{
host: parameter.domain
http: {
paths: [
for k, v in parameter.http {
path: k
backend: {
serviceName: context.name
servicePort: v
}
},
]
}
}]
}
}
parameter: {
// +usage=Specify the domain you want to expose
domain: string
// +usage=Specify the mapping relationship between the http path and the workload port
http: [string]: int
}
- name: register-grafana-datasource-traitdef
type: raw
properties:
apiVersion: core.oam.dev/v1beta1
kind: TraitDefinition
metadata:
annotations:
definition.oam.dev/description: "Add a datasource to Grafana"
name: register-grafana-datasource
namespace: vela-system
spec:
schematic:
cue:
template: |
outputs: registerdatasource: {
apiVersion: "grafana.extension.oam.dev/v1alpha1"
kind: "DatasourceRegistration"
spec: {
grafana: {
service: parameter.grafanaServiceName
namespace: parameter.grafanaServiceNamespace
credentialSecret: parameter.credentialSecret
credentialSecretNamespace: parameter.credentialSecretNamespace
}
datasource: {
name: parameter.name
type: parameter.type
access: parameter.access
service: parameter.service
namespace: parameter.namespace
}
}
}
parameter: {
grafanaServiceName: string
grafanaServiceNamespace: *"default" | string
credentialSecret: string
credentialSecretNamespace: string
name: string
type: string
access: *"proxy" | string
service: string
namespace: *"default" | string
}
- name: grafana-registration
type: helm
properties:
@@ -188,7 +24,7 @@ spec:
git:
branch: master
chart: ./chart
targetNamespace: observability
targetNamespace: vela-system
values:
replicaCount: 1
@@ -200,7 +36,7 @@ spec:
repoType: helm
# original url: https://grafana.github.io/helm-charts
url: https://charts.kubevela.net/addons
targetNamespace: observability
targetNamespace: vela-system
releaseName: grafana
type: helm
traits:
@@ -212,9 +48,9 @@ spec:
- type: import-grafana-dashboard
properties:
grafanaServiceName: grafana
grafanaServiceNamespace: observability
grafanaServiceNamespace: vela-system
credentialSecret: grafana
credentialSecretNamespace: observability
credentialSecretNamespace: vela-system
urls:
- https://charts.kubevela.net/addons/dashboards/kubevela_core_logging.json
- https://charts.kubevela.net/addons/dashboards/kubevela_core_monitoring.json
@@ -230,18 +66,18 @@ spec:
repoType: helm
# original url: https://grafana.github.io/helm-charts
url: https://charts.kubevela.net/addons
targetNamespace: observability
targetNamespace: vela-system
releaseName: loki
traits:
- type: register-grafana-datasource # register loki datasource to Grafana
properties:
grafanaServiceName: grafana
grafanaServiceNamespace: observability
grafanaServiceNamespace: vela-system
credentialSecret: grafana
credentialSecretNamespace: observability
credentialSecretNamespace: vela-system
name: loki
service: loki
namespace: observability
namespace: vela-system
type: loki
access: proxy
@@ -254,7 +90,7 @@ spec:
repoType: helm
# original url: https://prometheus-community.github.io/helm-charts
url: https://charts.kubevela.net/addons
targetNamespace: observability
targetNamespace: vela-system
releaseName: prometheus
values:
alertmanager:
@@ -271,12 +107,12 @@ spec:
- type: register-grafana-datasource # register Prometheus datasource to Grafana
properties:
grafanaServiceName: grafana
grafanaServiceNamespace: observability
grafanaServiceNamespace: vela-system
credentialSecret: grafana
credentialSecretNamespace: observability
credentialSecretNamespace: vela-system
name: prometheus
service: prometheus-server
namespace: observability
namespace: vela-system
type: prometheus
access: proxy
@@ -289,7 +125,7 @@ spec:
repoType: helm
# original url: https://prometheus-community.github.io/helm-charts
url: https://charts.kubevela.net/addons
targetNamespace: observability
targetNamespace: vela-system
values:
image:
repository: oamdev/kube-state-metrics

View File

@@ -21,9 +21,8 @@ template: {
}
}
}
load: op.#Steps & {
if dependsOn.err != _|_ && dependsOn.value == _|_ {
if dependsOn.err != _|_ {
configMap: op.#Read & {
value: {
apiVersion: "v1"
@@ -33,24 +32,22 @@ template: {
namespace: parameter.namespace
}
}
}
apply: op.#Apply & {
value: {
yaml.Unmarshal(configMap.value.data[parameter.name])
}
}
} @step(1)
template: configMap.value.data["application"]
apply: op.#Apply & {
value: yaml.Unmarshal(template)
} @step(2)
wait: op.#ConditionalWait & {
continue: load.apply.value.status.status == "running"
}
continue: apply.value.status.status == "running"
} @step(3)
}
if dependsOn.value != _|_ {
if dependsOn.err == _|_ {
wait: op.#ConditionalWait & {
continue: dependsOn.value.status.status == "running"
}
}
}
parameter: {
// +usage=Specify the name of the dependent Application
name: string

View File

@@ -0,0 +1,35 @@
"import-grafana-dashboard": {
attributes: {
appliesToWorkloads: []
conflictsWith: []
podDisruptive: false
workloadRefPath: ""
}
description: "Import dashboards to Grafana"
labels: {}
type: "trait"
}
template: {
outputs: registerdatasource: {
apiVersion: "grafana.extension.oam.dev/v1alpha1"
kind: "ImportDashboard"
spec: {
grafana: {
service: parameter.grafanaServiceName
namespace: parameter.grafanaServiceNamespace
credentialSecret: parameter.credentialSecret
credentialSecretNamespace: parameter.credentialSecretNamespace
}
urls: parameter.urls
}
}
parameter: {
grafanaServiceName: string
grafanaServiceNamespace: *"default" | string
credentialSecret: string
credentialSecretNamespace: *"default" | string
urls: [...string]
}
}

View File

@@ -0,0 +1,60 @@
"pure-ingress": {
annotations: {}
attributes: {
appliesToWorkloads: []
conflictsWith: []
podDisruptive: false
status: {
customStatus: #"""
let igs = context.outputs.ingress.status.loadBalancer.ingress
if igs == _|_ {
message: "No loadBalancer found, visiting by using 'vela port-forward " + context.appName + " --route'\n"
}
if len(igs) > 0 {
if igs[0].ip != _|_ {
message: "Visiting URL: " + context.outputs.ingress.spec.rules[0].host + ", IP: " + igs[0].ip
}
if igs[0].ip == _|_ {
message: "Visiting URL: " + context.outputs.ingress.spec.rules[0].host
}
}
"""#
}
workloadRefPath: ""
}
description: "Enable public web traffic for the component without creating a Service."
labels: {}
type: "trait"
}
template: {
outputs: ingress: {
apiVersion: "networking.k8s.io/v1beta1"
kind: "Ingress"
metadata:
name: context.name
spec: {
rules: [{
host: parameter.domain
http: {
paths: [
for k, v in parameter.http {
path: k
backend: {
serviceName: context.name
servicePort: v
}
},
]
}
}]
}
}
parameter: {
// +usage=Specify the domain you want to expose
domain: string
// +usage=Specify the mapping relationship between the http path and the workload port
http: [string]: int
}
}

View File

@@ -0,0 +1,46 @@
"register-grafana-datasource": {
annotations: {}
attributes: {
appliesToWorkloads: []
conflictsWith: []
podDisruptive: false
workloadRefPath: ""
}
description: "Add a datasource to Grafana"
labels: {}
type: "trait"
}
template: {
outputs: registerdatasource: {
apiVersion: "grafana.extension.oam.dev/v1alpha1"
kind: "DatasourceRegistration"
spec: {
grafana: {
service: parameter.grafanaServiceName
namespace: parameter.grafanaServiceNamespace
credentialSecret: parameter.credentialSecret
credentialSecretNamespace: parameter.credentialSecretNamespace
}
datasource: {
name: parameter.name
type: parameter.type
access: parameter.access
service: parameter.service
namespace: parameter.namespace
}
}
}
parameter: {
grafanaServiceName: string
grafanaServiceNamespace: *"default" | string
credentialSecret: string
credentialSecretNamespace: string
name: string
type: string
access: *"proxy" | string
service: string
namespace: *"default" | string
}
}