Feat: support wild match for env patch (#3116)

Signed-off-by: Somefive <yd219913@alibaba-inc.com>
(cherry picked from commit fe0d33c6d9)

Co-authored-by: Somefive <yd219913@alibaba-inc.com>
This commit is contained in:
github-actions[bot]
2022-01-18 18:07:05 +08:00
committed by GitHub
parent 7e447c6532
commit cd036b87ae
4 changed files with 321 additions and 4 deletions

View File

@@ -0,0 +1,74 @@
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: example-app
namespace: default
spec:
components:
- name: podinfo
type: webservice
properties:
image: stefanprodan/podinfo
traits:
- type: scaler
properties:
replicas: 1
- name: hello-world
type: webservice
properties:
image: crccheck/hello-world
traits:
- type: scaler
properties:
replicas: 1
- name: nginx
type: worker
properties:
image: nginx
traits:
- type: scaler
properties:
replicas: 1
policies:
- name: example-multi-env-policy
type: env-binding
properties:
envs:
- name: test
placement:
clusterSelector:
name: local
namespaceSelector:
name: test
patch:
components:
- name: podinfo # patch to component named podinfo, no type check
traits:
- type: scaler
properties:
replicas: 2
- name: staging
placement:
clusterSelector:
name: remote
patch:
components: # patch to all webservice components
- type: webservice
traits:
- type: scaler
properties:
replicas: 3
- name: prod
placement:
clusterSelector:
name: remote
namespaceSelector:
name: prod
patch:
components: # patch to all components
- traits:
- type: scaler
properties:
replicas: 3

View File

@@ -146,8 +146,17 @@ func PatchApplication(base *v1beta1.Application, patch *v1alpha1.EnvPatch, selec
var errs errors2.ErrorList
var err error
for _, comp := range patch.Components {
if baseComp, exists := compMaps[comp.Name]; exists {
if baseComp.Type != comp.Type {
if comp.Name == "" {
for compName, baseComp := range compMaps {
if comp.Type == "" || comp.Type == baseComp.Type {
compMaps[compName], err = MergeComponent(baseComp, comp.DeepCopy())
if err != nil {
errs = append(errs, errors.Wrapf(err, "failed to merge component %s", compName))
}
}
}
} else if baseComp, exists := compMaps[comp.Name]; exists {
if baseComp.Type != comp.Type && comp.Type != "" {
compMaps[comp.Name] = comp.ToApplicationComponent()
} else {
compMaps[comp.Name], err = MergeComponent(baseComp, comp.DeepCopy())

View File

@@ -294,6 +294,240 @@ func Test_EnvBindApp_GenerateConfiguredApplication(t *testing.T) {
},
},
},
"patch-all-comp": {
baseApp: &v1beta1.Application{
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{{
Name: "express-server",
Type: "webservice",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "crccheck/hello-world",
}),
Traits: []common.ApplicationTrait{{
Type: "ingress",
Properties: util.Object2RawExtension(map[string]interface{}{
"domain": "a.example.com",
}),
}, {
Type: "ingress-1-20",
Properties: util.Object2RawExtension(map[string]interface{}{
"domain": "a-1-20.example.com",
}),
}},
}, {
Name: "express-worker",
Type: "worker",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "crccheck/hello-world",
}),
}},
},
},
envName: "prod",
envPatch: v1alpha1.EnvPatch{
Components: []v1alpha1.EnvComponentPatch{{
Name: "",
Type: "",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "busybox",
}),
Traits: []v1alpha1.EnvTraitPatch{{
Type: "ingress",
Properties: util.Object2RawExtension(map[string]interface{}{
"domain": "b.example.com",
}),
}},
}},
},
expectedApp: &v1beta1.Application{
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{{
Name: "express-server",
Type: "webservice",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "busybox",
}),
Traits: []common.ApplicationTrait{{
Type: "ingress",
Properties: util.Object2RawExtension(map[string]interface{}{
"domain": "b.example.com",
}),
}, {
Type: "ingress-1-20",
Properties: util.Object2RawExtension(map[string]interface{}{
"domain": "a-1-20.example.com",
}),
}},
}, {
Name: "express-worker",
Type: "worker",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "busybox",
}),
Traits: []common.ApplicationTrait{{
Type: "ingress",
Properties: util.Object2RawExtension(map[string]interface{}{
"domain": "b.example.com",
}),
}},
}},
},
},
},
"patch-type-comp": {
baseApp: &v1beta1.Application{
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{{
Name: "express-server",
Type: "webservice",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "crccheck/hello-world",
}),
Traits: []common.ApplicationTrait{{
Type: "ingress",
Properties: util.Object2RawExtension(map[string]interface{}{
"domain": "a.example.com",
}),
}, {
Type: "ingress-1-20",
Properties: util.Object2RawExtension(map[string]interface{}{
"domain": "a-1-20.example.com",
}),
}},
}, {
Name: "express-worker",
Type: "worker",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "crccheck/hello-world",
}),
}},
},
},
envName: "prod",
envPatch: v1alpha1.EnvPatch{
Components: []v1alpha1.EnvComponentPatch{{
Name: "",
Type: "webservice",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "busybox",
}),
Traits: []v1alpha1.EnvTraitPatch{{
Type: "ingress",
Properties: util.Object2RawExtension(map[string]interface{}{
"domain": "b.example.com",
}),
}},
}},
},
expectedApp: &v1beta1.Application{
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{{
Name: "express-server",
Type: "webservice",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "busybox",
}),
Traits: []common.ApplicationTrait{{
Type: "ingress",
Properties: util.Object2RawExtension(map[string]interface{}{
"domain": "b.example.com",
}),
}, {
Type: "ingress-1-20",
Properties: util.Object2RawExtension(map[string]interface{}{
"domain": "a-1-20.example.com",
}),
}},
}, {
Name: "express-worker",
Type: "worker",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "crccheck/hello-world",
}),
}},
},
},
},
"patch-without-type-specified": {
baseApp: &v1beta1.Application{
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{{
Name: "express-server",
Type: "webservice",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "crccheck/hello-world",
}),
Traits: []common.ApplicationTrait{{
Type: "ingress",
Properties: util.Object2RawExtension(map[string]interface{}{
"domain": "a.example.com",
}),
}, {
Type: "ingress-1-20",
Properties: util.Object2RawExtension(map[string]interface{}{
"domain": "a-1-20.example.com",
}),
}},
}, {
Name: "express-worker",
Type: "worker",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "crccheck/hello-world",
}),
}},
},
},
envName: "prod",
envPatch: v1alpha1.EnvPatch{
Components: []v1alpha1.EnvComponentPatch{{
Name: "express-worker",
Type: "",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "busybox",
}),
Traits: []v1alpha1.EnvTraitPatch{{
Type: "ingress",
Properties: util.Object2RawExtension(map[string]interface{}{
"domain": "b.example.com",
}),
}},
}},
},
expectedApp: &v1beta1.Application{
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{{
Name: "express-server",
Type: "webservice",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "crccheck/hello-world",
}),
Traits: []common.ApplicationTrait{{
Type: "ingress",
Properties: util.Object2RawExtension(map[string]interface{}{
"domain": "a.example.com",
}),
}, {
Type: "ingress-1-20",
Properties: util.Object2RawExtension(map[string]interface{}{
"domain": "a-1-20.example.com",
}),
}},
}, {
Name: "express-worker",
Type: "worker",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "busybox",
}),
Traits: []common.ApplicationTrait{{
Type: "ingress",
Properties: util.Object2RawExtension(map[string]interface{}{
"domain": "b.example.com",
}),
}},
}},
},
},
},
}
for name, tc := range testCases {

View File

@@ -15,8 +15,8 @@
}
#Component: {
name: string
type: string
name?: string
type?: string
properties?: {...}
traits?: [...{
type: string