Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,11 @@ func (r *OpenStackDataPlaneDeploymentReconciler) setHashes(

for _, nodeSet := range nodeSets.Items {
instance.Status.NodeSetHashes[nodeSet.Name] = nodeSet.Status.ConfigHash

err = setNodeSetAnsibleVarsFromHashes(ctx, helper, &nodeSet, instance.Status.ConfigMapHashes, instance.Status.SecretHashes)
if err != nil {
return err
}
}

return nil
Expand Down Expand Up @@ -547,3 +552,27 @@ func (r *OpenStackDataPlaneDeploymentReconciler) listNodeSets(ctx context.Contex
}
return &nodeSets, err
}

func setNodeSetAnsibleVarsFromHashes(
ctx context.Context,
helper *helper.Helper,
nodeSetInstance *dataplanev1.OpenStackDataPlaneNodeSet,
configMapHashes map[string]string, // configMapHashes from deployment.instance.configMapHashes
secretHashes map[string]string, // secretHashes from deployment.instance.secretHashes
) error {
namespace := nodeSetInstance.Namespace

// Process NodeTemplate level AnsibleVarsFrom
if err := deployment.ProcessAnsibleVarsFrom(ctx, helper, namespace, configMapHashes, secretHashes, nodeSetInstance.Spec.NodeTemplate.Ansible.AnsibleVarsFrom); err != nil {
return err
}

// Process individual Node level AnsibleVarsFrom
for _, node := range nodeSetInstance.Spec.Nodes {
if err := deployment.ProcessAnsibleVarsFrom(ctx, helper, namespace, configMapHashes, secretHashes, node.Ansible.AnsibleVarsFrom); err != nil {
return err
}
}

return nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,17 @@ func checkDeployment(ctx context.Context, helper *helper.Helper,
deployment.Status.BmhRefHashes[instance.Name] != instance.Status.BmhRefHash) {
continue
}

hasAnsibleVarsFromChanged, err := checkAnsibleVarsFromChanged(ctx, helper, instance, deployment.Status.ConfigMapHashes, deployment.Status.SecretHashes)

if err != nil {
return isNodeSetDeploymentReady, isNodeSetDeploymentRunning, isNodeSetDeploymentFailed, failedDeploymentName, err
}

if hasAnsibleVarsFromChanged {
continue
}

isNodeSetDeploymentReady = true
for k, v := range deployment.Status.ConfigMapHashes {
instance.Status.ConfigMapHashes[k] = v
Expand Down Expand Up @@ -911,3 +922,49 @@ func (r *OpenStackDataPlaneNodeSetReconciler) GetSpecConfigHash(instance *datapl
}
return configHash, nil
}

// checkAnsibleVarsFromChanged computes current hashes for ConfigMaps/Secrets
// referenced in AnsibleVarsFrom and compares them with deployed hashes.
// Returns true if any content has changed, false otherwise.
func checkAnsibleVarsFromChanged(
ctx context.Context,
helper *helper.Helper,
instance *dataplanev1.OpenStackDataPlaneNodeSet,
deployedConfigMapHashes map[string]string,
deployedSecretHashes map[string]string,
) (bool, error) {
currentConfigMapHashes := make(map[string]string)
currentSecretHashes := make(map[string]string)

namespace := instance.Namespace

// Process NodeTemplate level AnsibleVarsFrom
if err := deployment.ProcessAnsibleVarsFrom(ctx, helper, namespace, currentConfigMapHashes, currentSecretHashes, instance.Spec.NodeTemplate.Ansible.AnsibleVarsFrom); err != nil {
return false, err
}

// Process individual Node level AnsibleVarsFrom
for _, node := range instance.Spec.Nodes {
if err := deployment.ProcessAnsibleVarsFrom(ctx, helper, namespace, currentConfigMapHashes, currentSecretHashes, node.Ansible.AnsibleVarsFrom); err != nil {
return false, err
}
}

// Compare current ConfigMap hashes with deployed hashes
for name, currentHash := range currentConfigMapHashes {
if deployedHash, exists := deployedConfigMapHashes[name]; !exists || deployedHash != currentHash {
helper.GetLogger().Info("ConfigMap content changed", "configMap", name)
return true, nil
}
}

// Compare current Secret hashes with deployed hashes
for name, currentHash := range currentSecretHashes {
if deployedHash, exists := deployedSecretHashes[name]; !exists || deployedHash != currentHash {
helper.GetLogger().Info("Secret content changed", "secret", name)
return true, nil
}
}

return false, nil
}
39 changes: 39 additions & 0 deletions internal/dataplane/hashes.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,42 @@ func GetDeploymentHashesForService(

return nil
}

// ProcessAnsibleVarsFrom computes hashes for ConfigMaps and Secrets
// referenced in the NodeSet's AnsibleVarsFrom field (both NodeTemplate and
// individual Nodes)
func ProcessAnsibleVarsFrom(
ctx context.Context,
helper *helper.Helper,
namespace string,
configMapHashes map[string]string,
secretHashes map[string]string,
varsFrom []dataplanev1.DataSource,
) error {
for _, dataSource := range varsFrom {
cm, sec, err := dataplaneutil.GetDataSourceCmSecret(ctx, helper, namespace, dataSource)

if err != nil {
return err
}

if cm != nil {
hash, err := configmap.Hash(cm)
if err != nil {
helper.GetLogger().Error(err, "Unable to hash ConfigMap", "configMap", cm.Name)
return err
}
configMapHashes[cm.Name] = hash
}

if sec != nil {
hash, err := secret.Hash(sec)
if err != nil {
helper.GetLogger().Error(err, "Unable to hash Secret", "secret", sec.Name)
return err
}
secretHashes[sec.Name] = hash
}
}
return nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Test ansibleVarsFrom ConfigMap/Secret change detection
# First, delete the failed deployment from step 05 to clear the NodeSet error state
# This step can be ignored if we did not want to check the status of the nodeSet
# and verify if that is waiting for deployment.
apiVersion: kuttl.dev/v1beta1
kind: TestStep
commands:
- script: oc delete openstackdataplanedeployment edpm-compute-no-nodes-non-existent-service -n openstack-kuttl-tests --ignore-not-found=true
---
# Create ConfigMap and Secret for ansibleVarsFrom
apiVersion: v1
kind: ConfigMap
metadata:
name: ansiblevars-test-cm
data:
test_var: original-value
---
apiVersion: v1
kind: Secret
metadata:
name: ansiblevars-test-secret
stringData:
secret_var: original-secret-value
---
# Patch existing NodeSet to add ansibleVarsFrom
apiVersion: dataplane.openstack.org/v1beta1
kind: OpenStackDataPlaneNodeSet
metadata:
name: edpm-compute-no-nodes
spec:
nodeTemplate:
ansible:
ansibleVarsFrom:
- configMapRef:
name: ansiblevars-test-cm
- secretRef:
name: ansiblevars-test-secret
---
# Create deployment to capture the hashes
apiVersion: dataplane.openstack.org/v1beta1
kind: OpenStackDataPlaneDeployment
metadata:
name: edpm-ansiblevars-deploy
spec:
nodeSets:
- edpm-compute-no-nodes
servicesOverride:
- configure-os
61 changes: 61 additions & 0 deletions test/kuttl/tests/dataplane-deploy-no-nodes-test/08-assert.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
apiVersion: kuttl.dev/v1beta1
kind: TestAssert
timeout: 600
collectors:
- type: command
command: oc logs -n openstack-operators -l openstack.org/operator-name=openstack
name: operator-logs
---
# Assert NodeSet is Ready with configMapHashes populated
apiVersion: dataplane.openstack.org/v1beta1
kind: OpenStackDataPlaneNodeSet
metadata:
name: edpm-compute-no-nodes
namespace: openstack-kuttl-tests
status:
conditions:
- message: NodeSet Ready
reason: Ready
status: "True"
type: Ready
- message: Deployment completed
reason: Ready
status: "True"
type: DeploymentReady
- message: Input data complete
reason: Ready
status: "True"
type: InputReady
- message: NodeSetDNSDataReady ready
reason: Ready
status: "True"
type: NodeSetDNSDataReady
- message: NodeSetIPReservationReady ready
reason: Ready
status: "True"
type: NodeSetIPReservationReady
- message: ServiceAccount created
reason: Ready
status: "True"
type: ServiceAccountReady
- message: Setup complete
reason: Ready
status: "True"
type: SetupReady
configMapHashes:
ansiblevars-test-cm: n5bbhc6h5fdhf8h57bh665h5b9h576h598h7dh5fdh667hch5b5h89h9dh668hc4hc6h669h74h575hf4h596h66dhd5h5f7hb7h689hf9hddh64q
secretHashes:
ansiblevars-test-secret: n5d8h67h5b8hc9h5cfh54bh76h544h66chf7h8bh5fbh59chdch76h96h54bh74h9bh5bh5cdh94h566h699h99hdch65fh5d6h5fbh5bfh586hfcq
---
# Assert deployment completed with hashes
apiVersion: dataplane.openstack.org/v1beta1
kind: OpenStackDataPlaneDeployment
metadata:
name: edpm-ansiblevars-deploy
namespace: openstack-kuttl-tests
status:
deployed: true
configMapHashes:
ansiblevars-test-cm: n5bbhc6h5fdhf8h57bh665h5b9h576h598h7dh5fdh667hch5b5h89h9dh668hc4hc6h669h74h575hf4h596h66dhd5h5f7hb7h689hf9hddh64q
secretHashes:
ansiblevars-test-secret: n5d8h67h5b8hc9h5cfh54bh76h544h66chf7h8bh5fbh59chdch76h96h54bh74h9bh5bh5cdh94h566h699h99hdch65fh5d6h5fbh5bfh586hfcq
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Update ConfigMap and Secret content to trigger change detection
apiVersion: v1
kind: ConfigMap
metadata:
name: ansiblevars-test-cm
data:
test_var: updated-value
---
apiVersion: v1
kind: Secret
metadata:
name: ansiblevars-test-secret
stringData:
secret_var: updated-secret-value
---
# Create deployment to capture the new hashes after content update
apiVersion: dataplane.openstack.org/v1beta1
kind: OpenStackDataPlaneDeployment
metadata:
name: edpm-ansiblevars-deploy-update
spec:
nodeSets:
- edpm-compute-no-nodes
servicesOverride:
- configure-os
63 changes: 63 additions & 0 deletions test/kuttl/tests/dataplane-deploy-no-nodes-test/09-assert.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
apiVersion: kuttl.dev/v1beta1
kind: TestAssert
timeout: 600
collectors:
- type: command
command: oc logs -n openstack-operators -l openstack.org/operator-name=openstack
name: operator-logs
---
# Assert NodeSet is Ready after deployment with updated ConfigMap/Secret completes
# The hash values will differ from step 08 due to content change
apiVersion: dataplane.openstack.org/v1beta1
kind: OpenStackDataPlaneNodeSet
metadata:
name: edpm-compute-no-nodes
namespace: openstack-kuttl-tests
status:
conditions:
- message: NodeSet Ready
reason: Ready
status: "True"
type: Ready
- message: Deployment completed
reason: Ready
status: "True"
type: DeploymentReady
- message: Input data complete
reason: Ready
status: "True"
type: InputReady
- message: NodeSetDNSDataReady ready
reason: Ready
status: "True"
type: NodeSetDNSDataReady
- message: NodeSetIPReservationReady ready
reason: Ready
status: "True"
type: NodeSetIPReservationReady
- message: ServiceAccount created
reason: Ready
status: "True"
type: ServiceAccountReady
- message: Setup complete
reason: Ready
status: "True"
type: SetupReady
configMapHashes:
ansiblevars-test-cm: nd7h5fdh54bh8chb7h5hc8h654hf8h5d5h66bh54dh56fh7bhf5h98h66fh59ch87h9ch5d6h664h668hb7h66fh7fh598h9fh57dhfh5fch655q
secretHashes:
ansiblevars-test-secret: n56hffh656h98hc9h4h79h86h5bfh695hd7h5f9h5d4h87h85h546h7dhc5h98h676h5fh66bh66bhb5h679h77hf8hdbh569h66dhb5h59dq
---
# Assert deployment completed with new hashes
apiVersion: dataplane.openstack.org/v1beta1
kind: OpenStackDataPlaneDeployment
metadata:
name: edpm-ansiblevars-deploy-update
namespace: openstack-kuttl-tests
status:
deployed: true
configMapHashes:
ansiblevars-test-cm: nd7h5fdh54bh8chb7h5hc8h654hf8h5d5h66bh54dh56fh7bhf5h98h66fh59ch87h9ch5d6h664h668hb7h66fh7fh598h9fh57dhfh5fch655q
secretHashes:
ansiblevars-test-secret: n56hffh656h98hc9h4h79h86h5bfh695hd7h5f9h5d4h87h85h546h7dhc5h98h676h5fh66bh66bhb5h679h77hf8hdbh569h66dhb5h59dq