Skip to content

Commit ee9843b

Browse files
committed
Make readyWhen variables start with their own name
This change ensures that all variables referenced in readyWhen expressions are referencing their own resource by name This change will also allow us in the future to reference other resource fields if needed changing from: ```yaml name: cluster readyWhen: - ${status.state == 'available'} ``` to ```yaml name: cluster readyWhen: - ${cluster.status.state == 'available'} ```
1 parent 3499476 commit ee9843b

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)