Skip to content

Commit e852713

Browse files
authored
Merge pull request #96 from awslabs/change/readiness-variable
Make readyWhen variables start with their own name
2 parents 9e087ef + ee9843b commit e852713

File tree

8 files changed

+38
-47
lines changed

8 files changed

+38
-47
lines changed

examples/ack-eks-cluster/eks-cluster.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ spec:
2020
resources:
2121
- name: clusterVPC
2222
readyWhen:
23-
- ${status.state == "available"}
23+
- ${clusterVPC.status.state == "available"}
2424
template:
2525
apiVersion: ec2.services.k8s.aws/v1alpha1
2626
kind: VPC
@@ -59,7 +59,7 @@ spec:
5959
gatewayID: ${clusterInternetGateway.status.internetGatewayID}
6060
- name: clusterSubnetA
6161
readyWhen:
62-
- ${status.state == "available"}
62+
- ${clusterSubnetA.status.state == "available"}
6363
template:
6464
apiVersion: ec2.services.k8s.aws/v1alpha1
6565
kind: Subnet
@@ -174,7 +174,7 @@ spec:
174174
}
175175
- name: cluster
176176
readyWhen:
177-
- ${status.status == "ACTIVE"}
177+
- ${cluster.status.status == "ACTIVE"}
178178
template:
179179
apiVersion: eks.services.k8s.aws/v1alpha1
180180
kind: Cluster

examples/deployment-service/deployment-service.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ spec:
1717
resources:
1818
- name: deployment
1919
readyWhen:
20-
- ${spec.replicas == status.availableReplicas}
20+
- ${deployment.spec.replicas == deployment.status.availableReplicas}
2121
template:
2222
apiVersion: apps/v1
2323
kind: Deployment

internal/graph/builder.go

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -731,27 +731,26 @@ func validateResourceCELExpressions(resources map[string]*Resource, instance *Re
731731
// I would also suggest separating the dryRuns of readyWhenExpressions
732732
// and the resourceExpressions.
733733
for _, readyWhenExpression := range resource.readyWhenExpressions {
734-
fieldNames := schema.GetResourceTopLevelFieldNames(resource.schema)
735-
fieldEnv, err := scel.DefaultEnvironment(scel.WithResourceNames(fieldNames))
734+
fieldEnv, err := scel.DefaultEnvironment(scel.WithResourceNames([]string{resource.id}))
736735
if err != nil {
737736
return fmt.Errorf("failed to create CEL environment: %w", err)
738737
}
739738

740-
err = validateCELExpressionContext(fieldEnv, readyWhenExpression, fieldNames)
739+
err = validateCELExpressionContext(fieldEnv, readyWhenExpression, []string{resource.id})
741740
if err != nil {
742741
return fmt.Errorf("failed to validate expression context: '%s' %w", readyWhenExpression, err)
743742
}
744743
// create context
745744
// add resource fields to the context
745+
resourceEmulatedCopy := resource.emulatedObject.DeepCopy()
746+
if resourceEmulatedCopy != nil && resourceEmulatedCopy.Object != nil {
747+
delete(resourceEmulatedCopy.Object, "apiVersion")
748+
delete(resourceEmulatedCopy.Object, "kind")
749+
}
746750
context := map[string]*Resource{}
747-
for _, n := range fieldNames {
748-
context[n] = &Resource{
749-
emulatedObject: &unstructured.Unstructured{
750-
Object: resource.emulatedObject.Object[n].(map[string]interface{}),
751-
},
752-
}
751+
context[resource.id] = &Resource{
752+
emulatedObject: resourceEmulatedCopy,
753753
}
754-
755754
output, err := dryRunExpression(fieldEnv, readyWhenExpression, context)
756755

757756
if err != nil {

internal/graph/builder_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ func TestGraphBuilder_Validation(t *testing.T) {
209209
"enableDNSSupport": true,
210210
"enableDNSHostnames": true,
211211
},
212-
}, []string{"${status.state == 'available'}"}, nil),
212+
}, []string{"${vpc.status.state == 'available'}"}, nil),
213213
generator.WithResource("subnet1", map[string]interface{}{
214214
"apiVersion": "ec2.services.k8s.aws/v1alpha1",
215215
"kind": "Subnet",
@@ -220,7 +220,7 @@ func TestGraphBuilder_Validation(t *testing.T) {
220220
"cidrBlock": "10.0.1.0/24",
221221
"vpcID": "${vpc.status.vpcID}",
222222
},
223-
}, []string{"${status.state == 'available'}"}, []string{"${spec.enableSubnets == true}"}),
223+
}, []string{"${subnet1.status.state == 'available'}"}, []string{"${spec.enableSubnets == true}"}),
224224
generator.WithResource("subnet2", map[string]interface{}{
225225
"apiVersion": "ec2.services.k8s.aws/v1alpha1",
226226
"kind": "Subnet",
@@ -231,7 +231,7 @@ func TestGraphBuilder_Validation(t *testing.T) {
231231
"cidrBlock": "10.0.127.0/24",
232232
"vpcID": "${vpc.status.vpcID}",
233233
},
234-
}, []string{"${status.state == 'available'}"}, []string{"${spec.enableSubnets}"})},
234+
}, []string{"${subnet2.status.state == 'available'}"}, []string{"${spec.enableSubnets}"})},
235235
wantErr: false,
236236
},
237237
{
@@ -1001,8 +1001,8 @@ func TestGraphBuilder_ExpressionParsing(t *testing.T) {
10011001
"cidrBlocks": []interface{}{"10.0.0.0/16"},
10021002
},
10031003
}, []string{
1004-
"${status.state == 'available'}",
1005-
"${status.vpcID != ''}",
1004+
"${vpc.status.state == 'available'}",
1005+
"${vpc.status.vpcID != ''}",
10061006
}, nil),
10071007
// Resource with mix of static and dynamic expressions
10081008
generator.WithResource("subnet", map[string]interface{}{
@@ -1021,7 +1021,7 @@ func TestGraphBuilder_ExpressionParsing(t *testing.T) {
10211021
},
10221022
},
10231023
},
1024-
}, []string{"${status.state == 'available'}"}, nil),
1024+
}, []string{"${subnet.status.state == 'available'}"}, nil),
10251025
// Non-standalone expressions
10261026
generator.WithResource("cluster", map[string]interface{}{
10271027
"apiVersion": "eks.services.k8s.aws/v1alpha1",
@@ -1038,7 +1038,7 @@ func TestGraphBuilder_ExpressionParsing(t *testing.T) {
10381038
},
10391039
},
10401040
}, []string{
1041-
"${status.status == 'ACTIVE'}",
1041+
"${cluster.status.status == 'ACTIVE'}",
10421042
}, []string{
10431043
"${spec.createMonitoring}",
10441044
}),
@@ -1075,7 +1075,7 @@ func TestGraphBuilder_ExpressionParsing(t *testing.T) {
10751075
},
10761076
},
10771077
}, []string{
1078-
"${status.phase == 'Running'}",
1078+
"${monitor.status.phase == 'Running'}",
10791079
}, []string{
10801080
"${spec.createMonitoring == true}",
10811081
}),
@@ -1091,8 +1091,8 @@ func TestGraphBuilder_ExpressionParsing(t *testing.T) {
10911091
vpc := g.Resources["vpc"]
10921092
assert.Empty(t, vpc.variables)
10931093
assert.Equal(t, []string{
1094-
"status.state == 'available'",
1095-
"status.vpcID != ''",
1094+
"vpc.status.state == 'available'",
1095+
"vpc.status.vpcID != ''",
10961096
}, vpc.GetReadyWhenExpressions())
10971097
assert.Empty(t, vpc.GetIncludeWhenExpressions())
10981098

internal/graph/variable/variable.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ const (
112112
// For example:
113113
// name: cluster
114114
// readyWhen:
115-
// - ${status.status == "Active"}
115+
// - ${cluster.status.status == "Active"}
116116
ResourceVariableKindReadyWhen ResourceVariableKind = "readyWhen"
117117
// ResourceVariableKindIncludeWhen represents an includeWhen variable.
118118
// IncludeWhen variables are resolved at the beginning of the execution and

internal/runtime/runtime.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -472,20 +472,16 @@ func (rt *ResourceGroupRuntime) IsResourceReady(resourceID string) (bool, string
472472
return true, "", nil
473473
}
474474

475-
topLevelFields := rt.resources[resourceID].GetTopLevelFields()
476-
477475
// we should not expect errors here since we already compiled it
478476
// in the dryRun
479-
env, err := scel.DefaultEnvironment(scel.WithResourceNames(topLevelFields))
477+
env, err := scel.DefaultEnvironment(scel.WithResourceNames([]string{resourceID}))
480478
if err != nil {
481479
return false, "", fmt.Errorf("failed creating new Environment: %w", err)
482480
}
483-
context := map[string]interface{}{}
484-
for _, n := range topLevelFields {
485-
if obj, ok := observed.Object[n]; ok {
486-
context[n] = obj.(map[string]interface{})
487-
}
481+
context := map[string]interface{}{
482+
resourceID: observed.Object,
488483
}
484+
489485
for _, expression := range expressions {
490486
out, err := evaluateExpression(env, context, expression)
491487
if err != nil {

internal/runtime/runtime_test.go

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2183,16 +2183,15 @@ func Test_IsResourceReady(t *testing.T) {
21832183
{
21842184
name: "resource not resolved",
21852185
resource: newTestResource(
2186-
withReadyExpressions([]string{"status.ready"}),
2186+
withReadyExpressions([]string{"test.status.ready"}),
21872187
),
21882188
want: false,
21892189
wantReason: "resource test is not resolved",
21902190
},
21912191
{
21922192
name: "ready expression true",
21932193
resource: newTestResource(
2194-
withReadyExpressions([]string{"status.ready"}),
2195-
withTopLevelFields([]string{"status"}),
2194+
withReadyExpressions([]string{"test.status.ready"}),
21962195
),
21972196
resolvedObject: map[string]interface{}{
21982197
"status": map[string]interface{}{
@@ -2204,22 +2203,20 @@ func Test_IsResourceReady(t *testing.T) {
22042203
{
22052204
name: "ready expression false",
22062205
resource: newTestResource(
2207-
withReadyExpressions([]string{"status.ready"}),
2208-
withTopLevelFields([]string{"status"}),
2206+
withReadyExpressions([]string{"test.status.ready"}),
22092207
),
22102208
resolvedObject: map[string]interface{}{
22112209
"status": map[string]interface{}{
22122210
"ready": false,
22132211
},
22142212
},
22152213
want: false,
2216-
wantReason: "expression status.ready evaluated to false",
2214+
wantReason: "expression test.status.ready evaluated to false",
22172215
},
22182216
{
22192217
name: "invalid expression",
22202218
resource: newTestResource(
22212219
withReadyExpressions([]string{"invalid )"}),
2222-
withTopLevelFields([]string{"status"}),
22232220
),
22242221
resolvedObject: map[string]interface{}{},
22252222
want: false,
@@ -2228,8 +2225,7 @@ func Test_IsResourceReady(t *testing.T) {
22282225
{
22292226
name: "multiple expressions all true",
22302227
resource: newTestResource(
2231-
withReadyExpressions([]string{"status.ready", "status.healthy && status.count > 10", "status.count > 5"}),
2232-
withTopLevelFields([]string{"status"}),
2228+
withReadyExpressions([]string{"test.status.ready", "test.status.healthy && test.status.count > 10", "test.status.count > 5"}),
22332229
),
22342230
resolvedObject: map[string]interface{}{
22352231
"status": map[string]interface{}{
@@ -2243,8 +2239,7 @@ func Test_IsResourceReady(t *testing.T) {
22432239
{
22442240
name: "multiple expressions one false",
22452241
resource: newTestResource(
2246-
withReadyExpressions([]string{"status.ready", "status.healthy"}),
2247-
withTopLevelFields([]string{"status"}),
2242+
withReadyExpressions([]string{"test.status.ready", "test.status.healthy"}),
22482243
),
22492244
resolvedObject: map[string]interface{}{
22502245
"status": map[string]interface{}{
@@ -2253,7 +2248,7 @@ func Test_IsResourceReady(t *testing.T) {
22532248
},
22542249
},
22552250
want: false,
2256-
wantReason: "expression status.healthy evaluated to false",
2251+
wantReason: "expression test.status.healthy evaluated to false",
22572252
},
22582253
}
22592254

test/integration/suites/core/readiness_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ var _ = Describe("Readiness", func() {
5151
Expect(env.Client.Create(ctx, ns)).To(Succeed())
5252
})
5353

54-
It("should wait for deployment to have spec.replicas == status.availableReplicas before creating service", func() {
54+
It(`should wait for deployment to have deployment.spec.replicas
55+
== deployment.status.availableReplicas before creating service`, func() {
5556
rg := generator.NewResourceGroup("test-readiness",
5657
generator.WithNamespace(namespace),
5758
generator.WithSchema(
@@ -97,7 +98,7 @@ var _ = Describe("Readiness", func() {
9798
},
9899
},
99100
},
100-
}, []string{"${spec.replicas == status.availableReplicas}"}, nil),
101+
}, []string{"${deployment.spec.replicas == deployment.status.availableReplicas}"}, nil),
101102
// ServiceB - depends on deploymentA and deploymentB
102103
generator.WithResource("service", map[string]interface{}{
103104
"apiVersion": "v1",

0 commit comments

Comments
 (0)