From 574d504fad30ccab845c6b5664324f9422e8babb Mon Sep 17 00:00:00 2001 From: Fabricio Aguiar Date: Wed, 6 Mar 2024 14:50:39 +0000 Subject: [PATCH] Add AnsibleVarsFrom Inspired by Pod's Env x EnvFrom: https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/#define-an-environment-variable-for-a-container https://github.com/kubernetes/kubernetes/blob/v1.28.7/pkg/apis/core/types.go#L2321-L2330 https://github.com/kubernetes/kubernetes/blob/v1.28.7/pkg/kubelet/kubelet_pods.go#L619 AnsibleVarsFrom will add variables from ConfigMap/Secret to the inventory, variables from AnsibleVars will take precedence Signed-off-by: Fabricio Aguiar --- ...nstack.org_openstackdataplanenodesets.yaml | 46 +++++++++ api/v1beta1/common.go | 5 + api/v1beta1/zz_generated.deepcopy.go | 7 ++ ...nstack.org_openstackdataplanenodesets.yaml | 46 +++++++++ ...ane_v1beta1_openstackdataplanenodeset.yaml | 4 +- docs/assemblies/ansible.adoc | 62 ++++++++++++- docs/assemblies/custom_resources.adoc | 5 + ...oc_creating-a-set-of-data-plane-nodes.adoc | 60 ++++++++++++ examples/base/config/varsfromname.yaml | 13 +++ .../base/crs/openstackdataplanenodeset.yaml | 59 ++++-------- examples/base/kustomization.yaml | 3 + examples/base/vars/neutron.yaml | 7 ++ examples/base/vars/nic-config.yaml | 37 ++++++++ examples/bgp/values.yaml | 4 +- examples/bgp_ovn_cluster/values.yaml | 4 +- examples/customnetworks/values.yaml | 4 +- examples/networker/values.yaml | 4 +- examples/nmstate/values.yaml | 4 +- examples/ovs_dpdk/values.yaml | 4 +- examples/post_ceph_hci/values.yaml | 4 +- examples/pre_ceph_hci/values.yaml | 4 +- pkg/deployment/inventory.go | 93 ++++++++++++++++++- .../dataplane-create-test/00-assert.yaml | 1 - .../00-dataplane-create.yaml | 43 ++++++++- .../00-assert.yaml | 5 +- .../00-dataplane-create.yaml | 44 ++++++++- .../dataplane-deploy-tls-test/00-assert.yaml | 5 +- .../00-dataplane-create.yaml | 43 ++++++++- .../00-assert.yaml | 5 +- .../00-dataplane-create.yaml | 43 ++++++++- 30 files changed, 593 insertions(+), 75 deletions(-) create mode 100644 examples/base/config/varsfromname.yaml create mode 100644 examples/base/vars/neutron.yaml create mode 100644 examples/base/vars/nic-config.yaml diff --git a/api/bases/dataplane.openstack.org_openstackdataplanenodesets.yaml b/api/bases/dataplane.openstack.org_openstackdataplanenodesets.yaml index 0c0e51a49..5720f9991 100644 --- a/api/bases/dataplane.openstack.org_openstackdataplanenodesets.yaml +++ b/api/bases/dataplane.openstack.org_openstackdataplanenodesets.yaml @@ -277,6 +277,29 @@ spec: type: string ansibleVars: x-kubernetes-preserve-unknown-fields: true + ansibleVarsFrom: + items: + properties: + configMapRef: + properties: + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array type: object ansibleSSHPrivateKeySecret: type: string @@ -1078,6 +1101,29 @@ spec: type: string ansibleVars: x-kubernetes-preserve-unknown-fields: true + ansibleVarsFrom: + items: + properties: + configMapRef: + properties: + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array type: object extraMounts: items: diff --git a/api/v1beta1/common.go b/api/v1beta1/common.go index 112ae95c2..d0ca6c650 100644 --- a/api/v1beta1/common.go +++ b/api/v1beta1/common.go @@ -43,6 +43,11 @@ type AnsibleOpts struct { // +kubebuilder:pruning:PreserveUnknownFields // +kubebuilder:validation:Schemaless AnsibleVars map[string]json.RawMessage `json:"ansibleVars,omitempty"` + + // AnsibleVarsFrom is a list of sources to populate ansible variables from. + // Values defined by an AnsibleVars with a duplicate key take precedence. + // +kubebuilder:validation:Optional + AnsibleVarsFrom []corev1.EnvFromSource `json:"ansibleVarsFrom,omitempty"` } // NodeSection defines the top level attributes inherited by nodes in the CR. diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index 194277b09..18cbad19f 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -102,6 +102,13 @@ func (in *AnsibleOpts) DeepCopyInto(out *AnsibleOpts) { (*out)[key] = outVal } } + if in.AnsibleVarsFrom != nil { + in, out := &in.AnsibleVarsFrom, &out.AnsibleVarsFrom + *out = make([]v1.EnvFromSource, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AnsibleOpts. diff --git a/config/crd/bases/dataplane.openstack.org_openstackdataplanenodesets.yaml b/config/crd/bases/dataplane.openstack.org_openstackdataplanenodesets.yaml index 0c0e51a49..5720f9991 100644 --- a/config/crd/bases/dataplane.openstack.org_openstackdataplanenodesets.yaml +++ b/config/crd/bases/dataplane.openstack.org_openstackdataplanenodesets.yaml @@ -277,6 +277,29 @@ spec: type: string ansibleVars: x-kubernetes-preserve-unknown-fields: true + ansibleVarsFrom: + items: + properties: + configMapRef: + properties: + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array type: object ansibleSSHPrivateKeySecret: type: string @@ -1078,6 +1101,29 @@ spec: type: string ansibleVars: x-kubernetes-preserve-unknown-fields: true + ansibleVarsFrom: + items: + properties: + configMapRef: + properties: + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array type: object extraMounts: items: diff --git a/config/samples/dataplane_v1beta1_openstackdataplanenodeset.yaml b/config/samples/dataplane_v1beta1_openstackdataplanenodeset.yaml index 1ed41fef8..736cf070f 100644 --- a/config/samples/dataplane_v1beta1_openstackdataplanenodeset.yaml +++ b/config/samples/dataplane_v1beta1_openstackdataplanenodeset.yaml @@ -44,8 +44,8 @@ spec: ansibleVars: # CHANGEME -- see https://access.redhat.com/solutions/253273 # edpm_bootstrap_command: | - # subscription-manager register --username --password - # podman login -u -p registry.redhat.io + # subscription-manager register --username {{ subscription_manager_username }} --password {{ subscription_manager_password }} + # podman login -u {{ registry_username }} -p {{ registry_password }} registry.redhat.io edpm_network_config_template: | --- {% set mtu_list = [ctlplane_mtu] %} diff --git a/docs/assemblies/ansible.adoc b/docs/assemblies/ansible.adoc index 9f1d70c8f..e17d7e544 100644 --- a/docs/assemblies/ansible.adoc +++ b/docs/assemblies/ansible.adoc @@ -8,11 +8,65 @@ OpenStackDataPlaneServices>> section. Common configurations that can be enabled with `ansibleVars` are also documented at xref:common_configurations.adoc[Common Configurations]. -''' - -*NOTE* - +[NOTE] +==== In the case of `ansibleVars`, the value is merged with that of the value from the nodeTemplate. This makes it so that the entire value of `ansibleVars` from the nodeTemplate does not need to be reproduced for each node just to set a few node specific values. +==== + +== Importing ansible variables + +`ansibleVarsFrom` allows you to set ansible variables for an `OpenStackDataPlaneNodeSet` by +referencing either a ConfigMap or a Secret. When you use `ansibleVarsFrom`, all the key-value +pairs in the referenced ConfigMap or Secret are set as environment variables for the `OpenStackDataPlaneNodeSet`. +You can also specify a common prefix string. + +.Example: +Adding ansible variables from ConfigMap: + +. Create a ConfigMap containing the ansible variables + + apiVersion: v1 + kind: ConfigMap + metadata: + name: common-edpm-vars + data: + edpm_config_var1: value1 + edpm_config_var2: value2 + +. Update the `ansibleVarsFrom` with the ConfigMap name + + ansibleVarsFrom: + - configMapRef: + name: common-edpm-vars + +.Example: +Execute `subscription-manager register` from corresponding Secret + +. Create a Secret containing the credentials + + apiVersion: v1 + kind: Secret + metadata: + name: subscription-manager + data: + username: + password: + +. Update the `ansibleVarsFrom` with the Secret name, and `ansibleVars` with the variables generated from the Secret + + ansibleVarsFrom: + - prefix: subscription_manager_ + secretRef: + name: subscription-manager + ansibleVars: + edpm_bootstrap_command: | + subscription-manager register --username {{ subscription_manager_username }} --password {{ subscription_manager_password }} + ++ +[NOTE] +==== +Values defined by an ansibleVars with a duplicate key take precedence +==== diff --git a/docs/assemblies/custom_resources.adoc b/docs/assemblies/custom_resources.adoc index 8fcece34f..dada8ac96 100644 --- a/docs/assemblies/custom_resources.adoc +++ b/docs/assemblies/custom_resources.adoc @@ -107,6 +107,11 @@ AnsibleOpts defines a logical grouping of Ansible related configuration options. | AnsibleVars for configuring ansible | map[string]json.RawMessage | false + +| ansibleVarsFrom +| AnsibleVarsFrom is a list of sources to populate ansible variables from. Values defined by an AnsibleVars with a duplicate key take precedence. +| []corev1.EnvFromSource +| false |=== <> diff --git a/docs/assemblies/proc_creating-a-set-of-data-plane-nodes.adoc b/docs/assemblies/proc_creating-a-set-of-data-plane-nodes.adoc index 6a980ba89..de746994a 100644 --- a/docs/assemblies/proc_creating-a-set-of-data-plane-nodes.adoc +++ b/docs/assemblies/proc_creating-a-set-of-data-plane-nodes.adoc @@ -162,7 +162,67 @@ spec: ---- + You can copy a sample template from https://github.com/openstack-k8s-operators/dataplane-operator/tree/main/config/samples/nic-config-samples. For information about customizing the template, see link:https://access.redhat.com/documentation/en-us/red_hat_openstack_platform/17.1/html/installing_and_managing_red_hat_openstack_platform_with_director/assembly_configuring-overcloud-networking_installing-director-on-the-undercloud#ref_network-interface-configuration-options_custom-network-interface-templates[Network interface configuration options]. +ifeval::["{build}" == "downstream"] +. Register the operating system of the nodes that are not registered to the Red Hat Customer Portal, and enable repositories for your nodes: ++ +---- +apiVersion: v1 +kind: Secret +metadata: + name: subscription-manager +data: + username: + password: +---- ++ +* Replace `` with the applicable user name. +* Replace `` with the applicable password. + ++ +---- +apiVersion: v1 +kind: Secret +metadata: + name: redhat-registry +data: + username: + password: +---- ++ +* Replace `` with the applicable user name. +* Replace `` with the applicable password. + ++ +---- +apiVersion: dataplane.openstack.org/v1beta1 +kind: OpenStackDataPlaneNodeSet +metadata: + name: openstack-edpm-ipam +spec: + preProvisioned: True + ... + nodeTemplate: + ansible: + ... + ansibleVars: + edpm_bootstrap_command: | + subscription-manager register --username {{ subscription_manager_username }} --password {{ subscription_manager_password }} + subscription-manager release --set=9.2 + subscription-manager repos --disable=* + subscription-manager repos --enable=rhel-9-for-x86_64-baseos-eus-rpms --enable=rhel-9-for-x86_64-appstream-eus-rpms --enable=rhel-9-for-x86_64-highavailability-eus-rpms --enable=openstack-17.1-for-rhel-9-x86_64-rpms --enable=fast-datapath-for-rhel-9-x86_64-rpms --enable=openstack-dev-preview-for-rhel-9-x86_64-rpms + podman login -u {{ registry_username }} -p {{ registry_password }} registry.redhat.io + ansibleVarsFrom: + - prefix: subscription_manager_ + secretRef: + name: subscription-manager + - prefix: registry_ + secretRef: + name: redhat-registry +---- ++ +For a complete list of the Red Hat Customer Portal registration commands, see https://access.redhat.com/solutions/253273. For information about how to log into `registry.redhat.io`, see https://access.redhat.com/RegistryAuthentication#creating-registry-service-accounts-6. +endif::[] . If your nodes are bare metal, you must configure the bare metal template, see xref:con_provisioning-bare-metal-data-plane-nodes_{context}[Provisioning bare metal data plane nodes]. . Optional: The sample `OpenStackDataPlaneNodeSet` CR you copied includes default node configurations under the `nodes` section. You can add additional nodes, and edit the configured values as required. For example, to add node-specific Ansible variables that customize the node, add the following configuration to your `openstack-edpm.yaml` file: diff --git a/examples/base/config/varsfromname.yaml b/examples/base/config/varsfromname.yaml new file mode 100644 index 000000000..35be02c95 --- /dev/null +++ b/examples/base/config/varsfromname.yaml @@ -0,0 +1,13 @@ +# This file is for teaching kustomize how to substitute ansibleVarsFrom name reference in OpenStackDataPlaneNodeSet +nameReference: +- kind: ConfigMap + version: v1 + fieldSpecs: + - kind: OpenStackDataPlaneNodeSet + version: v1beta1 + group: dataplane.openstack.org + path: spec/nodeTemplate/ansible/ansibleVarsFrom/configMapRef/name + - kind: OpenStackDataPlaneNodeSet + version: v1beta1 + group: dataplane.openstack.org + path: spec/nodeTemplate/ansible/ansibleVarsFrom/secretRef/name diff --git a/examples/base/crs/openstackdataplanenodeset.yaml b/examples/base/crs/openstackdataplanenodeset.yaml index da417c850..d86bdf830 100644 --- a/examples/base/crs/openstackdataplanenodeset.yaml +++ b/examples/base/crs/openstackdataplanenodeset.yaml @@ -44,54 +44,27 @@ spec: nodeTemplate: ansibleSSHPrivateKeySecret: dataplane-ansible-ssh-private-key-secret ansible: + ansibleVarsFrom: + - prefix: edpm_ + configMapRef: + name: network-config-template + - prefix: neutron_ + configMapRef: + name: neutron-edpm + # CHANGEME -- see https://access.redhat.com/solutions/253273 + # - prefix: subscription_manager_ + # secretRef: + # name: subscription-manager + # - prefix: registry_ + # secretRef: + # name: redhat-registry ansibleVars: # CHANGEME -- see https://access.redhat.com/solutions/253273 # edpm_bootstrap_command: | - # subscription-manager register --username --password - # podman login -u -p registry.redhat.io - edpm_network_config_template: | - --- - {% set mtu_list = [ctlplane_mtu] %} - {% for network in role_networks %} - {{ mtu_list.append(lookup('vars', networks_lower[network] ~ '_mtu')) }} - {%- endfor %} - {% set min_viable_mtu = mtu_list | max %} - network_config: - - type: ovs_bridge - name: {{ neutron_physical_bridge_name }} - mtu: {{ min_viable_mtu }} - use_dhcp: false - dns_servers: {{ ctlplane_dns_nameservers }} - domain: {{ dns_search_domains }} - addresses: - - ip_netmask: {{ ctlplane_ip }}/{{ ctlplane_cidr }} - routes: {{ ctlplane_host_routes }} - members: - - type: interface - name: nic1 - mtu: {{ min_viable_mtu }} - # force the MAC address of the bridge to this interface - primary: true - {% for network in role_networks %} - - type: vlan - mtu: {{ lookup('vars', networks_lower[network] ~ '_mtu') }} - vlan_id: {{ lookup('vars', networks_lower[network] ~ '_vlan_id') }} - addresses: - - ip_netmask: - {{ lookup('vars', networks_lower[network] ~ '_ip') }}/{{ lookup('vars', networks_lower[network] ~ '_cidr') }} - routes: {{ lookup('vars', networks_lower[network] ~ '_host_routes') }} - {% endfor %} - - # These vars are for the network config templates themselves and are - # considered EDPM network defaults. - neutron_physical_bridge_name: br-ex - neutron_public_interface_name: eth0 - # edpm_nodes_validation + # subscription-manager register --username {{ subscription_manager_username }} --password {{ subscription_manager_password }} + # podman login -u {{ registry_username }} -p {{ registry_password }} registry.redhat.io edpm_nodes_validation_validate_controllers_icmp: false edpm_nodes_validation_validate_gateway_icmp: false - ctlplane_dns_nameservers: - - 192.168.122.1 - dns_search_domains: [] gather_facts: false enable_debug: false # edpm firewall, change the allowed CIDR if needed diff --git a/examples/base/kustomization.yaml b/examples/base/kustomization.yaml index 564293f80..a2b08d249 100644 --- a/examples/base/kustomization.yaml +++ b/examples/base/kustomization.yaml @@ -4,8 +4,11 @@ kind: Component resources: - crs/openstackdataplanenodeset.yaml - crs/openstackdataplanedeployment.yaml +- vars/nic-config.yaml +- vars/neutron.yaml namespace: openstack configurations: - config/nodesetname.yaml +- config/varsfromname.yaml diff --git a/examples/base/vars/neutron.yaml b/examples/base/vars/neutron.yaml new file mode 100644 index 000000000..8c21d8fa0 --- /dev/null +++ b/examples/base/vars/neutron.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: neutron-edpm +data: + physical_bridge_name: br-ex + public_interface_name: eth0 diff --git a/examples/base/vars/nic-config.yaml b/examples/base/vars/nic-config.yaml new file mode 100644 index 000000000..f210e0de7 --- /dev/null +++ b/examples/base/vars/nic-config.yaml @@ -0,0 +1,37 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: network-config-template +data: + network_config_template: | + --- + {% set mtu_list = [ctlplane_mtu] %} + {% for network in role_networks %} + {{ mtu_list.append(lookup('vars', networks_lower[network] ~ '_mtu')) }} + {%- endfor %} + {% set min_viable_mtu = mtu_list | max %} + network_config: + - type: ovs_bridge + name: {{ neutron_physical_bridge_name }} + mtu: {{ min_viable_mtu }} + use_dhcp: false + dns_servers: {{ ctlplane_dns_nameservers }} + domain: {{ dns_search_domains }} + addresses: + - ip_netmask: {{ ctlplane_ip }}/{{ ctlplane_cidr }} + routes: {{ ctlplane_host_routes }} + members: + - type: interface + name: nic1 + mtu: {{ min_viable_mtu }} + # force the MAC address of the bridge to this interface + primary: true + {% for network in role_networks %} + - type: vlan + mtu: {{ lookup('vars', networks_lower[network] ~ '_mtu') }} + vlan_id: {{ lookup('vars', networks_lower[network] ~ '_vlan_id') }} + addresses: + - ip_netmask: + {{ lookup('vars', networks_lower[network] ~ '_ip') }}/{{ lookup('vars', networks_lower[network] ~ '_cidr') }} + routes: {{ lookup('vars', networks_lower[network] ~ '_host_routes') }} + {% endfor %} diff --git a/examples/bgp/values.yaml b/examples/bgp/values.yaml index fb5439e1b..116de7c0e 100644 --- a/examples/bgp/values.yaml +++ b/examples/bgp/values.yaml @@ -12,8 +12,8 @@ data: vars: # CHANGEME -- see https://access.redhat.com/solutions/253273 # edpm_bootstrap_command: | - # subscription-manager register --username --password - # podman login -u -p registry.redhat.io + # subscription-manager register --username {{ subscription_manager_username }} --password {{ subscription_manager_password }} + # podman login -u {{ registry_username }} -p {{ registry_password }} registry.redhat.io timesync_ntp_servers: - hostname: pool.ntp.org # edpm_network_config diff --git a/examples/bgp_ovn_cluster/values.yaml b/examples/bgp_ovn_cluster/values.yaml index 1e89f9aad..43069e82f 100644 --- a/examples/bgp_ovn_cluster/values.yaml +++ b/examples/bgp_ovn_cluster/values.yaml @@ -12,8 +12,8 @@ data: vars: # CHANGEME -- see https://access.redhat.com/solutions/253273 # edpm_bootstrap_command: | - # subscription-manager register --username --password - # podman login -u -p registry.redhat.io + # subscription-manager register --username {{ subscription_manager_username }} --password {{ subscription_manager_password }} + # podman login -u {{ registry_username }} -p {{ registry_password }} registry.redhat.io timesync_ntp_servers: - hostname: pool.ntp.org # edpm_network_config diff --git a/examples/customnetworks/values.yaml b/examples/customnetworks/values.yaml index 36d656dd1..19f2a8b43 100644 --- a/examples/customnetworks/values.yaml +++ b/examples/customnetworks/values.yaml @@ -12,8 +12,8 @@ data: vars: # CHANGEME -- see https://access.redhat.com/solutions/253273 # edpm_bootstrap_command: | - # subscription-manager register --username --password - # podman login -u -p registry.redhat.io + # subscription-manager register --username {{ subscription_manager_username }} --password {{ subscription_manager_password }} + # podman login -u {{ registry_username }} -p {{ registry_password }} registry.redhat.io neutron_public_interface_name: enp7s0 ctlplane_dns_nameservers: diff --git a/examples/networker/values.yaml b/examples/networker/values.yaml index f83713705..64dd24f47 100644 --- a/examples/networker/values.yaml +++ b/examples/networker/values.yaml @@ -12,8 +12,8 @@ data: vars: # CHANGEME -- see https://access.redhat.com/solutions/253273 # edpm_bootstrap_command: | - # subscription-manager register --username --password - # podman login -u -p registry.redhat.io + # subscription-manager register --username {{ subscription_manager_username }} --password {{ subscription_manager_password }} + # podman login -u {{ registry_username }} -p {{ registry_password }} registry.redhat.io edpm_enable_chassis_gw: true nodes: edpm-networker-0: diff --git a/examples/nmstate/values.yaml b/examples/nmstate/values.yaml index 743deb30e..05bfd089a 100644 --- a/examples/nmstate/values.yaml +++ b/examples/nmstate/values.yaml @@ -12,8 +12,8 @@ data: vars: # CHANGEME -- see https://access.redhat.com/solutions/253273 # edpm_bootstrap_command: | - # subscription-manager register --username --password - # podman login -u -p registry.redhat.io + # subscription-manager register --username {{ subscription_manager_username }} --password {{ subscription_manager_password }} + # podman login -u {{ registry_username }} -p {{ registry_password }} registry.redhat.io edpm_network_config_hide_sensitive_logs: false edpm_network_config_template: | --- diff --git a/examples/ovs_dpdk/values.yaml b/examples/ovs_dpdk/values.yaml index fe118d2b6..6bb6c9ed9 100644 --- a/examples/ovs_dpdk/values.yaml +++ b/examples/ovs_dpdk/values.yaml @@ -18,8 +18,8 @@ data: vars: # CHANGEME -- see https://access.redhat.com/solutions/253273 # edpm_bootstrap_command: | - # subscription-manager register --username --password - # podman login -u -p registry.redhat.io + # subscription-manager register --username {{ subscription_manager_username }} --password {{ subscription_manager_password }} + # podman login -u {{ registry_username }} -p {{ registry_password }} registry.redhat.io edpm_network_config_hide_sensitive_logs: false edpm_network_config_template: | --- diff --git a/examples/post_ceph_hci/values.yaml b/examples/post_ceph_hci/values.yaml index 13d6b6580..56eb78056 100644 --- a/examples/post_ceph_hci/values.yaml +++ b/examples/post_ceph_hci/values.yaml @@ -14,8 +14,8 @@ data: - hostname: clock.redhat.com # CHANGEME -- see https://access.redhat.com/solutions/253273 # edpm_bootstrap_command: | - # subscription-manager register --username --password - # podman login -u -p registry.redhat.io + # subscription-manager register --username {{ subscription_manager_username }} --password {{ subscription_manager_password }} + # podman login -u {{ registry_username }} -p {{ registry_password }} registry.redhat.io edpm_iscsid_image: '{{ registry_url }}/openstack-iscsid:{{ image_tag }}' edpm_logrotate_crond_image: '{{ registry_url }}/openstack-cron:{{ image_tag }}' edpm_network_config_hide_sensitive_logs: false diff --git a/examples/pre_ceph_hci/values.yaml b/examples/pre_ceph_hci/values.yaml index 8ca589c39..83b6534a2 100644 --- a/examples/pre_ceph_hci/values.yaml +++ b/examples/pre_ceph_hci/values.yaml @@ -14,8 +14,8 @@ data: - hostname: clock.redhat.com # CHANGEME -- see https://access.redhat.com/solutions/253273 # edpm_bootstrap_command: | - # subscription-manager register --username --password - # podman login -u -p registry.redhat.io + # subscription-manager register --username {{ subscription_manager_username }} --password {{ subscription_manager_password }} + # podman login -u {{ registry_username }} -p {{ registry_password }} registry.redhat.io edpm_iscsid_image: '{{ registry_url }}/openstack-iscsid:{{ image_tag }}' edpm_logrotate_crond_image: '{{ registry_url }}/openstack-cron:{{ image_tag }}' edpm_network_config_hide_sensitive_logs: false diff --git a/pkg/deployment/inventory.go b/pkg/deployment/inventory.go index a7c9aae0f..7e866c2be 100644 --- a/pkg/deployment/inventory.go +++ b/pkg/deployment/inventory.go @@ -25,6 +25,9 @@ import ( "strings" yaml "gopkg.in/yaml.v3" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" dataplanev1 "github.com/openstack-k8s-operators/dataplane-operator/api/v1beta1" infranetworkv1 "github.com/openstack-k8s-operators/infra-operator/apis/network/v1beta1" @@ -34,13 +37,93 @@ import ( utils "github.com/openstack-k8s-operators/lib-common/modules/common/util" ) +// getAnsibleVarsFrom gets ansible vars from ConfigMap/Secret +func getAnsibleVarsFrom(ctx context.Context, helper *helper.Helper, namespace string, ansible *dataplanev1.AnsibleOpts) (map[string]string, error) { + + var ( + configMaps = make(map[string]*v1.ConfigMap) + secrets = make(map[string]*v1.Secret) + result = make(map[string]string) + ) + client := helper.GetClient() + + // AnsibleVars will override AnsibleVarsFrom variables. + // Process AnsibleVarsFrom first then allow AnsibleVars to replace existing values. + for _, varFrom := range ansible.AnsibleVarsFrom { + switch { + case varFrom.ConfigMapRef != nil: + cm := varFrom.ConfigMapRef + name := cm.Name + configMap, ok := configMaps[name] + if !ok { + optional := cm.Optional != nil && *cm.Optional + configMap = &v1.ConfigMap{} + err := client.Get(ctx, types.NamespacedName{Name: name, Namespace: namespace}, configMap) + if err != nil { + if errors.IsNotFound(err) && optional { + // ignore error when marked optional + utils.LogErrorForObject(helper, err, "could not get ansible vars, the configMap: "+name+"is missing", configMap) + continue + } + return result, err + } + configMaps[name] = configMap + } + + for k, v := range configMap.Data { + if len(varFrom.Prefix) > 0 { + k = varFrom.Prefix + k + } + + result[k] = v + } + + case varFrom.SecretRef != nil: + s := varFrom.SecretRef + name := s.Name + secret, ok := secrets[name] + if !ok { + optional := s.Optional != nil && *s.Optional + secret = &v1.Secret{} + err := client.Get(ctx, types.NamespacedName{Name: name, Namespace: namespace}, secret) + if err != nil { + if errors.IsNotFound(err) && optional { + // ignore error when marked optional + utils.LogErrorForObject(helper, err, "could not get ansible vars, the secret: "+name+"is missing", secret) + continue + } + return result, err + } + secrets[name] = secret + } + + for k, v := range secret.Data { + if len(varFrom.Prefix) > 0 { + k = varFrom.Prefix + k + } + result[k] = string(v) + } + } + } + + return result, nil +} + // GenerateNodeSetInventory yields a parsed Inventory for role func GenerateNodeSetInventory(ctx context.Context, helper *helper.Helper, instance *dataplanev1.OpenStackDataPlaneNodeSet, allIPSets map[string]infranetworkv1.IPSet, dnsAddresses []string, defaultImages dataplanev1.DataplaneAnsibleImageDefaults) (string, error) { inventory := ansible.MakeInventory() nodeSetGroup := inventory.AddGroup(instance.Name) - err := resolveGroupAnsibleVars(&instance.Spec.NodeTemplate, &nodeSetGroup, defaultImages) + groupVars, err := getAnsibleVarsFrom(ctx, helper, instance.Namespace, &instance.Spec.NodeTemplate.Ansible) + if err != nil { + utils.LogErrorForObject(helper, err, "could not get ansible group vars from configMap/secret", instance) + return "", err + } + for k, v := range groupVars { + nodeSetGroup.Vars[k] = v + } + err = resolveGroupAnsibleVars(&instance.Spec.NodeTemplate, &nodeSetGroup, defaultImages) if err != nil { utils.LogErrorForObject(helper, err, "Could not resolve ansible group vars", instance) return "", err @@ -58,6 +141,14 @@ func GenerateNodeSetInventory(ctx context.Context, helper *helper.Helper, for _, node := range instance.Spec.Nodes { host := nodeSetGroup.AddHost(strings.Split(node.HostName, ".")[0]) + hostVars, err := getAnsibleVarsFrom(ctx, helper, instance.Namespace, &node.Ansible) + if err != nil { + utils.LogErrorForObject(helper, err, "could not get ansible host vars from configMap/secret", instance) + return "", err + } + for k, v := range hostVars { + host.Vars[k] = v + } // Use ansible_host if provided else use hostname. Fall back to // nodeName if all else fails. if node.Ansible.AnsibleHost != "" { diff --git a/tests/kuttl/tests/dataplane-create-test/00-assert.yaml b/tests/kuttl/tests/dataplane-create-test/00-assert.yaml index 2fee9bf5d..de74c42ff 100644 --- a/tests/kuttl/tests/dataplane-create-test/00-assert.yaml +++ b/tests/kuttl/tests/dataplane-create-test/00-assert.yaml @@ -35,7 +35,6 @@ spec: timesync_ntp_servers: - hostname: clock.redhat.com edpm_network_config_hide_sensitive_logs: false - edpm_network_config_template: templates/single_nic_vlans/single_nic_vlans.j2 edpm_nodes_validation_validate_controllers_icmp: false edpm_nodes_validation_validate_gateway_icmp: false edpm_selinux_mode: enforcing diff --git a/tests/kuttl/tests/dataplane-create-test/00-dataplane-create.yaml b/tests/kuttl/tests/dataplane-create-test/00-dataplane-create.yaml index 91606cbb5..b6768e442 100644 --- a/tests/kuttl/tests/dataplane-create-test/00-dataplane-create.yaml +++ b/tests/kuttl/tests/dataplane-create-test/00-dataplane-create.yaml @@ -1,3 +1,41 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: network-config-template +data: + network_config_template: | + --- + {% set mtu_list = [ctlplane_mtu] %} + {% for network in role_networks %} + {{ mtu_list.append(lookup('vars', networks_lower[network] ~ '_mtu')) }} + {%- endfor %} + {% set min_viable_mtu = mtu_list | max %} + network_config: + - type: ovs_bridge + name: {{ neutron_physical_bridge_name }} + mtu: {{ min_viable_mtu }} + use_dhcp: false + dns_servers: {{ ctlplane_dns_nameservers }} + domain: {{ dns_search_domains }} + addresses: + - ip_netmask: {{ ctlplane_ip }}/{{ ctlplane_cidr }} + routes: {{ ctlplane_host_routes }} + members: + - type: interface + name: nic1 + mtu: {{ min_viable_mtu }} + # force the MAC address of the bridge to this interface + primary: true + {% for network in role_networks %} + - type: vlan + mtu: {{ lookup('vars', networks_lower[network] ~ '_mtu') }} + vlan_id: {{ lookup('vars', networks_lower[network] ~ '_vlan_id') }} + addresses: + - ip_netmask: + {{ lookup('vars', networks_lower[network] ~ '_ip') }}/{{ lookup('vars', networks_lower[network] ~ '_cidr') }} + routes: {{ lookup('vars', networks_lower[network] ~ '_host_routes') }} + {% endfor %} +--- apiVersion: dataplane.openstack.org/v1beta1 kind: OpenStackDataPlaneNodeSet metadata: @@ -38,6 +76,10 @@ spec: ansible: ansibleUser: cloud-admin ansiblePort: 22 + ansibleVarsFrom: + - prefix: edpm_ + configMapRef: + name: network-config-template ansibleVars: service_net_map: nova_api_network: internalapi @@ -48,7 +90,6 @@ spec: # Default nic config template for a EDPM compute node # These vars are edpm_network_config role vars edpm_network_config_hide_sensitive_logs: false - edpm_network_config_template: templates/single_nic_vlans/single_nic_vlans.j2 # These vars are for the network config templates themselves and are # considered EDPM network defaults. neutron_physical_bridge_name: br-ex diff --git a/tests/kuttl/tests/dataplane-deploy-global-service-test/00-assert.yaml b/tests/kuttl/tests/dataplane-deploy-global-service-test/00-assert.yaml index c2bcf943f..cf911d4bb 100644 --- a/tests/kuttl/tests/dataplane-deploy-global-service-test/00-assert.yaml +++ b/tests/kuttl/tests/dataplane-deploy-global-service-test/00-assert.yaml @@ -33,6 +33,10 @@ spec: ansible: ansibleUser: cloud-admin ansiblePort: 22 + ansibleVarsFrom: + - prefix: edpm_ + configMapRef: + name: network-config-template ansibleVars: service_net_map: nova_api_network: internalapi @@ -43,7 +47,6 @@ spec: # Default nic config template for a EDPM compute node # These vars are edpm_network_config role vars edpm_network_config_hide_sensitive_logs: false - edpm_network_config_template: templates/single_nic_vlans/single_nic_vlans.j2 # These vars are for the network config templates themselves and are # considered EDPM network defaults. neutron_physical_bridge_name: br-ex diff --git a/tests/kuttl/tests/dataplane-deploy-global-service-test/00-dataplane-create.yaml b/tests/kuttl/tests/dataplane-deploy-global-service-test/00-dataplane-create.yaml index 2a05369e8..25392204d 100644 --- a/tests/kuttl/tests/dataplane-deploy-global-service-test/00-dataplane-create.yaml +++ b/tests/kuttl/tests/dataplane-deploy-global-service-test/00-dataplane-create.yaml @@ -36,7 +36,6 @@ metadata: data: 10-neutron-ovn.conf: dGVzdC1uZXV0cm9uLW92bi1hZ2VudC1jb25maWc= --- ---- apiVersion: v1 kind: Secret metadata: @@ -75,6 +74,44 @@ spec: delegate_to: localhost deployOnAllNodeSets: true --- +apiVersion: v1 +kind: ConfigMap +metadata: + name: network-config-template +data: + network_config_template: | + --- + {% set mtu_list = [ctlplane_mtu] %} + {% for network in role_networks %} + {{ mtu_list.append(lookup('vars', networks_lower[network] ~ '_mtu')) }} + {%- endfor %} + {% set min_viable_mtu = mtu_list | max %} + network_config: + - type: ovs_bridge + name: {{ neutron_physical_bridge_name }} + mtu: {{ min_viable_mtu }} + use_dhcp: false + dns_servers: {{ ctlplane_dns_nameservers }} + domain: {{ dns_search_domains }} + addresses: + - ip_netmask: {{ ctlplane_ip }}/{{ ctlplane_cidr }} + routes: {{ ctlplane_host_routes }} + members: + - type: interface + name: nic1 + mtu: {{ min_viable_mtu }} + # force the MAC address of the bridge to this interface + primary: true + {% for network in role_networks %} + - type: vlan + mtu: {{ lookup('vars', networks_lower[network] ~ '_mtu') }} + vlan_id: {{ lookup('vars', networks_lower[network] ~ '_vlan_id') }} + addresses: + - ip_netmask: + {{ lookup('vars', networks_lower[network] ~ '_ip') }}/{{ lookup('vars', networks_lower[network] ~ '_cidr') }} + routes: {{ lookup('vars', networks_lower[network] ~ '_host_routes') }} + {% endfor %} +--- apiVersion: dataplane.openstack.org/v1beta1 kind: OpenStackDataPlaneNodeSet metadata: @@ -108,6 +145,10 @@ spec: ansible: ansibleUser: cloud-admin ansiblePort: 22 + ansibleVarsFrom: + - prefix: edpm_ + configMapRef: + name: network-config-template ansibleVars: service_net_map: nova_api_network: internalapi @@ -118,7 +159,6 @@ spec: # Default nic config template for a EDPM compute node # These vars are edpm_network_config role vars edpm_network_config_hide_sensitive_logs: false - edpm_network_config_template: templates/single_nic_vlans/single_nic_vlans.j2 # These vars are for the network config templates themselves and are # considered EDPM network defaults. neutron_physical_bridge_name: br-ex diff --git a/tests/kuttl/tests/dataplane-deploy-tls-test/00-assert.yaml b/tests/kuttl/tests/dataplane-deploy-tls-test/00-assert.yaml index 640353744..fc8a26b08 100644 --- a/tests/kuttl/tests/dataplane-deploy-tls-test/00-assert.yaml +++ b/tests/kuttl/tests/dataplane-deploy-tls-test/00-assert.yaml @@ -58,11 +58,14 @@ spec: ansible: ansiblePort: 22 ansibleUser: cloud-admin + ansibleVarsFrom: + - prefix: edpm_ + configMapRef: + name: network-config-template ansibleVars: timesync_ntp_servers: - hostname: clock.redhat.com edpm_network_config_hide_sensitive_logs: false - edpm_network_config_template: templates/single_nic_vlans/single_nic_vlans.j2 edpm_nodes_validation_validate_controllers_icmp: false edpm_nodes_validation_validate_gateway_icmp: false edpm_selinux_mode: enforcing diff --git a/tests/kuttl/tests/dataplane-deploy-tls-test/00-dataplane-create.yaml b/tests/kuttl/tests/dataplane-deploy-tls-test/00-dataplane-create.yaml index 40dcf59e0..e276e28f4 100644 --- a/tests/kuttl/tests/dataplane-deploy-tls-test/00-dataplane-create.yaml +++ b/tests/kuttl/tests/dataplane-deploy-tls-test/00-dataplane-create.yaml @@ -44,6 +44,44 @@ spec: command: sleep 1 delegate_to: localhost --- +apiVersion: v1 +kind: ConfigMap +metadata: + name: network-config-template +data: + network_config_template: | + --- + {% set mtu_list = [ctlplane_mtu] %} + {% for network in role_networks %} + {{ mtu_list.append(lookup('vars', networks_lower[network] ~ '_mtu')) }} + {%- endfor %} + {% set min_viable_mtu = mtu_list | max %} + network_config: + - type: ovs_bridge + name: {{ neutron_physical_bridge_name }} + mtu: {{ min_viable_mtu }} + use_dhcp: false + dns_servers: {{ ctlplane_dns_nameservers }} + domain: {{ dns_search_domains }} + addresses: + - ip_netmask: {{ ctlplane_ip }}/{{ ctlplane_cidr }} + routes: {{ ctlplane_host_routes }} + members: + - type: interface + name: nic1 + mtu: {{ min_viable_mtu }} + # force the MAC address of the bridge to this interface + primary: true + {% for network in role_networks %} + - type: vlan + mtu: {{ lookup('vars', networks_lower[network] ~ '_mtu') }} + vlan_id: {{ lookup('vars', networks_lower[network] ~ '_vlan_id') }} + addresses: + - ip_netmask: + {{ lookup('vars', networks_lower[network] ~ '_ip') }}/{{ lookup('vars', networks_lower[network] ~ '_cidr') }} + routes: {{ lookup('vars', networks_lower[network] ~ '_host_routes') }} + {% endfor %} +--- apiVersion: dataplane.openstack.org/v1beta1 kind: OpenStackDataPlaneNodeSet metadata: @@ -76,6 +114,10 @@ spec: ansible: ansibleUser: cloud-admin ansiblePort: 22 + ansibleVarsFrom: + - prefix: edpm_ + configMapRef: + name: network-config-template ansibleVars: timesync_ntp_servers: - hostname: clock.redhat.com @@ -83,7 +125,6 @@ spec: # Default nic config template for a EDPM compute node # These vars are edpm_network_config role vars edpm_network_config_hide_sensitive_logs: false - edpm_network_config_template: templates/single_nic_vlans/single_nic_vlans.j2 edpm_nodes_validation_validate_controllers_icmp: false edpm_nodes_validation_validate_gateway_icmp: false gather_facts: false diff --git a/tests/kuttl/tests/dataplane-with-ipam-create-test/00-assert.yaml b/tests/kuttl/tests/dataplane-with-ipam-create-test/00-assert.yaml index dbe1303d2..96a1da9da 100644 --- a/tests/kuttl/tests/dataplane-with-ipam-create-test/00-assert.yaml +++ b/tests/kuttl/tests/dataplane-with-ipam-create-test/00-assert.yaml @@ -25,11 +25,14 @@ spec: ansible: ansiblePort: 22 ansibleUser: cloud-admin + ansibleVarsFrom: + - prefix: edpm_ + configMapRef: + name: network-config-template ansibleVars: timesync_ntp_servers: - hostname: clock.redhat.com edpm_network_config_hide_sensitive_logs: false - edpm_network_config_template: templates/single_nic_vlans/single_nic_vlans.j2 edpm_nodes_validation_validate_controllers_icmp: false edpm_nodes_validation_validate_gateway_icmp: false edpm_selinux_mode: enforcing diff --git a/tests/kuttl/tests/dataplane-with-ipam-create-test/00-dataplane-create.yaml b/tests/kuttl/tests/dataplane-with-ipam-create-test/00-dataplane-create.yaml index 92d14b0e4..a2949345b 100644 --- a/tests/kuttl/tests/dataplane-with-ipam-create-test/00-dataplane-create.yaml +++ b/tests/kuttl/tests/dataplane-with-ipam-create-test/00-dataplane-create.yaml @@ -11,6 +11,44 @@ spec: debug: service: false --- +apiVersion: v1 +kind: ConfigMap +metadata: + name: network-config-template +data: + network_config_template: | + --- + {% set mtu_list = [ctlplane_mtu] %} + {% for network in role_networks %} + {{ mtu_list.append(lookup('vars', networks_lower[network] ~ '_mtu')) }} + {%- endfor %} + {% set min_viable_mtu = mtu_list | max %} + network_config: + - type: ovs_bridge + name: {{ neutron_physical_bridge_name }} + mtu: {{ min_viable_mtu }} + use_dhcp: false + dns_servers: {{ ctlplane_dns_nameservers }} + domain: {{ dns_search_domains }} + addresses: + - ip_netmask: {{ ctlplane_ip }}/{{ ctlplane_cidr }} + routes: {{ ctlplane_host_routes }} + members: + - type: interface + name: nic1 + mtu: {{ min_viable_mtu }} + # force the MAC address of the bridge to this interface + primary: true + {% for network in role_networks %} + - type: vlan + mtu: {{ lookup('vars', networks_lower[network] ~ '_mtu') }} + vlan_id: {{ lookup('vars', networks_lower[network] ~ '_vlan_id') }} + addresses: + - ip_netmask: + {{ lookup('vars', networks_lower[network] ~ '_ip') }}/{{ lookup('vars', networks_lower[network] ~ '_cidr') }} + routes: {{ lookup('vars', networks_lower[network] ~ '_host_routes') }} + {% endfor %} +--- apiVersion: dataplane.openstack.org/v1beta1 kind: OpenStackDataPlaneNodeSet metadata: @@ -52,6 +90,10 @@ spec: ansible: ansibleUser: cloud-admin ansiblePort: 22 + ansibleVarsFrom: + - prefix: edpm_ + configMapRef: + name: network-config-template ansibleVars: timesync_ntp_servers: - hostname: clock.redhat.com @@ -59,7 +101,6 @@ spec: # Default nic config template for a EDPM compute node # These vars are edpm_network_config role vars edpm_network_config_hide_sensitive_logs: false - edpm_network_config_template: templates/single_nic_vlans/single_nic_vlans.j2 edpm_nodes_validation_validate_controllers_icmp: false edpm_nodes_validation_validate_gateway_icmp: false gather_facts: false