diff --git a/.github/workflows/kubevirt-ipam-controller.yaml b/.github/workflows/kubevirt-ipam-controller.yaml new file mode 100644 index 000000000..d3e5ddf1f --- /dev/null +++ b/.github/workflows/kubevirt-ipam-controller.yaml @@ -0,0 +1,23 @@ +name: Kubevirt IPAM controller Tests +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + e2e: + runs-on: ubuntu-latest + steps: + + - uses: actions/checkout@v3 + + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version-file: 'go.mod' + + - name: Run e2e tests + env: + KIND_ALLOW_SYSTEM_WRITES: true + run: automation/check-patch.e2e-kubevirt-ipam-controller-functests.sh diff --git a/Makefile b/Makefile index ad32321be..479d1e9c9 100644 --- a/Makefile +++ b/Makefile @@ -130,6 +130,7 @@ prom-rules-verify: cluster-up: ./cluster/up.sh + ./cluster/cert-manager-install.sh cluster-down: ./cluster/down.sh @@ -160,6 +161,7 @@ gen-manifests: manifest-templator MACVTAP_CNI_IMAGE=$(MACVTAP_CNI_IMAGE) \ MULTUS_DYNAMIC_NETWORKS_CONTROLLER_IMAGE=$(MULTUS_DYNAMIC_NETWORKS_CONTROLLER_IMAGE) \ KUBE_SECONDARY_DNS_IMAGE=$(KUBE_SECONDARY_DNS_IMAGE) \ + KUBEVIRT_IPAM_CONTROLLER_IMAGE=$(KUBEVIRT_IPAM_CONTROLLER_IMAGE) \ CORE_DNS_IMAGE=$(CORE_DNS_IMAGE) \ KUBE_RBAC_PROXY_IMAGE=$(KUBE_RBAC_PROXY_IMAGE) \ ./hack/generate-manifests.sh diff --git a/README.md b/README.md index d48b6aa66..6c1e5967b 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ spec: ovs: {} macvtap: {} kubeSecondaryDNS: {} + kubevirtIpamController: {} imagePullPolicy: Always ``` @@ -180,6 +181,29 @@ Additionally, container image used to deliver this plugin can be set using `KUBE_SECONDARY_DNS_IMAGE` environment variable in operator deployment manifest. +## kubevirtIpamController + +[This controller](https://github.com/maiqueb/kubevirt-ipam-claims) +allows to support IPAM for user defined networks. + +```yaml +apiVersion: networkaddonsoperator.network.kubevirt.io/v1 +kind: NetworkAddonsConfig +metadata: + name: cluster +spec: + multus: {} + kubevirtIpamController: {} +``` + +Additionally, container image used to deliver this plugin can be set using +`KUBEVIRT_IPAM_CONTROLLER_IMAGE` environment variable in operator +deployment manifest. + +Note: This component requires certificates mounted on the controller pods for the webhook to work. +On non OpenShift clusters, the user should manually install a certificate library (e.g. [cert-manager](https://github.com/cert-manager/cert-manager)). +It is done for convenience as part of the helper scripts. + ## Image Pull Policy Administrator can specify [image pull policy](https://kubernetes.io/docs/concepts/containers/images/) diff --git a/automation/check-patch.e2e-kubevirt-ipam-controller-functests.sh b/automation/check-patch.e2e-kubevirt-ipam-controller-functests.sh new file mode 100755 index 000000000..21da58025 --- /dev/null +++ b/automation/check-patch.e2e-kubevirt-ipam-controller-functests.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash + +set -xeuE + +# automation/check-patch.e2e-kubevirt-ipam-controller-functests.sh + +GITHUB_ACTIONS=${GITHUB_ACTIONS:-false} + +teardown() { + cd ${TMP_COMPONENT_PATH} + make cluster-down || true + rm -rf "${TMP_COMPONENT_PATH}" +} + +main() { + if [ "$GITHUB_ACTIONS" == "true" ]; then + ARCH="amd64" + OS_TYPE="linux" + kubevirt_version="$(curl -L https://storage.googleapis.com/kubevirt-prow/release/kubevirt/kubevirt/stable.txt)" + kubevirt_release_url="https://github.com/kubevirt/kubevirt/releases/download/${kubevirt_version}" + cli_name="virtctl-${kubevirt_version}-${OS_TYPE}-${ARCH}" + curl -LO "${kubevirt_release_url}/${cli_name}" + mv ${cli_name} virtctl + chmod +x virtctl + mv virtctl /usr/local/bin + fi + + # Setup CNAO and artifacts temp directory + source automation/check-patch.setup.sh + cd ${TMP_PROJECT_PATH} + + export USE_KUBEVIRTCI=false + COMPONENT="kubevirt-ipam-controller" source automation/components-functests.setup.sh + + cd ${TMP_COMPONENT_PATH} + export KIND_ARGS="-ic -i6 -mne" + make cluster-up + export KUBECONFIG=${TMP_COMPONENT_PATH}/.output/kubeconfig + + trap teardown EXIT + + cd ${TMP_PROJECT_PATH} + export KUBEVIRT_PROVIDER=external + export DEV_IMAGE_REGISTRY=localhost:5000 + ./cluster/cert-manager-install.sh + deploy_cnao + deploy_cnao_cr + ./hack/deploy-kubevirt.sh + + cd ${TMP_COMPONENT_PATH} + echo "Run kubevirt-ipam-controller functional tests" + make test-e2e +} + +[[ "${BASH_SOURCE[0]}" == "$0" ]] && main "$@" diff --git a/automation/components-functests.setup.sh b/automation/components-functests.setup.sh index 91cd432d1..14a0a162e 100644 --- a/automation/components-functests.setup.sh +++ b/automation/components-functests.setup.sh @@ -21,19 +21,27 @@ source hack/components/git-utils.sh source hack/components/yaml-utils.sh source cluster/cluster.sh -# Spin up Kubernetes cluster -make cluster-down cluster-up +USE_KUBEVIRTCI=${USE_KUBEVIRTCI:-"true"} # Export .kubeconfig full path, so it will be possible # to use 'kubectl' directly from the component directory path -export KUBECONFIG=$(cluster::kubeconfig) +export KUBECONFIG=${KUBECONFIG:-$(cluster::kubeconfig)} -# Deploy CNAO latest changes -make cluster-operator-push -make cluster-operator-install +function deploy_cluster { + # Spin up Kubernetes cluster + export KUBEVIRT_MEMORY_SIZE=9216M + make cluster-down cluster-up +} -# Test kubemacpool with restricted -if [ "$COMPONENT" == "kubemacpool" ]; then +function deploy_cnao { + # Deploy CNAO latest changes + make cluster-operator-push + make cluster-operator-install +} + +function patch_restricted_namespace { + # Test kubemacpool with restricted + if [ "$COMPONENT" == "kubemacpool" ]; then cluster/kubectl.sh apply -f - < cr.yaml apiVersion: networkaddonsoperator.network.kubevirt.io/v1 kind: NetworkAddonsConfig metadata: name: cluster spec: - multus: {} - multusDynamicNetworks: {} linuxBridge: {} kubeMacPool: rangeStart: "02:00:00:00:00:00" @@ -60,14 +69,23 @@ spec: ovs: {} macvtap: {} kubeSecondaryDNS: {} + kubevirtIpamController: {} imagePullPolicy: Always EOF -if [[ ! $(cluster/kubectl.sh wait networkaddonsconfig cluster --for condition=Available --timeout=13m) ]]; then - echo "Failed to wait for CNAO CR to be ready" - cluster/kubectl.sh get networkaddonsconfig -o custom-columns="":.status.conditions[*].message - exit 1 -fi + if [[ $USE_KUBEVIRTCI == true ]]; then + echo " multus: {}" >> cr.yaml + echo " multusDynamicNetworks: {}" >> cr.yaml + fi + + cluster/kubectl.sh apply -f cr.yaml + + if [[ ! $(cluster/kubectl.sh wait networkaddonsconfig cluster --for condition=Available --timeout=13m) ]]; then + echo "Failed to wait for CNAO CR to be ready" + cluster/kubectl.sh get networkaddonsconfig -o custom-columns="":.status.conditions[*].message + exit 1 + fi +} # Clone component repository component_url=$(yaml-utils::get_component_url ${COMPONENT}) @@ -80,3 +98,10 @@ component_path=${component_temp_dir}/${component_repo} git-utils::fetch_component ${component_path} ${component_url} ${component_commit} export TMP_COMPONENT_PATH=${component_path} + +if [[ $USE_KUBEVIRTCI == true ]]; then + deploy_cluster + deploy_cnao + patch_restricted_namespace + deploy_cnao_cr +fi diff --git a/cluster/cert-manager-install.sh b/cluster/cert-manager-install.sh new file mode 100755 index 000000000..5de4930fc --- /dev/null +++ b/cluster/cert-manager-install.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# +# Copyright 2024 Red Hat, Inc. +# +# 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. + +set -ex + +export DEPLOY_CERT_MANAGER=${DEPLOY_CERT_MANAGER:-true} + +if [[ $DEPLOY_CERT_MANAGER == true ]]; then + CERT_MANAGER_VERSION="v1.14.4" + echo "Installing cert-manager..." + manifest="https://github.com/cert-manager/cert-manager/releases/download/${CERT_MANAGER_VERSION}/cert-manager.yaml" + ./cluster/kubectl.sh apply -f "$manifest" +fi diff --git a/cluster/operator-install.sh b/cluster/operator-install.sh index d18f49479..892d3577c 100755 --- a/cluster/operator-install.sh +++ b/cluster/operator-install.sh @@ -23,3 +23,4 @@ if [[ ! $(./cluster/kubectl.sh -n cluster-network-addons wait deployment cluster ./cluster/kubectl.sh describe deployment cluster-network-addons-operator -n cluster-network-addons exit 1 fi + diff --git a/components.yaml b/components.yaml index 09933429f..c350275ad 100644 --- a/components.yaml +++ b/components.yaml @@ -17,6 +17,12 @@ components: branch: main update-policy: tagged metadata: v0.43.0 + kubevirt-ipam-controller: + url: https://github.com/maiqueb/kubevirt-ipam-claims + commit: c01d8855783da6b2a1773ec1f82694cd0658cd10 + branch: main + update-policy: tagged + metadata: v0.1.1-alpha linux-bridge: url: https://github.com/containernetworking/plugins commit: 14bdce598f9d332303c375c35719c4a158f1e7db diff --git a/data/kubevirt-ipam-controller/000-crd.yaml b/data/kubevirt-ipam-controller/000-crd.yaml new file mode 100644 index 000000000..05d3de891 --- /dev/null +++ b/data/kubevirt-ipam-controller/000-crd.yaml @@ -0,0 +1,65 @@ +{{ if not .IsOpenshift }} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: ipamclaims.k8s.cni.cncf.io +spec: + group: k8s.cni.cncf.io + names: + kind: IPAMClaim + listKind: IPAMClaimList + plural: ipamclaims + singular: ipamclaim + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: IPAMClaim is the Schema for the IPAMClaim API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + properties: + interface: + description: The pod interface name for which this allocation was + created + type: string + network: + description: The network name for which this persistent allocation + was created + type: string + required: + - interface + - network + type: object + status: + properties: + ips: + description: The list of IP addresses (v4, v6) that were allocated + for the pod interface + items: + type: string + type: array + required: + - ips + type: object + type: object + served: true + storage: true + subresources: + status: {} +{{ end }} diff --git a/data/kubevirt-ipam-controller/001-kubevirtipamcontroller.yaml b/data/kubevirt-ipam-controller/001-kubevirtipamcontroller.yaml new file mode 100644 index 000000000..074c38ee8 --- /dev/null +++ b/data/kubevirt-ipam-controller/001-kubevirtipamcontroller.yaml @@ -0,0 +1,289 @@ +--- +apiVersion: v1 +kind: Namespace +metadata: + labels: + app: ipam-virt-workloads + control-plane: controller-manager + name: {{ .Namespace }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app: ipam-virt-workloads + name: kubevirt-ipam-claims-controller-manager + namespace: {{ .Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + labels: + app: ipam-virt-workloads + name: kubevirt-ipam-claims-leader-election-role + namespace: {{ .Namespace }} +rules: + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - "" + resources: + - events + verbs: + - create + - patch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app: ipam-virt-workloads + name: kubevirt-ipam-claims-manager-role +rules: +- apiGroups: + - "" + resources: + - pods + verbs: + - get + - list + - watch +- apiGroups: + - kubevirt.io + resources: + - virtualmachines + - virtualmachineinstances + verbs: + - get + - list + - watch +- apiGroups: + - k8s.cni.cncf.io + resources: + - ipamclaims + - network-attachment-definitions + verbs: + - get + - list + - watch +- apiGroups: + - k8s.cni.cncf.io + resources: + - ipamclaims + verbs: + - create + - update +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + app: ipam-virt-workloads + name: kubevirt-ipam-claims-leader-election-rolebinding + namespace: {{ .Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: kubevirt-ipam-claims-leader-election-role +subjects: + - kind: ServiceAccount + name: kubevirt-ipam-claims-controller-manager + namespace: {{ .Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app: ipam-virt-workloads + name: kubevirt-ipam-claims-manager-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: kubevirt-ipam-claims-manager-role +subjects: + - kind: ServiceAccount + name: kubevirt-ipam-claims-controller-manager + namespace: {{ .Namespace }} +--- +apiVersion: v1 +kind: Service +metadata: +{{ if .IsOpenshift }} + annotations: + service.beta.openshift.io/serving-cert-secret-name: kubevirt-ipam-claims-webhook-service +{{ end }} + labels: + app: ipam-virt-workloads + name: kubevirt-ipam-claims-webhook-service + namespace: {{ .Namespace }} +spec: + ports: + - port: 443 + protocol: TCP + targetPort: 9443 + selector: + app: ipam-virt-workloads + control-plane: controller-manager +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: ipam-virt-workloads + control-plane: controller-manager + name: kubevirt-ipam-claims-controller-manager + namespace: {{ .Namespace }} +spec: + replicas: 1 + selector: + matchLabels: + app: ipam-virt-workloads + control-plane: controller-manager + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: manager + labels: + app: ipam-virt-workloads + control-plane: controller-manager + spec: + containers: + - args: + - --leader-elect + - "--certificates-dir={{ .CertDir }}" + command: + - /manager + image: {{ .KubevirtIpamControllerImage }} + livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 + name: manager + ports: + - containerPort: 9443 + name: webhook-server + protocol: TCP + readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 10m + memory: 64Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + volumeMounts: + - mountPath: {{ .MountPath }} + name: cert + readOnly: true + imagePullPolicy: {{ .ImagePullPolicy }} + securityContext: + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + serviceAccountName: kubevirt-ipam-claims-controller-manager + terminationGracePeriodSeconds: 10 + volumes: + - name: cert + secret: + defaultMode: 420 + secretName: {{ .SecretName }} + nodeSelector: {{ toYaml .Placement.NodeSelector | nindent 8 }} + affinity: {{ toYaml .Placement.Affinity | nindent 8 }} + tolerations: {{ toYaml .Placement.Tolerations | nindent 8 }} +{{ if not .IsOpenshift }} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + labels: + app: ipam-virt-workloads + name: kubevirt-ipam-claims-serving-cert + namespace: {{ .Namespace }} +spec: + dnsNames: + - kubevirt-ipam-claims-webhook-service.{{ .Namespace }}.svc + - kubevirt-ipam-claims-webhook-service.{{ .Namespace }}.svc.cluster.local + issuerRef: + kind: Issuer + name: kubevirt-ipam-claims-selfsigned-issuer + secretName: webhook-server-cert +{{ end }} +{{ if not .IsOpenshift }} +--- +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + labels: + app: ipam-virt-workloads + name: kubevirt-ipam-claims-selfsigned-issuer + namespace: {{ .Namespace }} +spec: + selfSigned: {} +{{ end }} +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + annotations: + {{ .WebhookAnnotation }} + labels: + app: ipam-virt-workloads + name: kubevirt-ipam-claims-mutating-webhook-configuration +webhooks: + - admissionReviewVersions: + - v1 + clientConfig: + service: + name: kubevirt-ipam-claims-webhook-service + namespace: {{ .Namespace }} + path: /mutate-v1-pod + failurePolicy: Fail + name: ipam-claims.k8s.cni.cncf.io + objectSelector: + matchLabels: + kubevirt.io: virt-launcher + rules: + - apiGroups: + - "" + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resources: + - pods + sideEffects: None diff --git a/hack/components/bump-kubevirt-ipam-controller.sh b/hack/components/bump-kubevirt-ipam-controller.sh new file mode 100755 index 000000000..6e0956a9e --- /dev/null +++ b/hack/components/bump-kubevirt-ipam-controller.sh @@ -0,0 +1,149 @@ +#!/usr/bin/env bash + +set -xeo pipefail + +source hack/components/yaml-utils.sh +source hack/components/git-utils.sh +source hack/components/docker-utils.sh + +IPAMCLAIMS_CRD_VERSION="v0.4.0-alpha" + +function __parametize_by_object() { + for f in ./*; do + case "${f}" in + ./Namespace_kubevirt-ipam-claims-system.yaml) + yaml-utils::update_param ${f} metadata.name '{{ .Namespace }}' + yaml-utils::remove_single_quotes_from_yaml ${f} + ;; + ./ClusterRoleBinding_kubevirt-ipam-claims-manager-rolebinding.yaml) + yaml-utils::update_param ${f} subjects[0].namespace '{{ .Namespace }}' + yaml-utils::remove_single_quotes_from_yaml ${f} + ;; + ./Deployment_kubevirt-ipam-claims-controller-manager.yaml) + yaml-utils::update_param ${f} metadata.namespace '{{ .Namespace }}' + yaml-utils::update_param ${f} spec.template.spec.containers[0].image '{{ .KubevirtIpamControllerImage }}' + yaml-utils::set_param ${f} spec.template.spec.containers[0].imagePullPolicy '{{ .ImagePullPolicy }}' + yaml-utils::set_param ${f} spec.template.spec.containers[0].args[1] '"--certificates-dir={{ .CertDir }}"' + yaml-utils::set_param ${f} spec.template.spec.containers[0].volumeMounts[0].mountPath '{{ .MountPath }}' + yaml-utils::set_param ${f} spec.template.spec.volumes[0].secret.secretName '{{ .SecretName }}' + yaml-utils::set_param ${f} spec.template.spec.nodeSelector '{{ toYaml .Placement.NodeSelector | nindent 8 }}' + yaml-utils::set_param ${f} spec.template.spec.affinity '{{ toYaml .Placement.Affinity | nindent 8 }}' + yaml-utils::set_param ${f} spec.template.spec.tolerations '{{ toYaml .Placement.Tolerations | nindent 8 }}' + yaml-utils::remove_single_quotes_from_yaml ${f} + ;; + ./Service_kubevirt-ipam-claims-webhook-service.yaml) + yaml-utils::update_param ${f} metadata.namespace '{{ .Namespace }}' + yaml-utils::remove_single_quotes_from_yaml ${f} + ;; + ./Certificate_kubevirt-ipam-claims-serving-cert.yaml) + yaml-utils::update_param ${f} metadata.namespace '{{ .Namespace }}' + yaml-utils::update_param ${f} spec.dnsNames[0] 'kubevirt-ipam-claims-webhook-service.{{ .Namespace }}.svc' + yaml-utils::update_param ${f} spec.dnsNames[1] 'kubevirt-ipam-claims-webhook-service.{{ .Namespace }}.svc.cluster.local' + yaml-utils::remove_single_quotes_from_yaml ${f} + ;; + ./Issuer_kubevirt-ipam-claims-selfsigned-issuer.yaml) + yaml-utils::update_param ${f} metadata.namespace '{{ .Namespace }}' + yaml-utils::remove_single_quotes_from_yaml ${f} + ;; + ./MutatingWebhookConfiguration_kubevirt-ipam-claims-mutating-webhook-configuration.yaml) + yaml-utils::update_param ${f} webhooks[0].clientConfig.service.namespace '{{ .Namespace }}' + sed -i '/cert-manager.io\/inject-ca-from/c\ {{ .WebhookAnnotation }}' ${f} + yaml-utils::remove_single_quotes_from_yaml ${f} + ;; + ./RoleBinding_kubevirt-ipam-claims-leader-election-rolebinding.yaml) + yaml-utils::update_param ${f} metadata.namespace '{{ .Namespace }}' + yaml-utils::update_param ${f} subjects[0].namespace '{{ .Namespace }}' + yaml-utils::remove_single_quotes_from_yaml ${f} + ;; + ./Role_kubevirt-ipam-claims-leader-election-role.yaml) + yaml-utils::update_param ${f} metadata.namespace '{{ .Namespace }}' + yaml-utils::remove_single_quotes_from_yaml ${f} + ;; + ./ServiceAccount_kubevirt-ipam-claims-controller-manager.yaml) + yaml-utils::update_param ${f} metadata.namespace '{{ .Namespace }}' + yaml-utils::remove_single_quotes_from_yaml ${f} + ;; + ./Service_kubevirt-ipam-claims-webhook-service.yaml) + yaml-utils::update_param ${f} metadata.namespace '{{ .Namespace }}' + yaml-utils::remove_single_quotes_from_yaml ${f} + ;; + esac + done +} + +echo 'Bumping kubevirt-ipam-controller' +KUBEVIRT_IPAM_CONTROLLER_URL=$(yaml-utils::get_component_url kubevirt-ipam-controller) +KUBEVIRT_IPAM_CONTROLLER_COMMIT=$(yaml-utils::get_component_commit kubevirt-ipam-controller) +KUBEVIRT_IPAM_CONTROLLER_REPO=$(yaml-utils::get_component_repo ${KUBEVIRT_IPAM_CONTROLLER_URL}) + +TEMP_DIR=$(git-utils::create_temp_path kubevirt-ipam-controller) +trap "rm -rf ${TEMP_DIR}" EXIT +KUBEVIRT_IPAM_CONTROLLER_PATH=${TEMP_DIR}/${KUBEVIRT_IPAM_CONTROLLER_REPO} + +echo 'Fetch kubevirt-ipam-controller sources' +git-utils::fetch_component ${KUBEVIRT_IPAM_CONTROLLER_PATH} ${KUBEVIRT_IPAM_CONTROLLER_URL} ${KUBEVIRT_IPAM_CONTROLLER_COMMIT} + +echo 'Adjust kubevirt-ipam-controller to CNAO' +( + cd ${KUBEVIRT_IPAM_CONTROLLER_PATH} + mkdir -p config/cnao + cp dist/install.yaml config/cnao + + echo 'Split manifest per object' + cd config/cnao + + $(yaml-utils::split_yaml_by_seperator . install.yaml) + + rm install.yaml + $(yaml-utils::rename_files_by_object .) + + echo 'parametize manifests by object' + __parametize_by_object + + sed -i '1i{{ if not .IsOpenshift }}' Issuer_kubevirt-ipam-claims-selfsigned-issuer.yaml + echo "{{ end }}" >> Issuer_kubevirt-ipam-claims-selfsigned-issuer.yaml + + sed -i '1i{{ if not .IsOpenshift }}' Certificate_kubevirt-ipam-claims-serving-cert.yaml + echo "{{ end }}" >> Certificate_kubevirt-ipam-claims-serving-cert.yaml + + sed -i '/metadata:/a\{{ if .IsOpenshift }}\ + annotations:\ + service.beta.openshift.io/serving-cert-secret-name: kubevirt-ipam-claims-webhook-service\ +{{ end }}' Service_kubevirt-ipam-claims-webhook-service.yaml + + echo 'rejoin sub-manifests to a final manifest' + cat Namespace_kubevirt-ipam-claims-system.yaml \ + ServiceAccount_kubevirt-ipam-claims-controller-manager.yaml \ + Role_kubevirt-ipam-claims-leader-election-role.yaml \ + ClusterRole_kubevirt-ipam-claims-manager-role.yaml \ + RoleBinding_kubevirt-ipam-claims-leader-election-rolebinding.yaml \ + ClusterRoleBinding_kubevirt-ipam-claims-manager-rolebinding.yaml \ + Service_kubevirt-ipam-claims-webhook-service.yaml \ + Deployment_kubevirt-ipam-claims-controller-manager.yaml \ + Certificate_kubevirt-ipam-claims-serving-cert.yaml \ + Issuer_kubevirt-ipam-claims-selfsigned-issuer.yaml \ + MutatingWebhookConfiguration_kubevirt-ipam-claims-mutating-webhook-configuration.yaml > 001-kubevirtipamcontroller.yaml + +) + +echo 'Copy manifests' +rm -rf data/kubevirt-ipam-controller/* + +# CRD +crd_manifest="https://raw.githubusercontent.com/k8snetworkplumbingwg/ipamclaims/${IPAMCLAIMS_CRD_VERSION}/artifacts/k8s.cni.cncf.io_ipamclaims.yaml" +echo "{{ if not .IsOpenshift }}" > data/kubevirt-ipam-controller/000-crd.yaml +curl $crd_manifest >> data/kubevirt-ipam-controller/000-crd.yaml +echo "{{ end }}" >> data/kubevirt-ipam-controller/000-crd.yaml + +# Kubevirt Ipam controller +cp ${KUBEVIRT_IPAM_CONTROLLER_PATH}/config/cnao/001-kubevirtipamcontroller.yaml data/kubevirt-ipam-controller +sed -i '/app\.kubernetes\.io\//d' data/kubevirt-ipam-controller/001-kubevirtipamcontroller.yaml + +echo 'Get kubevirt-ipam-controller image name and update it under CNAO' +KUBEVIRT_IPAM_CONTROLLER_TAG=$(git-utils::get_component_tag ${KUBEVIRT_IPAM_CONTROLLER_PATH}) +KUBEVIRT_IPAM_CONTROLLER_IMAGE=ghcr.io/maiqueb/kubevirt-ipam-claims +KUBEVIRT_IPAM_CONTROLLER_IMAGE_TAGGED=${KUBEVIRT_IPAM_CONTROLLER_IMAGE}:${KUBEVIRT_IPAM_CONTROLLER_TAG} +KUBEVIRT_IPAM_CONTROLLER_IMAGE_DIGEST="$(docker-utils::get_image_digest "${KUBEVIRT_IPAM_CONTROLLER_IMAGE_TAGGED}" "${KUBEVIRT_IPAM_CONTROLLER_IMAGE}")" + +sed -i -r "s#\"${KUBEVIRT_IPAM_CONTROLLER_IMAGE}(@sha256)?:.*\"#\"${KUBEVIRT_IPAM_CONTROLLER_IMAGE_DIGEST}\"#" pkg/components/components.go +sed -i -r "s#\"${KUBEVIRT_IPAM_CONTROLLER_IMAGE}(@sha256)?:.*\"#\"${KUBEVIRT_IPAM_CONTROLLER_IMAGE_DIGEST}\"#" test/releases/${CNAO_VERSION}.go diff --git a/pkg/apis/networkaddonsoperator/shared/networkaddonsconfig_types.go b/pkg/apis/networkaddonsoperator/shared/networkaddonsconfig_types.go index 7372faff1..b7e7ca8e4 100644 --- a/pkg/apis/networkaddonsoperator/shared/networkaddonsconfig_types.go +++ b/pkg/apis/networkaddonsoperator/shared/networkaddonsconfig_types.go @@ -18,6 +18,7 @@ type NetworkAddonsConfigSpec struct { NMState *NMState `json:"nmstate,omitempty"` KubeSecondaryDNS *KubeSecondaryDNS `json:"kubeSecondaryDNS,omitempty"` MacvtapCni *MacvtapCni `json:"macvtap,omitempty"` + KubevirtIpamController *KubevirtIpamController `json:"kubevirtIpamController,omitempty"` SelfSignConfiguration *SelfSignConfiguration `json:"selfSignConfiguration,omitempty"` PlacementConfiguration *PlacementConfiguration `json:"placementConfiguration,omitempty"` TLSSecurityProfile *ocpv1.TLSSecurityProfile `json:"tlsSecurityProfile,omitempty"` @@ -87,6 +88,9 @@ type MacvtapCni struct { DevicePluginConfig string `json:"devicePluginConfig,omitempty"` } +// KubevirtIpamController plugin allows to support IPAM for secondary networks +type KubevirtIpamController struct{} + // NetworkAddonsConfigStatus defines the observed state of NetworkAddonsConfig type NetworkAddonsConfigStatus struct { OperatorVersion string `json:"operatorVersion,omitempty"` diff --git a/pkg/components/components.go b/pkg/components/components.go index c47787147..5bcfb5e35 100644 --- a/pkg/components/components.go +++ b/pkg/components/components.go @@ -30,29 +30,31 @@ var ( ) const ( - MultusImageDefault = "ghcr.io/k8snetworkplumbingwg/multus-cni@sha256:3fbcc32bd4e4d15bd93c96def784a229cd84cca27942bf4858b581f31c97ee02" - MultusDynamicNetworksImageDefault = "ghcr.io/k8snetworkplumbingwg/multus-dynamic-networks-controller@sha256:83b460502671fb4f34116363a1a39b2ddfc9d14a920ee0a6413bfc3bd0580404" - LinuxBridgeCniImageDefault = "quay.io/kubevirt/cni-default-plugins@sha256:0c354fa9d695b8cab97b459e8afea2f7662407a987e83f6f6f1a8af4b45726be" - LinuxBridgeMarkerImageDefault = "quay.io/kubevirt/bridge-marker@sha256:bba066e3b5ff3fb8c5e20861fe8abe51e3c9b50ad6ce3b2616af9cb5479a06d0" - KubeMacPoolImageDefault = "quay.io/kubevirt/kubemacpool@sha256:20e156be33e6d3692c456081acbb91a4349f94de448f7d1f1cddd0228931b31f" - OvsCniImageDefault = "quay.io/kubevirt/ovs-cni-plugin@sha256:e16ac74343da21abb8fb668ce71e728053d00503a992dae2164b9e94a280113e" - MacvtapCniImageDefault = "quay.io/kubevirt/macvtap-cni@sha256:850b89343ace7c7ea6b18dd8e11964613974e9d1f7377af03854d407fb15230a" - KubeRbacProxyImageDefault = "quay.io/openshift/origin-kube-rbac-proxy@sha256:e2def4213ec0657e72eb790ae8a115511d5b8f164a62d3568d2f1bff189917e8" - KubeSecondaryDNSImageDefault = "ghcr.io/kubevirt/kubesecondarydns@sha256:6268d84154e2483fbce8c1adacbdaf6f0839117b2d48d9fa4687cc8f76bd5130" - CoreDNSImageDefault = "registry.k8s.io/coredns/coredns@sha256:a0ead06651cf580044aeb0a0feba63591858fb2e43ade8c9dea45a6a89ae7e5e" + MultusImageDefault = "ghcr.io/k8snetworkplumbingwg/multus-cni@sha256:3fbcc32bd4e4d15bd93c96def784a229cd84cca27942bf4858b581f31c97ee02" + MultusDynamicNetworksImageDefault = "ghcr.io/k8snetworkplumbingwg/multus-dynamic-networks-controller@sha256:83b460502671fb4f34116363a1a39b2ddfc9d14a920ee0a6413bfc3bd0580404" + LinuxBridgeCniImageDefault = "quay.io/kubevirt/cni-default-plugins@sha256:0c354fa9d695b8cab97b459e8afea2f7662407a987e83f6f6f1a8af4b45726be" + LinuxBridgeMarkerImageDefault = "quay.io/kubevirt/bridge-marker@sha256:bba066e3b5ff3fb8c5e20861fe8abe51e3c9b50ad6ce3b2616af9cb5479a06d0" + KubeMacPoolImageDefault = "quay.io/kubevirt/kubemacpool@sha256:20e156be33e6d3692c456081acbb91a4349f94de448f7d1f1cddd0228931b31f" + OvsCniImageDefault = "quay.io/kubevirt/ovs-cni-plugin@sha256:e16ac74343da21abb8fb668ce71e728053d00503a992dae2164b9e94a280113e" + MacvtapCniImageDefault = "quay.io/kubevirt/macvtap-cni@sha256:850b89343ace7c7ea6b18dd8e11964613974e9d1f7377af03854d407fb15230a" + KubeRbacProxyImageDefault = "quay.io/openshift/origin-kube-rbac-proxy@sha256:e2def4213ec0657e72eb790ae8a115511d5b8f164a62d3568d2f1bff189917e8" + KubeSecondaryDNSImageDefault = "ghcr.io/kubevirt/kubesecondarydns@sha256:6268d84154e2483fbce8c1adacbdaf6f0839117b2d48d9fa4687cc8f76bd5130" + CoreDNSImageDefault = "registry.k8s.io/coredns/coredns@sha256:a0ead06651cf580044aeb0a0feba63591858fb2e43ade8c9dea45a6a89ae7e5e" + KubevirtIpamControllerImageDefault = "ghcr.io/maiqueb/kubevirt-ipam-claims@sha256:4667b37655dc87b79a63ca0b127517d0f9b971808b8fda8f5ea01398e8833294" ) type AddonsImages struct { - Multus string - MultusDynamicNetworks string - LinuxBridgeCni string - LinuxBridgeMarker string - KubeMacPool string - OvsCni string - MacvtapCni string - KubeRbacProxy string - KubeSecondaryDNS string - CoreDNS string + Multus string + MultusDynamicNetworks string + LinuxBridgeCni string + LinuxBridgeMarker string + KubeMacPool string + OvsCni string + MacvtapCni string + KubeRbacProxy string + KubeSecondaryDNS string + CoreDNS string + KubevirtIpamController string } type RelatedImage struct { @@ -107,6 +109,9 @@ func (ai *AddonsImages) FillDefaults() *AddonsImages { if ai.CoreDNS == "" { ai.CoreDNS = CoreDNSImageDefault } + if ai.KubevirtIpamController == "" { + ai.KubevirtIpamController = KubevirtIpamControllerImageDefault + } return ai } @@ -122,6 +127,7 @@ func (ai AddonsImages) ToRelatedImages() RelatedImages { ai.KubeRbacProxy, ai.KubeSecondaryDNS, ai.CoreDNS, + ai.KubevirtIpamController, ) } @@ -239,6 +245,10 @@ func GetDeployment(version string, operatorVersion string, namespace string, rep Name: "CORE_DNS_IMAGE", Value: addonsImages.CoreDNS, }, + { + Name: "KUBEVIRT_IPAM_CONTROLLER_IMAGE", + Value: addonsImages.KubevirtIpamController, + }, { Name: "OPERATOR_IMAGE", Value: image, @@ -458,6 +468,49 @@ func GetRole(namespace string) *rbacv1.Role { "delete", }, }, + { + APIGroups: []string{ + "", + }, + Resources: []string{ + "configmaps", + }, + Verbs: []string{ + "patch", + }, + }, + { + APIGroups: []string{ + "coordination.k8s.io", + }, + Resources: []string{ + "leases", + }, + Verbs: []string{ + "get", + "list", + "watch", + "create", + "update", + "patch", + "delete", + }, + }, + { + APIGroups: []string{ + "cert-manager.io", + }, + Resources: []string{ + "certificates", + "issuers", + }, + Verbs: []string{ + "get", + "create", + "update", + "delete", + }, + }, }, } return role @@ -653,6 +706,34 @@ func GetClusterRole(allowMultus bool) *rbacv1.ClusterRole { "delete", }, }, + { + APIGroups: []string{ + "k8s.cni.cncf.io", + }, + Resources: []string{ + "ipamclaims", + }, + Verbs: []string{ + "get", + "list", + "watch", + "create", + "update", + }, + }, + { + APIGroups: []string{ + "k8s.cni.cncf.io", + }, + Resources: []string{ + "network-attachment-definitions", + }, + Verbs: []string{ + "get", + "list", + "watch", + }, + }, }, } @@ -1273,6 +1354,10 @@ func GetCrd() *extv1.CustomResourceDefinition { Description: "Ovs plugin allows users to define Kubernetes networks on top of Open vSwitch bridges available on nodes", Type: "object", }, + "kubevirtIpamController": extv1.JSONSchemaProps{ + Description: "KubevirtIpamController plugin allows to support IPAM for secondary networks", + Type: "object", + }, "selfSignConfiguration": extv1.JSONSchemaProps{ Description: "SelfSignConfiguration defines self sign configuration", Type: "object", @@ -1485,14 +1570,15 @@ func GetCRV1() *cnaov1.NetworkAddonsConfig { Name: "cluster", }, Spec: cnao.NetworkAddonsConfigSpec{ - Multus: &cnao.Multus{}, - MultusDynamicNetworks: &cnao.MultusDynamicNetworks{}, - LinuxBridge: &cnao.LinuxBridge{}, - KubeMacPool: &cnao.KubeMacPool{}, - Ovs: &cnao.Ovs{}, - MacvtapCni: &cnao.MacvtapCni{}, - KubeSecondaryDNS: &cnao.KubeSecondaryDNS{}, - ImagePullPolicy: corev1.PullIfNotPresent, + Multus: &cnao.Multus{}, + MultusDynamicNetworks: &cnao.MultusDynamicNetworks{}, + LinuxBridge: &cnao.LinuxBridge{}, + KubeMacPool: &cnao.KubeMacPool{}, + Ovs: &cnao.Ovs{}, + MacvtapCni: &cnao.MacvtapCni{}, + KubeSecondaryDNS: &cnao.KubeSecondaryDNS{}, + KubevirtIpamController: &cnao.KubevirtIpamController{}, + ImagePullPolicy: corev1.PullIfNotPresent, }, } } diff --git a/pkg/network/kubevirt_ipam_controller.go b/pkg/network/kubevirt_ipam_controller.go new file mode 100644 index 000000000..4a6319631 --- /dev/null +++ b/pkg/network/kubevirt_ipam_controller.go @@ -0,0 +1,47 @@ +package network + +import ( + "os" + "path/filepath" + + "github.com/pkg/errors" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + + cnao "github.com/kubevirt/cluster-network-addons-operator/pkg/apis/networkaddonsoperator/shared" + "github.com/kubevirt/cluster-network-addons-operator/pkg/render" +) + +// renderKubevirtIPAMController generates the manifests of kubevirt-ipam-controller +func renderKubevirtIPAMController(conf *cnao.NetworkAddonsConfigSpec, manifestDir string, clusterInfo *ClusterInfo) ([]*unstructured.Unstructured, error) { + if conf.KubevirtIpamController == nil { + return nil, nil + } + + // render the manifests on disk + data := render.MakeRenderData() + data.Data["Namespace"] = os.Getenv("OPERAND_NAMESPACE") + data.Data["ImagePullPolicy"] = conf.ImagePullPolicy + data.Data["Placement"] = conf.PlacementConfiguration.Workloads + data.Data["KubevirtIpamControllerImage"] = os.Getenv("KUBEVIRT_IPAM_CONTROLLER_IMAGE") + + if clusterInfo.OpenShift4 { + data.Data["WebhookAnnotation"] = `service.beta.openshift.io/inject-cabundle: "true"` + data.Data["CertDir"] = "/etc/ipam-controller/certificates" + data.Data["MountPath"] = data.Data["CertDir"] + data.Data["SecretName"] = "kubevirt-ipam-claims-webhook-service" + } else { + data.Data["WebhookAnnotation"] = + "cert-manager.io/inject-ca-from: " + os.Getenv("OPERAND_NAMESPACE") + "/kubevirt-ipam-claims-serving-cert" + data.Data["CertDir"] = "" + data.Data["MountPath"] = "/tmp/k8s-webhook-server/serving-certs" + data.Data["SecretName"] = "webhook-server-cert" + } + data.Data["IsOpenshift"] = clusterInfo.OpenShift4 + + objs, err := render.RenderDir(filepath.Join(manifestDir, "kubevirt-ipam-controller"), &data) + if err != nil { + return nil, errors.Wrap(err, "failed to render kubevirt-ipam-controller state handler manifests") + } + + return objs, nil +} diff --git a/pkg/network/network.go b/pkg/network/network.go index c3b9d23a4..51b8667c3 100644 --- a/pkg/network/network.go +++ b/pkg/network/network.go @@ -162,6 +162,13 @@ func Render(conf *cnao.NetworkAddonsConfigSpec, manifestDir string, openshiftNet } objs = append(objs, o...) + // render KubevirtIPAMController + o, err = renderKubevirtIPAMController(conf, manifestDir, clusterInfo) + if err != nil { + return nil, err + } + objs = append(objs, o...) + // render Monitoring Service o, err = monitoring.RenderMonitoring(manifestDir, clusterInfo.MonitoringAvailable) if err != nil { @@ -240,6 +247,14 @@ func RenderObjsToRemove(prev, conf *cnao.NetworkAddonsConfigSpec, manifestDir st objsToRemove = append(objsToRemove, o...) } + if conf.KubevirtIpamController == nil { + o, err := renderKubevirtIPAMController(prev, manifestDir, clusterInfo) + if err != nil { + return nil, err + } + objsToRemove = append(objsToRemove, o...) + } + // Remove OPERAND_NAMESPACE occurences // TODO cleanup OPERAND_NAMESPACE once there are no components using it. objsToRemoveWithoutNamespace := []*unstructured.Unstructured{} diff --git a/test/check/components.go b/test/check/components.go index f2fa6abf9..36d8aa4f8 100644 --- a/test/check/components.go +++ b/test/check/components.go @@ -86,6 +86,12 @@ var ( ClusterRoleBinding: "secondary", Deployments: []string{"secondary-dns"}, } + KubevirtIpamController = Component{ + ComponentName: "KubevirtIpamController", + ClusterRole: "kubevirt-ipam-claims-manager-role", + ClusterRoleBinding: "kubevirt-ipam-claims-manager-rolebinding", + Deployments: []string{"kubevirt-ipam-claims-controller-manager"}, + } AllComponents = []Component{ KubeMacPoolComponent, LinuxBridgeComponent, @@ -95,6 +101,7 @@ var ( MonitoringComponent, MultusDynamicNetworks, KubeSecondaryDNSComponent, + KubevirtIpamController, } ) diff --git a/test/e2e/workflow/deployment_test.go b/test/e2e/workflow/deployment_test.go index 8ca017c0d..f29a215b2 100644 --- a/test/e2e/workflow/deployment_test.go +++ b/test/e2e/workflow/deployment_test.go @@ -88,6 +88,13 @@ var _ = Describe("NetworkAddonsConfig", func() { }, []Component{KubeSecondaryDNSComponent}, ), + Entry( + KubevirtIpamController.ComponentName, + cnao.NetworkAddonsConfigSpec{ + KubevirtIpamController: &cnao.KubevirtIpamController{}, + }, + []Component{KubevirtIpamController}, + ), ) It("should deploy prometheus if NetworkAddonsConfigSpec is not empty", func() { testConfigCreate(gvk, cnao.NetworkAddonsConfigSpec{MacvtapCni: &cnao.MacvtapCni{}}, []Component{MacvtapComponent, MonitoringComponent}) @@ -102,15 +109,17 @@ var _ = Describe("NetworkAddonsConfig", func() { MacvtapComponent, MultusDynamicNetworks, KubeSecondaryDNSComponent, + KubevirtIpamController, } configSpec := cnao.NetworkAddonsConfigSpec{ - KubeMacPool: &cnao.KubeMacPool{}, - LinuxBridge: &cnao.LinuxBridge{}, - Multus: &cnao.Multus{}, - Ovs: &cnao.Ovs{}, - MacvtapCni: &cnao.MacvtapCni{}, - MultusDynamicNetworks: &cnao.MultusDynamicNetworks{}, - KubeSecondaryDNS: &cnao.KubeSecondaryDNS{}, + KubeMacPool: &cnao.KubeMacPool{}, + LinuxBridge: &cnao.LinuxBridge{}, + Multus: &cnao.Multus{}, + Ovs: &cnao.Ovs{}, + MacvtapCni: &cnao.MacvtapCni{}, + MultusDynamicNetworks: &cnao.MultusDynamicNetworks{}, + KubeSecondaryDNS: &cnao.KubeSecondaryDNS{}, + KubevirtIpamController: &cnao.KubevirtIpamController{}, } testConfigCreate(gvk, configSpec, components) }) @@ -159,6 +168,11 @@ var _ = Describe("NetworkAddonsConfig", func() { configSpec.KubeSecondaryDNS = &cnao.KubeSecondaryDNS{} components = append(components, KubeSecondaryDNSComponent) testConfigUpdate(gvk, configSpec, components) + + // Add KubevirtIpamController component + configSpec.KubevirtIpamController = &cnao.KubevirtIpamController{} + components = append(components, KubevirtIpamController) + testConfigUpdate(gvk, configSpec, components) }) Context("and workload PlacementConfiguration is deployed on components", func() { components := []Component{ @@ -167,6 +181,7 @@ var _ = Describe("NetworkAddonsConfig", func() { LinuxBridgeComponent, MultusComponent, KubeSecondaryDNSComponent, + KubevirtIpamController, } configSpec := cnao.NetworkAddonsConfigSpec{ LinuxBridge: &cnao.LinuxBridge{}, @@ -175,6 +190,7 @@ var _ = Describe("NetworkAddonsConfig", func() { MacvtapCni: &cnao.MacvtapCni{}, MultusDynamicNetworks: &cnao.MultusDynamicNetworks{}, KubeSecondaryDNS: &cnao.KubeSecondaryDNS{}, + KubevirtIpamController: &cnao.KubevirtIpamController{}, PlacementConfiguration: &cnao.PlacementConfiguration{}, } checkWorkloadPlacementOnComponents := func(expectedWorkLoadPlacement cnao.Placement) { diff --git a/test/releases/99.0.0.go b/test/releases/99.0.0.go index 2cd0e4ab8..920b0b141 100644 --- a/test/releases/99.0.0.go +++ b/test/releases/99.0.0.go @@ -80,14 +80,21 @@ func init() { Name: "secondary-dns", Image: "registry.k8s.io/coredns/coredns@sha256:a0ead06651cf580044aeb0a0feba63591858fb2e43ade8c9dea45a6a89ae7e5e", }, + { + ParentName: "kubevirt-ipam-claims-controller-manager", + ParentKind: "Deployment", + Name: "manager", + Image: "ghcr.io/maiqueb/kubevirt-ipam-claims@sha256:4667b37655dc87b79a63ca0b127517d0f9b971808b8fda8f5ea01398e8833294", + }, }, SupportedSpec: cnao.NetworkAddonsConfigSpec{ - KubeMacPool: &cnao.KubeMacPool{}, - LinuxBridge: &cnao.LinuxBridge{}, - Multus: &cnao.Multus{}, - Ovs: &cnao.Ovs{}, - MultusDynamicNetworks: &cnao.MultusDynamicNetworks{}, - KubeSecondaryDNS: &cnao.KubeSecondaryDNS{}, + KubeMacPool: &cnao.KubeMacPool{}, + LinuxBridge: &cnao.LinuxBridge{}, + Multus: &cnao.Multus{}, + Ovs: &cnao.Ovs{}, + MultusDynamicNetworks: &cnao.MultusDynamicNetworks{}, + KubeSecondaryDNS: &cnao.KubeSecondaryDNS{}, + KubevirtIpamController: &cnao.KubevirtIpamController{}, }, Manifests: []string{ "network-addons-config.crd.yaml", diff --git a/tools/manifest-templator/manifest-templator.go b/tools/manifest-templator/manifest-templator.go index fec0825a3..cf2a8f896 100644 --- a/tools/manifest-templator/manifest-templator.go +++ b/tools/manifest-templator/manifest-templator.go @@ -251,6 +251,7 @@ func main() { coreDNSImage := flag.String("core-dns-image", components.CoreDNSImageDefault, "The coredns image used by CNA") multusDynamicNetworksImage := flag.String("multus-dynamic-networks-image", components.MultusDynamicNetworksImageDefault, "The multus dynamic networks controller image managed by CNA") kubeSecondaryDNSImage := flag.String("kube-secondary-dns", components.KubeSecondaryDNSImageDefault, "The kubesecondarydns-image managed by CNA") + kubevirtIpamControllerImage := flag.String("kubevirt-ipam-controller", components.KubevirtIpamControllerImageDefault, "The kubevirtipamcontroller-image managed by CNA") dumpOperatorCRD := flag.Bool("dump-crds", false, "Append operator CRD to bottom of template. Used for csv-generator") inputFile := flag.String("input-file", "", "Not used for csv-generator") pflag.CommandLine.AddGoFlagSet(flag.CommandLine) @@ -267,16 +268,17 @@ func main() { ContainerTag: *containerTag, ImagePullPolicy: *imagePullPolicy, AddonsImages: (&components.AddonsImages{ - Multus: *multusImage, - LinuxBridgeCni: *linuxBridgeCniImage, - LinuxBridgeMarker: *linuxBridgeMarkerImage, - KubeMacPool: *kubeMacPoolImage, - OvsCni: *ovsCniImage, - MacvtapCni: *macvtapCniImage, - KubeRbacProxy: *kubeRbacProxyImage, - MultusDynamicNetworks: *multusDynamicNetworksImage, - KubeSecondaryDNS: *kubeSecondaryDNSImage, - CoreDNS: *coreDNSImage, + Multus: *multusImage, + LinuxBridgeCni: *linuxBridgeCniImage, + LinuxBridgeMarker: *linuxBridgeMarkerImage, + KubeMacPool: *kubeMacPoolImage, + OvsCni: *ovsCniImage, + MacvtapCni: *macvtapCniImage, + KubeRbacProxy: *kubeRbacProxyImage, + MultusDynamicNetworks: *multusDynamicNetworksImage, + KubeSecondaryDNS: *kubeSecondaryDNSImage, + KubevirtIpamController: *kubevirtIpamControllerImage, + CoreDNS: *coreDNSImage, }).FillDefaults(), }