diff --git a/api/v1/nodefeaturediscovery_types.go b/api/v1/nodefeaturediscovery_types.go index 37d571a2..9375435c 100644 --- a/api/v1/nodefeaturediscovery_types.go +++ b/api/v1/nodefeaturediscovery_types.go @@ -24,8 +24,17 @@ import ( // NodeFeatureDiscoverySpec defines the desired state of NodeFeatureDiscovery // +k8s:openapi-gen=true type NodeFeatureDiscoverySpec struct { + // +optional Operand OperandSpec `json:"operand"` + // Deploy the NFD-Topology-Updater + // NFD-Topology-Updater is a daemon responsible for examining allocated + // resources on a worker node to account for resources available to be + // allocated to new pod on a per-zone basis + // https://kubernetes-sigs.github.io/node-feature-discovery/v0.10/get-started/introduction.html#nfd-topology-updater + // +optional + TopologyUpdater bool `json:"topologyUpdater"` + // Instance name. Used to separate annotation namespaces for // multiple parallel deployments. // +optional diff --git a/build/assets/topologyupdater/01_sa.yaml b/build/assets/topologyupdater/01_sa.yaml new file mode 100644 index 00000000..3406b1f8 --- /dev/null +++ b/build/assets/topologyupdater/01_sa.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: nfd-topology-updater \ No newline at end of file diff --git a/build/assets/topologyupdater/02_clusterrole.yaml b/build/assets/topologyupdater/02_clusterrole.yaml new file mode 100644 index 00000000..5f8c2667 --- /dev/null +++ b/build/assets/topologyupdater/02_clusterrole.yaml @@ -0,0 +1,18 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: nfd-topology-updater +rules: +- apiGroups: + - "" + resources: + - nodes + verbs: + - get + - list +- apiGroups: + - "" + resources: + - pods + verbs: + - get \ No newline at end of file diff --git a/build/assets/topologyupdater/03_clusterrolebinding.yaml b/build/assets/topologyupdater/03_clusterrolebinding.yaml new file mode 100644 index 00000000..33e16d2d --- /dev/null +++ b/build/assets/topologyupdater/03_clusterrolebinding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: nfd-topology-updater +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: nfd-topology-updater +subjects: +- kind: ServiceAccount + name: nfd-topology-updater + namespace: node-feature-discovery \ No newline at end of file diff --git a/build/assets/topologyupdater/05_Daemonset.yaml b/build/assets/topologyupdater/05_Daemonset.yaml new file mode 100644 index 00000000..9b893194 --- /dev/null +++ b/build/assets/topologyupdater/05_Daemonset.yaml @@ -0,0 +1,63 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + labels: + app: nfd + name: nfd-topology-updater +spec: + selector: + matchLabels: + app: nfd-topology-updater + template: + metadata: + labels: + app: nfd-topology-updater + spec: + containers: + - args: + - -server=nfd-master:$(NFD_MASTER_SERVICE_PORT) + - -kubelet-config-file=/host-var/lib/kubelet/config.yaml + - -podresources-socket=/host-var/lib/kubelet/pod-resources/kubelet.sock + - -sleep-interval=3s + command: + - nfd-topology-updater + env: + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + image: $(NODE_FEATURE_DISCOVERY_IMAGE) + imagePullPolicy: Always + name: nfd-topology-updater + securityContext: + seLinuxOptions: + type: "container_runtime_t" + allowPrivilegeEscalation: true + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsUser: 0 + volumeMounts: + - mountPath: "/host-var/lib/kubelet/config.yaml" + name: kubelet-podresources-conf + readOnly: true + - mountPath: /host-var/lib/kubelet/pod-resources/kubelet.sock + name: kubelet-podresources-sock + - mountPath: /host-sys + name: host-sys + dnsPolicy: ClusterFirstWithHostNet + serviceAccount: nfd-topology-updater + volumes: + - hostPath: + path: /sys + type: Directory + name: host-sys + - hostPath: + path: "/etc/kubernetes/kubelet.conf" + type: File + name: kubelet-podresources-conf + - hostPath: + path: /var/lib/kubelet/pod-resources/kubelet.sock + type: Socket + name: kubelet-podresources-sock diff --git a/config/crd/bases/nfd.kubernetes.io_nodefeaturediscoveries.yaml b/config/crd/bases/nfd.kubernetes.io_nodefeaturediscoveries.yaml index 79d2b56d..c5293e37 100644 --- a/config/crd/bases/nfd.kubernetes.io_nodefeaturediscoveries.yaml +++ b/config/crd/bases/nfd.kubernetes.io_nodefeaturediscoveries.yaml @@ -79,6 +79,12 @@ spec: type: string nullable: true type: array + topologyUpdater: + description: Deploy the NFD-Topology-Updater NFD-Topology-Updater + is a daemon responsible for examining allocated resources on a worker + node to account for resources available to be allocated to new pod + on a per-zone basis https://kubernetes-sigs.github.io/node-feature-discovery/v0.10/get-started/introduction.html#nfd-topology-updater + type: boolean workerConfig: description: WorkerConfig describes configuration options for the NFD worker. @@ -89,8 +95,6 @@ spec: required: - configData type: object - required: - - operand type: object status: description: NodeFeatureDiscoveryStatus defines the observed state of diff --git a/controllers/nodefeaturediscovery_controls.go b/controllers/nodefeaturediscovery_controls.go index 48d0a7fb..1cdadfb1 100644 --- a/controllers/nodefeaturediscovery_controls.go +++ b/controllers/nodefeaturediscovery_controls.go @@ -68,6 +68,11 @@ func ServiceAccount(n NFD) (ResourceStatus, error) { // object obj := n.resources[state].ServiceAccount + // Check if nfd-topology-updater is needed, if not, skip + if !n.ins.Spec.TopologyUpdater && obj.ObjectMeta.Name == nfdTopologyApp { + return Ready, nil + } + // It is also assumed that our service account has a defined Namespace obj.SetNamespace(n.ins.GetNamespace()) @@ -116,6 +121,11 @@ func ClusterRole(n NFD) (ResourceStatus, error) { // object obj := n.resources[state].ClusterRole + // Check if nfd-topology-updater is needed, if not, skip + if !n.ins.Spec.TopologyUpdater && obj.ObjectMeta.Name == nfdTopologyApp { + return Ready, nil + } + // found states if the ClusterRole was found found := &rbacv1.ClusterRole{} @@ -158,6 +168,11 @@ func ClusterRoleBinding(n NFD) (ResourceStatus, error) { // ClusterRoleBinding object obj := n.resources[state].ClusterRoleBinding + // Check if nfd-topology-updater is needed, if not, skip + if !n.ins.Spec.TopologyUpdater && obj.ObjectMeta.Name == nfdTopologyApp { + return Ready, nil + } + // found states if the ClusterRoleBinding was found found := &rbacv1.ClusterRoleBinding{} @@ -365,6 +380,11 @@ func DaemonSet(n NFD) (ResourceStatus, error) { // DaemonSet object, so let's get the resource's DaemonSet object obj := n.resources[state].DaemonSet + // Check if nfd-topology-updater is needed, if not, skip + if !n.ins.Spec.TopologyUpdater && obj.ObjectMeta.Name == nfdTopologyApp { + return Ready, nil + } + // Update the NFD operand image obj.Spec.Template.Spec.Containers[0].Image = n.ins.Spec.Operand.ImagePath() diff --git a/controllers/nodefeaturediscovery_state.go b/controllers/nodefeaturediscovery_state.go index 4cd1353f..8bc32705 100644 --- a/controllers/nodefeaturediscovery_state.go +++ b/controllers/nodefeaturediscovery_state.go @@ -63,6 +63,7 @@ func (n *NFD) init( if len(n.controls) == 0 { n.addState("/opt/nfd/master") n.addState("/opt/nfd/worker") + n.addState("/opt/nfd/topologyupdater") } } diff --git a/controllers/nodefeaturediscovery_status.go b/controllers/nodefeaturediscovery_status.go index 1054d544..29b53beb 100644 --- a/controllers/nodefeaturediscovery_status.go +++ b/controllers/nodefeaturediscovery_status.go @@ -30,8 +30,9 @@ import ( ) const ( - nfdWorkerApp string = "nfd-worker" - nfdMasterApp string = "nfd-master" + nfdWorkerApp string = "nfd-worker" + nfdMasterApp string = "nfd-master" + nfdTopologyApp string = "nfd-topology-updater" ) const (