mirror of
https://github.com/kubevela/kubevela.git
synced 2026-03-03 02:01:05 +00:00
Compare commits
7 Commits
v1.3.0-bet
...
v1.3.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47050c90b6 | ||
|
|
685d73a20c | ||
|
|
dde8a8e4c0 | ||
|
|
943af3ddf6 | ||
|
|
a5c2edf777 | ||
|
|
83d8022ce9 | ||
|
|
6d63014c6f |
@@ -46,10 +46,11 @@ type GarbageCollectPolicyRule struct {
|
||||
|
||||
// GarbageCollectPolicyRuleSelector select the targets of the rule
|
||||
// if both traitTypes and componentTypes are specified, combination logic is OR
|
||||
// if one resources are specified with conflict strategy, strategy as component go first.
|
||||
// if one resource is specified with conflict strategies, strategy as component go first.
|
||||
type GarbageCollectPolicyRuleSelector struct {
|
||||
TraitTypes []string `json:"traitTypes"`
|
||||
CompNames []string `json:"componentNames"`
|
||||
CompTypes []string `json:"componentTypes"`
|
||||
TraitTypes []string `json:"traitTypes"`
|
||||
}
|
||||
|
||||
// GarbageCollectStrategy the strategy for target resource to recycle
|
||||
@@ -68,27 +69,22 @@ const (
|
||||
// FindStrategy find gc strategy for target resource
|
||||
func (in GarbageCollectPolicySpec) FindStrategy(manifest *unstructured.Unstructured) *GarbageCollectStrategy {
|
||||
for _, rule := range in.Rules {
|
||||
var (
|
||||
compType string
|
||||
traitType string
|
||||
)
|
||||
if manifest.GetLabels() != nil {
|
||||
traitType = manifest.GetLabels()[oam.TraitTypeLabel]
|
||||
compType = manifest.GetLabels()[oam.WorkloadTypeLabel]
|
||||
var compName, compType, traitType string
|
||||
if labels := manifest.GetLabels(); labels != nil {
|
||||
compName = labels[oam.LabelAppComponent]
|
||||
compType = labels[oam.WorkloadTypeLabel]
|
||||
traitType = labels[oam.TraitTypeLabel]
|
||||
}
|
||||
if compType != "" {
|
||||
for _, _compType := range rule.Selector.CompTypes {
|
||||
if _compType == compType {
|
||||
return &rule.Strategy
|
||||
}
|
||||
match := func(src []string, val string) (found bool) {
|
||||
for _, _val := range src {
|
||||
found = found || _val == val
|
||||
}
|
||||
return val != "" && found
|
||||
}
|
||||
if traitType != "" {
|
||||
for _, _traitType := range rule.Selector.TraitTypes {
|
||||
if _traitType == traitType {
|
||||
return &rule.Strategy
|
||||
}
|
||||
}
|
||||
if match(rule.Selector.CompNames, compName) ||
|
||||
match(rule.Selector.CompTypes, compType) ||
|
||||
match(rule.Selector.TraitTypes, traitType) {
|
||||
return &rule.Strategy
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -32,7 +32,7 @@ func TestGarbageCollectPolicySpec_FindStrategy(t *testing.T) {
|
||||
notFound bool
|
||||
expectStrategy GarbageCollectStrategy
|
||||
}{
|
||||
"trait rule match": {
|
||||
"trait type rule match": {
|
||||
rules: []GarbageCollectPolicyRule{{
|
||||
Selector: GarbageCollectPolicyRuleSelector{TraitTypes: []string{"a"}},
|
||||
Strategy: GarbageCollectStrategyNever,
|
||||
@@ -44,7 +44,7 @@ func TestGarbageCollectPolicySpec_FindStrategy(t *testing.T) {
|
||||
}},
|
||||
expectStrategy: GarbageCollectStrategyNever,
|
||||
},
|
||||
"trait rule mismatch": {
|
||||
"trait type rule mismatch": {
|
||||
rules: []GarbageCollectPolicyRule{{
|
||||
Selector: GarbageCollectPolicyRuleSelector{TraitTypes: []string{"a"}},
|
||||
Strategy: GarbageCollectStrategyNever,
|
||||
@@ -52,7 +52,7 @@ func TestGarbageCollectPolicySpec_FindStrategy(t *testing.T) {
|
||||
input: &unstructured.Unstructured{Object: map[string]interface{}{}},
|
||||
notFound: true,
|
||||
},
|
||||
"trait rule multiple match": {
|
||||
"trait type rule multiple match": {
|
||||
rules: []GarbageCollectPolicyRule{{
|
||||
Selector: GarbageCollectPolicyRuleSelector{TraitTypes: []string{"a"}},
|
||||
Strategy: GarbageCollectStrategyOnAppDelete,
|
||||
@@ -67,7 +67,7 @@ func TestGarbageCollectPolicySpec_FindStrategy(t *testing.T) {
|
||||
}},
|
||||
expectStrategy: GarbageCollectStrategyOnAppDelete,
|
||||
},
|
||||
"component rule match": {
|
||||
"component type rule match": {
|
||||
rules: []GarbageCollectPolicyRule{{
|
||||
Selector: GarbageCollectPolicyRuleSelector{CompTypes: []string{"comp"}},
|
||||
Strategy: GarbageCollectStrategyNever,
|
||||
@@ -79,7 +79,7 @@ func TestGarbageCollectPolicySpec_FindStrategy(t *testing.T) {
|
||||
}},
|
||||
expectStrategy: GarbageCollectStrategyNever,
|
||||
},
|
||||
"rule match both component and trait, component first": {
|
||||
"rule match both component type and trait type, component type first": {
|
||||
rules: []GarbageCollectPolicyRule{
|
||||
{
|
||||
Selector: GarbageCollectPolicyRuleSelector{CompTypes: []string{"comp"}},
|
||||
@@ -97,6 +97,18 @@ func TestGarbageCollectPolicySpec_FindStrategy(t *testing.T) {
|
||||
}},
|
||||
expectStrategy: GarbageCollectStrategyNever,
|
||||
},
|
||||
"component name rule match": {
|
||||
rules: []GarbageCollectPolicyRule{{
|
||||
Selector: GarbageCollectPolicyRuleSelector{CompNames: []string{"comp-name"}},
|
||||
Strategy: GarbageCollectStrategyNever,
|
||||
}},
|
||||
input: &unstructured.Unstructured{Object: map[string]interface{}{
|
||||
"metadata": map[string]interface{}{
|
||||
"labels": map[string]interface{}{oam.LabelAppComponent: "comp-name"},
|
||||
},
|
||||
}},
|
||||
expectStrategy: GarbageCollectStrategyNever,
|
||||
},
|
||||
}
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
|
||||
@@ -281,8 +281,8 @@ func (in *GarbageCollectPolicyRule) DeepCopy() *GarbageCollectPolicyRule {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *GarbageCollectPolicyRuleSelector) DeepCopyInto(out *GarbageCollectPolicyRuleSelector) {
|
||||
*out = *in
|
||||
if in.TraitTypes != nil {
|
||||
in, out := &in.TraitTypes, &out.TraitTypes
|
||||
if in.CompNames != nil {
|
||||
in, out := &in.CompNames, &out.CompNames
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
@@ -291,6 +291,11 @@ func (in *GarbageCollectPolicyRuleSelector) DeepCopyInto(out *GarbageCollectPoli
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.TraitTypes != nil {
|
||||
in, out := &in.TraitTypes, &out.TraitTypes
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GarbageCollectPolicyRuleSelector.
|
||||
|
||||
@@ -86,7 +86,7 @@ helm install --create-namespace -n vela-system kubevela kubevela/vela-core --wai
|
||||
| `multicluster.clusterGateway.replicaCount` | ClusterGateway replica count | `1` |
|
||||
| `multicluster.clusterGateway.port` | ClusterGateway port | `9443` |
|
||||
| `multicluster.clusterGateway.image.repository` | ClusterGateway image repository | `oamdev/cluster-gateway` |
|
||||
| `multicluster.clusterGateway.image.tag` | ClusterGateway image tag | `v1.1.7` |
|
||||
| `multicluster.clusterGateway.image.tag` | ClusterGateway image tag | `v1.3.0` |
|
||||
| `multicluster.clusterGateway.image.pullPolicy` | ClusterGateway image pull policy | `IfNotPresent` |
|
||||
| `multicluster.clusterGateway.resources.limits.cpu` | ClusterGateway cpu limit | `100m` |
|
||||
| `multicluster.clusterGateway.resources.limits.memory` | ClusterGateway memory limit | `200Mi` |
|
||||
|
||||
@@ -8,7 +8,7 @@ data:
|
||||
"KubeVela":{
|
||||
"name": "KubeVela",
|
||||
"helm": {
|
||||
"url": "https://addons.kubevela.net",
|
||||
"url": "https://addons.kubevela.net"
|
||||
}
|
||||
}
|
||||
}'
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
|
||||
# Definition source cue file: vela-templates/definitions/internal/config-dex-connector.cue
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
custom.definition.oam.dev/alias.config.oam.dev: Dex Connector
|
||||
definition.oam.dev/description: Config information to authenticate Dex connectors
|
||||
labels:
|
||||
custom.definition.oam.dev/catalog.config.oam.dev: velacore-config
|
||||
custom.definition.oam.dev/multi-cluster.config.oam.dev: "false"
|
||||
custom.definition.oam.dev/type.config.oam.dev: dex-connector
|
||||
name: config-dex-connector
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
output: {
|
||||
apiVersion: "v1"
|
||||
kind: "Secret"
|
||||
metadata: {
|
||||
name: parameter.name
|
||||
namespace: context.namespace
|
||||
labels: {
|
||||
"config.oam.dev/catalog": "velacore-config"
|
||||
"config.oam.dev/type": "dex-connector"
|
||||
"config.oam.dev/multi-cluster": "false"
|
||||
"config.oam.dev/identifier": parameter.name
|
||||
"config.oam.dev/sub-type": parameter.type
|
||||
}
|
||||
}
|
||||
type: "Opaque"
|
||||
|
||||
if parameter.type == "github" {
|
||||
stringData: parameter.github
|
||||
}
|
||||
if parameter.type == "ldap" {
|
||||
stringData: parameter.ldap
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
// +usage=Config type
|
||||
type: "github" | "ldap"
|
||||
github?: {
|
||||
// +usage=GitHub client ID
|
||||
clientID: string
|
||||
// +usage=GitHub client secret
|
||||
clientSecret: string
|
||||
// +usage=GitHub call back URL
|
||||
callbackURL: string
|
||||
}
|
||||
ldap?: {
|
||||
host: string
|
||||
insecureNoSSL: *true | bool
|
||||
insecureSkipVerify: bool
|
||||
startTLS: bool
|
||||
usernamePrompt: string
|
||||
userSearch: {
|
||||
baseDN: string
|
||||
username: string
|
||||
idAttr: string
|
||||
emailAttr: string
|
||||
nameAttr: string
|
||||
}
|
||||
}
|
||||
}
|
||||
workload:
|
||||
type: autodetects.core.oam.dev
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
|
||||
# Definition source cue file: vela-templates/definitions/internal/config-image-registry.cue
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
custom.definition.oam.dev/alias.config.oam.dev: Image Registry
|
||||
definition.oam.dev/description: Config information to authenticate image registry
|
||||
labels:
|
||||
custom.definition.oam.dev/catalog.config.oam.dev: velacore-config
|
||||
custom.definition.oam.dev/multi-cluster.config.oam.dev: "true"
|
||||
custom.definition.oam.dev/type.config.oam.dev: image-registry
|
||||
name: config-image-registry
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
output: {
|
||||
apiVersion: "v1"
|
||||
kind: "Secret"
|
||||
metadata: {
|
||||
name: context.name
|
||||
namespace: context.namespace
|
||||
labels: {
|
||||
"config.oam.dev/catalog": "velacore-config"
|
||||
"config.oam.dev/type": "image-registry"
|
||||
"config.oam.dev/multi-cluster": "true"
|
||||
"config.oam.dev/identifier": parameter.registry
|
||||
"config.oam.dev/sub-type": "auth"
|
||||
}
|
||||
}
|
||||
type: "kubernetes.io/dockerconfigjson"
|
||||
stringData: {
|
||||
if parameter.auth != _|_ {
|
||||
".dockerconfigjson": json.Marshal({
|
||||
auths: "\(parameter.registry)": {
|
||||
username: parameter.auth.username
|
||||
password: parameter.auth.password
|
||||
if parameter.auth.email != _|_ {
|
||||
email: parameter.auth.email
|
||||
}
|
||||
auth: base64.Encode(null, (parameter.auth.username + ":" + parameter.auth.password))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
// +usage=Image registry FQDN
|
||||
registry: string
|
||||
// +usage=Authenticate the image registry
|
||||
auth?: {
|
||||
// +usage=Private Image registry username
|
||||
username: string
|
||||
// +usage=Private Image registry password
|
||||
password: string
|
||||
// +usage=Private Image registry email
|
||||
email?: string
|
||||
}
|
||||
}
|
||||
workload:
|
||||
type: autodetects.core.oam.dev
|
||||
|
||||
@@ -104,7 +104,7 @@ multicluster:
|
||||
port: 9443
|
||||
image:
|
||||
repository: oamdev/cluster-gateway
|
||||
tag: v1.1.7
|
||||
tag: v1.3.0
|
||||
pullPolicy: IfNotPresent
|
||||
resources:
|
||||
limits:
|
||||
|
||||
@@ -105,7 +105,7 @@ helm install --create-namespace -n vela-system kubevela kubevela/vela-minimal --
|
||||
| `multicluster.clusterGateway.replicaCount` | ClusterGateway replica count | `1` |
|
||||
| `multicluster.clusterGateway.port` | ClusterGateway port | `9443` |
|
||||
| `multicluster.clusterGateway.image.repository` | ClusterGateway image repository | `oamdev/cluster-gateway` |
|
||||
| `multicluster.clusterGateway.image.tag` | ClusterGateway image tag | `v1.1.7` |
|
||||
| `multicluster.clusterGateway.image.tag` | ClusterGateway image tag | `v1.3.0` |
|
||||
| `multicluster.clusterGateway.image.pullPolicy` | ClusterGateway image pull policy | `IfNotPresent` |
|
||||
| `multicluster.clusterGateway.resources.limits.cpu` | ClusterGateway cpu limit | `100m` |
|
||||
| `multicluster.clusterGateway.resources.limits.memory` | ClusterGateway memory limit | `200Mi` |
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
|
||||
# Definition source cue file: vela-templates/definitions/internal/config-dex-connector.cue
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
custom.definition.oam.dev/alias.config.oam.dev: Dex Connector
|
||||
definition.oam.dev/description: Config information to authenticate Dex connectors
|
||||
labels:
|
||||
custom.definition.oam.dev/catalog.config.oam.dev: velacore-config
|
||||
custom.definition.oam.dev/multi-cluster.config.oam.dev: "false"
|
||||
custom.definition.oam.dev/type.config.oam.dev: dex-connector
|
||||
name: config-dex-connector
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
output: {
|
||||
apiVersion: "v1"
|
||||
kind: "Secret"
|
||||
metadata: {
|
||||
name: parameter.name
|
||||
namespace: context.namespace
|
||||
labels: {
|
||||
"config.oam.dev/catalog": "velacore-config"
|
||||
"config.oam.dev/type": "dex-connector"
|
||||
"config.oam.dev/multi-cluster": "false"
|
||||
"config.oam.dev/identifier": parameter.name
|
||||
"config.oam.dev/sub-type": parameter.type
|
||||
}
|
||||
}
|
||||
type: "Opaque"
|
||||
|
||||
if parameter.type == "github" {
|
||||
stringData: parameter.github
|
||||
}
|
||||
if parameter.type == "ldap" {
|
||||
stringData: parameter.ldap
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
// +usage=Config type
|
||||
type: "github" | "ldap"
|
||||
github?: {
|
||||
// +usage=GitHub client ID
|
||||
clientID: string
|
||||
// +usage=GitHub client secret
|
||||
clientSecret: string
|
||||
// +usage=GitHub call back URL
|
||||
callbackURL: string
|
||||
}
|
||||
ldap?: {
|
||||
host: string
|
||||
insecureNoSSL: *true | bool
|
||||
insecureSkipVerify: bool
|
||||
startTLS: bool
|
||||
usernamePrompt: string
|
||||
userSearch: {
|
||||
baseDN: string
|
||||
username: string
|
||||
idAttr: string
|
||||
emailAttr: string
|
||||
nameAttr: string
|
||||
}
|
||||
}
|
||||
}
|
||||
workload:
|
||||
type: autodetects.core.oam.dev
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
|
||||
# Definition source cue file: vela-templates/definitions/internal/config-image-registry.cue
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
custom.definition.oam.dev/alias.config.oam.dev: Image Registry
|
||||
definition.oam.dev/description: Config information to authenticate image registry
|
||||
labels:
|
||||
custom.definition.oam.dev/catalog.config.oam.dev: velacore-config
|
||||
custom.definition.oam.dev/multi-cluster.config.oam.dev: "true"
|
||||
custom.definition.oam.dev/type.config.oam.dev: image-registry
|
||||
name: config-image-registry
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
output: {
|
||||
apiVersion: "v1"
|
||||
kind: "Secret"
|
||||
metadata: {
|
||||
name: context.name
|
||||
namespace: context.namespace
|
||||
labels: {
|
||||
"config.oam.dev/catalog": "velacore-config"
|
||||
"config.oam.dev/type": "image-registry"
|
||||
"config.oam.dev/multi-cluster": "true"
|
||||
"config.oam.dev/identifier": parameter.registry
|
||||
"config.oam.dev/sub-type": "auth"
|
||||
}
|
||||
}
|
||||
type: "kubernetes.io/dockerconfigjson"
|
||||
stringData: {
|
||||
if parameter.auth != _|_ {
|
||||
".dockerconfigjson": json.Marshal({
|
||||
auths: "\(parameter.registry)": {
|
||||
username: parameter.auth.username
|
||||
password: parameter.auth.password
|
||||
if parameter.auth.email != _|_ {
|
||||
email: parameter.auth.email
|
||||
}
|
||||
auth: base64.Encode(null, (parameter.auth.username + ":" + parameter.auth.password))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
// +usage=Image registry FQDN
|
||||
registry: string
|
||||
// +usage=Authenticate the image registry
|
||||
auth?: {
|
||||
// +usage=Private Image registry username
|
||||
username: string
|
||||
// +usage=Private Image registry password
|
||||
password: string
|
||||
// +usage=Private Image registry email
|
||||
email?: string
|
||||
}
|
||||
}
|
||||
workload:
|
||||
type: autodetects.core.oam.dev
|
||||
|
||||
@@ -107,7 +107,7 @@ multicluster:
|
||||
port: 9443
|
||||
image:
|
||||
repository: oamdev/cluster-gateway
|
||||
tag: v1.1.7
|
||||
tag: v1.3.0
|
||||
pullPolicy: IfNotPresent
|
||||
resources:
|
||||
limits:
|
||||
|
||||
@@ -95,7 +95,32 @@ spec:
|
||||
properties:
|
||||
rules:
|
||||
- selector:
|
||||
componentTypes:
|
||||
- webservice
|
||||
strategy: never
|
||||
componentTypes:
|
||||
- webservice
|
||||
strategy: never
|
||||
```
|
||||
|
||||
A more straightforward way is to specify `compNames` to match specified components.
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: create-ns-app
|
||||
spec:
|
||||
components:
|
||||
- name: example-addon-namespace
|
||||
type: k8s-objects
|
||||
properties:
|
||||
objects:
|
||||
- apiVersion: v1
|
||||
kind: Namespace
|
||||
policies:
|
||||
- name: garbage-collect
|
||||
type: garbage-collect
|
||||
properties:
|
||||
rules:
|
||||
- selector:
|
||||
componentNames:
|
||||
- example-addon-namespace
|
||||
strategy: never
|
||||
```
|
||||
|
||||
15
docs/examples/config/app-config-dex-connector-github.yaml
Normal file
15
docs/examples/config/app-config-dex-connector-github.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: config-dex-connector-dev
|
||||
namespace: vela-system
|
||||
spec:
|
||||
components:
|
||||
- name: dev
|
||||
type: config-dex-connector
|
||||
properties:
|
||||
type: github
|
||||
github:
|
||||
clientID: "aa"
|
||||
clientSecret: "bb"
|
||||
callbackURL: "http://localhost:8080/callback"
|
||||
102
docs/examples/config/image-registry/README.md
Normal file
102
docs/examples/config/image-registry/README.md
Normal file
@@ -0,0 +1,102 @@
|
||||
# How to store and use configurations
|
||||
|
||||
## General
|
||||
|
||||
- list all configuration types
|
||||
```shell
|
||||
$ vela components --label custom.definition.oam.dev/catalog.config.oam.dev=velacore-config
|
||||
NAME DEFINITION
|
||||
config-dex-connector autodetects.core.oam.dev
|
||||
config-helm-repository autodetects.core.oam.dev
|
||||
config-image-registry autodetects.core.oam.dev
|
||||
terraform-azure autodetects.core.oam.dev
|
||||
terraform-baidu autodetects.core.oam.dev
|
||||
```
|
||||
|
||||
```json
|
||||
# Get http://127.0.0.1:8000/api/v1/configs
|
||||
|
||||
[
|
||||
{
|
||||
"definitions": [
|
||||
"config-dex-connector"
|
||||
],
|
||||
"name": "Dex Connectors",
|
||||
"type": "dex-connector"
|
||||
},
|
||||
{
|
||||
"definitions": [
|
||||
"config-helm-repository"
|
||||
],
|
||||
"name": "Helm Repository",
|
||||
"type": "helm-repository"
|
||||
},
|
||||
{
|
||||
"definitions": [
|
||||
"config-image-registry"
|
||||
],
|
||||
"name": "Image Registry",
|
||||
"type": "image-registry"
|
||||
},
|
||||
null,
|
||||
{
|
||||
"definitions": [
|
||||
"terraform-baidu"
|
||||
],
|
||||
"name": "Terraform Cloud Provider",
|
||||
"type": "terraform-provider"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
- list all configurations
|
||||
|
||||
```shell
|
||||
$ kubectl get secret -n vela-system -l=config.oam.dev/catalog=velacore-config
|
||||
NAME TYPE DATA AGE
|
||||
image-registry-dev kubernetes.io/dockerconfigjson 1 3h51m
|
||||
```
|
||||
|
||||
## Image registry
|
||||
|
||||
- Create a config for an image registry
|
||||
|
||||
```shell
|
||||
$ vela up -f app-config-image-registry-account-auth.yaml
|
||||
Applying an application in vela K8s object format...
|
||||
I0323 10:45:25.347102 85930 apply.go:107] "creating object" name="config-image-registry-account-auth-dev" resource="core.oam.dev/v1beta1, Kind=Application"
|
||||
✅ App has been deployed 🚀🚀🚀
|
||||
Port forward: vela port-forward config-image-registry-account-auth-dev
|
||||
SSH: vela exec config-image-registry-account-auth-dev
|
||||
Logging: vela logs config-image-registry-account-auth-dev
|
||||
App status: vela status config-image-registry-account-auth-dev
|
||||
Endpoint: vela status config-image-registry-account-auth-dev
|
||||
--endpoint%
|
||||
|
||||
|
||||
$ kubectl get secret -n vela-system -l=config.oam.dev/catalog=velacore-config
|
||||
NAME TYPE DATA AGE
|
||||
image-registry-dev kubernetes.io/dockerconfigjson 1 77s
|
||||
```
|
||||
|
||||
- Deliver the config secret to working cluster
|
||||
|
||||
```shell
|
||||
$ vela cluster list
|
||||
CLUSTER TYPE ENDPOINT ACCEPTED LABELS
|
||||
local Internal - true
|
||||
bj X509Certificate https://123.57.73.107:6443 true
|
||||
|
||||
$ vela up -f app-deliever-secret.yaml
|
||||
```
|
||||
|
||||
- Deploy an application who needs to pull images from the private image registry
|
||||
|
||||
```shell
|
||||
$ export KUBECONFIG=~/.kube/config-bj
|
||||
$ kubectl get secret -n vela-system -l=config.oam.dev/catalog=velacore-config
|
||||
NAME TYPE DATA AGE
|
||||
image-registry-dev kubernetes.io/dockerconfigjson 1 120s
|
||||
|
||||
$ vela up -f app-validate-imagePullSecret.yaml
|
||||
```
|
||||
@@ -0,0 +1,15 @@
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: config-image-registry-account-auth-dev
|
||||
namespace: vela-system
|
||||
spec:
|
||||
components:
|
||||
- name: account-auth
|
||||
type: config-image-registry
|
||||
properties:
|
||||
registry: "registry.cn-beijing.aliyuncs.com"
|
||||
auth:
|
||||
username: "xxx"
|
||||
password: "PfwrjwifjFaked"
|
||||
email: "a@gmail.com"
|
||||
23
docs/examples/config/image-registry/app-deliever-secret.yaml
Normal file
23
docs/examples/config/image-registry/app-deliever-secret.yaml
Normal file
@@ -0,0 +1,23 @@
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: config-project1
|
||||
namespace: vela-system
|
||||
labels:
|
||||
config.oam.dev/catalog: "velacore-config"
|
||||
config.oam.dev/type: "helm-repository"
|
||||
spec:
|
||||
components:
|
||||
- name: deliver-secret
|
||||
type: ref-objects
|
||||
properties:
|
||||
objects:
|
||||
- apiVersion: v1
|
||||
kind: Secret
|
||||
name: image-registry-dev
|
||||
policies:
|
||||
- type: topology
|
||||
name: dev
|
||||
properties:
|
||||
clusters: ["bj"]
|
||||
# namespaces: ["ns1"]
|
||||
14
docs/examples/config/image-registry/app-sample.yaml
Normal file
14
docs/examples/config/image-registry/app-sample.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: app-sample
|
||||
namespace: ns1
|
||||
spec:
|
||||
components:
|
||||
- name: sample
|
||||
type: webservice
|
||||
properties:
|
||||
image: registry.cn-beijing.aliyuncs.com/vela/nginx:latest
|
||||
imagePullPolicy: Always
|
||||
imagePullSecrets:
|
||||
- image-registry-dev
|
||||
@@ -0,0 +1,14 @@
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: app-validate-image-pull-secret
|
||||
namespace: vela-system
|
||||
spec:
|
||||
components:
|
||||
- name: validate
|
||||
type: webservice
|
||||
properties:
|
||||
image: registry.cn-beijing.aliyuncs.com/vela/nginx:latest
|
||||
imagePullPolicy: Always
|
||||
imagePullSecrets:
|
||||
- image-registry-dev
|
||||
@@ -22,6 +22,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
@@ -62,6 +64,7 @@ var _ = Describe("Addon Test", func() {
|
||||
Expect(output).To(ContainSubstring("Successfully disable addon"))
|
||||
Eventually(func(g Gomega) {
|
||||
g.Expect(apierrors.IsNotFound(k8sClient.Get(context.Background(), types.NamespacedName{Name: "addon-test-addon", Namespace: "vela-system"}, &v1beta1.Application{}))).Should(BeTrue())
|
||||
g.Expect(apierrors.IsNotFound(k8sClient.Get(context.Background(), types.NamespacedName{Name: "addon-secret-test-addon", Namespace: "vela-system"}, &v1.Secret{}))).Should(BeTrue())
|
||||
}, 60*time.Second).Should(Succeed())
|
||||
})
|
||||
|
||||
|
||||
@@ -567,7 +567,7 @@ func renderResources(addon *InstallPackage, args map[string]interface{}) ([]comm
|
||||
}
|
||||
|
||||
for _, tmpl := range addon.CUETemplates {
|
||||
comp, err := renderCUETemplate(tmpl, addon.Parameters, args)
|
||||
comp, err := renderCUETemplate(tmpl, addon.Parameters, args, addon.Meta)
|
||||
if err != nil {
|
||||
return nil, NewAddonError(fmt.Sprintf("fail to render cue template %s", err.Error()))
|
||||
}
|
||||
@@ -589,6 +589,9 @@ func formatAppFramework(addon *InstallPackage) *v1beta1.Application {
|
||||
},
|
||||
}
|
||||
}
|
||||
if app.Spec.Components == nil {
|
||||
app.Spec.Components = []common2.ApplicationComponent{}
|
||||
}
|
||||
app.Name = Convert2AppName(addon.Name)
|
||||
// force override the namespace defined vela with DefaultVelaNS,this value can be modified by Env
|
||||
app.SetNamespace(types.DefaultKubeVelaNS)
|
||||
@@ -929,17 +932,28 @@ func renderSchemaConfigmap(elem ElementFile) (*unstructured.Unstructured, error)
|
||||
}
|
||||
|
||||
// renderCUETemplate will return a component from cue template
|
||||
func renderCUETemplate(elem ElementFile, parameters string, args map[string]interface{}) (*common2.ApplicationComponent, error) {
|
||||
func renderCUETemplate(elem ElementFile, parameters string, args map[string]interface{}, metadata Meta) (*common2.ApplicationComponent, error) {
|
||||
bt, err := json.Marshal(args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var contextFile = strings.Builder{}
|
||||
var paramFile = cuemodel.ParameterFieldName + ": {}"
|
||||
if string(bt) != "null" {
|
||||
paramFile = fmt.Sprintf("%s: %s", cuemodel.ParameterFieldName, string(bt))
|
||||
}
|
||||
param := fmt.Sprintf("%s\n%s", paramFile, parameters)
|
||||
v, err := value.NewValue(param, nil, "")
|
||||
// addon metadata context
|
||||
metadataJSON, err := json.Marshal(metadata)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
contextFile.WriteString(fmt.Sprintf("context: metadata: %s\n", string(metadataJSON)))
|
||||
// parameter definition
|
||||
contextFile.WriteString(paramFile + "\n")
|
||||
// user custom parameter
|
||||
contextFile.WriteString(parameters + "\n")
|
||||
|
||||
v, err := value.NewValue(contextFile.String(), nil, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -880,3 +880,20 @@ func TestReadDefFile(t *testing.T) {
|
||||
// verify
|
||||
assert.True(t, len(uiData.Definitions) == 1)
|
||||
}
|
||||
|
||||
func TestRenderCUETemplate(t *testing.T) {
|
||||
fileDate, err := os.ReadFile("./testdata/example/resources/configmap.cue")
|
||||
assert.NoError(t, err)
|
||||
component, err := renderCUETemplate(ElementFile{Data: string(fileDate), Name: "configmap.cue"}, "{\"example\": \"\"}", map[string]interface{}{
|
||||
"example": "render",
|
||||
}, Meta{
|
||||
Version: "1.0.1",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, component.Type == "raw")
|
||||
var config = make(map[string]interface{})
|
||||
err = json.Unmarshal(component.Properties.Raw, &config)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, component.Type == "raw")
|
||||
assert.True(t, config["metadata"].(map[string]interface{})["labels"].(map[string]interface{})["version"] == "1.0.1")
|
||||
}
|
||||
|
||||
2
pkg/addon/testdata/example/metadata.yaml
vendored
2
pkg/addon/testdata/example/metadata.yaml
vendored
@@ -1,5 +1,5 @@
|
||||
name: example
|
||||
version: 1.0.0
|
||||
version: 1.0.1
|
||||
description: Extended workload to do continuous and progressive delivery
|
||||
icon: https://raw.githubusercontent.com/fluxcd/flux/master/docs/_files/weave-flux.png
|
||||
url: https://fluxcd.io
|
||||
|
||||
@@ -6,6 +6,9 @@ output: {
|
||||
metadata: {
|
||||
name: "exampleinput"
|
||||
namespace: "default"
|
||||
labels: {
|
||||
version: context.metadata.version
|
||||
}
|
||||
}
|
||||
data: input: parameter.example
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ func returns500(b *restful.RouteBuilder) {
|
||||
b.Returns(http.StatusInternalServerError, "Bummer, something went wrong", nil)
|
||||
}
|
||||
|
||||
// Init init all webservice, pass in the required parameter object.
|
||||
// Init inits all webservice, pass in the required parameter object.
|
||||
// It can be implemented using the idea of dependency injection.
|
||||
func Init(ctx context.Context, ds datastore.DataStore, addonCacheTime time.Duration, initDatabase bool) map[string]interface{} {
|
||||
clusterUsecase := usecase.NewClusterUsecase(ds)
|
||||
|
||||
@@ -73,6 +73,8 @@ const (
|
||||
var forceDisable bool
|
||||
var addonVersion string
|
||||
|
||||
var addonClusters string
|
||||
|
||||
// NewAddonCommand create `addon` command
|
||||
func NewAddonCommand(c common.Args, order string, ioStreams cmdutil.IOStreams) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
@@ -140,6 +142,7 @@ Enable addon for specific clusters, (local means control plane):
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
addonArgs[types.ClustersArg] = transClusters(addonClusters)
|
||||
config, err := c.GetConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -182,6 +185,7 @@ Enable addon for specific clusters, (local means control plane):
|
||||
}
|
||||
|
||||
cmd.Flags().StringVarP(&addonVersion, "version", "v", "", "specify the addon version to enable")
|
||||
cmd.Flags().StringVarP(&addonClusters, types.ClustersArg, "c", "", "specify the runtime-clusters to enable")
|
||||
return cmd
|
||||
}
|
||||
|
||||
@@ -239,6 +243,7 @@ Upgrade addon for specific clusters, (local means control plane):
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
addonArgs[types.ClustersArg] = transClusters(addonClusters)
|
||||
addonOrDir := args[0]
|
||||
var name string
|
||||
if file, err := os.Stat(addonOrDir); err == nil {
|
||||
@@ -287,22 +292,6 @@ func parseAddonArgsToMap(args []string) (map[string]interface{}, error) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
clusters, ok := res[types.ClustersArg]
|
||||
if ok {
|
||||
var clusterL []string
|
||||
clusterList, ok := clusters.([]interface{})
|
||||
if !ok {
|
||||
return nil, errors.Errorf("you must specify string list for --clusters instead of %v", clusters)
|
||||
}
|
||||
for _, v := range clusterList {
|
||||
val, strOk := v.(string)
|
||||
if !strOk {
|
||||
return nil, errors.Errorf("only string allowed in parameter --clusters list instead of %v", v)
|
||||
}
|
||||
clusterL = append(clusterL, strings.TrimSpace(val))
|
||||
}
|
||||
res[types.ClustersArg] = clusterL
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
@@ -555,6 +544,16 @@ func hasAddon(addons []*pkgaddon.UIData, name string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func transClusters(cstr string) []string {
|
||||
cstr = strings.TrimPrefix(strings.TrimSuffix(cstr, "}"), "{")
|
||||
var clusterL []string
|
||||
clusterList := strings.Split(cstr, ",")
|
||||
for _, v := range clusterList {
|
||||
clusterL = append(clusterL, strings.TrimSpace(v))
|
||||
}
|
||||
return clusterL
|
||||
}
|
||||
|
||||
// TODO(wangyike) addon can support multi-tenancy, an addon can be enabled multi times and will create many times
|
||||
// func checkWhetherTerraformProviderExist(ctx context.Context, k8sClient client.Client, addonName string, args map[string]string) (string, bool, error) {
|
||||
// _, providerName := getTerraformProviderArgumentValue(addonName, args)
|
||||
|
||||
@@ -65,16 +65,6 @@ func TestParseMap(t *testing.T) {
|
||||
},
|
||||
nilError: true,
|
||||
},
|
||||
{
|
||||
args: []string{"clusters={c1, c2, c3}", "image.tag=1.1"},
|
||||
res: map[string]interface{}{
|
||||
"clusters": []string{"c1", "c2", "c3"},
|
||||
"image": map[string]interface{}{
|
||||
"tag": "1.1",
|
||||
},
|
||||
},
|
||||
nilError: true,
|
||||
},
|
||||
}
|
||||
for _, s := range testcase {
|
||||
r, err := parseAddonArgsToMap(s.args)
|
||||
@@ -138,3 +128,26 @@ func TestAddonUpgradeCmdWithErrLocalPath(t *testing.T) {
|
||||
assert.Error(t, err, s.errMsg)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTransCluster(t *testing.T) {
|
||||
testcase := []struct {
|
||||
str string
|
||||
res []string
|
||||
}{
|
||||
{
|
||||
str: "{cluster1, cluster2}",
|
||||
res: []string{"cluster1", "cluster2"},
|
||||
},
|
||||
{
|
||||
str: "{cluster1,cluster2}",
|
||||
res: []string{"cluster1", "cluster2"},
|
||||
},
|
||||
{
|
||||
str: "{cluster1, cluster2 }",
|
||||
res: []string{"cluster1", "cluster2"},
|
||||
},
|
||||
}
|
||||
for _, s := range testcase {
|
||||
assert.DeepEqual(t, transClusters(s.str), s.res)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
"config-dex-connector": {
|
||||
type: "component"
|
||||
annotations: {
|
||||
"alias.config.oam.dev": "Dex Connector"
|
||||
}
|
||||
labels: {
|
||||
"catalog.config.oam.dev": "velacore-config"
|
||||
"type.config.oam.dev": "dex-connector"
|
||||
"multi-cluster.config.oam.dev": "false"
|
||||
}
|
||||
description: "Config information to authenticate Dex connectors"
|
||||
attributes: workload: type: "autodetects.core.oam.dev"
|
||||
}
|
||||
|
||||
template: {
|
||||
output: {
|
||||
apiVersion: "v1"
|
||||
kind: "Secret"
|
||||
metadata: {
|
||||
name: parameter.name
|
||||
namespace: context.namespace
|
||||
labels: {
|
||||
"config.oam.dev/catalog": "velacore-config"
|
||||
"config.oam.dev/type": "dex-connector"
|
||||
"config.oam.dev/multi-cluster": "false"
|
||||
"config.oam.dev/identifier": parameter.name
|
||||
"config.oam.dev/sub-type": parameter.type
|
||||
}
|
||||
}
|
||||
type: "Opaque"
|
||||
|
||||
if parameter.type == "github" {
|
||||
stringData: parameter.github
|
||||
}
|
||||
if parameter.type == "ldap" {
|
||||
stringData: parameter.ldap
|
||||
}
|
||||
}
|
||||
|
||||
parameter: {
|
||||
// +usage=Config type
|
||||
type: "github" | "ldap"
|
||||
github?: {
|
||||
// +usage=GitHub client ID
|
||||
clientID: string
|
||||
// +usage=GitHub client secret
|
||||
clientSecret: string
|
||||
// +usage=GitHub call back URL
|
||||
callbackURL: string
|
||||
}
|
||||
ldap?: {
|
||||
host: string
|
||||
insecureNoSSL: *true | bool
|
||||
insecureSkipVerify: bool
|
||||
startTLS: bool
|
||||
usernamePrompt: string
|
||||
userSearch: {
|
||||
baseDN: string
|
||||
username: string
|
||||
idAttr: string
|
||||
emailAttr: string
|
||||
nameAttr: string
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
"config-image-registry": {
|
||||
type: "component"
|
||||
annotations: {
|
||||
"alias.config.oam.dev": "Image Registry"
|
||||
}
|
||||
labels: {
|
||||
"catalog.config.oam.dev": "velacore-config"
|
||||
"type.config.oam.dev": "image-registry"
|
||||
"multi-cluster.config.oam.dev": "true"
|
||||
}
|
||||
description: "Config information to authenticate image registry"
|
||||
attributes: workload: type: "autodetects.core.oam.dev"
|
||||
}
|
||||
|
||||
template: {
|
||||
output: {
|
||||
apiVersion: "v1"
|
||||
kind: "Secret"
|
||||
metadata: {
|
||||
name: context.name
|
||||
namespace: context.namespace
|
||||
labels: {
|
||||
"config.oam.dev/catalog": "velacore-config"
|
||||
"config.oam.dev/type": "image-registry"
|
||||
"config.oam.dev/multi-cluster": "true"
|
||||
"config.oam.dev/identifier": parameter.registry
|
||||
"config.oam.dev/sub-type": "auth"
|
||||
}
|
||||
}
|
||||
type: "kubernetes.io/dockerconfigjson"
|
||||
stringData: {
|
||||
if parameter.auth != _|_ {
|
||||
".dockerconfigjson": json.Marshal({
|
||||
"auths": "\(parameter.registry)": {
|
||||
"username": parameter.auth.username
|
||||
"password": parameter.auth.password
|
||||
if parameter.auth.email != _|_ {
|
||||
"email": parameter.auth.email
|
||||
}
|
||||
"auth": base64.Encode(null, (parameter.auth.username + ":" + parameter.auth.password))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parameter: {
|
||||
// +usage=Image registry FQDN
|
||||
registry: string
|
||||
// +usage=Authenticate the image registry
|
||||
auth?: {
|
||||
// +usage=Private Image registry username
|
||||
username: string
|
||||
// +usage=Private Image registry password
|
||||
password: string
|
||||
// +usage=Private Image registry email
|
||||
email?: string
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user