From c514dc9566ecf47e9e1453314d9927e5ce488ca3 Mon Sep 17 00:00:00 2001
From: Brendan Shephard <bshephar@redhat.com>
Date: Tue, 14 Nov 2023 11:42:31 +1000
Subject: [PATCH] Add handling for max_fail_percentage and any_errors_fatal

This change adds handling for the max_fail_percentage and
any_errors_fatal arguments. These are provided via --extra-vars as
edpm_max_fail_percentage and edpm_any_errors_fatal.

These variables will be used in the playbooks to pass in user provided
options, else fallback to defaults.

Signed-off-by: Brendan Shephard <bshephar@redhat.com>
---
 ...nstack.org_openstackdataplaneservices.yaml |  5 ++++
 .../openstackdataplaneservice_types.go        |  4 +--
 ...nstack.org_openstackdataplaneservices.yaml |  5 ++++
 docs/openstack_dataplaneservice.md            |  2 ++
 pkg/deployment/service.go                     |  2 +-
 pkg/util/ansible_execution.go                 | 26 +++++++++++--------
 6 files changed, 30 insertions(+), 14 deletions(-)

diff --git a/api/bases/dataplane.openstack.org_openstackdataplaneservices.yaml b/api/bases/dataplane.openstack.org_openstackdataplaneservices.yaml
index 3adcfd10d..eb9b8c321 100644
--- a/api/bases/dataplane.openstack.org_openstackdataplaneservices.yaml
+++ b/api/bases/dataplane.openstack.org_openstackdataplaneservices.yaml
@@ -30,6 +30,11 @@ spec:
             type: object
           spec:
             properties:
+              ansibleAnyErrorsFatal:
+                type: boolean
+              ansibleMaxFailPercentage:
+                format: int64
+                type: integer
               configMaps:
                 items:
                   type: string
diff --git a/api/v1beta1/openstackdataplaneservice_types.go b/api/v1beta1/openstackdataplaneservice_types.go
index 868a065d8..5d3b281da 100644
--- a/api/v1beta1/openstackdataplaneservice_types.go
+++ b/api/v1beta1/openstackdataplaneservice_types.go
@@ -82,9 +82,9 @@ type OpenStackDataPlaneServiceSpec struct {
 	// +kubebuilder:validation:Optional
 	AnsibleMaxFailPercentage int64 `json:"ansibleMaxFailPercentage,omitempty"`
 
-	// AnyErrorsFatal is used to tune service specific, any_errors_fatal
+	// AnsibleAnyErrorsFatal is used to tune service specific, any_errors_fatal
 	// +kubebuilder:validation:Optional
-	AnyErrorsFatal bool `json:"anyErrorsFatal,omitempty"`
+	AnsibleAnyErrorsFatal bool `json:"ansibleAnyErrorsFatal,omitempty"`
 }
 
 // OpenStackDataPlaneServiceStatus defines the observed state of OpenStackDataPlaneService
diff --git a/config/crd/bases/dataplane.openstack.org_openstackdataplaneservices.yaml b/config/crd/bases/dataplane.openstack.org_openstackdataplaneservices.yaml
index 3adcfd10d..eb9b8c321 100644
--- a/config/crd/bases/dataplane.openstack.org_openstackdataplaneservices.yaml
+++ b/config/crd/bases/dataplane.openstack.org_openstackdataplaneservices.yaml
@@ -30,6 +30,11 @@ spec:
             type: object
           spec:
             properties:
+              ansibleAnyErrorsFatal:
+                type: boolean
+              ansibleMaxFailPercentage:
+                format: int64
+                type: integer
               configMaps:
                 items:
                   type: string
diff --git a/docs/openstack_dataplaneservice.md b/docs/openstack_dataplaneservice.md
index d59b7fbee..7b7dbc198 100644
--- a/docs/openstack_dataplaneservice.md
+++ b/docs/openstack_dataplaneservice.md
@@ -125,6 +125,8 @@ OpenStackDataPlaneServiceSpec defines the desired state of OpenStackDataPlaneSer
 | configMaps | ConfigMaps list of ConfigMap names to mount as ExtraMounts for the OpenStackAnsibleEE | []string | false |
 | secrets | Secrets list of Secret names to mount as ExtraMounts for the OpenStackAnsibleEE | []string | false |
 | openStackAnsibleEERunnerImage | OpenStackAnsibleEERunnerImage image to use as the ansibleEE runner image | string | false |
+| ansibleMaxFailPercentage | AnsibleMaxFailPercentage is used to tune service specific, allowable failure percentages during the Ansible execution https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_error_handling.html#setting-a-maximum-failure-percentage | int64 | false |
+| ansibleAnyErrorsFatal | AnsibleAnyErrorsFatal is used to tune service specific, any_errors_fatal | bool | false |
 
 [Back to Custom Resources](#custom-resources)
 
diff --git a/pkg/deployment/service.go b/pkg/deployment/service.go
index e1a08dad1..90a3806b3 100644
--- a/pkg/deployment/service.go
+++ b/pkg/deployment/service.go
@@ -45,7 +45,7 @@ type ServiceYAML struct {
 // DeployService service deployment
 func DeployService(ctx context.Context, helper *helper.Helper, obj client.Object, sshKeySecret string, inventorySecret string, aeeSpec dataplanev1.AnsibleEESpec, foundService dataplanev1.OpenStackDataPlaneService) error {
 
-	err := dataplaneutil.AnsibleExecution(ctx, helper, obj, foundService.Spec.Label, sshKeySecret, inventorySecret, foundService.Spec.Play, foundService.Spec.Playbook, aeeSpec)
+	err := dataplaneutil.AnsibleExecution(ctx, helper, obj, &foundService, sshKeySecret, inventorySecret, aeeSpec)
 	if err != nil {
 		helper.GetLogger().Error(err, fmt.Sprintf("Unable to execute Ansible for %s", foundService.Name))
 		return err
diff --git a/pkg/util/ansible_execution.go b/pkg/util/ansible_execution.go
index 5598d57e3..599b396bf 100644
--- a/pkg/util/ansible_execution.go
+++ b/pkg/util/ansible_execution.go
@@ -40,25 +40,23 @@ func AnsibleExecution(
 	ctx context.Context,
 	helper *helper.Helper,
 	obj client.Object,
-	label string,
+	service *dataplanev1.OpenStackDataPlaneService,
 	sshKeySecret string,
 	inventorySecret string,
-	play string,
-	playbook string,
 	aeeSpec dataplanev1.AnsibleEESpec,
 ) error {
 
 	var err error
 	var cmdLineArguments strings.Builder
 
-	ansibleEE, err := GetAnsibleExecution(ctx, helper, obj, label)
+	ansibleEE, err := GetAnsibleExecution(ctx, helper, obj, service.Spec.Label)
 	if err != nil && !k8serrors.IsNotFound(err) {
 		return err
 	}
 	if ansibleEE == nil {
 		var executionName string
-		if len(label) > 0 {
-			executionName = fmt.Sprintf("%s-%s", label, obj.GetName())
+		if len(service.Spec.Label) > 0 {
+			executionName = fmt.Sprintf("%s-%s", service.Spec.Label, obj.GetName())
 		} else {
 			executionName = obj.GetName()
 		}
@@ -67,7 +65,7 @@ func AnsibleExecution(
 				Name:      executionName,
 				Namespace: obj.GetNamespace(),
 				Labels: map[string]string{
-					label: string(obj.GetUID()),
+					service.Spec.Label: string(obj.GetUID()),
 				},
 			},
 		}
@@ -90,15 +88,21 @@ func AnsibleExecution(
 		if len(aeeSpec.AnsibleSkipTags) > 0 {
 			fmt.Fprintf(&cmdLineArguments, "--skip-tags %s ", aeeSpec.AnsibleSkipTags)
 		}
+		if service.Spec.AnsibleMaxFailPercentage != 0 {
+			fmt.Fprintf(&cmdLineArguments, "--extra-vars edpm_max_fail_percentage=%d ", service.Spec.AnsibleMaxFailPercentage)
+		}
+		if !service.Spec.AnsibleAnyErrorsFatal {
+			fmt.Fprintf(&cmdLineArguments, "--extra-vars edpm_any_errors_fatal=%t ", service.Spec.AnsibleAnyErrorsFatal)
+		}
 		if cmdLineArguments.Len() > 0 {
 			ansibleEE.Spec.CmdLine = strings.TrimSpace(cmdLineArguments.String())
 		}
 
-		if len(play) > 0 {
-			ansibleEE.Spec.Play = play
+		if len(service.Spec.Play) > 0 {
+			ansibleEE.Spec.Play = service.Spec.Play
 		}
-		if len(playbook) > 0 {
-			ansibleEE.Spec.Playbook = playbook
+		if len(service.Spec.Playbook) > 0 {
+			ansibleEE.Spec.Playbook = service.Spec.Playbook
 		}
 
 		ansibleEEMounts := storage.VolMounts{}