diff --git a/.ansible-lint b/.ansible-lint index bba0013e10..eca5d61350 100644 --- a/.ansible-lint +++ b/.ansible-lint @@ -19,6 +19,7 @@ exclude_paths: - roles/reproducer/files/cifmw-bootstrap.yml # invalid due to calls to "lookup('file')" - roles/kustomize_deploy/molecule/flexible_loop/files/networking-environment-definition.yml # Generated - roles/kustomize_deploy/molecule/flexible_loop/prepare.yml # import_playbook + - roles/*/molecule/*/side_effect.yml # syntax-check[empty-playbook] https://github.com/ansible/molecule/issues/3617 strict: true quiet: false verbosity: 1 diff --git a/roles/ci_multus/README.md b/roles/ci_multus/README.md index edc1a1ab89..dbf302246a 100644 --- a/roles/ci_multus/README.md +++ b/roles/ci_multus/README.md @@ -1,80 +1,90 @@ # ci_multus -Creates additional networks in a OCP cluster using NetworkAttachmentDefinition (NAD) resources. + +Creates additional networks in a OCP cluster using NetworkAttachmentDefinition +(NAD) resources. ## Parameters + * `cifmw_ci_multus_basedir`: (String) Base directory. Defaults to `cifmw_basedir` which defaults to `~/ci-framework-data`. * `cifmw_ci_multus_manifests_dir`: (String) Directory in where OCP manifests will be placed. Defaults to `"{{ cifmw_manifests | default(cifmw_ci_multus_basedir ~ '/artifacts/manifests') }}"`. -* `cifmw_ci_multus_namespace`: (String) The namespace where OCP resources will be installed. Defaults to `ci-multus`. +* `cifmw_ci_multus_namespace`: (String) The namespace where OCP resources will be installed. Defaults to `openstack`. * `cifmw_ci_multus_ocp_hostname`: (String) The OCP inventory hostname. Used to gather network information specific to those nodes, mostly the interfaces. Defaults to `crc`. * `cifmw_ci_multus_cniversion`: (String) The CNI specification version used when creating the resource. Defaults to `0.3.1`. * `cifmw_ci_multus_default_nad_type`: (String) Default NAD type used when not specified by the network configuration. Defaults to `macvlan`. * `cifmw_ci_multus_default_nad_ipam_type`: (String) Default NAD IPAM type to be used when not specified by the network configuration. Defaults to `whereabouts`. -* `cifmw_ci_multus_nad_list`: (List) List of NAD configuration to be created in destination OCP cluster. When not provided, `ci_multus` will build a list based on known cifmw variables (`cifmw_network_layout`, `crc_ci_bootstrap_networks_out`).Defaults to `[]`. -* `cifmw_ci_multus_nad_extra_list`: (List) Additional list of NAD configuration to be created in destination OCP cluster. Defaults to `[]`. +* `cifmw_ci_multus_default_nad_ipam_type_ip_version``: (String) Default IP version to use in IPAM config. Defaults to `v4`. +* `cifmw_ci_multus_dryrun`: (Bool) When enabled, tasks that require an OCP environment are skipped. Defaults to `false`. +* `cifmw_ci_multus_allow_list`: (List) Adding network names to this list allows you to define what networks will be rendered into the NAD manifest. Defaults to `[]`. +* `cifmw_ci_multus_deny_list`: (List) Adding network names to this list allows you to define what networks should be skipped from being rendered into the NAD manifest. Defaults to `[]`. + +By default the `ci_multus` role reads the `cifmw_networking_env_definition` variable to generate NetworkAttachmentDefinition manifests for networks who have the Multus tool defined. -## NAD configuration layout -The user can provide a list of NAD configuration as follow: +In addition to that, you can also pass any number of "patch" variables using `cifmw_ci_multus_net_info_patch` that allow you to extend the config used to render the NetworkAttachmentDefinition manifests. +For a working example, please see `cifmw_ci_multus_net_info_patch_1` in molecule/local/molecule.yml + +## cifmw_ci_multus_net_info_patch example ```YAML -cifmw_ci_multus_nad_list: - - name: storage - iface: enps6s0.21 - type: macvlan - ipam: - type: whereabouts - range: 172.18.0.0/24 - range_start: 172.18.0.30 - range_end: 172.18.0.70 - - name: bgpnet1 - iface: bgpiface - type: interface - ipam: - type: whereabouts - range: 100.65.4.0/30 - range_start: 100.65.4.1 - range_end: 100.65.4.2 +cifmw_ci_multus_net_info_patch_1: + patchnetwork: + gw_v4: 192.168.122.1 + network_name: patchnetwork + network_v4: 192.168.122.0/24 + interface_name: eth2 + tools: + multus: + ipv4_ranges: + - start: 192.168.122.30 + end: 192.168.122.70 ``` -`cifmw_ci_multus_nad_list` can be passed directly, but if not given it will default, by that order, to the following: -1. The content of the `cifmw_network_layout` variable. -2. The content of the `crc_ci_bootstrap_networks_out` variable. -3. The content of the `crc_ci_bootstrap_networks_out` variable loaded from `/etc/ci/env`. - -If an additional NAD configuration needs to be configured, in addition to the content build from cifmw variables, the `cifmw_ci_multus_nad_extra_list` can be specified. ## Limitations + * Not all NetworkAttachmentDefinition types and parameters are supported by this role. * Not all IPAM configurations are supported by this role. * When consuming network info from CI variables, the user must provide the OCP host, using `cifmw_ci_multus_ocp_hostname` parameter, since the role doesn't perform a Node discovery on the OCP node. ## Examples -### 1 - Use of `cifmw_ci_multus_nad_list`: + +### 1 - Default use case consuming cifmw_networking_env_definition + ```YAML - name: Configure additional networks using multus - vars: - cifmw_ci_multus_nad_list: - - name: storage - iface: enps6s0.21 - type: macvlan - ipam: - type: whereabouts - range: 172.18.0.0/24 - range_start: 172.18.0.30 - range_end: 172.18.0.70 ansible.builtin.include_role: name: "ci_multus" ``` -### 2 - Content from `cifmw_network_layout`: + +### 2 - Using patch: + ```YAML - name: Configure additional networks using multus vars: - cifmw_network_layout: - networks: - default: - iface: enps6s0 - mtu: 1500 - range: 192.168.122.0/24 + cifmw_ci_multus_net_info_patch_1: + patchnetwork: + gw_v4: 192.168.122.1 + network_name: patchnetwork + network_v4: 192.168.122.0/24 + interface_name: eth2 + tools: multus: - range: 192.168.122.30-192.168.122.70 + ipv4_ranges: + - start: 192.168.122.30 + end: 192.168.122.70 + ansible.builtin.include_role: + name: "ci_multus" +``` + +### 2 - Using allow and deny list: + +```YAML + - name: Configure additional networks using multus + vars: + cifmw_ci_multus_allow_list: + - default + - awesomenet + - maybenet + cifmw_ci_multus_deny_list: + - maybenet ansible.builtin.include_role: name: "ci_multus" ``` diff --git a/roles/ci_multus/defaults/main.yml b/roles/ci_multus/defaults/main.yml index 3f34397d3e..24b9166223 100644 --- a/roles/ci_multus/defaults/main.yml +++ b/roles/ci_multus/defaults/main.yml @@ -20,11 +20,13 @@ cifmw_ci_multus_basedir: "{{ cifmw_basedir | default(ansible_user_dir ~ '/ci-framework-data') }}" cifmw_ci_multus_manifests_dir: "{{ cifmw_manifests | default(cifmw_ci_multus_basedir ~ '/artifacts/manifests') }}/ci_multus" -cifmw_ci_multus_namespace: "ci-multus" +cifmw_ci_multus_namespace: "openstack" cifmw_ci_multus_ocp_hostname: "crc" cifmw_ci_multus_cniversion: "0.3.1" cifmw_ci_multus_default_nad_type: "macvlan" cifmw_ci_multus_default_nad_ipam_type: "whereabouts" +cifmw_ci_multus_default_nad_ipam_type_ip_version: "v4" # Input configuration for ci_multus role -cifmw_ci_multus_nad_list: [] -cifmw_ci_multus_nad_extra_list: [] +cifmw_ci_multus_dryrun: false +cifmw_ci_multus_allow_list: [] +cifmw_ci_multus_deny_list: [] diff --git a/roles/ci_multus/molecule/default/converge.yml b/roles/ci_multus/molecule/default/converge.yml index 8817d8aeff..07d790fef9 100644 --- a/roles/ci_multus/molecule/default/converge.yml +++ b/roles/ci_multus/molecule/default/converge.yml @@ -14,14 +14,9 @@ # License for the specific language governing permissions and limitations # under the License. - - name: Converge hosts: all gather_facts: true - vars: - cifmw_path: "{{ ansible_user_dir }}/.crc/bin:{{ ansible_user_dir }}/.crc/bin/oc:{{ ansible_user_dir }}/bin:{{ ansible_env.PATH }}" - cifmw_openshift_kubeconfig: "{{ ansible_user_dir }}/.crc/machines/crc/kubeconfig" - testpod_name: "pod-testnad" tasks: - name: Add crc hostname with it's IP to /etc/hosts become: true @@ -41,161 +36,21 @@ delegate_to: crc delegate_facts: true - - name: Prepare the network var for the role + - name: Load shared variables + ansible.builtin.include_vars: + file: ../resources/vars/shared_vars.yml + + - name: Override interface name in cifmw_networking_env_definition + vars: + _cifmw_networking_env_definition_patch: + instances: + crc: + networks: + default: + interface_name: "{{ hostvars.crc.ansible_default_ipv4.interface }}" ansible.builtin.set_fact: - crc_ci_bootstrap_networks_out: - networks: - default: - iface: "{{ hostvars.crc.ansible_default_ipv4.interface }}" - mtu: 1500 - range: 192.168.122.0/24 - multus: - range: 192.168.122.30-192.168.122.70 - cifmw_ci_multus_nad_extra_list: - - name: bgpnet1 - iface: bgpnet1_iface - type: interface - ipam: - type: whereabouts - range: 100.65.4.0/30 - range_start: 100.65.4.1 - range_end: 100.65.4.2 + cifmw_networking_env_definition: "{{ cifmw_networking_env_definition | combine(_cifmw_networking_env_definition_patch, recursive=True) }}" - name: Call ci_multus role ansible.builtin.include_role: name: "ci_multus" - - # Verify the run - - name: Fetch files stat results - ansible.builtin.stat: - path: >- - {{ - [ - ansible_user_dir, - 'ci-framework-data', - 'artifacts', - item - ] | ansible.builtin.path_join - }} - register: _ci_multus_molecule_stat_out - loop: - - manifests/ci_multus/ci_multus_nads.yml - - - name: Assert that all expected files exist - ansible.builtin.assert: - that: >- - _ci_multus_molecule_stat_out.results | - map(attribute="stat.exists") | - select("equalto", true) | - length == (_ci_multus_molecule_stat_out.results | length) - - - name: Fetch all files content - ansible.builtin.slurp: - path: "{{ item }}" - register: _ci_multus_molecule_slurp_out - loop: >- - {{ - _ci_multus_molecule_stat_out.results | - map(attribute="stat.path") - }} - - - name: Assert that all files contains proper YAML data - ansible.builtin.assert: - that: "item.content | b64decode | from_yaml_all | length > 0" - loop: "{{ _ci_multus_molecule_slurp_out.results }}" - loop_control: - label: "{{ item.source }}" - - - name: Check if NADs were created - kubernetes.core.k8s_info: - kubeconfig: "{{ cifmw_openshift_kubeconfig }}" - namespace: "{{ cifmw_ci_multus_namespace }}" - api_version: k8s.cni.cncf.io/v1 - kind: NetworkAttachmentDefinition - register: _ci_multus_molecule_nads_out - failed_when: >- - (_ci_multus_molecule_nads_out is not defined) or - (_ci_multus_molecule_nads_out is failed) or - (_ci_multus_molecule_nads_out.resources | length == 0) - - - name: Create a test pod to attach a network - kubernetes.core.k8s: - kubeconfig: "{{ cifmw_openshift_kubeconfig }}" - namespace: "{{ cifmw_ci_multus_namespace }}" - state: present - definition: - api_version: v1 - kind: Pod - metadata: - name: "{{ testpod_name }}" - annotations: - k8s.v1.cni.cncf.io/networks: default - spec: - containers: - - name: testnad - image: quay.rdoproject.org/openstack-k8s-operators/alpine:latest - imagePullPolicy: Always - command: - - "/bin/ash" - - "-c" - - "trap : TERM INT; sleep infinity & wait" - wait: true - wait_sleep: 10 - wait_timeout: 300 - wait_condition: - type: Ready - status: "True" - register: _ci_multus_molecule_test_pod_out - - - name: Assert that test pod has the additional network - ansible.builtin.assert: - that: - - _ci_multus_molecule_test_pod_out.result.metadata.annotations[ - 'k8s.v1.cni.cncf.io/networks'] == "default" - - - name: Delete test pod - kubernetes.core.k8s: - kubeconfig: "{{ cifmw_openshift_kubeconfig }}" - api_key: "{{ cifmw_openshift_token | default(omit)}}" - context: "{{ cifmw_openshift_context | default(omit)}}" - namespace: "{{ cifmw_ci_multus_namespace }}" - state: absent - api_version: v1 - kind: Pod - name: "{{ testpod_name }}" - - - name: Call cleanup - ansible.builtin.import_role: - name: ci_multus - tasks_from: cleanup.yml - - - name: Check if NADs were deleted - kubernetes.core.k8s_info: - kubeconfig: "{{ cifmw_openshift_kubeconfig }}" - namespace: "{{ cifmw_ci_multus_namespace }}" - api_version: k8s.cni.cncf.io/v1 - kind: NetworkAttachmentDefinition - register: _ci_multus_molecule_nads_cleanup_out - failed_when: >- - (_ci_multus_molecule_nads_cleanup_out is not defined) or - (_ci_multus_molecule_nads_cleanup_out is failed) or - (_ci_multus_molecule_nads_cleanup_out.resources | length > 0) - - - name: Get all namespaces - kubernetes.core.k8s_info: - kubeconfig: "{{ cifmw_openshift_kubeconfig }}" - api_key: "{{ cifmw_openshift_token | default(omit)}}" - context: "{{ cifmw_openshift_context | default(omit)}}" - kind: Namespace - register: _ci_multus_molecule_ns_out - - - name: Assert that multus namespace is absent - vars: - ns_names: >- - {{ - _ci_multus_molecule_ns_out.resources | - default([]) | - map(attribute='metadata.name') - }} - ansible.builtin.assert: - that: "cifmw_ci_multus_namespace not in ns_names" diff --git a/roles/ci_multus/molecule/default/molecule.yml b/roles/ci_multus/molecule/default/molecule.yml index fda947cafe..0e9c7db50e 100644 --- a/roles/ci_multus/molecule/default/molecule.yml +++ b/roles/ci_multus/molecule/default/molecule.yml @@ -7,5 +7,37 @@ log: true provisioner: name: ansible log: true - env: - ANSIBLE_STDOUT_CALLBACK: yaml + playbooks: + side_effect: side_effect.yml + inventory: + host_vars: + instance: + _expected_multus_networks: + - default + - patchnetwork + cifmw_ci_multus_net_info_patch_1: + patchnetwork: + gw_v4: 192.168.122.1 + network_name: patchnetwork + network_v4: 192.168.122.0/24 + interface_name: eth2 + tools: + multus: + ipv4_ranges: + - start: 192.168.122.30 + end: 192.168.122.70 + + cifmw_path: "{{ ansible_user_dir }}/.crc/bin:{{ ansible_user_dir }}/.crc/bin/oc:{{ ansible_user_dir }}/bin:{{ ansible_env.PATH }}" + cifmw_openshift_kubeconfig: "{{ ansible_user_dir }}/.crc/machines/crc/kubeconfig" + testpod_name: "pod-testnad" +prerun: false +scenario: + test_sequence: + - destroy + - create + - converge + - verify ../resources/verify.yml + - verify verify_crc.yml + - side_effect ../resources/clean.yml + - verify ../resources/verify_clean.yml + - verify verify_clean_crc.yml diff --git a/roles/ci_multus/molecule/default/side_effect.yml b/roles/ci_multus/molecule/default/side_effect.yml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/roles/ci_multus/molecule/default/verify_clean_crc.yml b/roles/ci_multus/molecule/default/verify_clean_crc.yml new file mode 100644 index 0000000000..6f54e6bcce --- /dev/null +++ b/roles/ci_multus/molecule/default/verify_clean_crc.yml @@ -0,0 +1,36 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Verify Clean CRC + hosts: all + gather_facts: true + tasks: + - name: Include default vars + ansible.builtin.include_vars: + dir: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') }}/defaults/" + extensions: + - 'yml' + + - name: Check if NADs were deleted + kubernetes.core.k8s_info: + kubeconfig: "{{ cifmw_openshift_kubeconfig }}" + namespace: "{{ cifmw_ci_multus_namespace }}" + api_version: k8s.cni.cncf.io/v1 + kind: NetworkAttachmentDefinition + register: _ci_multus_molecule_nads_cleanup_out + failed_when: >- + (_ci_multus_molecule_nads_cleanup_out is failed) or + (_ci_multus_molecule_nads_cleanup_out.resources | length > 0) diff --git a/roles/ci_multus/molecule/default/verify_crc.yml b/roles/ci_multus/molecule/default/verify_crc.yml new file mode 100644 index 0000000000..6f8e17e078 --- /dev/null +++ b/roles/ci_multus/molecule/default/verify_crc.yml @@ -0,0 +1,82 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Verify CRC + hosts: all + gather_facts: true + tasks: + - name: Include default vars + ansible.builtin.include_vars: + dir: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') }}/defaults/" + extensions: + - 'yml' + + - name: Check if NADs were created + kubernetes.core.k8s_info: + kubeconfig: "{{ cifmw_openshift_kubeconfig }}" + namespace: "{{ cifmw_ci_multus_namespace }}" + api_version: k8s.cni.cncf.io/v1 + kind: NetworkAttachmentDefinition + register: _ci_multus_molecule_nads_out + failed_when: >- + (_ci_multus_molecule_nads_out is failed) or + (_ci_multus_molecule_nads_out.resources | length == 0) + + - name: Create a test pod to attach a network + kubernetes.core.k8s: + kubeconfig: "{{ cifmw_openshift_kubeconfig }}" + namespace: "{{ cifmw_ci_multus_namespace }}" + state: present + definition: + api_version: v1 + kind: Pod + metadata: + name: "{{ testpod_name }}" + annotations: + k8s.v1.cni.cncf.io/networks: default + spec: + containers: + - name: testnad + image: quay.rdoproject.org/openstack-k8s-operators/alpine:latest + imagePullPolicy: Always + command: + - "/bin/ash" + - "-c" + - "trap : TERM INT; sleep infinity & wait" + wait: true + wait_sleep: 10 + wait_timeout: 300 + wait_condition: + type: Ready + status: "True" + register: _ci_multus_molecule_test_pod_out + + - name: Assert that test pod has the additional network + ansible.builtin.assert: + that: + - _ci_multus_molecule_test_pod_out.result.metadata.annotations[ + 'k8s.v1.cni.cncf.io/networks'] == "default" + + - name: Delete test pod + kubernetes.core.k8s: + kubeconfig: "{{ cifmw_openshift_kubeconfig }}" + api_key: "{{ cifmw_openshift_token | default(omit)}}" + context: "{{ cifmw_openshift_context | default(omit)}}" + namespace: "{{ cifmw_ci_multus_namespace }}" + state: absent + api_version: v1 + kind: Pod + name: "{{ testpod_name }}" diff --git a/roles/ci_multus/molecule/local/converge.yml b/roles/ci_multus/molecule/local/converge.yml new file mode 100644 index 0000000000..f1480a070c --- /dev/null +++ b/roles/ci_multus/molecule/local/converge.yml @@ -0,0 +1,29 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Converge + hosts: all + gather_facts: true + vars: + cifmw_ci_multus_dryrun: true + tasks: + - name: Load shared variables + ansible.builtin.include_vars: + file: ../resources/vars/shared_vars.yml + + - name: Call ci_multus role + ansible.builtin.include_role: + name: "ci_multus" diff --git a/roles/ci_multus/molecule/local/molecule.yml b/roles/ci_multus/molecule/local/molecule.yml new file mode 100644 index 0000000000..9ed0aa2a52 --- /dev/null +++ b/roles/ci_multus/molecule/local/molecule.yml @@ -0,0 +1,38 @@ +--- +# Mainly used to override the defaults set in .config/molecule/ +# By default, it uses the "config_podman.yml" - in CI, it will use +# "config_local.yml". +log: true + +provisioner: + name: ansible + log: true + playbooks: + side_effect: side_effect.yml + inventory: + host_vars: + instance: + _expected_multus_networks: + - default + - patchnetwork + cifmw_ci_multus_net_info_patch_1: + patchnetwork: + gw_v4: 192.168.122.1 + network_name: patchnetwork + network_v4: 192.168.122.0/24 + interface_name: eth2 + tools: + multus: + ipv4_ranges: + - start: 192.168.122.30 + end: 192.168.122.70 + +prerun: false +scenario: + test_sequence: + - destroy + - create + - converge + - verify ../resources/verify.yml + - side_effect ../resources/clean.yml + - verify ../resources/verify_clean.yml diff --git a/roles/ci_multus/molecule/local/side_effect.yml b/roles/ci_multus/molecule/local/side_effect.yml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/roles/ci_multus/molecule/local_ipv6/converge.yml b/roles/ci_multus/molecule/local_ipv6/converge.yml new file mode 100644 index 0000000000..7394d47699 --- /dev/null +++ b/roles/ci_multus/molecule/local_ipv6/converge.yml @@ -0,0 +1,49 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Converge + hosts: all + gather_facts: true + vars: + cifmw_ci_multus_dryrun: true + cifmw_ci_multus_default_nad_ipam_type_ip_version: "v6" + tasks: + - name: Load shared variables + ansible.builtin.include_vars: + file: ../resources/vars/shared_vars.yml + + - name: Call ci_multus role + vars: + cifmw_networking_env_definition: + instances: + crc: + name: crc + networks: + default: + interface_name: "eth1" + network_name: default + networks: + default: + gw_v6: fdc0:8b54:108a:c949:0000:0000:0000:0001 + network_name: default + network_v6: fdc0:8b54:108a:c949::/64 + tools: + multus: + ipv6_ranges: + - start: fdc0:8b54:108a:c949:0000:0000:0000:001e + end: fdc0:8b54:108a:c949:0000:0000:0000:0027 + ansible.builtin.include_role: + name: "ci_multus" diff --git a/roles/ci_multus/molecule/local_ipv6/molecule.yml b/roles/ci_multus/molecule/local_ipv6/molecule.yml new file mode 100644 index 0000000000..f38939e911 --- /dev/null +++ b/roles/ci_multus/molecule/local_ipv6/molecule.yml @@ -0,0 +1,26 @@ +--- +# Mainly used to override the defaults set in .config/molecule/ +# By default, it uses the "config_podman.yml" - in CI, it will use +# "config_local.yml". +log: true + +provisioner: + name: ansible + log: true + playbooks: + side_effect: side_effect.yml + inventory: + host_vars: + instance: + _expected_multus_networks: + - default + +prerun: false +scenario: + test_sequence: + - destroy + - create + - converge + - verify ../resources/verify.yml + - side_effect ../resources/clean.yml + - verify ../resources/verify_clean.yml diff --git a/roles/ci_multus/molecule/local_ipv6/side_effect.yml b/roles/ci_multus/molecule/local_ipv6/side_effect.yml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/roles/ci_multus/molecule/resources/clean.yml b/roles/ci_multus/molecule/resources/clean.yml new file mode 100644 index 0000000000..2f9abfbd4b --- /dev/null +++ b/roles/ci_multus/molecule/resources/clean.yml @@ -0,0 +1,30 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Clean + hosts: all + gather_facts: true + tasks: + - name: Backup NAD before cleanup so they can be inspected in CI + ansible.builtin.copy: + src: "{{ cifmw_ci_multus_manifests_dir }}" + dest: "{{ cifmw_ci_multus_manifests_dir }}.backup" + remote_src: true + + - name: Call cleanup + ansible.builtin.import_role: + name: ci_multus + tasks_from: cleanup.yml diff --git a/roles/ci_multus/molecule/resources/vars/shared_vars.yml b/roles/ci_multus/molecule/resources/vars/shared_vars.yml new file mode 100644 index 0000000000..ba0c56b73c --- /dev/null +++ b/roles/ci_multus/molecule/resources/vars/shared_vars.yml @@ -0,0 +1,62 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +cifmw_networking_env_definition: + instances: + crc: + name: crc + networks: + default: + interface_name: "eth1" + network_name: default + networks: + default: + gw_v4: 192.168.122.1 + network_name: default + network_v4: 192.168.122.0/24 + tools: + multus: + ipv4_ranges: + - start: 192.168.122.30 + end: 192.168.122.70 + deny_network: + gw_v4: 192.168.122.1 + network_name: deny_network + network_v4: 192.168.122.0/24 + tools: + multus: + ipv4_ranges: + - start: 192.168.122.30 + end: 192.168.122.70 + not_allowed_network: + gw_v4: 192.168.122.1 + network_name: not_allowed_network + network_v4: 192.168.122.0/24 + tools: + multus: + ipv4_ranges: + - start: 192.168.122.30 + end: 192.168.122.70 + no_multus_network: + gw_v4: 192.168.122.1 + network_name: patchnetwork + network_v4: 192.168.122.0/24 + interface_name: eth2 +cifmw_ci_multus_deny_list: + - deny_network +cifmw_ci_multus_allow_list: + - default + - patchnetwork diff --git a/roles/ci_multus/molecule/resources/verify.yml b/roles/ci_multus/molecule/resources/verify.yml new file mode 100644 index 0000000000..f5d0cd5b21 --- /dev/null +++ b/roles/ci_multus/molecule/resources/verify.yml @@ -0,0 +1,61 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Verify + hosts: all + tasks: + - name: Load shared variables + ansible.builtin.include_vars: + file: ../vars/shared_vars.yml + + - name: Fetch files stat results + ansible.builtin.stat: + path: >- + {{ + [ + ansible_user_dir, + 'ci-framework-data', + 'artifacts', + 'manifests', + 'ci_multus', + 'ci_multus_nads.yml' + ] | ansible.builtin.path_join + }} + register: _ci_multus_molecule_stat_out + + - name: Assert that expected file exist + ansible.builtin.assert: + that: _ci_multus_molecule_stat_out.stat.exists + + - name: Fetch file content + ansible.builtin.slurp: + path: "{{ _ci_multus_molecule_stat_out.stat.path }}" + register: _ci_multus_molecule_slurp_out + + - name: Set _ci_multus_nad variable + ansible.builtin.set_fact: + _ci_multus_nad: >- + {{ + _ci_multus_molecule_slurp_out.content | + b64decode | + from_yaml_all + }} + + - name: Assert expected number of Network Attachment Definitions are created + ansible.builtin.assert: + that: + - _ci_multus_nad | length == _expected_multus_networks | length + quiet: true diff --git a/roles/ci_multus/molecule/resources/verify_clean.yml b/roles/ci_multus/molecule/resources/verify_clean.yml new file mode 100644 index 0000000000..858db767e5 --- /dev/null +++ b/roles/ci_multus/molecule/resources/verify_clean.yml @@ -0,0 +1,33 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Verify Clean + hosts: all + tasks: + - name: Include default vars + ansible.builtin.include_vars: + dir: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') }}/defaults/" + extensions: + - 'yml' + + - name: Fetch file stat results + ansible.builtin.stat: + path: "{{ cifmw_ci_multus_manifests_dir }}" + register: _ci_multus_molecule_stat_out + + - name: Assert that created file are removed by cleanup + ansible.builtin.assert: + that: not _ci_multus_molecule_stat_out.stat.exists diff --git a/roles/ci_multus/tasks/cleanup.yml b/roles/ci_multus/tasks/cleanup.yml index 6a56c0a32d..4dcdc5f373 100644 --- a/roles/ci_multus/tasks/cleanup.yml +++ b/roles/ci_multus/tasks/cleanup.yml @@ -14,10 +14,10 @@ # License for the specific language governing permissions and limitations # under the License. -- name: Clean OCP resources if available +- name: Cleanup - Clean OCP resources if available when: cifmw_openshift_kubeconfig is defined block: - - name: Fetch NADs in multus namespace + - name: "Cleanup - Fetch NADs in namespace: {{ cifmw_ci_multus_namespace }}" kubernetes.core.k8s_info: kubeconfig: "{{ cifmw_openshift_kubeconfig }}" api_key: "{{ cifmw_openshift_token | default(omit)}}" @@ -27,7 +27,7 @@ kind: NetworkAttachmentDefinition register: _nads_info_cleanup_out - - name: Delete NADs + - name: Cleanup - Delete NADs kubernetes.core.k8s: state: absent kubeconfig: "{{ cifmw_openshift_kubeconfig }}" @@ -39,12 +39,7 @@ loop_control: label: "{{ item.metadata.name}}" - - name: Remove ci-multus namespace - kubernetes.core.k8s: - kubeconfig: "{{ cifmw_openshift_kubeconfig }}" - api_key: "{{ cifmw_openshift_token | default(omit)}}" - context: "{{ cifmw_openshift_context | default(omit) }}" - name: "{{ cifmw_ci_multus_namespace }}" - kind: Namespace - state: absent - wait: true +- name: Cleanup - Remove if artifact directory exists + ansible.builtin.file: + path: "{{ cifmw_ci_multus_manifests_dir }}" + state: absent diff --git a/roles/ci_multus/tasks/extract_ci_data.yml b/roles/ci_multus/tasks/extract_ci_data.yml deleted file mode 100644 index b146122851..0000000000 --- a/roles/ci_multus/tasks/extract_ci_data.yml +++ /dev/null @@ -1,61 +0,0 @@ ---- -# Copyright Red Hat, Inc.the -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -- name: Extract data from network env file if available - when: - - cifmw_network_layout is not defined - - crc_ci_bootstrap_networks_out is not defined - block: - - name: Check for CI env directory - when: crc_ci_bootstrap_networks_out is not defined - register: _cifmw_ci_multus_ci_env_stat - ansible.builtin.stat: - path: /etc/ci/env - - - name: Load network env file - when: _cifmw_ci_multus_ci_env_stat.stat.exists - ansible.builtin.include_vars: - dir: /etc/ci/env/ - -- name: Gather network layout from OCP host or default networks - ansible.builtin.set_fact: - _cifmw_ci_multus_net_info: >- - {{ - cifmw_network_layout[cifmw_ci_multus_ocp_hostname] | default({}) | - combine( cifmw_network_layout['networks'], recursive=true) - if cifmw_network_layout is defined else - (crc_ci_bootstrap_networks_out[cifmw_ci_multus_ocp_hostname] | default({})| - combine( crc_ci_bootstrap_networks_out['networks'], recursive=true) - ) - }} - -- name: Build list of NetworkAttachmentDefinition - ansible.builtin.set_fact: - cifmw_ci_multus_nad_list: >- - {{ - cifmw_ci_multus_nad_list + - [{ - 'name': item.key, - 'iface': item.value.iface, - 'ipam': - { - 'range': item.value.range, - 'range_start': item.value.multus.range | split('-') | first, - 'range_end': item.value.multus.range | split('-') | last - } - }] - }} - loop: "{{ _cifmw_ci_multus_net_info | dict2items }}" diff --git a/roles/ci_multus/tasks/main.yml b/roles/ci_multus/tasks/main.yml index 310f9f1ea0..5edcdfb30f 100644 --- a/roles/ci_multus/tasks/main.yml +++ b/roles/ci_multus/tasks/main.yml @@ -19,31 +19,121 @@ path: "{{ cifmw_ci_multus_manifests_dir }}" state: directory -- name: Build NetAttDef list from ci environment - when: - - cifmw_ci_multus_nad_list | length == 0 - ansible.builtin.include_tasks: extract_ci_data.yml - -- name: Create network attachment definitions in manifest dir - vars: - _cifmw_ci_multus_nad_list: "{{ cifmw_ci_multus_nad_list + cifmw_ci_multus_nad_extra_list }}" +- name: Build list of networks from cifmw_networking_env_definition + block: + - name: Load Networking Environment Definition + ansible.builtin.import_role: + name: networking_mapper + tasks_from: load_env_definition.yml + + - name: Gather network layout from OCP host or default networks + ansible.builtin.set_fact: + _cifmw_ci_multus_net_info: >- + {{ + ( + cifmw_networking_env_definition.instances[cifmw_ci_multus_ocp_hostname].networks | default({})| + combine(cifmw_networking_env_definition['networks'], recursive=true) + ) + }} + + - name: Merge any available multus net info patches + vars: + _net_info_patches: >- + {{ + hostvars[inventory_hostname] | + dict2items | + selectattr("key", "match", + "^cifmw_ci_multus_net_info_patch.*") | + sort(attribute='key') | + map(attribute='value') | + list + }} + when: _net_info_patches | default([]) | length > 0 + ansible.builtin.set_fact: + _cifmw_ci_multus_net_info: >- + {{ + _cifmw_ci_multus_net_info | default({}) | + combine(item, recursive=True) + }} + loop: "{{ [_cifmw_ci_multus_net_info] + _net_info_patches }}" + + - name: Remove any networks without Multus networking defined + vars: + _networks_without_multus_config: >- + {% set _networks_without_multus_config = [] -%} + {% for name, data in _cifmw_ci_multus_net_info.items() -%} + {% if data.tools.multus is not defined -%} + {% set _ = _networks_without_multus_config.append(name) -%} + {% endif -%} + {% endfor -%} + {{ _networks_without_multus_config }} + ansible.builtin.set_fact: + _cifmw_ci_multus_net_info: >- + {{ + _cifmw_ci_multus_net_info | + ansible.utils.remove_keys( + target=_networks_without_multus_config) + }} + + - name: Remove any networks not in cifmw_ci_multus_allow_list if defined + when: cifmw_ci_multus_allow_list | length > 0 + vars: + _networks_not_present_in_allow_list: >- + {% set _networks_not_present_in_allow_list = [] -%} + {% for name, data in _cifmw_ci_multus_net_info.items() -%} + {% if name not in cifmw_ci_multus_allow_list -%} + {% set _ = _networks_not_present_in_allow_list.append(name) -%} + {% endif -%} + {% endfor -%} + {{ _networks_not_present_in_allow_list }} + ansible.builtin.set_fact: + _cifmw_ci_multus_net_info: >- + {{ + _cifmw_ci_multus_net_info | + ansible.utils.remove_keys( + target=_networks_not_present_in_allow_list) + }} + + - name: Remove any networks in cifmw_ci_multus_deny_list if defined + when: cifmw_ci_multus_deny_list | length > 0 + vars: + _networks_present_in_deny_list: >- + {% set _networks_present_in_deny_list = [] -%} + {% for name, data in _cifmw_ci_multus_net_info.items() -%} + {% if name in cifmw_ci_multus_deny_list -%} + {% set _ = _networks_present_in_deny_list.append(name) -%} + {% endif -%} + {% endfor -%} + {{ _networks_present_in_deny_list }} + ansible.builtin.set_fact: + _cifmw_ci_multus_net_info: >- + {{ + _cifmw_ci_multus_net_info | + ansible.utils.remove_keys( + target=_networks_present_in_deny_list) + }} + +- name: Render NetworkAttachmenktDefinition manifests ansible.builtin.template: src: "nad.yml.j2" dest: "{{ cifmw_ci_multus_manifests_dir }}/ci_multus_nads.yml" -- name: Create the multus namespace - kubernetes.core.k8s: - kubeconfig: "{{ cifmw_openshift_kubeconfig }}" - api_key: "{{ cifmw_openshift_token | default(omit)}}" - context: "{{ cifmw_openshift_context | default(omit) }}" - name: "{{ cifmw_ci_multus_namespace }}" - kind: Namespace - state: present - -- name: Apply network attachment definitions - kubernetes.core.k8s: - kubeconfig: "{{ cifmw_openshift_kubeconfig }}" - api_key: "{{ cifmw_openshift_token | default(omit) }}" - context: "{{ cifmw_openshift_context | default(omit) }}" - state: present - definition: "{{ lookup('file', cifmw_ci_multus_manifests_dir+'/ci_multus_nads.yml') | from_yaml_all }}" +- name: Create resources in OCP + when: not cifmw_ci_multus_dryrun + block: + - name: Create the multus namespace + kubernetes.core.k8s: + kubeconfig: "{{ cifmw_openshift_kubeconfig }}" + api_key: "{{ cifmw_openshift_token | default(omit)}}" + context: "{{ cifmw_openshift_context | default(omit) }}" + name: "{{ cifmw_ci_multus_namespace }}" + kind: Namespace + state: present + + - name: Apply network attachment definition manifests + kubernetes.core.k8s: + kubeconfig: "{{ cifmw_openshift_kubeconfig }}" + api_key: "{{ cifmw_openshift_token | default(omit) }}" + context: "{{ cifmw_openshift_context | default(omit) }}" + state: present + definition: "{{ lookup('file', cifmw_ci_multus_manifests_dir+'/ci_multus_nads.yml') | from_yaml_all }}" diff --git a/roles/ci_multus/templates/nad.yml.j2 b/roles/ci_multus/templates/nad.yml.j2 index f6ec97472d..10324ec080 100644 --- a/roles/ci_multus/templates/nad.yml.j2 +++ b/roles/ci_multus/templates/nad.yml.j2 @@ -1,24 +1,38 @@ -{% for nad in _cifmw_ci_multus_nad_list %} +{% for network_name, network_details in _cifmw_ci_multus_net_info.items() %} --- apiVersion: k8s.cni.cncf.io/v1 kind: NetworkAttachmentDefinition metadata: labels: - osp/net: {{ nad.name }} - name: {{ nad.name }} + osp/net: {{ network_name }} + name: {{ network_name }} namespace: {{ cifmw_ci_multus_namespace }} spec: config: | { "cniVersion": "{{ cifmw_ci_multus_cniversion }}", - "name": "{{ nad.name }}", - "type": "{{ nad.type | default(cifmw_ci_multus_default_nad_type) }}", - "master": "{{ nad.iface }}", + "name": "{{ network_name }}", +{% if cifmw_ci_multus_default_nad_type == "macvlan" %} + "type": "macvlan", + "master": "{{ network_details.interface_name }}", +{% endif %} +{% if cifmw_ci_multus_default_nad_type == "bridge" %} + "type": "bridge", + "bridge": "{{ network_details.interface_name }}", +{% endif %} "ipam": { - "type": "{{ nad.ipam.type | default(cifmw_ci_multus_default_nad_ipam_type) }}", - "range": "{{ nad.ipam.range }}", - "range_start": "{{ nad.ipam.range_start }}", - "range_end": "{{ nad.ipam.range_end }}" + "type": "{{ cifmw_ci_multus_default_nad_ipam_type }}", +{% if cifmw_ci_multus_default_nad_ipam_type == "whereabouts" %} +{% if cifmw_ci_multus_default_nad_ipam_type_ip_version == "v4" %} + "range": "{{ network_details.network_v4 }}", + "range_start": "{{ network_details.tools.multus.ipv4_ranges[0].start }}", + "range_end": "{{ network_details.tools.multus.ipv4_ranges[0].end }}" +{% elif cifmw_ci_multus_default_nad_ipam_type_ip_version == "v6" %} + "range": "{{ network_details.network_v6 }}", + "range_start": "{{ network_details.tools.multus.ipv6_ranges[0].start }}", + "range_end": "{{ network_details.tools.multus.ipv6_ranges[0].end }}" +{% endif %} +{% endif %} } } {% endfor %}