mirror of
https://github.com/intel/intel-device-plugins-for-kubernetes.git
synced 2025-06-03 03:59:37 +00:00
operator: test NewDaemonSet for all plugins
Signed-off-by: Ed Bartosh <eduard.bartosh@intel.com>
This commit is contained in:
parent
b6caadfc63
commit
b9b2de7889
146
pkg/controllers/dlb/controller_test.go
Normal file
146
pkg/controllers/dlb/controller_test.go
Normal file
@ -0,0 +1,146 @@
|
||||
// Copyright 2021 Intel Corporation. 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.
|
||||
|
||||
// Package dlb contains DLB specific reconciliation logic.
|
||||
package dlb
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
apps "k8s.io/api/apps/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
devicepluginv1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/deviceplugin/v1"
|
||||
)
|
||||
|
||||
const appLabel = "intel-dlb-plugin"
|
||||
|
||||
func (c *controller) newDaemonSetExpected(rawObj client.Object) *apps.DaemonSet {
|
||||
devicePlugin := rawObj.(*devicepluginv1.DlbDevicePlugin)
|
||||
yes := true
|
||||
|
||||
daemonSet := apps.DaemonSet{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "DaemonSet",
|
||||
APIVersion: "apps/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: c.ns,
|
||||
Name: "intel-dlb-plugin",
|
||||
Labels: map[string]string{
|
||||
"app": appLabel,
|
||||
},
|
||||
},
|
||||
Spec: apps.DaemonSetSpec{
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"app": appLabel,
|
||||
},
|
||||
},
|
||||
Template: v1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{
|
||||
"app": appLabel,
|
||||
},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: appLabel,
|
||||
Env: []v1.EnvVar{
|
||||
{
|
||||
Name: "NODE_NAME",
|
||||
ValueFrom: &v1.EnvVarSource{
|
||||
FieldRef: &v1.ObjectFieldSelector{
|
||||
FieldPath: "spec.nodeName",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
TerminationMessagePath: "/tmp/termination-log",
|
||||
Args: getPodArgs(devicePlugin),
|
||||
Image: devicePlugin.Spec.Image,
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
SecurityContext: &v1.SecurityContext{
|
||||
ReadOnlyRootFilesystem: &yes,
|
||||
},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: "devfs",
|
||||
MountPath: "/dev",
|
||||
ReadOnly: true,
|
||||
},
|
||||
{
|
||||
Name: "sysfs",
|
||||
MountPath: "/sys/class/dlb2",
|
||||
ReadOnly: true,
|
||||
},
|
||||
{
|
||||
Name: "kubeletsockets",
|
||||
MountPath: "/var/lib/kubelet/device-plugins",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
NodeSelector: map[string]string{"kubernetes.io/arch": "amd64"},
|
||||
Volumes: []v1.Volume{
|
||||
{
|
||||
Name: "devfs",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: &v1.HostPathVolumeSource{
|
||||
Path: "/dev",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "sysfs",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: &v1.HostPathVolumeSource{
|
||||
Path: "/sys/class/dlb2",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "kubeletsockets",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: &v1.HostPathVolumeSource{
|
||||
Path: "/var/lib/kubelet/device-plugins",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
return &daemonSet
|
||||
}
|
||||
|
||||
// Test that DLB daemonset created by using go:embed is
|
||||
// equal to the expected daemonset.
|
||||
func TestNewDaemonSetDLB(t *testing.T) {
|
||||
plugin := &devicepluginv1.DlbDevicePlugin{}
|
||||
c := &controller{}
|
||||
|
||||
expected := c.newDaemonSetExpected(plugin)
|
||||
actual := c.NewDaemonSet(plugin)
|
||||
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Errorf("expected and actuall daemonsets differ: %+s", diff.ObjectGoPrintDiff(expected, actual))
|
||||
}
|
||||
}
|
205
pkg/controllers/dsa/controller_test.go
Normal file
205
pkg/controllers/dsa/controller_test.go
Normal file
@ -0,0 +1,205 @@
|
||||
// Copyright 2021 Intel Corporation. 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.
|
||||
|
||||
package dsa
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
apps "k8s.io/api/apps/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
devicepluginv1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/deviceplugin/v1"
|
||||
)
|
||||
|
||||
const appLabel = "intel-dsa-plugin"
|
||||
|
||||
// newDaemonSetExpected creates plugin daemonset
|
||||
// it's copied from the original controller code (before the usage of go:embed).
|
||||
func (c *controller) newDaemonSetExpected(rawObj client.Object) *apps.DaemonSet {
|
||||
devicePlugin := rawObj.(*devicepluginv1.DsaDevicePlugin)
|
||||
|
||||
var nodeSelector map[string]string
|
||||
dpNodeSelectorSize := len(devicePlugin.Spec.NodeSelector)
|
||||
if dpNodeSelectorSize > 0 {
|
||||
nodeSelector = make(map[string]string, dpNodeSelectorSize+1)
|
||||
for k, v := range devicePlugin.Spec.NodeSelector {
|
||||
nodeSelector[k] = v
|
||||
}
|
||||
nodeSelector["kubernetes.io/arch"] = "amd64"
|
||||
} else {
|
||||
nodeSelector = map[string]string{"kubernetes.io/arch": "amd64"}
|
||||
}
|
||||
|
||||
yes := true
|
||||
daemonSet := apps.DaemonSet{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "DaemonSet",
|
||||
APIVersion: "apps/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: c.ns,
|
||||
Name: "intel-dsa-plugin",
|
||||
Labels: map[string]string{
|
||||
"app": appLabel,
|
||||
},
|
||||
},
|
||||
Spec: apps.DaemonSetSpec{
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"app": appLabel,
|
||||
},
|
||||
},
|
||||
Template: v1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{
|
||||
"app": appLabel,
|
||||
},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: appLabel,
|
||||
Env: []v1.EnvVar{
|
||||
{
|
||||
Name: "NODE_NAME",
|
||||
ValueFrom: &v1.EnvVarSource{
|
||||
FieldRef: &v1.ObjectFieldSelector{
|
||||
FieldPath: "spec.nodeName",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Args: getPodArgs(devicePlugin),
|
||||
Image: devicePlugin.Spec.Image,
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
SecurityContext: &v1.SecurityContext{
|
||||
ReadOnlyRootFilesystem: &yes,
|
||||
},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: "devfs",
|
||||
MountPath: "/dev/dsa",
|
||||
ReadOnly: true,
|
||||
},
|
||||
{
|
||||
Name: "chardevs",
|
||||
MountPath: "/dev/char",
|
||||
ReadOnly: true,
|
||||
},
|
||||
{
|
||||
Name: "sysfs",
|
||||
MountPath: "/sys/bus/dsa",
|
||||
ReadOnly: true,
|
||||
},
|
||||
{
|
||||
Name: "kubeletsockets",
|
||||
MountPath: "/var/lib/kubelet/device-plugins",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
NodeSelector: nodeSelector,
|
||||
Volumes: []v1.Volume{
|
||||
{
|
||||
Name: "devfs",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: &v1.HostPathVolumeSource{
|
||||
Path: "/dev/dsa",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "chardevs",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: &v1.HostPathVolumeSource{
|
||||
Path: "/dev/char",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "sysfs",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: &v1.HostPathVolumeSource{
|
||||
Path: "/sys/bus/dsa",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "kubeletsockets",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: &v1.HostPathVolumeSource{
|
||||
Path: "/var/lib/kubelet/device-plugins",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// add the optional init container
|
||||
if devicePlugin.Spec.InitImage != "" {
|
||||
setInitContainer(&daemonSet.Spec.Template.Spec, devicePlugin.Spec.InitImage)
|
||||
|
||||
daemonSet.Spec.Template.Spec.Volumes = append(daemonSet.Spec.Template.Spec.Volumes, v1.Volume{
|
||||
Name: "sys-devices",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: &v1.HostPathVolumeSource{
|
||||
Path: "/sys/devices",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if devicePlugin.Spec.ProvisioningConfig != "" {
|
||||
daemonSet.Spec.Template.Spec.Volumes = append(daemonSet.Spec.Template.Spec.Volumes, v1.Volume{
|
||||
Name: "intel-dsa-config-volume",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
ConfigMap: &v1.ConfigMapVolumeSource{
|
||||
LocalObjectReference: v1.LocalObjectReference{Name: devicePlugin.Spec.ProvisioningConfig}},
|
||||
},
|
||||
})
|
||||
|
||||
for i, initcontainer := range daemonSet.Spec.Template.Spec.InitContainers {
|
||||
if initcontainer.Name == "intel-idxd-initcontainer" {
|
||||
daemonSet.Spec.Template.Spec.InitContainers[i].VolumeMounts = append(daemonSet.Spec.Template.Spec.InitContainers[i].VolumeMounts, v1.VolumeMount{
|
||||
Name: "intel-dsa-config-volume",
|
||||
MountPath: "/idxd-init/conf",
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &daemonSet
|
||||
}
|
||||
|
||||
// Test that DSA daemonset created by using go:embed is
|
||||
// equal to the expected daemonset.
|
||||
func TestNewDaemonSetDSA(t *testing.T) {
|
||||
plugin := &devicepluginv1.DsaDevicePlugin{}
|
||||
c := &controller{}
|
||||
|
||||
expected := c.newDaemonSetExpected(plugin)
|
||||
actual := c.NewDaemonSet(plugin)
|
||||
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Errorf("expected and actuall daemonsets differ: %+s", diff.ObjectGoPrintDiff(expected, actual))
|
||||
}
|
||||
}
|
190
pkg/controllers/fpga/controller_test.go
Normal file
190
pkg/controllers/fpga/controller_test.go
Normal file
@ -0,0 +1,190 @@
|
||||
// Copyright 2021 Intel Corporation. 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.
|
||||
|
||||
// Package fpga contains FPGA specific reconciliation logic.
|
||||
package fpga
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
apps "k8s.io/api/apps/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
devicepluginv1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/deviceplugin/v1"
|
||||
)
|
||||
|
||||
const appLabel = "intel-fpga-plugin"
|
||||
|
||||
// newDaemonSetExpected creates plugin daemonset
|
||||
// it's copied from the original controller code (before the usage of go:embed).
|
||||
func (c *controller) newDaemonSetExpected(rawObj client.Object) *apps.DaemonSet {
|
||||
devicePlugin := rawObj.(*devicepluginv1.FpgaDevicePlugin)
|
||||
yes := true
|
||||
directoryOrCreate := v1.HostPathDirectoryOrCreate
|
||||
return &apps.DaemonSet{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "DaemonSet",
|
||||
APIVersion: "apps/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: c.ns,
|
||||
Name: "fpgadeviceplugin",
|
||||
Labels: map[string]string{
|
||||
"app": appLabel,
|
||||
},
|
||||
},
|
||||
Spec: apps.DaemonSetSpec{
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"app": appLabel,
|
||||
},
|
||||
},
|
||||
Template: v1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{
|
||||
"app": appLabel,
|
||||
},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Args: getPodArgs(devicePlugin),
|
||||
Env: []v1.EnvVar{
|
||||
{
|
||||
Name: "NODE_NAME",
|
||||
ValueFrom: &v1.EnvVarSource{
|
||||
FieldRef: &v1.ObjectFieldSelector{
|
||||
FieldPath: "spec.nodeName",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Image: devicePlugin.Spec.Image,
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
Name: appLabel,
|
||||
SecurityContext: &v1.SecurityContext{
|
||||
ReadOnlyRootFilesystem: &yes,
|
||||
},
|
||||
TerminationMessagePath: "/tmp/termination-log",
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
MountPath: "/dev",
|
||||
Name: "devfs",
|
||||
ReadOnly: true,
|
||||
},
|
||||
{
|
||||
MountPath: "/sys/class",
|
||||
Name: "sysfs",
|
||||
ReadOnly: true,
|
||||
},
|
||||
{
|
||||
MountPath: "/var/lib/kubelet/device-plugins",
|
||||
Name: "kubeletsockets",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
InitContainers: []v1.Container{
|
||||
{
|
||||
Image: devicePlugin.Spec.InitImage,
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
Name: "intel-fpga-initcontainer",
|
||||
SecurityContext: &v1.SecurityContext{
|
||||
ReadOnlyRootFilesystem: &yes,
|
||||
},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
MountPath: "/opt/intel/fpga-sw",
|
||||
Name: "intel-fpga-sw",
|
||||
},
|
||||
{
|
||||
MountPath: "/etc/containers/oci/hooks.d",
|
||||
Name: "oci-hooks-config",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
NodeSelector: devicePlugin.Spec.NodeSelector,
|
||||
Volumes: []v1.Volume{
|
||||
{
|
||||
Name: "devfs",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: &v1.HostPathVolumeSource{
|
||||
Path: "/dev",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "sysfs",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: &v1.HostPathVolumeSource{
|
||||
Path: "/sys/class",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "kubeletsockets",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: &v1.HostPathVolumeSource{
|
||||
Path: "/var/lib/kubelet/device-plugins",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "intel-fpga-sw",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: &v1.HostPathVolumeSource{
|
||||
Path: "/opt/intel/fpga-sw",
|
||||
Type: &directoryOrCreate,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "oci-hooks-config",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: &v1.HostPathVolumeSource{
|
||||
Path: "/etc/containers/oci/hooks.d",
|
||||
Type: &directoryOrCreate,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Test that FPGA daemonset created by using go:embed is
|
||||
// equal to the expected daemonset.
|
||||
func TestNewDaemonSetFPGA(t *testing.T) {
|
||||
c := &controller{}
|
||||
|
||||
plugin := &devicepluginv1.FpgaDevicePlugin{
|
||||
Spec: devicepluginv1.FpgaDevicePluginSpec{
|
||||
InitImage: "intel/intel-fpga-initcontainer:devel",
|
||||
},
|
||||
}
|
||||
|
||||
expected := c.newDaemonSetExpected(plugin)
|
||||
actual := c.NewDaemonSet(plugin)
|
||||
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Errorf("expected and actuall daemonsets differ: %+s", diff.ObjectGoPrintDiff(expected, actual))
|
||||
}
|
||||
}
|
210
pkg/controllers/gpu/controller_test.go
Normal file
210
pkg/controllers/gpu/controller_test.go
Normal file
@ -0,0 +1,210 @@
|
||||
// Copyright 2021 Intel Corporation. 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.
|
||||
|
||||
// Package gpu contains GPU specific reconciliation logic.
|
||||
package gpu
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
apps "k8s.io/api/apps/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
devicepluginv1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/deviceplugin/v1"
|
||||
)
|
||||
|
||||
const appLabel = "intel-gpu-plugin"
|
||||
|
||||
// newDaemonSetExpected creates plugin daemonset
|
||||
// it's copied from the original controller code (before the usage of go:embed).
|
||||
func (c *controller) newDaemonSetExpected(rawObj client.Object) *apps.DaemonSet {
|
||||
devicePlugin := rawObj.(*devicepluginv1.GpuDevicePlugin)
|
||||
|
||||
var nodeSelector map[string]string
|
||||
dpNodeSelectorSize := len(devicePlugin.Spec.NodeSelector)
|
||||
if dpNodeSelectorSize > 0 {
|
||||
nodeSelector = make(map[string]string, dpNodeSelectorSize+1)
|
||||
for k, v := range devicePlugin.Spec.NodeSelector {
|
||||
nodeSelector[k] = v
|
||||
}
|
||||
nodeSelector["kubernetes.io/arch"] = "amd64"
|
||||
} else {
|
||||
nodeSelector = map[string]string{"kubernetes.io/arch": "amd64"}
|
||||
}
|
||||
|
||||
yes := true
|
||||
daemonSet := apps.DaemonSet{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "DaemonSet",
|
||||
APIVersion: "apps/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: c.ns,
|
||||
Name: "intel-gpu-plugin",
|
||||
Labels: map[string]string{
|
||||
"app": appLabel,
|
||||
},
|
||||
},
|
||||
Spec: apps.DaemonSetSpec{
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"app": appLabel,
|
||||
},
|
||||
},
|
||||
Template: v1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{
|
||||
"app": appLabel,
|
||||
},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: appLabel,
|
||||
Env: []v1.EnvVar{
|
||||
{
|
||||
Name: "NODE_NAME",
|
||||
ValueFrom: &v1.EnvVarSource{
|
||||
FieldRef: &v1.ObjectFieldSelector{
|
||||
FieldPath: "spec.nodeName",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Args: getPodArgs(devicePlugin),
|
||||
Image: devicePlugin.Spec.Image,
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
SecurityContext: &v1.SecurityContext{
|
||||
ReadOnlyRootFilesystem: &yes,
|
||||
},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: "devfs",
|
||||
MountPath: "/dev/dri",
|
||||
ReadOnly: true,
|
||||
},
|
||||
{
|
||||
Name: "sysfs",
|
||||
MountPath: "/sys/class/drm",
|
||||
ReadOnly: true,
|
||||
},
|
||||
{
|
||||
Name: "kubeletsockets",
|
||||
MountPath: "/var/lib/kubelet/device-plugins",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
NodeSelector: nodeSelector,
|
||||
Volumes: []v1.Volume{
|
||||
{
|
||||
Name: "devfs",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: &v1.HostPathVolumeSource{
|
||||
Path: "/dev/dri",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "sysfs",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: &v1.HostPathVolumeSource{
|
||||
Path: "/sys/class/drm",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "kubeletsockets",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: &v1.HostPathVolumeSource{
|
||||
Path: "/var/lib/kubelet/device-plugins",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// add the optional init container
|
||||
if devicePlugin.Spec.InitImage != "" {
|
||||
setInitContainer(&daemonSet.Spec.Template.Spec, devicePlugin.Spec.InitImage)
|
||||
}
|
||||
|
||||
// add service account if resource manager is enabled
|
||||
if devicePlugin.Spec.ResourceManager {
|
||||
daemonSet.Spec.Template.Spec.ServiceAccountName = serviceAccountName
|
||||
addVolumeIfMissing(&daemonSet.Spec.Template.Spec, "podresources", "/var/lib/kubelet/pod-resources", v1.HostPathDirectory)
|
||||
addVolumeMountIfMissing(&daemonSet.Spec.Template.Spec, "podresources", "/var/lib/kubelet/pod-resources")
|
||||
}
|
||||
|
||||
return &daemonSet
|
||||
}
|
||||
|
||||
// Test that GPU daemonsets created by using go:embed
|
||||
// are equal to the expected daemonsets.
|
||||
func TestNewDamonSetGPU(t *testing.T) {
|
||||
tcases := []struct {
|
||||
name string
|
||||
resourceManager bool
|
||||
isInitImage bool
|
||||
}{
|
||||
{
|
||||
"plugin without resource manager and without initcontainer",
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"plugin without resource manager and with initcontainer",
|
||||
false,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"plugin with resource manager and without initcontainer",
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"plugin with resource manager and with initcontainer",
|
||||
true,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
c := &controller{}
|
||||
|
||||
for _, tc := range tcases {
|
||||
plugin := &devicepluginv1.GpuDevicePlugin{}
|
||||
if tc.resourceManager {
|
||||
plugin.Spec.ResourceManager = true
|
||||
}
|
||||
if tc.isInitImage {
|
||||
plugin.Spec.InitImage = "intel/intel-gpu-initcontainer:devel"
|
||||
}
|
||||
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
expected := c.newDaemonSetExpected(plugin)
|
||||
actual := c.NewDaemonSet(plugin)
|
||||
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Errorf("expected and actuall daemonsets differ: %+s", diff.ObjectGoPrintDiff(expected, actual))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
137
pkg/controllers/qat/controller_test.go
Normal file
137
pkg/controllers/qat/controller_test.go
Normal file
@ -0,0 +1,137 @@
|
||||
// Copyright 2021 Intel Corporation. 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.
|
||||
|
||||
// Package qat contains QAT specific reconciliation logic.
|
||||
package qat
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
apps "k8s.io/api/apps/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
devicepluginv1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/deviceplugin/v1"
|
||||
)
|
||||
|
||||
const appLabel = "intel-qat-plugin"
|
||||
|
||||
// newDaemonSetExpected creates plugin daemonset
|
||||
// it's copied from the original controller code (before the usage of go:embed).
|
||||
func (c *controller) newDaemonSetExpected(rawObj client.Object) *apps.DaemonSet {
|
||||
devicePlugin := rawObj.(*devicepluginv1.QatDevicePlugin)
|
||||
yes := true
|
||||
pluginAnnotations := devicePlugin.ObjectMeta.DeepCopy().Annotations
|
||||
return &apps.DaemonSet{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "DaemonSet",
|
||||
APIVersion: "apps/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: c.ns,
|
||||
Name: "intel-qat-plugin",
|
||||
Labels: map[string]string{
|
||||
"app": appLabel,
|
||||
},
|
||||
Annotations: pluginAnnotations,
|
||||
},
|
||||
Spec: apps.DaemonSetSpec{
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"app": appLabel,
|
||||
},
|
||||
},
|
||||
Template: v1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{
|
||||
"app": appLabel,
|
||||
},
|
||||
Annotations: pluginAnnotations,
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: appLabel,
|
||||
Args: getPodArgs(devicePlugin),
|
||||
Image: devicePlugin.Spec.Image,
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
SecurityContext: &v1.SecurityContext{
|
||||
ReadOnlyRootFilesystem: &yes,
|
||||
},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: "devdir",
|
||||
MountPath: "/dev/vfio",
|
||||
ReadOnly: true,
|
||||
},
|
||||
{
|
||||
Name: "pcidir",
|
||||
MountPath: "/sys/bus/pci",
|
||||
},
|
||||
{
|
||||
Name: "kubeletsockets",
|
||||
MountPath: "/var/lib/kubelet/device-plugins",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
NodeSelector: devicePlugin.Spec.NodeSelector,
|
||||
Volumes: []v1.Volume{
|
||||
{
|
||||
Name: "devdir",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: &v1.HostPathVolumeSource{
|
||||
Path: "/dev/vfio",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "pcidir",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: &v1.HostPathVolumeSource{
|
||||
Path: "/sys/bus/pci",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "kubeletsockets",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: &v1.HostPathVolumeSource{
|
||||
Path: "/var/lib/kubelet/device-plugins",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Test that QAT daemonset created by using go:embed is
|
||||
// equal to the expected daemonset.
|
||||
func TestNewDaemonSetQAT(t *testing.T) {
|
||||
c := &controller{}
|
||||
|
||||
plugin := &devicepluginv1.QatDevicePlugin{}
|
||||
expected := c.newDaemonSetExpected(plugin)
|
||||
actual := c.NewDaemonSet(plugin)
|
||||
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Errorf("expected and actuall daemonsets differ: %+s", diff.ObjectGoPrintDiff(expected, actual))
|
||||
}
|
||||
}
|
171
pkg/controllers/sgx/controller_test.go
Normal file
171
pkg/controllers/sgx/controller_test.go
Normal file
@ -0,0 +1,171 @@
|
||||
// Copyright 2021 Intel Corporation. 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.
|
||||
|
||||
// Package sgx contains SGX specific reconciliation logic.
|
||||
package sgx
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
apps "k8s.io/api/apps/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
devicepluginv1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/deviceplugin/v1"
|
||||
)
|
||||
|
||||
const appLabel = "intel-sgx-plugin"
|
||||
|
||||
// newDaemonSetExpected creates plugin daemonset
|
||||
// it's copied from the original controller code (before the usage of go:embed).
|
||||
func (c *controller) newDaemonSetExpected(rawObj client.Object) *apps.DaemonSet {
|
||||
devicePlugin := rawObj.(*devicepluginv1.SgxDevicePlugin)
|
||||
|
||||
var nodeSelector map[string]string
|
||||
dpNodeSelectorSize := len(devicePlugin.Spec.NodeSelector)
|
||||
if dpNodeSelectorSize > 0 {
|
||||
nodeSelector = make(map[string]string, dpNodeSelectorSize+1)
|
||||
for k, v := range devicePlugin.Spec.NodeSelector {
|
||||
nodeSelector[k] = v
|
||||
}
|
||||
nodeSelector["kubernetes.io/arch"] = "amd64"
|
||||
} else {
|
||||
nodeSelector = map[string]string{"kubernetes.io/arch": "amd64"}
|
||||
}
|
||||
|
||||
yes := true
|
||||
charDevice := v1.HostPathCharDev
|
||||
directoryOrCreate := v1.HostPathDirectoryOrCreate
|
||||
daemonSet := apps.DaemonSet{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "DaemonSet",
|
||||
APIVersion: "apps/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: c.ns,
|
||||
Name: "intel-sgx-plugin",
|
||||
Labels: map[string]string{
|
||||
"app": appLabel,
|
||||
},
|
||||
},
|
||||
Spec: apps.DaemonSetSpec{
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"app": appLabel,
|
||||
},
|
||||
},
|
||||
Template: v1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{
|
||||
"app": appLabel,
|
||||
},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: appLabel,
|
||||
Args: getPodArgs(devicePlugin),
|
||||
Image: devicePlugin.Spec.Image,
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
SecurityContext: &v1.SecurityContext{
|
||||
ReadOnlyRootFilesystem: &yes,
|
||||
},
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: "kubeletsockets",
|
||||
MountPath: "/var/lib/kubelet/device-plugins",
|
||||
},
|
||||
{
|
||||
Name: "sgxdevices",
|
||||
MountPath: "/dev/sgx",
|
||||
ReadOnly: true,
|
||||
},
|
||||
{
|
||||
Name: "sgx-enclave",
|
||||
MountPath: "/dev/sgx_enclave",
|
||||
ReadOnly: true,
|
||||
},
|
||||
{
|
||||
Name: "sgx-provision",
|
||||
MountPath: "/dev/sgx_provision",
|
||||
ReadOnly: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
NodeSelector: nodeSelector,
|
||||
Volumes: []v1.Volume{
|
||||
{
|
||||
Name: "kubeletsockets",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: &v1.HostPathVolumeSource{
|
||||
Path: "/var/lib/kubelet/device-plugins",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "sgxdevices",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: &v1.HostPathVolumeSource{
|
||||
Path: "/dev/sgx",
|
||||
Type: &directoryOrCreate,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "sgx-enclave",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: &v1.HostPathVolumeSource{
|
||||
Path: "/dev/sgx_enclave",
|
||||
Type: &charDevice,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "sgx-provision",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: &v1.HostPathVolumeSource{
|
||||
Path: "/dev/sgx_provision",
|
||||
Type: &charDevice,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
// add the optional init container
|
||||
if devicePlugin.Spec.InitImage != "" {
|
||||
setInitContainer(&daemonSet.Spec.Template.Spec, devicePlugin.Spec.InitImage)
|
||||
}
|
||||
return &daemonSet
|
||||
}
|
||||
|
||||
// Test that SGX daemonset created by using go:embed is
|
||||
// equal to the expected daemonset.
|
||||
func TestNewDaemonSetSGX(t *testing.T) {
|
||||
c := &controller{}
|
||||
|
||||
plugin := &devicepluginv1.SgxDevicePlugin{}
|
||||
expected := c.newDaemonSetExpected(plugin)
|
||||
actual := c.NewDaemonSet(plugin)
|
||||
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Errorf("expected and actuall daemonsets differ: %+s", diff.ObjectGoPrintDiff(expected, actual))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user