Compare commits

...

9 Commits

Author SHA1 Message Date
github-actions[bot]
c66f5f103f Fix: fix depends on app built-in step (#2435)
(cherry picked from commit b126cf1a34)

Co-authored-by: FogDong <dongtianxin.tx@alibaba-inc.com>
2021-10-09 18:52:57 +08:00
github-actions[bot]
e6779f6906 [Backport release-1.1] Fix: fix apiserver 1.1.3 not available bug (#2431)
* Fix: fix apiserver 1.1.3 not available bug

(cherry picked from commit a0b0c032d4)

* Feat: change apiserver image repository

(cherry picked from commit d417e9014a)

* Fix(helm chart): fix startup args for apiserver

(cherry picked from commit fa759459af)

Co-authored-by: barnettZQG <yiyun.pro>
2021-10-09 16:52:05 +08:00
github-actions[bot]
a48b74d4be Feat: add secure tls for cluster-gateway (#2428)
(cherry picked from commit cf4d508189)

Co-authored-by: Yin Da <yd219913@alibaba-inc.com>
2021-10-09 15:24:41 +08:00
github-actions[bot]
2da80af3c4 [Backport release-1.1] Feat: add apply raw built in workflow steps (#2424)
* Feat: add apply raw built in workflow steps

(cherry picked from commit be68f388a2)

* Feat: add apply raw example

(cherry picked from commit 8243b6d916)

* Fix: change the name to apply object

(cherry picked from commit b996a04862)

* Fix: example server name

(cherry picked from commit 2341bf0f5a)

Co-authored-by: FogDong <dongtianxin.tx@alibaba-inc.com>
2021-10-09 12:21:28 +08:00
github-actions[bot]
7bf5e17262 Chore(deps): bump github.com/containerd/containerd from 1.4.8 to 1.4.11 (#2422)
(cherry picked from commit 8450b4153e)

Co-authored-by: 天元 <jianbo.sjb@alibaba-inc.com>
2021-10-09 11:12:08 +08:00
Zheng Xi Zhou
53a6d54b73 Fix: support terraform/provider-azure addon (#2402) (#2418)
Also added some componentdefinitions for Azure cloud resource
2021-10-08 19:14:59 +08:00
github-actions[bot]
bcd072507b [Backport release-1.1] Feat: multicluster support ServiceAccountToken (#2415)
* Feat: support serviceaccount in multicluster

(cherry picked from commit 6168af830e)

* Fix: add compatibility & support sa

(cherry picked from commit 0193d74dfa)

* Fix: add multicluster sa test

(cherry picked from commit d445d29649)

* Fix: add test for upgrade func

(cherry picked from commit f4ba55b540)

* Style: format

(cherry picked from commit 0a8645c30c)

Co-authored-by: Yin Da <yd219913@alibaba-inc.com>
2021-10-08 15:55:12 +08:00
qiaozp
ae075e6cb6 Refactor(cli): Refactor vela env, deprecate vela config (#2037) (#2413)
* Refactor(cli): cut env to namespace, use application to save

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* Fix: test

* Fix: typo

(cherry picked from commit a574fc0fbf)
2021-10-08 14:44:30 +08:00
Somefive
b2127ee4fa Feat: use #ApplyComponent for EnvBinding (#2382) (#2414)
* Feat: use #ApplyComponent in EnvBinding

* Fix: application test compRev control by resourcetracker

* Fix: add more detail in error info
2021-10-08 14:43:44 +08:00
109 changed files with 2488 additions and 1969 deletions

View File

@@ -20,6 +20,8 @@ import (
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
types "github.com/oam-dev/terraform-controller/api/types/crossplane-runtime"
"github.com/oam-dev/kubevela/apis/core.oam.dev/condition"
"github.com/oam-dev/kubevela/apis/standard.oam.dev/v1alpha1"
@@ -109,6 +111,9 @@ type Terraform struct {
// +kubebuilder:default:=hcl
// +kubebuilder:validation:Enum:=hcl;json;remote
Type string `json:"type,omitempty"`
// ProviderReference specifies the reference to Provider
ProviderReference *types.Reference `json:"providerRef,omitempty"`
}
// A WorkloadTypeDescriptor refer to a Workload Type

View File

@@ -21,6 +21,7 @@ limitations under the License.
package common
import (
crossplane_runtime "github.com/oam-dev/terraform-controller/api/types/crossplane-runtime"
v1 "k8s.io/api/core/v1"
)
@@ -439,7 +440,7 @@ func (in *Schematic) DeepCopyInto(out *Schematic) {
if in.Terraform != nil {
in, out := &in.Terraform, &out.Terraform
*out = new(Terraform)
**out = **in
(*in).DeepCopyInto(*out)
}
}
@@ -529,6 +530,11 @@ func (in *SubStepsStatus) DeepCopy() *SubStepsStatus {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Terraform) DeepCopyInto(out *Terraform) {
*out = *in
if in.ProviderReference != nil {
in, out := &in.ProviderReference, &out.ProviderReference
*out = new(crossplane_runtime.Reference)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Terraform.

View File

@@ -47,12 +47,13 @@ const (
StatusStaging = "Staging"
)
// EnvMeta stores the info for app environment
// Config contains key/value pairs
type Config map[string]string
// EnvMeta stores the namespace for app environment
type EnvMeta struct {
Name string `json:"name"`
Namespace string `json:"namespace"`
Email string `json:"email,omitempty"`
Domain string `json:"domain,omitempty"`
Current string `json:"current,omitempty"`
}

View File

@@ -188,6 +188,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference to
Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -454,6 +468,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference to
Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration

View File

@@ -193,6 +193,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference to
Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -440,6 +454,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference to
Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration

View File

@@ -1232,6 +1232,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -1621,6 +1635,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -1908,6 +1936,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -3318,6 +3360,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -3600,6 +3656,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -3971,6 +4041,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -4221,6 +4305,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -4487,6 +4585,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration

View File

@@ -179,6 +179,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference to
Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -449,6 +463,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference to
Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration

View File

@@ -222,6 +222,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -492,6 +506,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -755,6 +783,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -999,6 +1041,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration

View File

@@ -151,6 +151,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference to
Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration

View File

@@ -188,6 +188,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference to
Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -454,6 +468,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference to
Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration

View File

@@ -148,6 +148,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference to
Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration

View File

@@ -193,6 +193,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference to
Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -440,6 +454,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference to
Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration

View File

@@ -0,0 +1,65 @@
apiVersion: v1
data:
initializer: |
apiVersion: core.oam.dev/v1beta1
kind: Initializer
metadata:
annotations:
addons.oam.dev/description: Kubernetes Terraform Controller for Azure
addons.oam.dev/name: terraform/provider-azure
name: terraform-provider-azure
namespace: default
spec:
appTemplate:
spec:
components:
- name: azure-account-creds
properties:
apiVersion: v1
kind: Secret
metadata:
name: azure-account-creds
namespace: vela-system
stringData:
credentials: |
armClientID: [[ index .Args "ARM_CLIENT_ID" ]]
armClientSecret: [[ index .Args "ARM_CLIENT_SECRET" ]]
armSubscriptionID: [[ index .Args "ARM_SUBSCRIPTION_ID" ]]
armTenantID: [[ index .Args "ARM_TENANT_ID" ]]
type: Opaque
type: raw
- name: azure
properties:
apiVersion: terraform.core.oam.dev/v1beta1
kind: Provider
metadata:
name: azure
namespace: default
spec:
credentials:
secretRef:
key: credentials
name: azure-account-creds
namespace: vela-system
source: Secret
provider: azure
type: raw
status:
rollout:
batchRollingState: ""
currentBatch: 0
lastTargetAppRevision: ""
rollingState: ""
upgradedReadyReplicas: 0
upgradedReplicas: 0
status:
observedGeneration: 0
kind: ConfigMap
metadata:
annotations:
addons.oam.dev/description: Kubernetes Terraform Controller for Azure
addons.oam.dev/name: terraform/provider-azure
labels:
addons.oam.dev/type: terraform-provider-azure
name: terraform-provider-azure
namespace: {{.Values.systemDefinitionNamespace}}

View File

@@ -354,6 +354,83 @@ data:
apiVersion: terraform.core.oam.dev/v1beta1
kind: Configuration
type: raw
- name: azure-database-mariadb
properties:
apiVersion: core.oam.dev/v1alpha2
kind: ComponentDefinition
metadata:
annotations:
definition.oam.dev/description: Terraform configuration for Azure Database
Mariadb
provider: azure
labels:
type: terraform
name: azure-database-mariadb
namespace: vela-system
spec:
schematic:
terraform:
configuration: |
# Configure the Microsoft Azure Provider
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "example" {
name = "tfex-mariadb-database-RG"
location = "West Europe"
}
resource "azurerm_mariadb_server" "example" {
name = "mariadb-svr-sample"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
sku_name = "B_Gen5_2"
storage_mb = 51200
backup_retention_days = 7
geo_redundant_backup_enabled = false
administrator_login = var.username
administrator_login_password = var.password
version = "10.2"
ssl_enforcement_enabled = true
}
resource "azurerm_mariadb_database" "example" {
name = var.name
resource_group_name = azurerm_resource_group.example.name
server_name = azurerm_mariadb_server.example.name
charset = "utf8"
collation = "utf8_general_ci"
}
variable "name" {
default = "mariadb_database"
type = string
description = "Database instance name"
}
variable "username" {
default = "acctestun"
type = string
description = "Database instance username"
}
variable "password" {
default = "H@Sh1CoR3!faked"
type = string
description = "Database instance password"
}
providerRef:
name: azure
namespace: default
workload:
definition:
apiVersion: terraform.core.oam.dev/v1beta1
kind: Configuration
type: raw
status:
rollout:
batchRollingState: ""

View File

@@ -32,12 +32,28 @@ spec:
- "--secure-port={{ .Values.multicluster.clusterGateway.port }}"
- "--secret-namespace={{ .Release.Namespace }}"
- "--feature-gates=APIPriorityAndFairness=false"
{{ if .Values.multicluster.clusterGateway.secureTLS.enabled }}
- "--cert-dir={{ .Values.multicluster.clusterGateway.secureTLS.certPath }}"
{{ end }}
image: {{ .Values.multicluster.clusterGateway.image.repository }}:{{ .Values.multicluster.clusterGateway.image.tag }}
imagePullPolicy: {{ .Values.multicluster.clusterGateway.image.pullPolicy }}
resources:
{{- toYaml .Values.multicluster.clusterGateway.resources | nindent 12 }}
ports:
- containerPort: {{ .Values.multicluster.clusterGateway.port }}
{{ if .Values.multicluster.clusterGateway.secureTLS.enabled }}
volumeMounts:
- mountPath: {{ .Values.multicluster.clusterGateway.secureTLS.certPath }}
name: tls-cert-vol
readOnly: true
{{- end }}
{{ if .Values.multicluster.clusterGateway.secureTLS.enabled }}
volumes:
- name: tls-cert-vol
secret:
defaultMode: 420
secretName: {{ template "kubevela.fullname" . }}-cluster-gateway-tls
{{ end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
@@ -84,5 +100,92 @@ spec:
namespace: {{ .Release.Namespace }}
port: {{ .Values.multicluster.clusterGateway.port }}
versionPriority: 10
insecureSkipTLSVerify: true
insecureSkipTLSVerify: {{ not .Values.multicluster.clusterGateway.secureTLS.enabled }}
{{ if .Values.multicluster.clusterGateway.secureTLS.enabled }}
caBundle: Cg==
{{ end }}
{{ end }}
---
{{ if and .Values.multicluster.enabled .Values.multicluster.clusterGateway.secureTLS.enabled }}
apiVersion: batch/v1
kind: Job
metadata:
name: {{ template "kubevela.fullname" . }}-cluster-gateway-tls-secret-create
namespace: {{ .Release.Namespace }}
annotations:
"helm.sh/hook": pre-install,pre-upgrade
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
labels:
app: {{ template "kubevela.fullname" . }}-cluster-gateway-tls-secret-create
{{- include "kubevela.labels" . | nindent 4 }}
spec:
{{- if .Capabilities.APIVersions.Has "batch/v1alpha1" }}
# Alpha feature since k8s 1.12
ttlSecondsAfterFinished: 0
{{- end }}
template:
metadata:
name: {{ template "kubevela.fullname" . }}-cluster-gateway-tls-secret-create
labels:
app: {{ template "kubevela.fullname" . }}-cluster-gateway-tls-secret-create
{{- include "kubevela.labels" . | nindent 8 }}
spec:
containers:
- name: create
image: {{ .Values.admissionWebhooks.patch.image.repository }}:{{ .Values.admissionWebhooks.patch.image.tag }}
imagePullPolicy: {{ .Values.admissionWebhooks.patch.image.pullPolicy }}
args:
- create
- --host={{ .Release.Name }}-cluster-gateway-service,{{ .Release.Name }}-cluster-gateway-service.{{ .Release.Namespace }}.svc
- --namespace={{ .Release.Namespace }}
- --secret-name={{ template "kubevela.fullname" . }}-cluster-gateway-tls
- --key-name=apiserver.key
- --cert-name=apiserver.crt
restartPolicy: OnFailure
serviceAccountName: {{ template "kubevela.fullname" . }}-admission
securityContext:
runAsGroup: 2000
runAsNonRoot: true
runAsUser: 2000
{{ end }}
---
{{ if and .Values.multicluster.enabled .Values.multicluster.clusterGateway.secureTLS.enabled }}
apiVersion: batch/v1
kind: Job
metadata:
name: {{ template "kubevela.fullname" . }}-cluster-gateway-tls-secret-patch
namespace: {{ .Release.Namespace }}
annotations:
"helm.sh/hook": post-install,post-upgrade
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
labels:
app: {{ template "kubevela.fullname" . }}-cluster-gateway-tls-secret-patch
{{- include "kubevela.labels" . | nindent 4 }}
spec:
{{- if .Capabilities.APIVersions.Has "batch/v1alpha1" }}
# Alpha feature since k8s 1.12
ttlSecondsAfterFinished: 0
{{- end }}
template:
metadata:
name: {{ template "kubevela.fullname" . }}-cluster-gateway-tls-secret-patch
labels:
app: {{ template "kubevela.fullname" . }}-cluster-gateway-tls-secret-patch
{{- include "kubevela.labels" . | nindent 8 }}
spec:
containers:
- name: patch
image: {{ .Values.multicluster.clusterGateway.image.repository }}:{{ .Values.multicluster.clusterGateway.image.tag }}
imagePullPolicy: {{ .Values.multicluster.clusterGateway.image.pullPolicy }}
command:
- /patch
args:
- --secret-namespace={{ .Release.Namespace }}
- --secret-name={{ template "kubevela.fullname" . }}-cluster-gateway-tls
restartPolicy: OnFailure
serviceAccountName: {{ include "kubevela.serviceAccountName" . }}
securityContext:
runAsGroup: 2000
runAsNonRoot: true
runAsUser: 2000
{{ end }}

View File

@@ -0,0 +1,22 @@
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
# Definition source cue file: vela-templates/definitions/internal/apply-object.cue
apiVersion: core.oam.dev/v1beta1
kind: WorkflowStepDefinition
metadata:
annotations:
definition.oam.dev/description: Apply raw kubernetes objects for your workflow steps
name: apply-object
namespace: {{.Values.systemDefinitionNamespace}}
spec:
schematic:
cue:
template: |
import (
"vela/op"
)
apply: op.#Apply & {
value: parameter
}
parameter: {}

View File

@@ -27,7 +27,7 @@ spec:
}
}
load: op.#Steps & {
if dependsOn.err != _|_ {
if dependsOn.err != _|_ && dependsOn.value == _|_ {
configMap: op.#Read & {
value: {
apiVersion: "v1"
@@ -43,18 +43,16 @@ spec:
yaml.Unmarshal(configMap.value.data[parameter.name])
}
}
}
if dependsOn.err == _|_ {
apply: op.#Apply & {
value: {
dependsOn.value
}
wait: op.#ConditionalWait & {
continue: load.apply.value.status.status == "running"
}
}
if dependsOn.value != _|_ {
wait: op.#ConditionalWait & {
continue: dependsOn.value.status.status == "running"
}
}
}
phase: load.apply.value.status.status
wait: op.#ConditionalWait & {
continue: phase == "running"
}
parameter: {
// +usage=Specify the name of the dependent Application

View File

@@ -29,9 +29,9 @@ spec:
{{- toYaml .Values.securityContext | nindent 12 }}
args:
- "apiserver"
- "--bind-addr=0.0.0.0:{{ .Values.apiServer.port }}"
image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
imagePullPolicy: {{ quote .Values.image.pullPolicy }}
- "--port={{ .Values.apiServer.port }}"
image: {{ .Values.apiserverImage.repository }}:{{ .Values.apiserverImage.tag }}
imagePullPolicy: {{ quote .Values.apiserverImage.pullPolicy }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
ports:

View File

@@ -11,6 +11,10 @@ image:
repository: oamdev/vela-core
tag: latest
pullPolicy: Always
apiserverImage:
repository: oamdev/vela-apiserver
tag: v1.1.2
pullPolicy: Always
imagePullSecrets: []
nameOverride: ""
@@ -118,9 +122,12 @@ multicluster:
port: 9443
image:
repository: oamdev/cluster-gateway
tag: v1.1.1
tag: v1.1.3
pullPolicy: Always
resources:
limits:
cpu: 100m
memory: 200Mi
memory: 200Mi
secureTLS:
enabled: true
certPath: /etc/k8s-cluster-gateway-certs

View File

@@ -1232,6 +1232,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -1621,6 +1635,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -1908,6 +1936,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -3318,6 +3360,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -3600,6 +3656,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -3971,6 +4041,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -4221,6 +4305,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -4487,6 +4585,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration

View File

@@ -222,6 +222,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -492,6 +506,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -755,6 +783,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -999,6 +1041,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration

View File

@@ -151,6 +151,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference to
Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration

View File

@@ -188,6 +188,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference to
Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -454,6 +468,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference to
Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration

View File

@@ -148,6 +148,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference to
Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration

View File

@@ -193,6 +193,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference to
Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -440,6 +454,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference to
Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration

View File

@@ -32,12 +32,28 @@ spec:
- "--secure-port={{ .Values.multicluster.clusterGateway.port }}"
- "--secret-namespace={{ .Release.Namespace }}"
- "--feature-gates=APIPriorityAndFairness=false"
{{ if .Values.multicluster.clusterGateway.secureTLS.enabled }}
- "--cert-dir={{ .Values.multicluster.clusterGateway.secureTLS.certPath }}"
{{ end }}
image: {{ .Values.multicluster.clusterGateway.image.repository }}:{{ .Values.multicluster.clusterGateway.image.tag }}
imagePullPolicy: {{ .Values.multicluster.clusterGateway.image.pullPolicy }}
resources:
{{- toYaml .Values.multicluster.clusterGateway.resources | nindent 12 }}
ports:
- containerPort: {{ .Values.multicluster.clusterGateway.port }}
{{ if .Values.multicluster.clusterGateway.secureTLS.enabled }}
volumeMounts:
- mountPath: {{ .Values.multicluster.clusterGateway.secureTLS.certPath }}
name: tls-cert-vol
readOnly: true
{{- end }}
{{ if .Values.multicluster.clusterGateway.secureTLS.enabled }}
volumes:
- name: tls-cert-vol
secret:
defaultMode: 420
secretName: {{ template "kubevela.fullname" . }}-cluster-gateway-tls
{{ end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
@@ -50,9 +66,9 @@ spec:
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{ end }}
{{ end }}
---
{{ if .Values.multicluster.enabled }}
{{ if .Values.multicluster.enabled }}
apiVersion: v1
kind: Service
metadata:
@@ -65,9 +81,9 @@ spec:
- protocol: TCP
port: {{ .Values.multicluster.clusterGateway.port }}
targetPort: {{ .Values.multicluster.clusterGateway.port }}
{{ end }}
{{ end }}
---
{{ if .Values.multicluster.enabled }}
{{ if .Values.multicluster.enabled }}
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
@@ -84,5 +100,92 @@ spec:
namespace: {{ .Release.Namespace }}
port: {{ .Values.multicluster.clusterGateway.port }}
versionPriority: 10
insecureSkipTLSVerify: true
{{ end }}
insecureSkipTLSVerify: {{ not .Values.multicluster.clusterGateway.secureTLS.enabled }}
{{ if .Values.multicluster.clusterGateway.secureTLS.enabled }}
caBundle: Cg==
{{ end }}
{{ end }}
---
{{ if and .Values.multicluster.enabled .Values.multicluster.clusterGateway.secureTLS.enabled }}
apiVersion: batch/v1
kind: Job
metadata:
name: {{ template "kubevela.fullname" . }}-cluster-gateway-tls-secret-create
namespace: {{ .Release.Namespace }}
annotations:
"helm.sh/hook": pre-install,pre-upgrade
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
labels:
app: {{ template "kubevela.fullname" . }}-cluster-gateway-tls-secret-create
{{- include "kubevela.labels" . | nindent 4 }}
spec:
{{- if .Capabilities.APIVersions.Has "batch/v1alpha1" }}
# Alpha feature since k8s 1.12
ttlSecondsAfterFinished: 0
{{- end }}
template:
metadata:
name: {{ template "kubevela.fullname" . }}-cluster-gateway-tls-secret-create
labels:
app: {{ template "kubevela.fullname" . }}-cluster-gateway-tls-secret-create
{{- include "kubevela.labels" . | nindent 8 }}
spec:
containers:
- name: create
image: {{ .Values.admissionWebhooks.patch.image.repository }}:{{ .Values.admissionWebhooks.patch.image.tag }}
imagePullPolicy: {{ .Values.admissionWebhooks.patch.image.pullPolicy }}
args:
- create
- --host={{ .Release.Name }}-cluster-gateway-service,{{ .Release.Name }}-cluster-gateway-service.{{ .Release.Namespace }}.svc
- --namespace={{ .Release.Namespace }}
- --secret-name={{ template "kubevela.fullname" . }}-cluster-gateway-tls
- --key-name=apiserver.key
- --cert-name=apiserver.crt
restartPolicy: OnFailure
serviceAccountName: {{ template "kubevela.fullname" . }}-admission
securityContext:
runAsGroup: 2000
runAsNonRoot: true
runAsUser: 2000
{{ end }}
---
{{ if and .Values.multicluster.enabled .Values.multicluster.clusterGateway.secureTLS.enabled }}
apiVersion: batch/v1
kind: Job
metadata:
name: {{ template "kubevela.fullname" . }}-cluster-gateway-tls-secret-patch
namespace: {{ .Release.Namespace }}
annotations:
"helm.sh/hook": post-install,post-upgrade
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
labels:
app: {{ template "kubevela.fullname" . }}-cluster-gateway-tls-secret-patch
{{- include "kubevela.labels" . | nindent 4 }}
spec:
{{- if .Capabilities.APIVersions.Has "batch/v1alpha1" }}
# Alpha feature since k8s 1.12
ttlSecondsAfterFinished: 0
{{- end }}
template:
metadata:
name: {{ template "kubevela.fullname" . }}-cluster-gateway-tls-secret-patch
labels:
app: {{ template "kubevela.fullname" . }}-cluster-gateway-tls-secret-patch
{{- include "kubevela.labels" . | nindent 8 }}
spec:
containers:
- name: patch
image: {{ .Values.multicluster.clusterGateway.image.repository }}:{{ .Values.multicluster.clusterGateway.image.tag }}
imagePullPolicy: {{ .Values.multicluster.clusterGateway.image.pullPolicy }}
command:
- /patch
args:
- --secret-namespace={{ .Release.Namespace }}
- --secret-name={{ template "kubevela.fullname" . }}-cluster-gateway-tls
restartPolicy: OnFailure
serviceAccountName: {{ include "kubevela.serviceAccountName" . }}
securityContext:
runAsGroup: 2000
runAsNonRoot: true
runAsUser: 2000
{{ end }}

View File

@@ -0,0 +1,22 @@
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
# Definition source cue file: vela-templates/definitions/internal/apply-object.cue
apiVersion: core.oam.dev/v1beta1
kind: WorkflowStepDefinition
metadata:
annotations:
definition.oam.dev/description: Apply raw kubernetes objects for your workflow steps
name: apply-object
namespace: {{.Values.systemDefinitionNamespace}}
spec:
schematic:
cue:
template: |
import (
"vela/op"
)
apply: op.#Apply & {
value: parameter
}
parameter: {}

View File

@@ -27,7 +27,7 @@ spec:
}
}
load: op.#Steps & {
if dependsOn.err != _|_ {
if dependsOn.err != _|_ && dependsOn.value == _|_ {
configMap: op.#Read & {
value: {
apiVersion: "v1"
@@ -43,18 +43,16 @@ spec:
yaml.Unmarshal(configMap.value.data[parameter.name])
}
}
}
if dependsOn.err == _|_ {
apply: op.#Apply & {
value: {
dependsOn.value
}
wait: op.#ConditionalWait & {
continue: load.apply.value.status.status == "running"
}
}
if dependsOn.value != _|_ {
wait: op.#ConditionalWait & {
continue: dependsOn.value.status.status == "running"
}
}
}
phase: load.apply.value.status.status
wait: op.#ConditionalWait & {
continue: phase == "running"
}
parameter: {
// +usage=Specify the name of the dependent Application

View File

@@ -117,9 +117,12 @@ multicluster:
port: 9443
image:
repository: oamdev/cluster-gateway
tag: v1.1.1
tag: v1.1.3
pullPolicy: Always
resources:
limits:
cpu: 100m
memory: 200Mi
memory: 200Mi
secureTLS:
enabled: true
certPath: /etc/k8s-cluster-gateway-certs

View File

@@ -30,6 +30,7 @@ import (
"strings"
"time"
appsv1 "k8s.io/api/apps/v1"
"k8s.io/klog/v2"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -206,7 +207,7 @@ func main() {
LeaseDuration: &leaseDuration,
RenewDeadline: &renewDeadline,
RetryPeriod: &retryPeriod,
ClientDisableCacheFor: []client.Object{&v1beta1.ResourceTracker{}},
ClientDisableCacheFor: []client.Object{&v1beta1.ResourceTracker{}, &appsv1.ControllerRevision{}},
})
if err != nil {
klog.ErrorS(err, "Unable to create a controller manager")

View File

@@ -0,0 +1,39 @@
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: server-with-pvc
namespace: default
spec:
components:
- name: express-server
type: webservice
properties:
image: crccheck/hello-world
port: 8000
volumes:
- name: "my-pvc"
type: "pvc"
mountPath: "/test"
claimName: "myclaim"
workflow:
steps:
- name: apply-pvc
type: apply-object
properties:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: myclaim
namespace: default
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 8Gi
storageClassName: standard
- name: apply-server
type: apply-component
properties:
component: express-server

View File

@@ -1,56 +0,0 @@
apiVersion: core.oam.dev/v1beta1
kind: WorkflowStepDefinition
metadata:
name: apply-component
spec:
schematic:
cue:
template: |
import ("vela/op")
parameter: {
component: string
prefixIP?: string
}
load: op.#Load
// apply workload to kubernetes cluster
apply: op.#ApplyComponent & {
value: load.value[parameter.component]
}
// wait until workload.status equal "Running"
wait: op.#ConditionalWait & {
continue: apply.output.status.phase =="Running"
}
// export podIP
myIP: apply.output.status.podIP
---
apiVersion: core.oam.dev/v1beta1
kind: WorkflowStepDefinition
metadata:
name: apply-remaining
spec:
schematic:
cue:
template: |
import ("vela/op")
parameter: {
exceptions?: [componentName=string]: {
// skipApplyWorkload indicates whether to skip apply the workload resource
skipApplyWorkload: *true | bool
// skipAllTraits indicates to skip apply all resources of the traits.
// If this is true, skipApplyTraits will be ignored
skipAllTraits: *true| bool
// skipApplyTraits specifies the names of the traits to skip apply
skipApplyTraits: [...string]
}
}
apply: op.#ApplyRemaining & {
parameter
}

View File

@@ -0,0 +1,26 @@
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: kruise
namespace: vela-system
spec:
components:
- name: kruise
type: helm
properties:
branch: master
chart: ./charts/kruise/v0.9.0
version: "*"
repoType: git
url: https://github.com/openkruise/kruise
workflow:
steps:
- name: check-flux
type: depends-on-app
properties:
name: fluxcd
namespace: vela-system
- name: apply-kruise
type: apply-component
properties:
component: kruise

View File

@@ -111,7 +111,7 @@ var ApplicationExecContext = func(context string, appName string) bool {
var ApplicationPortForwardContext = func(context string, appName string) bool {
return ginkgo.Context(context, func() {
ginkgo.It("should get output of portward successfully", func() {
ginkgo.It("should get output of port-forward successfully", func() {
cli := fmt.Sprintf("vela port-forward %s 80:80 ", appName)
output, err := e2e.ExecAndTerminate(cli)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
@@ -128,14 +128,6 @@ var ApplicationInitIntercativeCliContext = func(context string, appName string,
data := []struct {
q, a string
}{
{
q: "What is the domain of your application service (optional): ",
a: "testdomain",
},
{
q: "What is your email (optional, used to generate certification): ",
a: "test@mail",
},
{
q: "What would you like to name your application (required): ",
a: appName,

View File

@@ -33,7 +33,7 @@ var (
cli := fmt.Sprintf("vela env init %s", envName)
output, err := Exec(cli)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
expectedOutput := fmt.Sprintf("environment %s created,", envName)
expectedOutput := fmt.Sprintf("environment %s created", envName)
gomega.Expect(output).To(gomega.ContainSubstring(expectedOutput))
})
})
@@ -45,7 +45,7 @@ var (
cli := fmt.Sprintf("vela env init %s --namespace %s", envName, namespace)
output, err := Exec(cli)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
expectedOutput := fmt.Sprintf("environment %s created,", envName)
expectedOutput := fmt.Sprintf("environment %s created", envName)
gomega.Expect(output).To(gomega.ContainSubstring(expectedOutput))
})
})

2
e2e/env/env_test.go vendored
View File

@@ -32,7 +32,7 @@ var _ = ginkgo.Describe("Env", func() {
e2e.EnvInitContext("env init", envName)
e2e.EnvInitContext("env init another one", envName2)
e2e.EnvShowContext("env show", envName)
e2e.EnvSetContext("env sw", envName)
e2e.EnvSetContext("env set", envName)
ginkgo.Context("env list", func() {
ginkgo.It("should list all envs", func() {

6
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.8
github.com/containerd/containerd v1.4.11
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
@@ -32,9 +32,9 @@ require (
github.com/imdario/mergo v0.3.12
github.com/kyokomi/emoji v2.2.4+incompatible
github.com/mitchellh/hashstructure/v2 v2.0.1
github.com/oam-dev/cluster-gateway v0.0.0-20210907072424-2f8720b116f8
github.com/oam-dev/cluster-gateway v1.1.2
github.com/oam-dev/terraform-config-inspect v0.0.0-20210418082552-fc72d929aa28
github.com/oam-dev/terraform-controller v0.2.0
github.com/oam-dev/terraform-controller v0.2.1
github.com/olekukonko/tablewriter v0.0.5
github.com/onsi/ginkgo v1.16.4
github.com/onsi/gomega v1.16.0

17
go.sum
View File

@@ -307,8 +307,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.8 h1:H0wkS4AbVKTg9vyvBdCBrxoax8AMObKbNz9Fl2N0i4Y=
github.com/containerd/containerd v1.4.8/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/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=
@@ -580,7 +580,6 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
github.com/go-openapi/swag v0.19.6/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY=
github.com/go-openapi/swag v0.19.7/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY=
github.com/go-openapi/swag v0.19.9/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY=
github.com/go-openapi/swag v0.19.11/go.mod h1:Uc0gKkdR+ojzsEpjh39QChyu92vPgIr72POcgHMAgSY=
github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng=
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-openapi/validate v0.17.2/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
@@ -1201,14 +1200,14 @@ github.com/nishanths/predeclared v0.2.1/go.mod h1:HvkGJcA3naj4lOwnFXFDkFxVtSqQMB
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oam-dev/cluster-gateway v0.0.0-20210907072424-2f8720b116f8 h1:aTfUhMr6DC+jTiBvCzv+fcgqBvIoGLvrnmXjIUgib7I=
github.com/oam-dev/cluster-gateway v0.0.0-20210907072424-2f8720b116f8/go.mod h1:ZB7/tubU3MtdQ9bzQjksjO8UK+9e0Wrw3HAqKdY/lZY=
github.com/oam-dev/cluster-gateway v1.1.2 h1:sxC8Uyx/d3Yu8nIFSz31i+4JKhJfDAS9XVIPEWa1y+Q=
github.com/oam-dev/cluster-gateway v1.1.2/go.mod h1:EjPUZwTYBe+gFtPV/yGohLE19fDr3CUg4tfSRY72fkM=
github.com/oam-dev/stern v1.13.0-alpha h1:EVjM8Qvh6LssB6t4RZrjf9DtCq1cz+/cy6OF7fpy9wk=
github.com/oam-dev/stern v1.13.0-alpha/go.mod h1:AOkvfFUv0Arz7GBi0jz7S0Jsu4K/kdvSjNsnRt1+BIg=
github.com/oam-dev/terraform-config-inspect v0.0.0-20210418082552-fc72d929aa28 h1:tD8HiFKnt0jnwdTWjeqUnfnUYLD/+Nsmj8ZGIxqDWiU=
github.com/oam-dev/terraform-config-inspect v0.0.0-20210418082552-fc72d929aa28/go.mod h1:Mu8i0/DdplvnjwRbAYPsc8+LRR27n/mp8VWdkN10GzE=
github.com/oam-dev/terraform-controller v0.2.0 h1:GBQ+CvXtY9bcRkwGaPYHbYFkbVWzDExc05hz0NL0rqs=
github.com/oam-dev/terraform-controller v0.2.0/go.mod h1:wd4rnqnJzz274Sg1/qoeIhBx1rvTZ/ECzXoMff0ucR0=
github.com/oam-dev/terraform-controller v0.2.1 h1:gGXcUDBMWKfWet84STm99RX6gXo89pyTRsgQSLq2mog=
github.com/oam-dev/terraform-controller v0.2.1/go.mod h1:5Vy6jLx9fjotEd6E005Ve1f0x3fEpVlG/DVjmqLjAq0=
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
@@ -2523,8 +2522,8 @@ sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyz
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.19/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22 h1:fmRfl9WJ4ApJn7LxNuED4m0t18qivVQOxP6aAYG9J6c=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
sigs.k8s.io/apiserver-runtime v1.0.3-0.20210906132642-810075b08b5f h1:RM+QxWPIZi3mo3i4fiUSvyFELyKr7jjMSJ5EEmt+i6M=
sigs.k8s.io/apiserver-runtime v1.0.3-0.20210906132642-810075b08b5f/go.mod h1:ynhMgoDTl6cihO5OpeV95iG+3bzKfHwWQU2VSbmoNmk=
sigs.k8s.io/apiserver-runtime v1.0.3-0.20210913073608-0663f60bfee2 h1:c6RYHA1wUg9IEsfjnxg0WsPwvDC2Qw2eryXKXgSEF1c=
sigs.k8s.io/apiserver-runtime v1.0.3-0.20210913073608-0663f60bfee2/go.mod h1:gvPfh5FX3Wi3kIRpkh7qvY0i/DQl3SDpRtvqMGZE3Vo=
sigs.k8s.io/controller-runtime v0.6.0/go.mod h1:CpYf5pdNY/B352A1TFLAS2JVSlnGQ5O2cftPHndTroo=
sigs.k8s.io/controller-runtime v0.6.2/go.mod h1:vhcq/rlnENJ09SIRp3EveTaZ0yqH526hjf9iJdbUJ/E=
sigs.k8s.io/controller-runtime v0.9.2/go.mod h1:TxzMCHyEUpaeuOiZx/bIdc2T81vfs/aKdvJt9wuu0zk=

View File

@@ -1232,6 +1232,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -1621,6 +1635,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -1908,6 +1936,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -3318,6 +3360,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -3600,6 +3656,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -3971,6 +4041,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -4221,6 +4305,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -4487,6 +4585,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration

View File

@@ -179,6 +179,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference to
Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -449,6 +463,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference to
Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration

View File

@@ -222,6 +222,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -492,6 +506,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -755,6 +783,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -999,6 +1041,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference
to Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration

View File

@@ -151,6 +151,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference to
Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration

View File

@@ -188,6 +188,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference to
Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -454,6 +468,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference to
Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration

View File

@@ -148,6 +148,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference to
Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration

View File

@@ -193,6 +193,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference to
Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration
@@ -440,6 +454,20 @@ spec:
configuration:
description: Configuration is Terraform Configuration
type: string
providerRef:
description: ProviderReference specifies the reference to
Provider
properties:
name:
description: Name of the referenced object.
type: string
namespace:
default: default
description: Namespace of the secret.
type: string
required:
- name
type: object
type:
default: hcl
description: Type specifies which Terraform configuration

View File

@@ -649,7 +649,7 @@ func generateComponentFromKubeModule(wl *Workload, appName, revision, ns string)
}
func generateTerraformConfigurationWorkload(wl *Workload, ns string) (*unstructured.Unstructured, error) {
if wl.FullTemplate.Terraform.Configuration == "" {
if wl.FullTemplate == nil || wl.FullTemplate.Terraform == nil || wl.FullTemplate.Terraform.Configuration == "" {
return nil, errors.New(errTerraformConfigurationIsNotSet)
}
params, err := json.Marshal(wl.Params)
@@ -671,6 +671,10 @@ func generateTerraformConfigurationWorkload(wl *Workload, ns string) (*unstructu
configuration.Spec.Remote = wl.FullTemplate.Terraform.Configuration
}
if wl.FullTemplate.Terraform.ProviderReference != nil {
configuration.Spec.ProviderReference = wl.FullTemplate.Terraform.ProviderReference
}
// 1. parse writeConnectionSecretToRef
if err := json.Unmarshal(params, &configuration.Spec); err != nil {
return nil, errors.Wrap(err, errFailToConvertTerraformComponentProperties)

View File

@@ -909,6 +909,7 @@ func TestGenerateTerraformConfigurationWorkload(t *testing.T) {
hcl string
remote string
params map[string]interface{}
providerRef *terraformtypes.Reference
}
type want struct {
@@ -967,7 +968,18 @@ func TestGenerateTerraformConfigurationWorkload(t *testing.T) {
params: badParam,
hcl: "abc",
},
want: want{err: errors.Wrap(badParamMarshalError, errFailToConvertTerraformComponentProperties)}},
want: want{err: errors.Wrap(badParamMarshalError, errFailToConvertTerraformComponentProperties)},
},
"terraform workload has a provider reference": {
args: args{
params: badParam,
hcl: "abc",
providerRef: &terraformtypes.Reference{Name: "azure", Namespace: "default"},
},
want: want{err: errors.Wrap(badParamMarshalError, errFailToConvertTerraformComponentProperties)},
},
}
for tcName, tc := range testcases {
@@ -1027,6 +1039,9 @@ func TestGenerateTerraformConfigurationWorkload(t *testing.T) {
WriteConnectionSecretToReference: tc.args.writeConnectionSecretToRef,
}
}
if tc.args.providerRef != nil {
template.Terraform.ProviderReference = tc.args.providerRef
}
wl := &Workload{
FullTemplate: template,

View File

@@ -1,96 +0,0 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package config
import (
"context"
"strings"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)
const (
// Splitter is a splitter for configmap name generation
Splitter = "-"
// TypeConfigMap defines the type of Configmap
TypeConfigMap = "configmap"
)
// ToConfigMap will get the data of the store and upload to configmap.
// Serverside Application controller can only use the config in appfile context by configmap.
func ToConfigMap(s Store, name, envName string, configData map[string]string) (*v1.ConfigMap, error) {
namespace, err := s.Namespace(envName)
if err != nil {
return nil, err
}
var cm = v1.ConfigMap{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "ConfigMap",
},
}
cm.SetName(name)
cm.SetNamespace(namespace)
cm.Data = configData
return &cm, nil
}
// GenConfigMapName is a fixed way to name the configmap name for appfile config
func GenConfigMapName(appName, serviceName, configName string) string {
return strings.Join([]string{"kubevela", appName, serviceName, configName}, Splitter)
}
var _ Store = &Configmap{}
// Configmap is the configmap implementation of config store
type Configmap struct {
Client client.Client
}
// GetConfigData will get config data from configmap
func (f *Configmap) GetConfigData(name, envName string) ([]map[string]string, error) {
namespace, err := f.Namespace(envName)
if err != nil {
return nil, err
}
var cm v1.ConfigMap
err = f.Client.Get(context.Background(), client.ObjectKey{Name: name, Namespace: namespace}, &cm)
if err != nil {
return nil, err
}
var data []map[string]string
for k, v := range cm.Data {
data = append(data, EncodeConfigFormat(k, v))
}
return data, nil
}
// Namespace returns the namespace of the config store from env
func (f *Configmap) Namespace(envName string) (string, error) {
// TODO(wonderflow): now we regard env as namespace, it should be fixed when env is store serverside as configmap
return envName, nil
}
// Type returns the type of the config store
func (Configmap) Type() string {
return TypeConfigMap
}

View File

@@ -1,65 +0,0 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package config
import (
"bufio"
"bytes"
"github.com/oam-dev/kubevela/pkg/utils/config"
env2 "github.com/oam-dev/kubevela/pkg/utils/env"
)
// TypeLocal defines the local config store type
const TypeLocal = "local"
// Local is the local implementation of config store
type Local struct{}
var _ Store = &Local{}
// GetConfigData will return config data from local
func (l *Local) GetConfigData(configName, envName string) ([]map[string]string, error) {
cfgData, err := config.ReadConfig(envName, configName)
if err != nil {
return nil, err
}
scanner := bufio.NewScanner(bytes.NewReader(cfgData))
var data []map[string]string
for scanner.Scan() {
k, v, err := config.ReadConfigLine(scanner.Text())
if err != nil {
return nil, err
}
data = append(data, EncodeConfigFormat(k, v))
}
return data, nil
}
// Namespace return namespace from env
func (l *Local) Namespace(envName string) (string, error) {
env, err := env2.GetEnvByName(envName)
if err != nil {
return "", err
}
return env.Namespace, nil
}
// Type returns the type of this config store implementation
func (l *Local) Type() string {
return TypeLocal
}

View File

@@ -1,76 +0,0 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package config
import "errors"
// Store will get config data
type Store interface {
GetConfigData(configName, envName string) ([]map[string]string, error)
Type() string
Namespace(envName string) (string, error)
}
// TypeFake is a fake type
const TypeFake = "fake"
var _ Store = &Fake{}
// Fake is a fake implementation of config store, help for test
type Fake struct {
Data []map[string]string
}
// GetConfigData get data
func (f *Fake) GetConfigData(_ string, _ string) ([]map[string]string, error) {
return f.Data, nil
}
// Type return the type
func (Fake) Type() string {
return TypeFake
}
// Namespace return the Namespace
func (Fake) Namespace(_ string) (string, error) {
return "", nil
}
// EncodeConfigFormat will encode key-value to config{name: key, value: value} format
func EncodeConfigFormat(key, value string) map[string]string {
return map[string]string{
"name": key,
"value": value,
}
}
// DecodeConfigFormat will decode config{name: key, value: value} format to key-value mode.
func DecodeConfigFormat(data []map[string]string) (map[string]string, error) {
var res = make(map[string]string)
for _, d := range data {
key, ok := d["name"]
if !ok {
return nil, errors.New("invalid data format, no 'name' found")
}
value, ok := d["value"]
if !ok {
return nil, errors.New("invalid data format, no 'value' found")
}
res[key] = value
}
return res, nil
}

View File

@@ -22,6 +22,7 @@ import (
"github.com/pkg/errors"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -79,30 +80,20 @@ func (engine *ClusterGatewayEngine) prepare(ctx context.Context, configs []v1alp
}
func (engine *ClusterGatewayEngine) initEnvBindApps(ctx context.Context, envBinding *v1alpha1.EnvBinding, baseApp *v1beta1.Application, appParser *appfile.Parser) ([]*EnvBindApp, error) {
envBindApps, err := CreateEnvBindApps(envBinding, baseApp)
if err != nil {
return nil, err
}
if err = RenderEnvBindApps(ctx, envBindApps, appParser); err != nil {
return nil, err
}
if err = AssembleEnvBindApps(envBindApps); err != nil {
return nil, err
}
return envBindApps, nil
return CreateEnvBindApps(envBinding, baseApp)
}
func (engine *ClusterGatewayEngine) schedule(ctx context.Context, apps []*EnvBindApp) ([]v1alpha1.ClusterDecision, error) {
for _, app := range apps {
app.ScheduledManifests = make(map[string]*unstructured.Unstructured)
clusterName := engine.clusterDecisions[app.envConfig.Name].Cluster
for _, component := range app.PatchedApp.Spec.Components {
for _, manifest := range app.assembledManifests[component.Name] {
manifestName := component.Name + "/" + manifest.GetName()
multicluster.SetClusterName(manifest, clusterName)
app.ScheduledManifests[manifestName] = manifest
}
raw, err := runtime.DefaultUnstructuredConverter.ToUnstructured(app.PatchedApp)
if err != nil {
return nil, errors.Wrapf(err, "failed to convert app [Env: %s](%s/%s) into unstructured", app.envConfig.Name, app.PatchedApp.Namespace, app.PatchedApp.Name)
}
patchedApp := &unstructured.Unstructured{Object: raw}
multicluster.SetClusterName(patchedApp, clusterName)
app.ScheduledManifests[patchedApp.GetName()] = patchedApp
}
var decisions []v1alpha1.ClusterDecision
for _, decision := range engine.clusterDecisions {

View File

@@ -199,7 +199,7 @@ func (a *AppManifestsDispatcher) retrieveLegacyResourceTrackers(ctx context.Cont
}
for _, rt := range rtList.Items {
if rt.Name != a.currentRTName &&
(a.previousRT != nil && rt.Name != a.previousRT.Name) {
(a.previousRT != nil && rt.Name != a.previousRT.Name) && !IsLifeLongResourceTracker(rt) {
a.legacyRTs = append(a.legacyRTs, rt.DeepCopy())
}
}
@@ -357,3 +357,9 @@ func setOrOverrideOAMControllerOwner(obj ObjectOwner, controllerOwner metav1.Own
}
obj.SetOwnerReferences(newOwnerRefs)
}
// IsLifeLongResourceTracker check if resourcetracker shares the same whole life with the entire application
func IsLifeLongResourceTracker(rt v1beta1.ResourceTracker) bool {
_, ok := rt.GetAnnotations()[oam.AnnotationResourceTrackerLifeLong]
return ok
}

View File

@@ -31,6 +31,7 @@ import (
"github.com/oam-dev/kubevela/pkg/controller/core.oam.dev/v1alpha2/application/assemble"
"github.com/oam-dev/kubevela/pkg/cue/model/value"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/multicluster"
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
"github.com/oam-dev/kubevela/pkg/oam/util"
"github.com/oam-dev/kubevela/pkg/utils"
@@ -123,7 +124,8 @@ func convertStepProperties(step *v1beta1.WorkflowStep, app *v1beta1.Application)
}
func (h *AppHandler) applyComponentFunc(appParser *appfile.Parser, appRev *v1beta1.ApplicationRevision, af *appfile.Appfile, cli client.Client) oamProvider.ComponentApply {
return func(comp common.ApplicationComponent, patcher *value.Value) (*unstructured.Unstructured, []*unstructured.Unstructured, bool, error) {
return func(comp common.ApplicationComponent, patcher *value.Value, clusterName string) (*unstructured.Unstructured, []*unstructured.Unstructured, bool, error) {
ctx := multicluster.ContextWithClusterName(context.Background(), clusterName)
wl, err := appParser.ParseWorkloadFromRevision(comp, appRev)
if err != nil {
@@ -137,11 +139,11 @@ func (h *AppHandler) applyComponentFunc(appParser *appfile.Parser, appRev *v1bet
if err := af.SetOAMContract(manifest); err != nil {
return nil, nil, false, errors.WithMessage(err, "SetOAMContract")
}
if err := h.HandleComponentsRevision(context.TODO(), []*types.ComponentManifest{manifest}); err != nil {
if err := h.HandleComponentsRevision(ctx, []*types.ComponentManifest{manifest}); err != nil {
return nil, nil, false, errors.WithMessage(err, "HandleComponentsRevision")
}
if len(manifest.PackagedWorkloadResources) != 0 {
if err := h.Dispatch(context.TODO(), "", common.WorkflowResourceCreator, manifest.PackagedWorkloadResources...); err != nil {
if err := h.Dispatch(ctx, clusterName, common.WorkflowResourceCreator, manifest.PackagedWorkloadResources...); err != nil {
return nil, nil, false, errors.WithMessage(err, "cannot dispatch packaged workload resources")
}
}
@@ -152,12 +154,12 @@ func (h *AppHandler) applyComponentFunc(appParser *appfile.Parser, appRev *v1bet
skipStandardWorkload := skipApplyWorkload(wl)
if !skipStandardWorkload {
if err := h.Dispatch(context.TODO(), "", common.WorkflowResourceCreator, readyWorkload); err != nil {
if err := h.Dispatch(ctx, clusterName, common.WorkflowResourceCreator, readyWorkload); err != nil {
return nil, nil, false, errors.WithMessage(err, "DispatchStandardWorkload")
}
}
if err := h.Dispatch(context.TODO(), "", common.WorkflowResourceCreator, readyTraits...); err != nil {
if err := h.Dispatch(ctx, clusterName, common.WorkflowResourceCreator, readyTraits...); err != nil {
return nil, nil, false, errors.WithMessage(err, "DispatchTraits")
}
@@ -169,7 +171,7 @@ func (h *AppHandler) applyComponentFunc(appParser *appfile.Parser, appRev *v1bet
if !isHealth {
return nil, nil, false, nil
}
workload, traits, err := getComponentResources(manifest, skipStandardWorkload, cli)
workload, traits, err := getComponentResources(ctx, manifest, skipStandardWorkload, cli)
return workload, traits, true, err
}
}
@@ -183,14 +185,14 @@ func skipApplyWorkload(wl *appfile.Workload) bool {
return false
}
func getComponentResources(manifest *types.ComponentManifest, skipStandardWorkload bool, cli client.Client) (*unstructured.Unstructured, []*unstructured.Unstructured, error) {
func getComponentResources(ctx context.Context, manifest *types.ComponentManifest, skipStandardWorkload bool, cli client.Client) (*unstructured.Unstructured, []*unstructured.Unstructured, error) {
var (
workload *unstructured.Unstructured
traits []*unstructured.Unstructured
)
if !skipStandardWorkload {
v := manifest.StandardWorkload.DeepCopy()
if err := cli.Get(context.Background(), client.ObjectKeyFromObject(manifest.StandardWorkload), v); err != nil {
if err := cli.Get(ctx, client.ObjectKeyFromObject(manifest.StandardWorkload), v); err != nil {
return nil, nil, err
}
workload = v
@@ -198,7 +200,7 @@ func getComponentResources(manifest *types.ComponentManifest, skipStandardWorklo
for _, trait := range manifest.Traits {
v := trait.DeepCopy()
if err := cli.Get(context.Background(), client.ObjectKeyFromObject(trait), v); err != nil {
if err := cli.Get(ctx, client.ObjectKeyFromObject(trait), v); err != nil {
return workload, nil, err
}
traits = append(traits, v)

View File

@@ -582,6 +582,27 @@ func ComputeComponentRevisionHash(comp *types.ComponentManifest) (string, error)
return utils.ComputeSpecHash(&compRevisionHash)
}
// createOrGetResourceTracker create or get a resource tracker to manage all componentRevisions
func (h *AppHandler) createOrGetResourceTracker(ctx context.Context) (*v1beta1.ResourceTracker, error) {
rt := &v1beta1.ResourceTracker{}
rtName := h.app.Name + "-" + h.app.Namespace
if err := h.r.Get(ctx, ktypes.NamespacedName{Name: rtName}, rt); err != nil {
if !apierrors.IsNotFound(err) {
return nil, err
}
rt.SetName(rtName)
rt.SetLabels(map[string]string{
oam.LabelAppName: h.app.Name,
oam.LabelAppNamespace: h.app.Namespace,
})
rt.SetAnnotations(map[string]string{oam.AnnotationResourceTrackerLifeLong: "true"})
if err = h.r.Create(ctx, rt); err != nil {
return nil, err
}
}
return rt, nil
}
// createControllerRevision records snapshot of a component
func (h *AppHandler) createControllerRevision(ctx context.Context, cm *types.ComponentManifest) error {
comp, err := componentManifest2Component(cm)
@@ -589,6 +610,10 @@ func (h *AppHandler) createControllerRevision(ctx context.Context, cm *types.Com
return err
}
revision, _ := utils.ExtractRevision(cm.RevisionName)
rt, err := h.createOrGetResourceTracker(ctx)
if err != nil {
return err
}
cr := &appsv1.ControllerRevision{
ObjectMeta: metav1.ObjectMeta{
Name: cm.RevisionName,
@@ -596,9 +621,9 @@ func (h *AppHandler) createControllerRevision(ctx context.Context, cm *types.Com
OwnerReferences: []metav1.OwnerReference{
{
APIVersion: v1beta1.SchemeGroupVersion.String(),
Kind: v1beta1.ApplicationKind,
Name: h.app.Name,
UID: h.app.UID,
Kind: v1beta1.ResourceTrackerKind,
Name: rt.GetName(),
UID: rt.GetUID(),
Controller: pointer.BoolPtr(true),
},
},
@@ -757,6 +782,9 @@ func gatherUsingAppRevision(ctx context.Context, h *AppHandler) (map[string]bool
return nil, err
}
for _, rt := range rtList.Items {
if dispatch.IsLifeLongResourceTracker(rt) {
continue
}
appRev := dispatch.ExtractAppRevisionName(rt.Name, ns)
usingRevision[appRev] = true
}

View File

@@ -25,6 +25,7 @@ import (
"github.com/oam-dev/cluster-gateway/pkg/apis/cluster/v1alpha1"
errors2 "github.com/pkg/errors"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/types"
@@ -34,6 +35,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/oam-dev/kubevela/pkg/utils/common"
errors3 "github.com/oam-dev/kubevela/pkg/utils/errors"
)
type contextKey string
@@ -52,11 +54,6 @@ var (
ClusterGatewaySecretNamespace string
)
// Context create context with multi-cluster
func Context(ctx context.Context, obj *unstructured.Unstructured) context.Context {
return ContextWithClusterName(ctx, obj.GetLabels()[ClusterLabelKey])
}
// ContextWithClusterName create context with multi-cluster by cluster name
func ContextWithClusterName(ctx context.Context, clusterName string) context.Context {
return context.WithValue(ctx, ClusterContextKey, clusterName)
@@ -129,5 +126,34 @@ func Initialize(restConfig *rest.Config) error {
ClusterGatewaySecretNamespace = svc.Namespace
klog.Infof("find cluster gateway service %s/%s:%d", svc.Namespace, svc.Name, *svc.Port)
restConfig.Wrap(NewSecretModeMultiClusterRoundTripper)
if err = UpgradeExistingClusterSecret(context.Background(), c); err != nil {
// this error do not affect the running of current version
klog.ErrorS(err, "error encountered while grading existing cluster secret to the latest version")
}
return nil
}
// UpgradeExistingClusterSecret upgrade outdated cluster secrets in v1.1.1 to latest
func UpgradeExistingClusterSecret(ctx context.Context, c client.Client) error {
const outdatedClusterCredentialLabelKey = "cluster.core.oam.dev/cluster-credential"
secrets := &v1.SecretList{}
if err := c.List(ctx, secrets, client.InNamespace(ClusterGatewaySecretNamespace), client.HasLabels{outdatedClusterCredentialLabelKey}); err != nil {
if err != nil {
return errors2.Wrapf(err, "failed to find outdated cluster secrets to do upgrade")
}
}
errs := errors3.ErrorList{}
for _, item := range secrets.Items {
credType := item.Labels[v1alpha1.LabelKeyClusterCredentialType]
if credType == "" && item.Type == v1.SecretTypeTLS {
item.Labels[v1alpha1.LabelKeyClusterCredentialType] = string(v1alpha1.CredentialTypeX509Certificate)
if err := c.Update(ctx, item.DeepCopy()); err != nil {
errs.Append(errors2.Wrapf(err, "failed to update outdated secret %s", item.Name))
}
}
}
if errs.HasError() {
return errs
}
return nil
}

View File

@@ -0,0 +1,63 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package multicluster
import (
"context"
"testing"
"github.com/oam-dev/cluster-gateway/pkg/apis/cluster/v1alpha1"
v1 "k8s.io/api/core/v1"
v12 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"github.com/oam-dev/kubevela/pkg/utils/common"
)
func TestUpgradeExistingClusterSecret(t *testing.T) {
oldClusterGatewaySecretNamespace := ClusterGatewaySecretNamespace
ClusterGatewaySecretNamespace = "default"
defer func() {
ClusterGatewaySecretNamespace = oldClusterGatewaySecretNamespace
}()
ctx := context.Background()
c := fake.NewClientBuilder().WithScheme(common.Scheme).Build()
secret := &v1.Secret{
ObjectMeta: v12.ObjectMeta{
Name: "example-outdated-cluster-secret",
Namespace: "default",
Labels: map[string]string{
"cluster.core.oam.dev/cluster-credential": "tls",
},
},
Type: v1.SecretTypeTLS,
}
if err := c.Create(ctx, secret); err != nil {
t.Fatalf("failed to create fake outdated cluster secret, err: %v", err)
}
if err := UpgradeExistingClusterSecret(ctx, c); err != nil {
t.Fatalf("expect no error while upgrading outdated cluster secret but encounter error: %v", err)
}
newSecret := &v1.Secret{}
if err := c.Get(ctx, client.ObjectKeyFromObject(secret), newSecret); err != nil {
t.Fatalf("found error while getting updated cluster secret: %v", err)
}
if newSecret.Labels[v1alpha1.LabelKeyClusterCredentialType] != string(v1alpha1.CredentialTypeX509Certificate) {
t.Fatalf("updated secret label should has credential type x509")
}
}

View File

@@ -117,6 +117,9 @@ const (
// AnnotationDefinitionRevisionName is used to specify the name of DefinitionRevision in component/trait definition
AnnotationDefinitionRevisionName = "definitionrevision.oam.dev/name"
// AnnotationResourceTrackerLifeLong is used to identify life-long resourcetracker which should only be recycled when application is deleted
AnnotationResourceTrackerLifeLong = "resourcetracker.oam.dev/life-long"
// AnnotationAddonsName records the name of initializer stored in configMap
AnnotationAddonsName = "addons.oam.dev/name"
)

View File

@@ -109,13 +109,14 @@ import (
}
} @step(3)
target: yaml.Unmarshal(configMap.value.data["\(env)"])
apply: #Steps & {
for key, val in target {
"\(key)": kube.#Apply & {
value: val
if val.metadata.labels != _|_ && val.metadata.labels["cluster.oam.dev/clusterName"] != _|_ {
cluster: val.metadata.labels["cluster.oam.dev/clusterName"]
patchedApp: yaml.Unmarshal(configMap.value.data["\(env)"])[context.name]
components: patchedApp.spec.components
apply: #Steps & {
for key, comp in components {
"\(key)": #ApplyComponent & {
value: comp
if patchedApp.metadata.labels != _|_ && patchedApp.metadata.labels["cluster.oam.dev/clusterName"] != _|_ {
cluster: patchedApp.metadata.labels["cluster.oam.dev/clusterName"]
}
} @step(4)
}

View File

@@ -1,6 +1,7 @@
#ApplyComponent: {
#provider: "oam"
#do: "component-apply"
cluster: *"" | string
value: {...}
patch?: {...}
...

View File

@@ -91,6 +91,23 @@ func InitBaseRestConfig() (Args, error) {
}, nil
}
// globalClient will be a client for whole command lifecycle
var globalClient client.Client
// SetGlobalClient will set a client for one cli command
func SetGlobalClient(clt client.Client) error {
globalClient = clt
return nil
}
// GetClient will K8s client in args
func GetClient() (client.Client, error) {
if globalClient != nil {
return globalClient, nil
}
return nil, errors.New("client not set, call SetGlobalClient first")
}
// HTTPGet will send GET http request with context
func HTTPGet(ctx context.Context, url string) ([]byte, error) {
// Change NewRequest to NewRequestWithContext and pass context it

View File

@@ -1,84 +0,0 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package config
import (
b64 "encoding/base64"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/oam-dev/kubevela/pkg/utils/env"
)
// ReadConfigLine will read config from line
func ReadConfigLine(line string) (string, string, error) {
ss := strings.SplitN(line, ":", 2)
if len(ss) != 2 {
return "", "", fmt.Errorf("config data is malformed: %s", line)
}
for i := range ss {
ss[i] = strings.TrimSpace(ss[i])
}
vDec, err := b64.StdEncoding.DecodeString(ss[1])
if err != nil {
return "", "", err
}
return ss[0], string(vDec), nil
}
// GetConfigsDir will get config from dir
func GetConfigsDir(envName string) (string, error) {
cfgDir := filepath.Join(env.GetEnvDirByName(envName), "configs")
err := os.MkdirAll(cfgDir, 0700)
return cfgDir, err
}
// DeleteConfig will delete local config file
func DeleteConfig(envName, configName string) error {
d, err := GetConfigsDir(envName)
if err != nil {
return err
}
cfgFile := filepath.Join(d, configName)
return os.RemoveAll(cfgFile)
}
// ReadConfig will read the config data from local
func ReadConfig(envName, configName string) ([]byte, error) {
d, err := GetConfigsDir(envName)
if err != nil {
return nil, err
}
cfgFile := filepath.Join(d, configName)
b, err := os.ReadFile(filepath.Clean(cfgFile))
if os.IsNotExist(err) {
return []byte{}, nil
}
return b, err
}
// WriteConfig will write data into local config
func WriteConfig(envName, configName string, data []byte) error {
d, err := GetConfigsDir(envName)
if err != nil {
return err
}
cfgFile := filepath.Join(d, configName)
return os.WriteFile(cfgFile, data, 0600)
}

374
pkg/utils/env/env.go vendored
View File

@@ -18,151 +18,150 @@ package env
import (
"context"
"encoding/json"
"errors"
"fmt"
"os"
"path/filepath"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"cuelang.org/go/pkg/strings"
"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8stypes "k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
common2 "github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/utils/apply"
"github.com/oam-dev/kubevela/pkg/utils/common"
"github.com/oam-dev/kubevela/pkg/utils/system"
)
// GetEnvDirByName will get env dir from name
func GetEnvDirByName(name string) string {
envdir, _ := system.GetEnvDir()
return filepath.Join(envdir, name)
const (
// IndicatingLabel is label key indicating application is an env
IndicatingLabel = "cli.env.oam.dev/name"
// RawType is component type of raw
RawType = "raw"
// DefaultEnvName is name of default env
DefaultEnvName = "default"
// DefaultEnvNamespace is namespace of default env
DefaultEnvNamespace = "default"
// AppNameSchema is used to generate env app name
AppNameSchema = "vela-env-%s"
// AppNamePrefix is prefix of AppNameSchema
AppNamePrefix = "vela-env-"
)
// app2Env and env2App are helper convert functions
func app2Env(app *v1beta1.Application) (*types.EnvMeta, error) {
namespace := getEnvNamespace(app)
env := types.EnvMeta{
Name: strings.Replace(app.Name, AppNamePrefix, "", 1),
Namespace: namespace,
Current: "",
}
return &env, nil
}
func env2App(meta *types.EnvMeta) *v1beta1.Application {
app := v1beta1.Application{
TypeMeta: metav1.TypeMeta{
Kind: v1beta1.ApplicationKind,
APIVersion: v1beta1.SchemeGroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf(AppNameSchema, meta.Name),
Namespace: types.DefaultKubeVelaNS,
},
Spec: v1beta1.ApplicationSpec{
Components: []common2.ApplicationComponent{},
},
}
addNamespaceObjectIfNeeded(meta, &app)
labels := map[string]string{
IndicatingLabel: meta.Name,
}
app.SetLabels(labels)
return &app
}
// getEnvAppByName and deleteAppByName are application operation helper functions
func getEnvAppByName(envName string) (*v1beta1.Application, error) {
list, err := getEnvAppList()
if err != nil {
return nil, err
}
// match envName
for _, app := range list {
if app.Name == fmt.Sprintf(AppNameSchema, envName) {
return &app, nil
}
}
if envName == DefaultEnvName {
_ = initDefaultEnv()
return getEnvAppByName(envName)
}
return nil, errors.Errorf("application %s not found", envName)
}
func deleteAppByName(name string) error {
clt, err := common.GetClient()
if err != nil {
return errors.Wrap(err, "get client fail")
}
app, err := getEnvAppByName(name)
if err != nil {
return err
}
err = clt.Delete(context.Background(), app)
if err != nil {
return err
}
return nil
}
// following functions are CRUD of env
// CreateEnv will create e env.
// Because Env equals to namespace, one env should not be updated
func CreateEnv(envName string, envArgs *types.EnvMeta) error {
c, err := common.GetClient()
if err != nil {
return err
}
e := envArgs
nowEnv, err := GetEnvByName(envName)
if err == nil {
if nowEnv.Namespace != envArgs.Namespace {
return errors.Errorf("env %s has existed", envName)
}
return nil
}
if e.Namespace == "" {
e.Namespace = "default"
}
app := env2App(envArgs)
err = applyApp(context.TODO(), app, c)
if err != nil {
return err
}
return nil
}
// GetEnvByName will get env info by name
func GetEnvByName(name string) (*types.EnvMeta, error) {
data, err := os.ReadFile(filepath.Join(GetEnvDirByName(name), system.EnvConfigName))
init, err := getEnvAppByName(name)
if err != nil {
if os.IsNotExist(err) {
return nil, fmt.Errorf("env %s not exist", name)
}
return nil, err
return nil, errors.Wrap(err, "Env not exist")
}
var meta types.EnvMeta
if err = json.Unmarshal(data, &meta); err != nil {
return nil, err
}
return &meta, nil
}
// CreateOrUpdateEnv will create or update env.
// If it does not exist, create it and set to the new env.
// If it exists, update it and set to the new env.
func CreateOrUpdateEnv(ctx context.Context, c client.Client, envName string, envArgs *types.EnvMeta) (string, error) {
createOrUpdated := "created"
old, err := GetEnvByName(envName)
if err == nil {
createOrUpdated = "updated"
if envArgs.Domain == "" {
envArgs.Domain = old.Domain
}
if envArgs.Email == "" {
envArgs.Email = old.Email
}
if envArgs.Namespace == "" {
envArgs.Namespace = old.Namespace
}
}
if envArgs.Namespace == "" {
envArgs.Namespace = "default"
}
var message = ""
// Check If Namespace Exists
if err := c.Get(ctx, k8stypes.NamespacedName{Name: envArgs.Namespace}, &corev1.Namespace{}); err != nil {
if !apierrors.IsNotFound(err) {
return message, err
}
// Create Namespace if not found
if err := c.Create(ctx, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: envArgs.Namespace}}); err != nil {
return message, err
}
}
data, err := json.Marshal(envArgs)
if err != nil {
return message, err
}
envdir, err := system.GetEnvDir()
if err != nil {
return message, err
}
subEnvDir := filepath.Join(envdir, envName)
if _, err = system.CreateIfNotExist(subEnvDir); err != nil {
return message, err
}
// nolint:gosec
if err = os.WriteFile(filepath.Join(subEnvDir, system.EnvConfigName), data, 0644); err != nil {
return message, err
}
curEnvPath, err := system.GetCurrentEnvPath()
if err != nil {
return message, err
}
// nolint:gosec
if err = os.WriteFile(curEnvPath, []byte(envName), 0644); err != nil {
return message, err
}
message = fmt.Sprintf("environment %s %s, Namespace: %s", envName, createOrUpdated, envArgs.Namespace)
if envArgs.Email != "" {
message += fmt.Sprintf(", Email: %s", envArgs.Email)
}
return message, nil
}
// CreateEnv will only create. If env already exists, return error
func CreateEnv(ctx context.Context, c client.Client, envName string, envArgs *types.EnvMeta) (string, error) {
_, err := GetEnvByName(envName)
if err == nil {
message := fmt.Sprintf("Env %s already exist", envName)
return message, errors.New(message)
}
return CreateOrUpdateEnv(ctx, c, envName, envArgs)
}
// UpdateEnv will update Env, if env does not exist, return error
func UpdateEnv(ctx context.Context, c client.Client, envName string, namespace string) (string, error) {
var message = ""
envMeta, err := GetEnvByName(envName)
if err != nil {
return err.Error(), err
}
if err := c.Create(ctx, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: envMeta.Namespace}}); err != nil && !apierrors.IsAlreadyExists(err) {
return message, err
}
envMeta.Namespace = namespace
data, err := json.Marshal(envMeta)
if err != nil {
return message, err
}
envdir, err := system.GetEnvDir()
if err != nil {
return message, err
}
subEnvDir := filepath.Join(envdir, envName)
// nolint:gosec
if err = os.WriteFile(filepath.Join(subEnvDir, system.EnvConfigName), data, 0644); err != nil {
return message, err
}
message = "Update env succeed"
return message, err
return app2Env(init)
}
// ListEnvs will list all envs
// if envName specified, return list that only contains one env
func ListEnvs(envName string) ([]*types.EnvMeta, error) {
var envList []*types.EnvMeta
if envName != "" {
@@ -176,40 +175,59 @@ func ListEnvs(envName string) ([]*types.EnvMeta, error) {
envList = append(envList, env)
return envList, err
}
envDir, err := system.GetEnvDir()
apps, err := getEnvAppList()
if err != nil {
return envList, err
return nil, err
}
files, err := os.ReadDir(envDir)
if err != nil {
return envList, err
// if even one env is not exist, create a default env
if len(apps) == 0 {
err := initDefaultEnv()
if err != nil {
return nil, err
}
return ListEnvs(envName)
}
curEnv, err := GetCurrentEnvName()
curEnv, err := getCurrentEnvName()
if err != nil {
curEnv = types.DefaultEnvName
}
for _, f := range files {
if !f.IsDir() {
continue
}
data, err := os.ReadFile(filepath.Clean(filepath.Join(envDir, f.Name(), system.EnvConfigName)))
for i := range apps {
env, err := app2Env(&apps[i])
if err != nil {
fmt.Printf("error occurred while listing env:" + err.Error())
continue
}
var envMeta types.EnvMeta
if err = json.Unmarshal(data, &envMeta); err != nil {
continue
if curEnv == env.Name {
env.Current = "*"
}
if curEnv == f.Name() {
envMeta.Current = "*"
}
envList = append(envList, &envMeta)
envList = append(envList, env)
}
return envList, nil
}
// GetCurrentEnvName will get current env name
func GetCurrentEnvName() (string, error) {
// DeleteEnv will delete env and its application
func DeleteEnv(envName string) (string, error) {
var message string
var err error
curEnv, err := getCurrentEnvName()
if err != nil {
return message, err
}
if envName == curEnv {
err = fmt.Errorf("you can't delete current using environment %s", curEnv)
return message, err
}
err = deleteAppByName(envName)
if err != nil {
return message, errors.Wrap(err, fmt.Sprintf("error deleting env %s", envName))
}
message = "env" + envName + " deleted"
return message, err
}
// getCurrentEnvName will get current env name
func getCurrentEnvName() (string, error) {
currentEnvPath, err := system.GetCurrentEnvPath()
if err != nil {
return "", err
@@ -221,34 +239,19 @@ func GetCurrentEnvName() (string, error) {
return string(data), nil
}
// DeleteEnv will delete env locally
func DeleteEnv(envName string) (string, error) {
var message string
var err error
curEnv, err := GetCurrentEnvName()
// GetCurrentEnv will get current env, create default env if not exist
func GetCurrentEnv() (*types.EnvMeta, error) {
envName, err := getCurrentEnvName()
if err != nil {
return message, err
}
if envName == curEnv {
err = fmt.Errorf("you can't delete current using environment %s", curEnv)
return message, err
}
envdir, err := system.GetEnvDir()
if err != nil {
return message, err
}
envPath := filepath.Join(envdir, envName)
if _, err := os.Stat(envPath); err != nil {
if os.IsNotExist(err) {
err = fmt.Errorf("%s does not exist", envName)
return message, err
if !os.IsNotExist(err) {
return nil, err
}
if err = initDefaultEnv(); err != nil {
return nil, err
}
envName = types.DefaultEnvName
}
if err = os.RemoveAll(envPath); err != nil {
return message, err
}
message = envName + " deleted"
return message, err
return GetEnvByName(envName)
}
// SetEnv will set the current env to the specified one
@@ -269,3 +272,34 @@ func SetEnv(envName string) (string, error) {
msg = fmt.Sprintf("Set environment succeed, current environment is " + envName + ", namespace is " + envMeta.Namespace)
return msg, nil
}
// applyApp helps apply app
func applyApp(ctx context.Context, app *v1beta1.Application, c client.Client) error {
applicator := apply.NewAPIApplicator(c)
err := applicator.Apply(ctx, app)
return err
}
// initDefaultEnv create default env if not exist
func initDefaultEnv() error {
fmt.Println("Initializing default vela env...")
defaultEnv := &types.EnvMeta{Name: DefaultEnvName, Namespace: DefaultEnvNamespace}
app := env2App(defaultEnv)
clt, err := common.GetClient()
if err != nil {
return err
}
err = applyApp(context.Background(), app, clt)
if err != nil {
return err
}
currentEnvPath, err := system.GetCurrentEnvPath()
if err != nil {
return err
}
//nolint:gosec
if err = os.WriteFile(currentEnvPath, []byte(DefaultEnvName), 0644); err != nil {
return err
}
return nil
}

92
pkg/utils/env/env_test.go vendored Normal file
View File

@@ -0,0 +1,92 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package env
import (
"fmt"
"testing"
"gotest.tools/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
common2 "github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/pkg/oam/util"
"github.com/oam-dev/kubevela/apis/types"
)
func TestEnv(t *testing.T) {
testCases := []struct {
envName string
namespace string
wantComponents []common2.ApplicationComponent
labels map[string]string
}{
{
envName: "test-env",
namespace: "test-env-ns",
wantComponents: []common2.ApplicationComponent{
{
Name: "test-env-ns",
Type: RawType,
Properties: util.Object2RawExtension(map[string]interface{}{
"apiVersion": "v1",
"kind": "Namespace",
"metadata": map[string]string{"name": "test-env-ns"},
})},
},
labels: map[string]string{IndicatingLabel: "test-env"},
},
{
envName: "test-env-default",
namespace: "default",
wantComponents: []common2.ApplicationComponent{},
labels: map[string]string{IndicatingLabel: "test-env-default"},
},
}
baseApp := v1beta1.Application{
TypeMeta: metav1.TypeMeta{
Kind: v1beta1.ApplicationKind,
APIVersion: v1beta1.SchemeGroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: "",
Namespace: types.DefaultKubeVelaNS,
},
Spec: v1beta1.ApplicationSpec{
Components: []common2.ApplicationComponent{}}}
for _, c := range testCases {
env := &types.EnvMeta{
Name: c.envName,
Namespace: c.namespace,
}
rightApp := baseApp.DeepCopy()
rightApp.ObjectMeta.Name = fmt.Sprintf(AppNameSchema, c.envName)
rightApp.ObjectMeta.Labels = c.labels
rightApp.Spec.Components = c.wantComponents
generatedApp := env2App(env)
assert.DeepEqual(t, generatedApp, rightApp)
generatedEnv, err := app2Env(rightApp)
assert.NilError(t, err)
assert.DeepEqual(t, generatedEnv, env)
}
}

87
pkg/utils/env/helper.go vendored Normal file
View File

@@ -0,0 +1,87 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package env
import (
"context"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
common2 "github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"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"
)
// getEnvAppList will filter application that represent an env
func getEnvAppList() ([]v1beta1.Application, error) {
list := v1beta1.ApplicationList{}
clt, err := common.GetClient()
if err != nil {
return nil, err
}
ctx := context.Background()
matchLabels := metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{{
Key: IndicatingLabel,
Operator: metav1.LabelSelectorOpExists,
}},
}
selector, err := metav1.LabelSelectorAsSelector(&matchLabels)
if err != nil {
return nil, err
}
err = clt.List(ctx, &list, &client.ListOptions{LabelSelector: selector})
if err != nil {
return nil, err
}
return list.Items, nil
}
func getEnvNamespace(application *v1beta1.Application) string {
namespace := DefaultEnvNamespace
for _, comp := range application.Spec.Components {
if comp.Type == RawType {
obj, err := util.RawExtension2Unstructured(&comp.Properties)
if err != nil {
return ""
}
return obj.GetName()
}
}
return namespace
}
// add namespace object if env namespace is not default
func addNamespaceObjectIfNeeded(meta *types.EnvMeta, app *v1beta1.Application) {
if meta.Namespace != DefaultEnvNamespace {
app.Spec.Components = append(app.Spec.Components, common2.ApplicationComponent{
Name: meta.Namespace,
Type: RawType,
Properties: util.Object2RawExtension(map[string]interface{}{
"apiVersion": "v1",
"kind": "Namespace",
"metadata": map[string]string{
"name": meta.Namespace,
},
}),
})
}
}

View File

@@ -17,11 +17,10 @@ limitations under the License.
package system
import (
"encoding/json"
"os"
"path/filepath"
"github.com/oam-dev/kubevela/apis/types"
"github.com/pkg/errors"
)
const defaultVelaHome = ".vela"
@@ -35,14 +34,23 @@ const (
// GetVelaHomeDir return vela home dir
func GetVelaHomeDir() (string, error) {
var velaHome string
if custom := os.Getenv(VelaHomeEnv); custom != "" {
return custom, nil
velaHome = custom
} else {
home, err := os.UserHomeDir()
if err != nil {
return "", err
}
velaHome = filepath.Join(home, defaultVelaHome)
}
home, err := os.UserHomeDir()
if err != nil {
return "", err
if _, err := os.Stat(velaHome); err != nil && os.IsNotExist(err) {
err := os.MkdirAll(velaHome, 0750)
if err != nil {
return "", errors.Wrap(err, "error when create vela home directory")
}
}
return filepath.Join(home, defaultVelaHome), nil
return velaHome, nil
}
// GetDefaultFrontendDir return default vela frontend dir
@@ -81,22 +89,14 @@ func GetCapabilityDir() (string, error) {
return filepath.Join(home, "capabilities"), nil
}
// GetEnvDir return KubeVela environments dir
func GetEnvDir() (string, error) {
homedir, err := GetVelaHomeDir()
if err != nil {
return "", err
}
return filepath.Join(homedir, "envs"), nil
}
// GetCurrentEnvPath return current env config
func GetCurrentEnvPath() (string, error) {
homedir, err := GetVelaHomeDir()
if err != nil {
return "", err
}
return filepath.Join(homedir, "curenv"), nil
envPath := filepath.Join(homedir, "curenv")
return envPath, nil
}
// InitDirs create dir if not exits
@@ -107,9 +107,6 @@ func InitDirs() error {
if err := InitCapCenterDir(); err != nil {
return err
}
if err := InitDefaultEnv(); err != nil {
return err
}
return nil
}
@@ -133,39 +130,6 @@ func InitCapabilityDir() error {
return err
}
// EnvConfigName defines config
const EnvConfigName = "config.json"
// InitDefaultEnv create dir if not exits
func InitDefaultEnv() error {
envDir, err := GetEnvDir()
if err != nil {
return err
}
defaultEnvDir := filepath.Join(envDir, types.DefaultEnvName)
exist, err := CreateIfNotExist(defaultEnvDir)
if err != nil {
return err
}
if exist {
return nil
}
data, _ := json.Marshal(&types.EnvMeta{Namespace: types.DefaultAppNamespace, Name: types.DefaultEnvName})
//nolint:gosec
if err = os.WriteFile(filepath.Join(defaultEnvDir, EnvConfigName), data, 0644); err != nil {
return err
}
curEnvPath, err := GetCurrentEnvPath()
if err != nil {
return err
}
//nolint:gosec
if err = os.WriteFile(curEnvPath, []byte(types.DefaultEnvName), 0644); err != nil {
return err
}
return nil
}
// CreateIfNotExist create dir if not exist
func CreateIfNotExist(dir string) (bool, error) {
_, err := os.Stat(dir)

View File

@@ -39,7 +39,7 @@ const (
)
// ComponentApply apply oam component.
type ComponentApply func(comp common.ApplicationComponent, patcher *value.Value) (*unstructured.Unstructured, []*unstructured.Unstructured, bool, error)
type ComponentApply func(comp common.ApplicationComponent, patcher *value.Value, clusterName string) (*unstructured.Unstructured, []*unstructured.Unstructured, bool, error)
type provider struct {
apply ComponentApply
@@ -58,7 +58,11 @@ func (p *provider) ApplyComponent(ctx wfContext.Context, v *value.Value, act wfT
return err
}
patcher, _ := v.LookupValue("patch")
workload, traits, healthy, err := p.apply(comp, patcher)
clusterName, err := v.GetString("cluster")
if err != nil {
clusterName = ""
}
workload, traits, healthy, err := p.apply(comp, patcher, clusterName)
if err != nil {
return err
}

View File

@@ -115,7 +115,7 @@ func TestLoadComponent(t *testing.T) {
var testHealthy bool
func simpleComponentApplyForTest(comp common.ApplicationComponent, _ *value.Value) (*unstructured.Unstructured, []*unstructured.Unstructured, bool, error) {
func simpleComponentApplyForTest(comp common.ApplicationComponent, _ *value.Value, _ string) (*unstructured.Unstructured, []*unstructured.Unstructured, bool, error) {
workload := new(unstructured.Unstructured)
workload.UnmarshalJSON([]byte(`{
"apiVersion": "v1",

View File

@@ -32,7 +32,6 @@ 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/appfile/config"
"github.com/oam-dev/kubevela/pkg/builtin"
"github.com/oam-dev/kubevela/pkg/oam"
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
@@ -64,16 +63,14 @@ type AppFile struct {
Services map[string]Service `json:"services"`
Secrets map[string]string `json:"secrets,omitempty"`
configGetter config.Store
initialized bool
initialized bool
}
// NewAppFile init an empty AppFile struct
func NewAppFile() *AppFile {
return &AppFile{
Services: make(map[string]Service),
Secrets: make(map[string]string),
configGetter: &config.Local{},
Services: make(map[string]Service),
Secrets: make(map[string]string),
}
}
@@ -158,26 +155,10 @@ func (app *AppFile) BuildOAMApplication(env *types.EnvMeta, io cmdutil.IOStreams
servApp.SetNamespace(env.Namespace)
servApp.SetName(app.Name)
servApp.Spec.Components = []common.ApplicationComponent{}
if !silence {
io.Infof("parsing application components")
}
for serviceName, svc := range app.GetServices() {
if !silence {
io.Infof("\nRendering configs for service (%s)...\n", serviceName)
}
configname := svc.GetUserConfigName()
if configname != "" {
configData, err := app.configGetter.GetConfigData(configname, env.Name)
if err != nil {
return nil, nil, err
}
decodedData, err := config.DecodeConfigFormat(configData)
if err != nil {
return nil, nil, err
}
cm, err := config.ToConfigMap(app.configGetter, config.GenConfigMapName(app.Name, serviceName, configname), env.Name, decodedData)
if err != nil {
return nil, nil, err
}
auxiliaryObjects = append(auxiliaryObjects, cm)
}
comp, err := svc.RenderServiceToApplicationComponent(tm, serviceName)
if err != nil {
return nil, nil, err

View File

@@ -30,7 +30,6 @@ 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/appfile/config"
"github.com/oam-dev/kubevela/pkg/oam"
"github.com/oam-dev/kubevela/pkg/oam/util"
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
@@ -137,7 +136,7 @@ func TestBuildOAMApplication2(t *testing.T) {
In: os.Stdin,
Out: os.Stdout,
}, tm, false)
assert.Equal(t, nil, err)
assert.NoError(t, err)
assert.Equal(t, tcase.expectApp, o)
}
}
@@ -168,19 +167,6 @@ services:
cmd: ["node", "server.js"]
`
yamlWithConfig := `name: myapp
services:
express-server:
type: withconfig
image: oamdev/testapp:v1
cmd: ["node", "server.js"]
route:
domain: example.com
http:
"/": 8080
config: test
`
templateWebservice := `parameter: #webservice
#webservice: {
cmd: [...string]
@@ -216,25 +202,6 @@ output: {
command: parameter.cmd
}
}`
templateWithConfig := `parameter: #withconfig
#withconfig: {
cmd: [...string]
image: string
}
output: {
apiVersion: "test.oam.dev/v1"
kind: "WebService"
metadata: {
name: context.name
}
spec: {
image: parameter.image
command: parameter.cmd
env: context.config
}
}
`
templateRoute := `parameter: #route
#route: {
domain: string
@@ -324,22 +291,6 @@ outputs: ingress: {
// TODO application 那边补测试:
// 2. 1对多的情况多对1 的情况
fakeConfigData2 := []map[string]string{{
"name": "test",
"value": "test-value",
}}
ac3cm := &corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "ConfigMap",
},
Data: map[string]string{
"test": "test-value",
},
}
ac3cm.SetName("kubevela-myapp-express-server-test")
health := &v1alpha2.HealthScope{
TypeMeta: metav1.TypeMeta{
APIVersion: v1alpha2.HealthScopeGroupVersionKind.GroupVersion().String(),
@@ -402,21 +353,6 @@ outputs: ingress: {
err: ErrImageNotDefined,
},
},
"config data should be set, add return configmap objects": {
args: args{
appfileData: yamlWithConfig,
workloadTemplates: map[string]string{
"withconfig": templateWithConfig,
},
traitTemplates: map[string]string{
"route": templateRoute,
},
},
want: want{
app: ac3,
objs: []oam.Object{ac3cm, health},
},
},
}
io := cmdutil.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr}
@@ -424,9 +360,6 @@ outputs: ingress: {
t.Run(caseName, func(t *testing.T) {
app := NewAppFile()
app.configGetter = &config.Fake{
Data: fakeConfigData2,
}
err := yaml.Unmarshal([]byte(c.args.appfileData), app)
if err != nil {
t.Fatal(err)

View File

@@ -84,16 +84,6 @@ func LoadApplication(namespace, appName string, c common.Args) (*v1beta1.Applica
return app, nil
}
// Delete will delete an app along with it's appfile.
func Delete(envName, appName string) error {
return GetStorage().Delete(envName, appName)
}
// Save will save appfile into default dir.
func Save(app *api.Application, envName string) error {
return GetStorage().Save(app, envName)
}
// GetComponents will get oam components from Appfile.
func GetComponents(app *v1beta1.Application) []string {
var components []string

View File

@@ -1,65 +0,0 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package driver
import (
"errors"
"github.com/oam-dev/kubevela/references/appfile/api"
)
// ConfigMapDriverName is local storage driver name
const ConfigMapDriverName = "ConfigMap"
// ConfigMap Storage
type ConfigMap struct {
api.Driver
}
// NewConfigMapStorage get storage client of ConfigMap type
func NewConfigMapStorage() *ConfigMap {
return &ConfigMap{}
}
// Name of local storage
func (c *ConfigMap) Name() string {
return ConfigMapDriverName
}
// List applications from configmap storage
func (c *ConfigMap) List(envName string) ([]*api.Application, error) {
// TODO support configmap storage
return nil, errors.New("not implement")
}
// Save applications from configmap storage
func (c *ConfigMap) Save(app *api.Application, envName string) error {
// TODO support configmap storage
return errors.New("not implement")
}
// Delete applications from configmap storage
func (c *ConfigMap) Delete(envName, appName string) error {
// TODO support configmap storage
return errors.New("not implement")
}
// Get applications from configmap storage
func (c *ConfigMap) Get(envName, appName string) (*api.Application, error) {
// TODO support configmap storage
return nil, errors.New("not implement")
}

View File

@@ -1,140 +0,0 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package driver
import (
"reflect"
"testing"
"github.com/oam-dev/kubevela/references/appfile/api"
)
func TestConfigMapDelete(t *testing.T) {
type args struct {
envName string
appName string
}
tests := []struct {
name string
args args
wantErr bool
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := &ConfigMap{}
if err := c.Delete(tt.args.envName, tt.args.appName); (err != nil) != tt.wantErr {
t.Errorf("Delete() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
func TestConfigMapGet(t *testing.T) {
type args struct {
envName string
appName string
}
tests := []struct {
name string
args args
want *api.Application
wantErr bool
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := &ConfigMap{}
got, err := c.Get(tt.args.envName, tt.args.appName)
if (err != nil) != tt.wantErr {
t.Errorf("Get() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Get() got = %v, want %v", got, tt.want)
}
})
}
}
func TestConfigMapList(t *testing.T) {
type args struct {
envName string
}
tests := []struct {
name string
args args
want []*api.Application
wantErr bool
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := &ConfigMap{}
got, err := c.List(tt.args.envName)
if (err != nil) != tt.wantErr {
t.Errorf("List() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("List() got = %v, want %v", got, tt.want)
}
})
}
}
func TestConfigMapName(t *testing.T) {
tests := []struct {
name string
want string
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := &ConfigMap{}
if got := c.Name(); got != tt.want {
t.Errorf("Name() = %v, want %v", got, tt.want)
}
})
}
}
func TestConfigMapSave(t *testing.T) {
type args struct {
app *api.Application
envName string
}
tests := []struct {
name string
args args
wantErr bool
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := &ConfigMap{}
if err := c.Save(tt.args.app, tt.args.envName); (err != nil) != tt.wantErr {
t.Errorf("Save() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

View File

@@ -1,84 +0,0 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package driver
import (
"fmt"
"os"
"path/filepath"
"time"
"sigs.k8s.io/yaml"
"github.com/oam-dev/kubevela/pkg/utils/env"
"github.com/oam-dev/kubevela/pkg/utils/system"
"github.com/oam-dev/kubevela/references/appfile/api"
)
// LocalDriverName is local storage driver name
const LocalDriverName = "Local"
// Local Storage
type Local struct {
api.Driver
}
// NewLocalStorage get storage client of Local type
func NewLocalStorage() *Local {
return &Local{}
}
// Name is local storage driver name
func (l *Local) Name() string {
return LocalDriverName
}
// Save application from local storage
func (l *Local) Save(app *api.Application, envName string) error {
appDir, err := getApplicationDir(envName)
if err != nil {
return err
}
if app.CreateTime.IsZero() {
app.CreateTime = time.Now()
}
app.UpdateTime = time.Now()
out, err := yaml.Marshal(app)
if err != nil {
return err
}
//nolint:gosec
return os.WriteFile(filepath.Join(appDir, app.Name+".yaml"), out, 0644)
}
// Delete application from local storage
func (l *Local) Delete(envName, appName string) error {
appDir, err := getApplicationDir(envName)
if err != nil {
return err
}
return os.Remove(filepath.Join(appDir, appName+".yaml"))
}
func getApplicationDir(envName string) (string, error) {
appDir := filepath.Join(env.GetEnvDirByName(envName), "applications")
_, err := system.CreateIfNotExist(appDir)
if err != nil {
err = fmt.Errorf("getting application directory from env %s failed, error: %w ", envName, err)
}
return appDir, err
}

View File

@@ -1,155 +0,0 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package driver
import (
"os"
"path/filepath"
"reflect"
"strings"
"testing"
"sigs.k8s.io/yaml"
"github.com/oam-dev/kubevela/references/appfile/api"
)
var dir string
var afile *api.AppFile
var appName = "testsvc"
var envName = "default"
func init() {
dir, _ = getApplicationDir(envName)
afile = api.NewAppFile()
afile.Name = appName
svcs := make(map[string]api.Service)
svcs["wordpress"] = map[string]interface{}{
"type": "webservice",
"image": "wordpress:php7.4-apache",
"port": "80",
"cpu": "1",
"route": "",
}
afile.Services = svcs
out, _ := yaml.Marshal(afile)
_ = os.WriteFile(filepath.Join(dir, appName+".yaml"), out, 0644)
}
func TestLocalDelete(t *testing.T) {
type args struct {
envName string
appName string
}
tests := []struct {
name string
args args
wantErr bool
}{
{"testLocalDelete1", args{envName: envName, appName: appName}, false},
{"testLocalDelete2", args{envName: envName, appName: "test"}, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
l := &Local{}
if err := l.Delete(tt.args.envName, tt.args.appName); (err != nil) != tt.wantErr {
t.Errorf("Delete() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
func TestLocalSave(t *testing.T) {
type args struct {
app *api.Application
envName string
}
tests := []struct {
name string
args args
wantErr bool
}{
{"TestLocal_Save1", args{&api.Application{AppFile: afile, Tm: nil}, envName}, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
l := &Local{}
if err := l.Save(tt.args.app, tt.args.envName); (err != nil) != tt.wantErr {
t.Errorf("Save() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
func TestLocalName(t *testing.T) {
tests := []struct {
name string
want string
}{
{"testDriverName", "Local"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
l := &Local{}
if got := l.Name(); got != tt.want {
t.Errorf("Name() = %v, want %v", got, tt.want)
}
})
}
}
func TestNewLocalStorage(t *testing.T) {
tests := []struct {
name string
want *Local
}{
{"testNewLocal", &Local{}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := NewLocalStorage(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("NewLocalStorage() = %v, want %v", got, tt.want)
}
})
}
}
func TestGetApplicationDir(t *testing.T) {
type args struct {
envName string
}
tests := []struct {
name string
args args
want string
wantErr bool
}{
{"testGetApplicationDir", args{envName: envName}, "/envs/default/applications", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := getApplicationDir(tt.args.envName)
if (err != nil) != tt.wantErr {
t.Errorf("getApplicationDir() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !strings.Contains(got, tt.want) {
t.Errorf("getApplicationDir() got = %v, want %v", got, tt.want)
}
})
}
}

View File

@@ -1,60 +0,0 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package appfile
import (
"os"
"github.com/oam-dev/kubevela/pkg/utils/system"
"github.com/oam-dev/kubevela/references/appfile/api"
"github.com/oam-dev/kubevela/references/appfile/driver"
)
// Store application store client
var store *Storage
// Storage is common storage clientuse it to get app and others resource
type Storage struct {
api.Driver
}
// GetStorage will create storage driver from the system environment of "STORAGE_DRIVER"
func GetStorage() *Storage {
driverName := os.Getenv(system.StorageDriverEnv)
if store == nil || store.Name() != driverName {
switch driverName {
// TODO mutli implement Storage
case driver.ConfigMapDriverName:
store = &Storage{driver.NewConfigMapStorage()}
case driver.LocalDriverName:
store = &Storage{driver.NewLocalStorage()}
default:
store = &Storage{driver.NewLocalStorage()}
}
}
return store
}
// Save application storage common implement
func (s *Storage) Save(app *api.Application, envName string) error {
return s.Driver.Save(app, envName)
}
// Delete application storage common implement
func (s *Storage) Delete(envName, appName string) error {
return s.Driver.Delete(envName, appName)
}

View File

@@ -1,44 +0,0 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package appfile
import (
"os"
"testing"
"github.com/oam-dev/kubevela/pkg/utils/system"
"github.com/oam-dev/kubevela/references/appfile/driver"
)
func TestGetStorage(t *testing.T) {
_ = os.Setenv(system.StorageDriverEnv, driver.ConfigMapDriverName)
store := &Storage{driver.NewConfigMapStorage()}
tests := []struct {
name string
want *Storage
}{
{name: "TestGetStorage_ConfigMap", want: store},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := GetStorage(); got.Name() != tt.want.Name() {
t.Errorf("GetStorage() = %v, want %v", got, tt.want)
}
})
}
}

View File

@@ -154,7 +154,7 @@ func NewCapUninstallCommand(c common2.Args, ioStreams cmdutil.IOStreams) *cobra.
}
name = l[1]
}
env, err := GetEnv(cmd)
env, err := GetFlagEnvOrCurrent(cmd, c)
if err != nil {
return err
}
@@ -199,7 +199,7 @@ func NewCapListCommand(c common2.Args, ioStreams cmdutil.IOStreams) *cobra.Comma
if len(args) > 0 {
repoName = args[0]
}
env, err := GetEnv(cmd)
env, err := GetFlagEnvOrCurrent(cmd, c)
if err != nil {
return err
}

View File

@@ -87,7 +87,6 @@ func NewCommand() *cobra.Command {
NewPortForwardCommand(commandArgs, ioStream),
NewLogsCommand(commandArgs, ioStream),
NewEnvCommand(commandArgs, ioStream),
NewConfigCommand(ioStream),
// Workflows
NewWorkflowCommand(commandArgs, ioStream),

View File

@@ -19,8 +19,8 @@ package cli
import (
"context"
"fmt"
"strings"
v1alpha12 "github.com/oam-dev/cluster-gateway/pkg/apis/cluster/v1alpha1"
"github.com/pkg/errors"
"github.com/spf13/cobra"
v1 "k8s.io/api/core/v1"
@@ -42,8 +42,6 @@ import (
)
const (
// ClusterCredentialLabelKey identifies the cluster secrets
ClusterCredentialLabelKey = "cluster.core.oam.dev/cluster-credential"
// FlagClusterName specifies the cluster name
FlagClusterName = "name"
)
@@ -99,12 +97,12 @@ func NewClusterListCommand(c *common.Args) *cobra.Command {
Args: cobra.ExactValidArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
secrets := v1.SecretList{}
if err := c.Client.List(context.Background(), &secrets, client.HasLabels{ClusterCredentialLabelKey}, client.InNamespace(multicluster.ClusterGatewaySecretNamespace)); err != nil {
if err := c.Client.List(context.Background(), &secrets, client.HasLabels{v1alpha12.LabelKeyClusterCredentialType}, client.InNamespace(multicluster.ClusterGatewaySecretNamespace)); err != nil {
return errors.Wrapf(err, "failed to get cluster secrets")
}
table := newUITable().AddRow("CLUSTER", "TYPE", "ENDPOINT")
for _, secret := range secrets.Items {
table.AddRow(secret.Name, secret.GetLabels()[ClusterCredentialLabelKey], string(secret.Data["endpoint"]))
table.AddRow(secret.Name, secret.GetLabels()[v1alpha12.LabelKeyClusterCredentialType], string(secret.Data["endpoint"]))
}
if len(table.Rows) == 1 {
cmd.Println("No managed cluster found.")
@@ -198,20 +196,28 @@ func NewClusterJoinCommand(c *common.Args) *cobra.Command {
if err := ensureClusterNotExists(c.Client, clusterName); err != nil {
return errors.Wrapf(err, "cannot use cluster name %s", clusterName)
}
credentialType := v1.SecretTypeTLS
var credentialType v1alpha12.CredentialType
data := map[string][]byte{
"endpoint": []byte(cluster.Server),
"ca.crt": cluster.CertificateAuthorityData,
"tls.crt": authInfo.ClientCertificateData,
"tls.key": authInfo.ClientKeyData,
}
if len(authInfo.Token) > 0 {
credentialType = v1alpha12.CredentialTypeServiceAccountToken
data["token"] = []byte(authInfo.Token)
} else {
credentialType = v1alpha12.CredentialTypeX509Certificate
data["tls.crt"] = authInfo.ClientCertificateData
data["tls.key"] = authInfo.ClientKeyData
}
secret := &v1.Secret{
ObjectMeta: v12.ObjectMeta{
Name: clusterName,
Namespace: multicluster.ClusterGatewaySecretNamespace,
Labels: map[string]string{ClusterCredentialLabelKey: strings.Split(string(credentialType), "/")[1]},
Labels: map[string]string{
v1alpha12.LabelKeyClusterCredentialType: string(credentialType),
},
},
Type: credentialType,
Type: v1.SecretTypeOpaque,
Data: data,
}
if err := c.Client.Create(context.Background(), secret); err != nil {
@@ -235,8 +241,8 @@ func getMutableClusterSecret(c client.Client, clusterName string) (*v1.Secret, e
return nil, errors.Wrapf(err, "failed to find target cluster secret %s", clusterName)
}
labels := clusterSecret.GetLabels()
if labels == nil || labels[ClusterCredentialLabelKey] == "" {
return nil, fmt.Errorf("invalid cluster secret %s: cluster credential type label %s is not set", clusterName, ClusterCredentialLabelKey)
if labels == nil || labels[v1alpha12.LabelKeyClusterCredentialType] == "" {
return nil, fmt.Errorf("invalid cluster secret %s: cluster credential type label %s is not set", clusterName, v1alpha12.LabelKeyClusterCredentialType)
}
ebs := &v1alpha1.EnvBindingList{}
if err := c.List(context.Background(), ebs); err != nil {

View File

@@ -51,7 +51,7 @@ func NewComponentsCommand(c common2.Args, ioStreams cmdutil.IOStreams) *cobra.Co
},
RunE: func(cmd *cobra.Command, args []string) error {
isDiscover, _ := cmd.Flags().GetBool("discover")
env, err := GetEnv(cmd)
env, err := GetFlagEnvOrCurrent(cmd, c)
if err != nil {
return err
}

View File

@@ -1,274 +0,0 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cli
import (
"bufio"
"bytes"
b64 "encoding/base64"
"fmt"
"os"
"strings"
"github.com/spf13/cobra"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/utils/config"
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
)
// Notes about config dir layout:
// Under each env dir, there are individual files for each config.
// The format is the same as k8s Secret.Data field with value base64 encoded.
// NewConfigCommand will create command for config management for AppFile
func NewConfigCommand(io cmdutil.IOStreams) *cobra.Command {
cmd := &cobra.Command{
Use: "config",
DisableFlagsInUseLine: true,
Short: "Manage configurations",
Long: "Manage configurations",
Annotations: map[string]string{
types.TagCommandType: types.TypeApp,
},
}
cmd.SetOut(io.Out)
cmd.AddCommand(
NewConfigListCommand(io),
NewConfigGetCommand(io),
NewConfigSetCommand(io),
NewConfigDeleteCommand(io),
)
return cmd
}
// NewConfigListCommand list all created configs
func NewConfigListCommand(io cmdutil.IOStreams) *cobra.Command {
cmd := &cobra.Command{
Use: "ls",
Aliases: []string{"list"},
DisableFlagsInUseLine: true,
Short: "List configs",
Long: "List all configs",
Example: `vela config ls`,
RunE: func(cmd *cobra.Command, args []string) error {
return ListConfigs(io, cmd)
},
Annotations: map[string]string{
types.TagCommandType: types.TypeStart,
},
}
cmd.SetOut(io.Out)
return cmd
}
func getConfigDir(cmd *cobra.Command) (string, error) {
e, err := GetEnv(cmd)
if err != nil {
return "", err
}
return config.GetConfigsDir(e.Name)
}
// ListConfigs will list all configs
func ListConfigs(ioStreams cmdutil.IOStreams, cmd *cobra.Command) error {
d, err := getConfigDir(cmd)
if err != nil {
return err
}
table := newUITable()
table.AddRow("NAME")
cfgList, err := listConfigs(d)
if err != nil {
return err
}
for _, name := range cfgList {
table.AddRow(name)
}
ioStreams.Info(table.String())
return nil
}
func listConfigs(dir string) ([]string, error) {
files, err := os.ReadDir(dir)
if err != nil {
return nil, err
}
l := []string{}
for _, f := range files {
l = append(l, f.Name())
}
return l, nil
}
// NewConfigGetCommand get config from local
func NewConfigGetCommand(io cmdutil.IOStreams) *cobra.Command {
cmd := &cobra.Command{
Use: "get",
Aliases: []string{"get"},
DisableFlagsInUseLine: true,
Short: "Get data for a config",
Long: "Get data for a config",
Example: `vela config get <config-name>`,
RunE: func(cmd *cobra.Command, args []string) error {
return getConfig(args, io, cmd)
},
Annotations: map[string]string{
types.TagCommandType: types.TypeStart,
},
}
cmd.SetOut(io.Out)
return cmd
}
func getConfig(args []string, io cmdutil.IOStreams, cmd *cobra.Command) error {
e, err := GetEnv(cmd)
if err != nil {
return err
}
if len(args) < 1 {
return fmt.Errorf("must specify config name, vela config get <name>")
}
configName := args[0]
cfgData, err := config.ReadConfig(e.Name, configName)
if err != nil {
return err
}
io.Infof("Data:\n")
scanner := bufio.NewScanner(bytes.NewReader(cfgData))
for scanner.Scan() {
k, v, err := config.ReadConfigLine(scanner.Text())
if err != nil {
return err
}
io.Infof(" %s: %s\n", k, v)
}
return nil
}
// NewConfigSetCommand set a config data in local
func NewConfigSetCommand(io cmdutil.IOStreams) *cobra.Command {
cmd := &cobra.Command{
Use: "set",
Aliases: []string{"set"},
DisableFlagsInUseLine: true,
Short: "Set data for a config",
Long: "Set data for a config",
Example: `vela config set <config-name> KEY=VALUE K2=V2`,
RunE: func(cmd *cobra.Command, args []string) error {
return setConfig(args, io, cmd)
},
Annotations: map[string]string{
types.TagCommandType: types.TypeStart,
},
}
cmd.SetOut(io.Out)
return cmd
}
func setConfig(args []string, io cmdutil.IOStreams, cmd *cobra.Command) error {
e, err := GetEnv(cmd)
if err != nil {
return err
}
envName := e.Name
if len(args) < 1 {
return fmt.Errorf("must specify config name, vela config set <name> KEY=VALUE")
}
configName := args[0]
input := map[string]string{}
for _, arg := range args[1:] {
ss := strings.SplitN(arg, "=", 2)
if len(ss) != 2 {
return fmt.Errorf("KV argument malformed: %s, should be KEY=VALUE", arg)
}
k := strings.TrimSpace(ss[0])
v := strings.TrimSpace(ss[1])
if _, ok := input[k]; ok {
return fmt.Errorf("KEY is not unique: %s", arg)
}
input[k] = v
}
cfgData, err := config.ReadConfig(envName, configName)
if err != nil {
return err
}
io.Infof("reading existing config data and merging with user input\n")
scanner := bufio.NewScanner(bytes.NewReader(cfgData))
for scanner.Scan() {
k, v, err := config.ReadConfigLine(scanner.Text())
if err != nil {
return err
}
input[k] = v
}
var out bytes.Buffer
for k, v := range input {
vEnc := b64.StdEncoding.EncodeToString([]byte(v))
out.WriteString(fmt.Sprintf("%s: %s\n", k, vEnc))
}
err = config.WriteConfig(envName, configName, out.Bytes())
if err != nil {
return err
}
io.Infof("config data saved successfully %s\n", emojiSucceed)
return nil
}
// NewConfigDeleteCommand delete a config from local
func NewConfigDeleteCommand(io cmdutil.IOStreams) *cobra.Command {
cmd := &cobra.Command{
Use: "del",
Aliases: []string{"del"},
DisableFlagsInUseLine: true,
Short: "Delete config",
Long: "Delete config",
Example: `vela config del <config-name>`,
RunE: func(cmd *cobra.Command, args []string) error {
return deleteConfig(args, io, cmd)
},
Annotations: map[string]string{
types.TagCommandType: types.TypeStart,
},
}
cmd.SetOut(io.Out)
return cmd
}
func deleteConfig(args []string, io cmdutil.IOStreams, cmd *cobra.Command) error {
e, err := GetEnv(cmd)
if err != nil {
return err
}
if len(args) < 1 {
return fmt.Errorf("must specify config name, vela config get <name>")
}
configName := args[0]
err = config.DeleteConfig(e.Name, configName)
if err != nil {
return err
}
io.Infof("config (%s) deleted successfully\n", configName)
return nil
}

View File

@@ -1,90 +0,0 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cli
import (
"bytes"
"os"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/oam-dev/kubevela/pkg/utils/system"
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
)
func TestConfigCommand(t *testing.T) {
// Set VELA_HOME to local
assert.NoError(t, os.Setenv(system.VelaHomeEnv, ".test_vela"))
home, err := system.GetVelaHomeDir()
assert.NoError(t, err)
assert.Equal(t, true, strings.HasSuffix(home, ".test_vela"))
defer os.RemoveAll(home)
// Create Default Env
err = system.InitDefaultEnv()
assert.NoError(t, err)
// vela config set test a=b
io := cmdutil.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr}
err = setConfig([]string{"test", "a=b"}, io, nil)
if err != nil {
t.Fatal(err)
}
// vela config get test
var b bytes.Buffer
io.Out = &b
err = getConfig([]string{"test"}, io, nil)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "Data:\n a: b\n", b.String())
// vela config set test2 c=d
io.Out = os.Stdout
err = setConfig([]string{"test2", "c=d"}, io, nil)
if err != nil {
t.Fatal(err)
}
// vela config ls
b = bytes.Buffer{}
io.Out = &b
err = ListConfigs(io, nil)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "NAME \ntest \ntest2\n", b.String())
// vela config del test
io.Out = os.Stdout
err = deleteConfig([]string{"test"}, io, nil)
if err != nil {
t.Fatal(err)
}
// vela config ls
b = bytes.Buffer{}
io.Out = &b
err = ListConfigs(io, nil)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "NAME \ntest2\n", b.String())
}

View File

@@ -54,7 +54,7 @@ func NewDeleteCommand(c common2.Args, ioStreams cmdutil.IOStreams) *cobra.Comman
C: c,
}
o.Client = newClient
o.Env, err = GetEnv(cmd)
o.Env, err = GetFlagEnvOrCurrent(cmd, c)
if err != nil {
return err
}

View File

@@ -72,7 +72,7 @@ func NewDryRunCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Command
return c.SetConfig()
},
RunE: func(cmd *cobra.Command, args []string) error {
velaEnv, err := GetEnv(cmd)
velaEnv, err := GetFlagEnvOrCurrent(cmd, c)
if err != nil {
return err
}

View File

@@ -17,17 +17,14 @@ limitations under the License.
package cli
import (
"context"
"fmt"
"os"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/utils/common"
"github.com/oam-dev/kubevela/pkg/utils/env"
"github.com/oam-dev/kubevela/pkg/utils/system"
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
)
@@ -38,17 +35,20 @@ func NewEnvCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Command {
DisableFlagsInUseLine: true,
Short: "Manage environments",
Long: "Manage environments",
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
return c.SetConfig()
},
Annotations: map[string]string{
types.TagCommandType: types.TypeApp,
},
}
cmd.SetOut(ioStream.Out)
cmd.AddCommand(NewEnvListCommand(ioStream), NewEnvInitCommand(c, ioStream), NewEnvSetCommand(ioStream), NewEnvDeleteCommand(ioStream))
cmd.AddCommand(NewEnvListCommand(c, ioStream), NewEnvInitCommand(c, ioStream), NewEnvSetCommand(c, ioStream), NewEnvDeleteCommand(c, ioStream))
return cmd
}
// NewEnvListCommand creates `env list` command for listing all environments
func NewEnvListCommand(ioStream cmdutil.IOStreams) *cobra.Command {
func NewEnvListCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Command {
cmd := &cobra.Command{
Use: "ls",
Aliases: []string{"list"},
@@ -57,6 +57,14 @@ func NewEnvListCommand(ioStream cmdutil.IOStreams) *cobra.Command {
Long: "List all environments",
Example: `vela env ls [env-name]`,
RunE: func(cmd *cobra.Command, args []string) error {
clt, err := c.GetClient()
if err != nil {
return err
}
err = common.SetGlobalClient(clt)
if err != nil {
return err
}
return ListEnvs(args, ioStream)
},
Annotations: map[string]string{
@@ -70,23 +78,22 @@ func NewEnvListCommand(ioStream cmdutil.IOStreams) *cobra.Command {
// NewEnvInitCommand creates `env init` command for initializing environments
func NewEnvInitCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
var envArgs types.EnvMeta
ctx := context.Background()
cmd := &cobra.Command{
Use: "init <envName>",
DisableFlagsInUseLine: true,
Short: "Create environments",
Long: "Create environment and set the currently using environment",
Example: `vela env init test --namespace test --email my@email.com`,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
return c.SetConfig()
},
Example: `vela env init test --namespace test`,
RunE: func(cmd *cobra.Command, args []string) error {
newClient, err := c.GetClient()
clt, err := c.GetClient()
if err != nil {
return err
}
return CreateOrUpdateEnv(ctx, newClient, &envArgs, args, ioStreams)
err = common.SetGlobalClient(clt)
if err != nil {
return err
}
return CreateEnv(&envArgs, args, ioStreams)
},
Annotations: map[string]string{
types.TagCommandType: types.TypeStart,
@@ -94,14 +101,11 @@ func NewEnvInitCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Comman
}
cmd.SetOut(ioStreams.Out)
cmd.Flags().StringVar(&envArgs.Namespace, "namespace", "", "specify K8s namespace for env")
cmd.Flags().StringVar(&envArgs.Email, "email", "", "specify email for production TLS Certificate notification")
cmd.Flags().StringVar(&envArgs.Domain, "domain", "", "specify domain your applications")
return cmd
}
// NewEnvDeleteCommand creates `env delete` command for deleting environments
func NewEnvDeleteCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
ctx := context.Background()
func NewEnvDeleteCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
cmd := &cobra.Command{
Use: "delete",
DisableFlagsInUseLine: true,
@@ -109,7 +113,15 @@ func NewEnvDeleteCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
Long: "Delete environment",
Example: `vela env delete test`,
RunE: func(cmd *cobra.Command, args []string) error {
return DeleteEnv(ctx, args, ioStreams)
clt, err := c.GetClient()
if err != nil {
return err
}
err = common.SetGlobalClient(clt)
if err != nil {
return err
}
return DeleteEnv(args, ioStreams)
},
Annotations: map[string]string{
types.TagCommandType: types.TypeStart,
@@ -120,7 +132,7 @@ func NewEnvDeleteCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
}
// NewEnvSetCommand creates `env set` command for setting current environment
func NewEnvSetCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
func NewEnvSetCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
cmd := &cobra.Command{
Use: "set",
Aliases: []string{"sw"},
@@ -129,6 +141,14 @@ func NewEnvSetCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
Long: "Set an environment as the current using one",
Example: `vela env set test`,
RunE: func(cmd *cobra.Command, args []string) error {
clt, err := c.GetClient()
if err != nil {
return err
}
err = common.SetGlobalClient(clt)
if err != nil {
return err
}
return SetEnv(args, ioStreams)
},
Annotations: map[string]string{
@@ -142,7 +162,7 @@ func NewEnvSetCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
// ListEnvs shows info of all environments
func ListEnvs(args []string, ioStreams cmdutil.IOStreams) error {
table := newUITable()
table.AddRow("NAME", "CURRENT", "NAMESPACE", "EMAIL", "DOMAIN")
table.AddRow("NAME", "NAMESPACE", "CURRENT")
var envName = ""
if len(args) > 0 {
envName = args[0]
@@ -152,14 +172,14 @@ func ListEnvs(args []string, ioStreams cmdutil.IOStreams) error {
return err
}
for _, env := range envList {
table.AddRow(env.Name, env.Current, env.Namespace, env.Email, env.Domain)
table.AddRow(env.Name, env.Namespace, env.Current)
}
ioStreams.Info(table.String())
return nil
}
// DeleteEnv deletes an environment
func DeleteEnv(ctx context.Context, args []string, ioStreams cmdutil.IOStreams) error {
func DeleteEnv(args []string, ioStreams cmdutil.IOStreams) error {
if len(args) < 1 {
return fmt.Errorf("you must specify environment name for 'vela env delete' command")
}
@@ -173,18 +193,18 @@ func DeleteEnv(ctx context.Context, args []string, ioStreams cmdutil.IOStreams)
return nil
}
// CreateOrUpdateEnv creates or updates an environment
func CreateOrUpdateEnv(ctx context.Context, c client.Client, envArgs *types.EnvMeta, args []string, ioStreams cmdutil.IOStreams) error {
// CreateEnv creates an environment
func CreateEnv(envArgs *types.EnvMeta, args []string, ioStreams cmdutil.IOStreams) error {
if len(args) < 1 {
return fmt.Errorf("you must specify environment name for 'vela env init' command")
}
envName := args[0]
envArgs.Name = envName
msg, err := env.CreateOrUpdateEnv(ctx, c, envName, envArgs)
err := env.CreateEnv(envName, envArgs)
if err != nil {
return err
}
ioStreams.Info(msg)
ioStreams.Infof("environment %s created\n", envName)
return nil
}
@@ -202,26 +222,23 @@ func SetEnv(args []string, ioStreams cmdutil.IOStreams) error {
return nil
}
// GetEnv gets environment by name or current environment
// GetFlagEnvOrCurrent gets environment by name or current environment
// if no env exists, then init default environment
func GetEnv(cmd *cobra.Command) (*types.EnvMeta, error) {
func GetFlagEnvOrCurrent(cmd *cobra.Command, args common.Args) (*types.EnvMeta, error) {
clt, err := args.GetClient()
if err != nil {
return nil, err
}
err = common.SetGlobalClient(clt)
if err != nil {
return nil, errors.Wrap(err, "get flag env fail")
}
var envName string
var err error
if cmd != nil {
envName = cmd.Flag("env").Value.String()
}
if envName != "" {
return env.GetEnvByName(envName)
}
envName, err = env.GetCurrentEnvName()
if err != nil {
if !os.IsNotExist(err) {
return nil, err
}
if err = system.InitDefaultEnv(); err != nil {
return nil, err
}
envName = types.DefaultEnvName
}
return env.GetEnvByName(envName)
return env.GetCurrentEnv()
}

View File

@@ -17,108 +17,19 @@ limitations under the License.
package cli
import (
"bytes"
"context"
"os"
"strings"
"testing"
"github.com/crossplane/crossplane-runtime/pkg/test"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/utils/common"
"github.com/oam-dev/kubevela/pkg/utils/env"
"github.com/oam-dev/kubevela/pkg/utils/system"
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
)
func TestENV(t *testing.T) {
ctx := context.Background()
assert.NoError(t, os.Setenv(system.VelaHomeEnv, ".test_vela"))
home, err := system.GetVelaHomeDir()
assert.NoError(t, err)
assert.Equal(t, true, strings.HasSuffix(home, ".test_vela"))
defer os.RemoveAll(home)
// Create Default Env
err = system.InitDefaultEnv()
assert.NoError(t, err)
// check and compare create default env success
curEnvName, err := env.GetCurrentEnvName()
assert.NoError(t, err)
assert.Equal(t, "default", curEnvName)
gotEnv, err := GetEnv(nil)
assert.NoError(t, err)
assert.Equal(t, &types.EnvMeta{
Namespace: "default",
Name: "default",
}, gotEnv)
ioStream := cmdutil.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr}
exp := &types.EnvMeta{
Namespace: "test1",
Name: "env1",
}
client := test.NewMockClient()
// Create env1
err = CreateOrUpdateEnv(ctx, client, exp, []string{"env1"}, ioStream)
assert.NoError(t, err)
// check and compare create env success
curEnvName, err = env.GetCurrentEnvName()
assert.NoError(t, err)
assert.Equal(t, "env1", curEnvName)
gotEnv, err = GetEnv(nil)
assert.NoError(t, err)
assert.Equal(t, exp, gotEnv)
// List all env
var b bytes.Buffer
ioStream.Out = &b
err = ListEnvs([]string{}, ioStream)
assert.NoError(t, err)
assert.Equal(t, "NAME \tCURRENT\tNAMESPACE\tEMAIL\tDOMAIN\ndefault\t \tdefault \t \t \nenv1 \t* \ttest1 \t \t \n", b.String())
b.Reset()
err = ListEnvs([]string{"env1"}, ioStream)
assert.NoError(t, err)
assert.Equal(t, "NAME\tCURRENT\tNAMESPACE\tEMAIL\tDOMAIN\nenv1\t \ttest1 \t \t \n", b.String())
ioStream.Out = os.Stdout
// can not delete current env
err = DeleteEnv(ctx, []string{"env1"}, ioStream)
assert.Error(t, err)
// set as default env
err = SetEnv([]string{"default"}, ioStream)
assert.NoError(t, err)
// check env set success
gotEnv, err = GetEnv(nil)
assert.NoError(t, err)
assert.Equal(t, &types.EnvMeta{
Namespace: "default",
Name: "default",
}, gotEnv)
// delete env
err = DeleteEnv(ctx, []string{"env1"}, ioStream)
assert.NoError(t, err)
// can not set as a non-exist env
err = SetEnv([]string{"env1"}, ioStream)
assert.Error(t, err)
// set success
err = SetEnv([]string{"default"}, ioStream)
assert.NoError(t, err)
}
func TestEnvInitCommandPersistentPreRunE(t *testing.T) {
io := cmdutil.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr}
fakeC := common.Args{}
cmd := NewEnvInitCommand(fakeC, io)
assert.Nil(t, cmd.PersistentPreRunE(new(cobra.Command), []string{}))
}

View File

@@ -133,7 +133,7 @@ func (o *VelaExecOptions) Init(ctx context.Context, c *cobra.Command, argsIn []s
o.Cmd = c
o.Args = argsIn
env, err := GetEnv(o.Cmd)
env, err := GetFlagEnvOrCurrent(o.Cmd, o.VelaC)
if err != nil {
return err
}

View File

@@ -27,6 +27,7 @@ import (
// NewExportCommand will create command for exporting deploy manifests from an AppFile
func NewExportCommand(c common2.Args, ioStream cmdutil.IOStreams) *cobra.Command {
appFilePath := new(string)
cmd := &cobra.Command{
Use: "export",
DisableFlagsInUseLine: true,
@@ -36,7 +37,7 @@ func NewExportCommand(c common2.Args, ioStream cmdutil.IOStreams) *cobra.Command
types.TagCommandType: types.TypeStart,
},
RunE: func(cmd *cobra.Command, args []string) error {
velaEnv, err := GetEnv(cmd)
velaEnv, err := GetFlagEnvOrCurrent(cmd, c)
if err != nil {
return err
}
@@ -44,11 +45,7 @@ func NewExportCommand(c common2.Args, ioStream cmdutil.IOStreams) *cobra.Command
IO: ioStream,
Env: velaEnv,
}
filePath, err := cmd.Flags().GetString(appFilePath)
if err != nil {
return err
}
_, data, err := o.Export(filePath, velaEnv.Namespace, true, c)
_, data, err := o.Export(*appFilePath, velaEnv.Namespace, true, c)
if err != nil {
return err
}
@@ -58,6 +55,6 @@ func NewExportCommand(c common2.Args, ioStream cmdutil.IOStreams) *cobra.Command
}
cmd.SetOut(ioStream.Out)
cmd.Flags().StringP(appFilePath, "f", "", "specify file path for appfile")
cmd.Flags().StringVarP(appFilePath, "file", "f", "", "specify file path for appfile")
return cmd
}

View File

@@ -26,6 +26,7 @@ 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"
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -72,7 +73,7 @@ func NewInitCommand(c common2.Args, ioStreams cmdutil.IOStreams) *cobra.Command
return err
}
o.client = newClient
o.Env, err = GetEnv(cmd)
o.Env, err = GetFlagEnvOrCurrent(cmd, c)
if err != nil {
return err
}
@@ -146,27 +147,8 @@ func (o *appInitOptions) CheckEnv() error {
if o.Env.Namespace == "" {
o.Env.Namespace = "default"
}
o.Infof("Environment: %s, namespace: %s\n\n", o.Env.Name, o.Env.Namespace)
if o.Env.Domain == "" {
prompt := &survey.Input{
Message: "What is the domain of your application service (optional): ",
}
err := survey.AskOne(prompt, &o.Env.Domain)
if err != nil {
return fmt.Errorf("read domain err %w", err)
}
}
if o.Env.Email == "" {
prompt := &survey.Input{
Message: "What is your email (optional, used to generate certification): ",
}
err := survey.AskOne(prompt, &o.Env.Email)
if err != nil {
return fmt.Errorf("read email err %w", err)
}
}
if _, err := env.CreateOrUpdateEnv(context.Background(), o.client, o.Env.Name, o.Env); err != nil {
return err
if err := env.CreateEnv(o.Env.Name, o.Env); err != nil {
return errors.Wrap(err, "app init create namespace err")
}
return nil
}

View File

@@ -73,7 +73,7 @@ func NewLiveDiffCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Comma
return c.SetConfig()
},
RunE: func(cmd *cobra.Command, args []string) error {
velaEnv, err := GetEnv(cmd)
velaEnv, err := GetFlagEnvOrCurrent(cmd, c)
if err != nil {
return err
}

View File

@@ -57,7 +57,7 @@ func NewLogsCommand(c common.Args, ioStreams util.IOStreams) *cobra.Command {
ioStreams.Errorf("please specify app name")
return nil
}
env, err := GetEnv(cmd)
env, err := GetFlagEnvOrCurrent(cmd, c)
if err != nil {
return err
}

View File

@@ -44,7 +44,7 @@ func NewListCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
return c.SetConfig()
},
RunE: func(cmd *cobra.Command, args []string) error {
env, err := GetEnv(cmd)
env, err := GetFlagEnvOrCurrent(cmd, c)
if err != nil {
return err
}

View File

@@ -124,7 +124,7 @@ func (o *VelaPortForwardOptions) Init(ctx context.Context, cmd *cobra.Command, a
o.Cmd = cmd
o.Args = argsIn
env, err := GetEnv(o.Cmd)
env, err := GetFlagEnvOrCurrent(o.Cmd, o.VelaC)
if err != nil {
return err
}

View File

@@ -74,7 +74,7 @@ func NewCapabilityShowCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra
}
ctx := context.Background()
capabilityName := args[0]
velaEnv, err := GetEnv(cmd)
velaEnv, err := GetFlagEnvOrCurrent(cmd, c)
if err != nil {
return err
}

View File

@@ -106,7 +106,7 @@ func NewAppStatusCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Comm
os.Exit(1)
}
appName := args[0]
env, err := GetEnv(cmd)
env, err := GetFlagEnvOrCurrent(cmd, c)
if err != nil {
ioStreams.Errorf("Error: failed to get Env: %s", err)
return err

View File

@@ -50,7 +50,7 @@ func NewTraitsCommand(c common2.Args, ioStreams cmdutil.IOStreams) *cobra.Comman
},
RunE: func(cmd *cobra.Command, args []string) error {
isDiscover, _ := cmd.Flags().GetBool("discover")
env, err := GetEnv(cmd)
env, err := GetFlagEnvOrCurrent(cmd, c)
if err != nil {
return err
}

View File

@@ -31,12 +31,9 @@ import (
"github.com/oam-dev/kubevela/references/common"
)
var (
appFilePath string
)
// NewUpCommand will create command for applying an AppFile
func NewUpCommand(c common2.Args, ioStream cmdutil.IOStreams) *cobra.Command {
appFilePath := new(string)
cmd := &cobra.Command{
Use: "up",
DisableFlagsInUseLine: true,
@@ -49,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 := GetEnv(cmd)
velaEnv, err := GetFlagEnvOrCurrent(cmd, c)
if err != nil {
return err
}
@@ -57,11 +54,7 @@ func NewUpCommand(c common2.Args, ioStream cmdutil.IOStreams) *cobra.Command {
if err != nil {
return err
}
filePath, err := cmd.Flags().GetString(appFilePath)
if err != nil {
return err
}
fileContent, err := os.ReadFile(filepath.Clean(filePath))
fileContent, err := os.ReadFile(filepath.Clean(*appFilePath))
if err != nil {
return err
}
@@ -81,12 +74,12 @@ func NewUpCommand(c common2.Args, ioStream cmdutil.IOStreams) *cobra.Command {
IO: ioStream,
Env: velaEnv,
}
return o.Run(filePath, velaEnv.Namespace, c)
return o.Run(*appFilePath, velaEnv.Namespace, c)
}
return nil
},
}
cmd.SetOut(ioStream.Out)
cmd.Flags().StringP(appFilePath, "f", "", "specify file path for appfile")
cmd.Flags().StringVarP(appFilePath, "file", "f", "", "specify file path for appfile")
return cmd
}

View File

@@ -60,7 +60,7 @@ func NewWorkflowSuspendCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra
if len(args) < 1 {
return fmt.Errorf("must specify application name")
}
env, err := GetEnv(cmd)
env, err := GetFlagEnvOrCurrent(cmd, c)
if err != nil {
return err
}
@@ -99,7 +99,7 @@ func NewWorkflowResumeCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.
if len(args) < 1 {
return fmt.Errorf("must specify application name")
}
env, err := GetEnv(cmd)
env, err := GetFlagEnvOrCurrent(cmd, c)
if err != nil {
return err
}
@@ -148,7 +148,7 @@ func NewWorkflowTerminateCommand(c common.Args, ioStream cmdutil.IOStreams) *cob
if len(args) < 1 {
return fmt.Errorf("must specify application name")
}
env, err := GetEnv(cmd)
env, err := GetFlagEnvOrCurrent(cmd, c)
if err != nil {
return err
}
@@ -187,7 +187,7 @@ func NewWorkflowRestartCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra
if len(args) < 1 {
return fmt.Errorf("must specify application name")
}
env, err := GetEnv(cmd)
env, err := GetFlagEnvOrCurrent(cmd, c)
if err != nil {
return err
}

View File

@@ -38,7 +38,7 @@ func NewWorkloadsCommand(c common2.Args, ioStreams cmdutil.IOStreams) *cobra.Com
return c.SetConfig()
},
RunE: func(cmd *cobra.Command, args []string) error {
env, err := GetEnv(cmd)
env, err := GetFlagEnvOrCurrent(cmd, c)
if err != nil {
return err
}

View File

@@ -209,9 +209,6 @@ func RetrieveApplicationStatusByName(ctx context.Context, c client.Reader, appli
// DeleteApp will delete app including server side
func (o *DeleteOptions) DeleteApp() (string, error) {
if err := appfile.Delete(o.Env.Name, o.AppName); err != nil && !os.IsNotExist(err) {
return "", err
}
ctx := context.Background()
var app = new(corev1beta1.Application)
err := o.Client.Get(ctx, client.ObjectKey{Name: o.AppName, Namespace: o.Env.Namespace}, app)
@@ -443,9 +440,6 @@ 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 {
if err := o.saveToAppDir(result.appFile); err != nil {
return errors.Wrap(err, "save to app dir failed")
}
kubernetesComponent, err := appfile.ApplyTerraform(result.application, o.Kubecli, o.IO, o.Env.Namespace, args)
if err != nil {
@@ -457,11 +451,6 @@ func (o *AppfileOptions) BaseAppFileRun(result *BuildResult, args common.Args) e
return o.ApplyApp(result.application, result.scopes)
}
func (o *AppfileOptions) saveToAppDir(f *api.AppFile) error {
app := &api.Application{AppFile: f}
return appfile.Save(app, o.Env.Name)
}
// ApplyApp applys config resources for the app.
// It differs by create and update:
// - for create, it displays app status along with information of url, metrics, ssh, logging.

Some files were not shown because too many files have changed in this diff Show More