Skip to content

Commit

Permalink
Adding general map field for configuring AEE
Browse files Browse the repository at this point in the history
Also moves raw string parsing to AnsibleEE utils.go

Signed-off-by: Jiri Podivin <[email protected]>
  • Loading branch information
jpodivin committed Oct 4, 2024
1 parent efa2ec3 commit ad8e3a0
Show file tree
Hide file tree
Showing 10 changed files with 221 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ spec:
type: object
spec:
properties:
ansibleEeConfig:
x-kubernetes-preserve-unknown-fields: true
ansibleExtraVars:
x-kubernetes-preserve-unknown-fields: true
ansibleLimit:
Expand Down
3 changes: 3 additions & 0 deletions apis/dataplane/v1beta1/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,4 +198,7 @@ type AnsibleEESpec struct {
// the ansible execution run with. Without specifying, it will run with
// default serviceaccount
ServiceAccountName string
// EnvConfigMapName name of configuration config map to be used
// defaults to openstack-aee-default-env
EnvConfigMapName string `json:"envConfigMapName,omitempty"`
}
6 changes: 6 additions & 0 deletions apis/dataplane/v1beta1/openstackdataplanedeployment_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ type OpenStackDataPlaneDeploymentSpec struct {
// +kubebuilder:validation:Minimum:=1
// +kubebuilder:default:=15
DeploymentRequeueTime int `json:"deploymentRequeueTime"`

// Additional configuration options for AnsibleExecutionEnvironment
// +kubebuilder:validation:Optional
// +kubebuilder:pruning:PreserveUnknownFields
// +kubebuilder:validation:Schemaless
AnsibleEEConfig map[string]json.RawMessage `json:"ansibleEeConfig,omitempty"`
}

// OpenStackDataPlaneDeploymentStatus defines the observed state of OpenStackDataPlaneDeployment
Expand Down
15 changes: 15 additions & 0 deletions apis/dataplane/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ spec:
type: object
spec:
properties:
ansibleEeConfig:
x-kubernetes-preserve-unknown-fields: true
ansibleExtraVars:
x-kubernetes-preserve-unknown-fields: true
ansibleLimit:
Expand Down
30 changes: 30 additions & 0 deletions pkg/dataplane/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,14 @@ func (d *Deployer) Deploy(services []string) (*ctrl.Result, error) {
}
}

// set additional ansible options
// don't fail if there is a problem with struct
// since it's purely optional
err = d.setAdditionalAEEOptions()
if err != nil {
log.Error(err, fmt.Sprintf("error: %e while parsing ansibleEeConfig, defaults will be used", err))
}

err = d.ConditionalDeploy(
readyCondition,
readyMessage,
Expand Down Expand Up @@ -496,3 +504,25 @@ func (d *Deployer) addServiceExtraMounts(

return d.AeeSpec, nil
}

func (d *Deployer) setAdditionalAEEOptions() error {
additionalAEEOptions := make(map[string]interface{})
var test bool

err := dataplaneutil.UnmarshalRawStrings(
d.Deployment.Spec.AnsibleEEConfig, additionalAEEOptions)
if err != nil {
return err
}

// Check presence of the key, type and contents
configMapName, test := additionalAEEOptions["envConfMapName"]

if test && reflect.TypeOf(configMapName).Kind() == reflect.String && configMapName != "" {
d.AeeSpec.EnvConfigMapName = configMapName.(string)
} else {
d.AeeSpec.EnvConfigMapName = "openstack-aee-default-env"
}

return nil
}
21 changes: 2 additions & 19 deletions pkg/dataplane/inventory.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ import (
"strconv"
"strings"

yaml "gopkg.in/yaml.v3"

infranetworkv1 "github.com/openstack-k8s-operators/infra-operator/apis/network/v1beta1"
"github.com/openstack-k8s-operators/lib-common/modules/ansible"
"github.com/openstack-k8s-operators/lib-common/modules/common/helper"
Expand Down Expand Up @@ -303,7 +301,7 @@ func resolveGroupAnsibleVars(template *dataplanev1.NodeTemplate, group *ansible.
group.Vars["edpm_telemetry_kepler_image"] = containerImages.EdpmKeplerImage
}

err := unmarshalAnsibleVars(template.Ansible.AnsibleVars, group.Vars)
err := util.UnmarshalRawStrings(template.Ansible.AnsibleVars, group.Vars)
if err != nil {
return err
}
Expand Down Expand Up @@ -332,7 +330,7 @@ func resolveHostAnsibleVars(node *dataplanev1.NodeSection,
host.Vars["management_network"] = node.ManagementNetwork
}

err := unmarshalAnsibleVars(node.Ansible.AnsibleVars, host.Vars)
err := util.UnmarshalRawStrings(node.Ansible.AnsibleVars, host.Vars)
if err != nil {
return err
}
Expand All @@ -347,21 +345,6 @@ func resolveHostAnsibleVars(node *dataplanev1.NodeSection,

}

// unmarshal raw strings into an ansible vars dictionary
func unmarshalAnsibleVars(ansibleVars map[string]json.RawMessage,
parsedVars map[string]interface{}) error {

for key, val := range ansibleVars {
var v interface{}
err := yaml.Unmarshal(val, &v)
if err != nil {
return err
}
parsedVars[key] = v
}
return nil
}

func buildNetworkVars(networks []infranetworkv1.IPSetNetwork,
netServiceNetMap map[string]string) ([]string, map[string]string) {
serviceNetMap := make(map[string]string)
Expand Down
3 changes: 1 addition & 2 deletions pkg/dataplane/util/ansible_execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ func AnsibleExecution(
nodeSet client.Object,
) error {
var err error

executionName, labels := GetAnsibleExecutionNameAndLabels(service, deployment.GetName(), nodeSet.GetName())

existingAnsibleEE, err := GetAnsibleExecution(ctx, helper, deployment, labels)
Expand All @@ -67,7 +66,7 @@ func AnsibleExecution(
Name: executionName,
Namespace: deployment.GetNamespace(),
Labels: labels,
EnvConfigMapName: "openstack-aee-default-env",
EnvConfigMapName: aeeSpec.EnvConfigMapName,
}

ansibleEE.NetworkAttachments = aeeSpec.NetworkAttachments
Expand Down
15 changes: 15 additions & 0 deletions pkg/dataplane/util/ansibleee.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,3 +295,18 @@ func calculateHash(envVar string) (string, error) {
}
return hash, nil
}

// unmarshal raw strings into a dictionary
func UnmarshalRawStrings(rawStrings map[string]json.RawMessage,
parsedVars map[string]interface{}) error {

for key, val := range rawStrings {
var v interface{}
err := yaml.Unmarshal(val, &v)
if err != nil {
return err
}
parsedVars[key] = v
}
return nil
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package functional

import (
"encoding/json"
"fmt"
"os"

Expand Down Expand Up @@ -1777,4 +1778,148 @@ var _ = Describe("Dataplane Deployment Test", func() {

})

When("A dataplaneDeployment is created with matching NodeSet and additional AEE options", func() {
BeforeEach(func() {
CreateSSHSecret(dataplaneSSHSecretName)
DeferCleanup(th.DeleteInstance, th.CreateSecret(neutronOvnMetadataSecretName, map[string][]byte{
"fake_keys": []byte("blih"),
}))
DeferCleanup(th.DeleteInstance, th.CreateSecret(novaNeutronMetadataSecretName, map[string][]byte{
"fake_keys": []byte("blih"),
}))
DeferCleanup(th.DeleteInstance, th.CreateSecret(novaCellComputeConfigSecretName, map[string][]byte{
"fake_keys": []byte("blih"),
}))
DeferCleanup(th.DeleteInstance, th.CreateSecret(novaMigrationSSHKey, map[string][]byte{
"ssh-privatekey": []byte("fake-ssh-private-key"),
"ssh-publickey": []byte("fake-ssh-public-key"),
}))
DeferCleanup(th.DeleteInstance, th.CreateSecret(ceilometerConfigSecretName, map[string][]byte{
"fake_keys": []byte("blih"),
}))
// DefaultDataPlanenodeSetSpec comes with three mock services
// default service
CreateDataplaneService(dataplaneServiceName, false)
// marked for deployment on all nodesets
CreateDataplaneService(dataplaneGlobalServiceName, true)
// with EDPMServiceType set
CreateDataPlaneServiceFromSpec(dataplaneUpdateServiceName, map[string]interface{}{
"edpmServiceType": "foo-update-service",
"openStackAnsibleEERunnerImage": "foo-image:latest"})
deploymentSpec := DefaultDataPlaneDeploymentSpec()
deploymentSpec["ansibleEeConfig"] = map[string]json.RawMessage{
"envConfMapName": json.RawMessage([]byte("\"some-map\"")),
}
DeferCleanup(th.DeleteService, dataplaneServiceName)
DeferCleanup(th.DeleteService, dataplaneGlobalServiceName)
DeferCleanup(th.DeleteInstance, CreateNetConfig(dataplaneNetConfigName, DefaultNetConfigSpec()))
DeferCleanup(th.DeleteInstance, CreateDNSMasq(dnsMasqName, DefaultDNSMasqSpec()))
SimulateDNSMasqComplete(dnsMasqName)
DeferCleanup(th.DeleteInstance, CreateDataplaneNodeSet(dataplaneNodeSetName, DefaultDataPlaneNodeSetSpec(dataplaneNodeSetName.Name)))
SimulateIPSetComplete(dataplaneNodeName)
SimulateDNSDataComplete(dataplaneNodeSetName)
DeferCleanup(th.DeleteInstance, CreateDataplaneDeployment(dataplaneDeploymentName, deploymentSpec))
})

It("Should have Spec fields initialized", func() {
dataplaneDeploymentInstance := GetDataplaneDeployment(dataplaneDeploymentName)
expectedSpec := dataplanev1.OpenStackDataPlaneDeploymentSpec{
NodeSets: []string{"edpm-compute-nodeset"},
AnsibleTags: "",
AnsibleLimit: "",
AnsibleSkipTags: "",
BackoffLimit: &DefaultBackoffLimit,
PreserveJobs: true,
DeploymentRequeueTime: 15,
ServicesOverride: nil,
AnsibleEEConfig: map[string]json.RawMessage{
"envConfMapName": json.RawMessage([]byte(`"some-map"`)),
},
}
Expect(dataplaneDeploymentInstance.Spec).Should(Equal(expectedSpec))
})

It("should have conditions set", func() {

nodeSet := dataplanev1.OpenStackDataPlaneNodeSet{}
baremetal := baremetalv1.OpenStackBaremetalSet{
ObjectMeta: metav1.ObjectMeta{
Name: nodeSet.Name,
Namespace: nodeSet.Namespace,
},
}
// Create config map for OVN service
ovnConfigMapName := types.NamespacedName{
Namespace: namespace,
Name: "ovncontroller-config",
}
mapData := map[string]interface{}{
"ovsdb-config": "test-ovn-config",
}
th.CreateConfigMap(ovnConfigMapName, mapData)

nodeSet = *GetDataplaneNodeSet(dataplaneNodeSetName)

// Set baremetal provisioning conditions to True
Eventually(func(g Gomega) {
// OpenStackBaremetalSet has the same name as OpenStackDataPlaneNodeSet
g.Expect(th.K8sClient.Get(th.Ctx, dataplaneNodeSetName, &baremetal)).To(Succeed())
baremetal.Status.Conditions.MarkTrue(
condition.ReadyCondition,
condition.ReadyMessage)
g.Expect(th.K8sClient.Status().Update(th.Ctx, &baremetal)).To(Succeed())

}, th.Timeout, th.Interval).Should(Succeed())

// Create all services necessary for deployment
for _, serviceName := range nodeSet.Spec.Services {
dataplaneServiceName := types.NamespacedName{
Name: serviceName,
Namespace: namespace,
}
service := GetService(dataplaneServiceName)
deployment := GetDataplaneDeployment(dataplaneDeploymentName)
//Retrieve service AnsibleEE and set JobStatus to Successful
aeeName, _ := dataplaneutil.GetAnsibleExecutionNameAndLabels(
service, deployment.GetName(), nodeSet.GetName())
Eventually(func(g Gomega) {
// Make an AnsibleEE name for each service
ansibleeeName := types.NamespacedName{
Name: aeeName,
Namespace: dataplaneDeploymentName.Namespace,
}
ansibleEE := GetAnsibleee(ansibleeeName)

ansibleEE.Status.Succeeded = 1
g.Expect(th.K8sClient.Status().Update(th.Ctx, ansibleEE)).To(Succeed())
if service.Spec.EDPMServiceType != "" {
g.Expect(findEnvVar(ansibleEE.Spec.Template.Spec.Containers[0].Env).Value).To(ContainSubstring("edpm_service_type"))
g.Expect(findEnvVar(ansibleEE.Spec.Template.Spec.Containers[0].Env).Value).To(ContainSubstring(service.Spec.EDPMServiceType))
} else {
g.Expect(findEnvVar(ansibleEE.Spec.Template.Spec.Containers[0].Env).Value).To(ContainSubstring(serviceName))
}
if service.Spec.DeployOnAllNodeSets {
g.Expect(findEnvVar(ansibleEE.Spec.Template.Spec.Containers[0].Env).Value).To(ContainSubstring("edpm_override_hosts"))
g.Expect(findEnvVar(ansibleEE.Spec.Template.Spec.Containers[0].Env).Value).To(ContainSubstring("all"))
} else {
g.Expect(findEnvVar(ansibleEE.Spec.Template.Spec.Containers[0].Env).Value).To(ContainSubstring("edpm_override_hosts"))
g.Expect(findEnvVar(ansibleEE.Spec.Template.Spec.Containers[0].Env).Value).To(ContainSubstring(dataplaneNodeSetName.Name))
}
}, th.Timeout, th.Interval).Should(Succeed())
}

th.ExpectCondition(
dataplaneDeploymentName,
ConditionGetterFunc(DataplaneDeploymentConditionGetter),
condition.ReadyCondition,
corev1.ConditionTrue,
)
th.ExpectCondition(
dataplaneDeploymentName,
ConditionGetterFunc(DataplaneDeploymentConditionGetter),
condition.InputReadyCondition,
corev1.ConditionTrue,
)
})
})
})

0 comments on commit ad8e3a0

Please sign in to comment.