diff --git a/cmd/operator/main.go b/cmd/operator/main.go index 2fca03da5..384d485e8 100644 --- a/cmd/operator/main.go +++ b/cmd/operator/main.go @@ -34,6 +34,7 @@ import ( devicepluginv1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/deviceplugin/v1" fpgav2 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/fpga/v2" + "github.com/intel/intel-device-plugins-for-kubernetes/pkg/controllers" "github.com/intel/intel-device-plugins-for-kubernetes/pkg/controllers/dlb" "github.com/intel/intel-device-plugins-for-kubernetes/pkg/controllers/dsa" "github.com/intel/intel-device-plugins-for-kubernetes/pkg/controllers/fpga" @@ -61,7 +62,7 @@ func init() { // +kubebuilder:scaffold:scheme } -type devicePluginControllerAndWebhook map[string](func(ctrl.Manager, string, bool) error) +type devicePluginControllerAndWebhook map[string](func(ctrl.Manager, controllers.ControllerArgs) error) type flagList []string @@ -208,15 +209,17 @@ func main() { os.Exit(1) } - ns := os.Getenv("DEVICEPLUGIN_NAMESPACE") - if ns == "" { - ns = devicePluginNamespace + cargs := controllers.ControllerArgs{WithWebhook: true} + + cargs.Namespace = os.Getenv("DEVICEPLUGIN_NAMESPACE") + if cargs.Namespace == "" { + cargs.Namespace = devicePluginNamespace } - withWebhook := true + cargs.Secret = os.Getenv("DEVICEPLUGIN_SECRET") for _, device := range devices { - if err = setupControllerAndWebhook[device](mgr, ns, withWebhook); err != nil { + if err = setupControllerAndWebhook[device](mgr, cargs); err != nil { setupLog.Error(err, "unable to initialize controller", "controller", device) os.Exit(1) } diff --git a/pkg/controllers/dlb/controller.go b/pkg/controllers/dlb/controller.go index ba770a528..9c41ab41b 100644 --- a/pkg/controllers/dlb/controller.go +++ b/pkg/controllers/dlb/controller.go @@ -43,13 +43,13 @@ var defaultNodeSelector map[string]string = deployments.DLBPluginDaemonSet().Spe // +kubebuilder:rbac:groups=deviceplugin.intel.com,resources=dlbdeviceplugins/finalizers,verbs=update // SetupReconciler creates a new reconciler for DlbDevicePlugin objects. -func SetupReconciler(mgr ctrl.Manager, namespace string, withWebhook bool) error { - c := &controller{scheme: mgr.GetScheme(), ns: namespace} +func SetupReconciler(mgr ctrl.Manager, args controllers.ControllerArgs) error { + c := &controller{scheme: mgr.GetScheme(), args: args} if err := controllers.SetupWithManager(mgr, c, devicepluginv1.GroupVersion.String(), "DlbDevicePlugin", ownerKey); err != nil { return err } - if withWebhook { + if args.WithWebhook { return (&devicepluginv1.DlbDevicePlugin{}).SetupWebhookWithManager(mgr) } @@ -59,7 +59,7 @@ func SetupReconciler(mgr ctrl.Manager, namespace string, withWebhook bool) error type controller struct { controllers.DefaultServiceAccountFactory scheme *runtime.Scheme - ns string + args controllers.ControllerArgs } func (c *controller) CreateEmptyObject() client.Object { @@ -92,7 +92,13 @@ func (c *controller) NewDaemonSet(rawObj client.Object) *apps.DaemonSet { setInitContainer(&ds.Spec.Template.Spec, devicePlugin.Spec) } - ds.ObjectMeta.Namespace = c.ns + ds.ObjectMeta.Namespace = c.args.Namespace + + if len(c.args.Secret) > 0 { + ds.Spec.Template.Spec.ImagePullSecrets = []v1.LocalObjectReference{ + {Name: c.args.Secret}, + } + } ds.Spec.Template.Spec.Containers[0].Args = getPodArgs(devicePlugin) ds.Spec.Template.Spec.Containers[0].Image = devicePlugin.Spec.Image diff --git a/pkg/controllers/dlb/controller_test.go b/pkg/controllers/dlb/controller_test.go index 34770861d..0aa448564 100644 --- a/pkg/controllers/dlb/controller_test.go +++ b/pkg/controllers/dlb/controller_test.go @@ -45,7 +45,7 @@ func (c *controller) newDaemonSetExpected(rawObj client.Object) *apps.DaemonSet APIVersion: "apps/v1", }, ObjectMeta: metav1.ObjectMeta{ - Namespace: c.ns, + Namespace: c.args.Namespace, Name: appLabel + "-" + devicePlugin.Name, Labels: map[string]string{ "app": appLabel, @@ -155,6 +155,12 @@ func (c *controller) newDaemonSetExpected(rawObj client.Object) *apps.DaemonSet }, } + if len(c.args.Secret) > 0 { + daemonSet.Spec.Template.Spec.ImagePullSecrets = []v1.LocalObjectReference{ + {Name: c.args.Secret}, + } + } + return &daemonSet } @@ -171,4 +177,12 @@ func TestNewDaemonSetDLB(t *testing.T) { if !reflect.DeepEqual(expected, actual) { t.Errorf("expected and actuall daemonsets differ: %+s", diff.ObjectGoPrintDiff(expected, actual)) } + + c.args.Secret = "mysecret" + + expected = c.newDaemonSetExpected(plugin) + actual = c.NewDaemonSet(plugin) + if !reflect.DeepEqual(expected, actual) { + t.Errorf("expected and actual daemonsets with secret differ: %+s", diff.ObjectGoPrintDiff(expected, actual)) + } } diff --git a/pkg/controllers/dsa/controller.go b/pkg/controllers/dsa/controller.go index fd7f6078e..07aec2506 100644 --- a/pkg/controllers/dsa/controller.go +++ b/pkg/controllers/dsa/controller.go @@ -47,13 +47,13 @@ var defaultNodeSelector = deployments.DSAPluginDaemonSet().Spec.Template.Spec.No // +kubebuilder:rbac:groups=deviceplugin.intel.com,resources=dsadeviceplugins/finalizers,verbs=update // SetupReconciler creates a new reconciler for DsaDevicePlugin objects. -func SetupReconciler(mgr ctrl.Manager, namespace string, withWebhook bool) error { - c := &controller{scheme: mgr.GetScheme(), ns: namespace} +func SetupReconciler(mgr ctrl.Manager, args controllers.ControllerArgs) error { + c := &controller{scheme: mgr.GetScheme(), args: args} if err := controllers.SetupWithManager(mgr, c, devicepluginv1.GroupVersion.String(), "DsaDevicePlugin", ownerKey); err != nil { return err } - if withWebhook { + if args.WithWebhook { return (&devicepluginv1.DsaDevicePlugin{}).SetupWebhookWithManager(mgr) } @@ -63,7 +63,7 @@ func SetupReconciler(mgr ctrl.Manager, namespace string, withWebhook bool) error type controller struct { controllers.DefaultServiceAccountFactory scheme *runtime.Scheme - ns string + args controllers.ControllerArgs } func (c *controller) CreateEmptyObject() client.Object { @@ -200,7 +200,7 @@ func (c *controller) NewDaemonSet(rawObj client.Object) *apps.DaemonSet { daemonSet.Spec.Template.Spec.Tolerations = devicePlugin.Spec.Tolerations } - daemonSet.ObjectMeta.Namespace = c.ns + daemonSet.ObjectMeta.Namespace = c.args.Namespace daemonSet.Spec.Template.Spec.Containers[0].Args = getPodArgs(devicePlugin) daemonSet.Spec.Template.Spec.Containers[0].Image = devicePlugin.Spec.Image @@ -208,6 +208,12 @@ func (c *controller) NewDaemonSet(rawObj client.Object) *apps.DaemonSet { addInitContainer(daemonSet, devicePlugin) } + if len(c.args.Secret) > 0 { + daemonSet.Spec.Template.Spec.ImagePullSecrets = []v1.LocalObjectReference{ + {Name: c.args.Secret}, + } + } + return daemonSet } diff --git a/pkg/controllers/dsa/controller_test.go b/pkg/controllers/dsa/controller_test.go index 4181e42b1..7ad069cbf 100644 --- a/pkg/controllers/dsa/controller_test.go +++ b/pkg/controllers/dsa/controller_test.go @@ -47,7 +47,7 @@ func (c *controller) newDaemonSetExpected(rawObj client.Object) *apps.DaemonSet APIVersion: "apps/v1", }, ObjectMeta: metav1.ObjectMeta{ - Namespace: c.ns, + Namespace: c.args.Namespace, Name: appLabel + "-" + devicePlugin.Name, Labels: map[string]string{ "app": appLabel, @@ -177,6 +177,12 @@ func (c *controller) newDaemonSetExpected(rawObj client.Object) *apps.DaemonSet addInitContainer(&daemonSet, devicePlugin) } + if len(c.args.Secret) > 0 { + daemonSet.Spec.Template.Spec.ImagePullSecrets = []v1.LocalObjectReference{ + {Name: c.args.Secret}, + } + } + return &daemonSet } @@ -193,4 +199,12 @@ func TestNewDaemonSetDSA(t *testing.T) { if !reflect.DeepEqual(expected, actual) { t.Errorf("expected and actuall daemonsets differ: %+s", diff.ObjectGoPrintDiff(expected, actual)) } + + c.args.Secret = "mysecret" + + expected = c.newDaemonSetExpected(plugin) + actual = c.NewDaemonSet(plugin) + if !reflect.DeepEqual(expected, actual) { + t.Errorf("expected and actual daemonsets with secret differ: %+s", diff.ObjectGoPrintDiff(expected, actual)) + } } diff --git a/pkg/controllers/fpga/controller.go b/pkg/controllers/fpga/controller.go index 3614fb166..643c54b3b 100644 --- a/pkg/controllers/fpga/controller.go +++ b/pkg/controllers/fpga/controller.go @@ -22,6 +22,7 @@ import ( "strings" apps "k8s.io/api/apps/v1" + v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/tools/reference" ctrl "sigs.k8s.io/controller-runtime" @@ -42,13 +43,13 @@ var defaultNodeSelector = deployments.FPGAPluginDaemonSet().Spec.Template.Spec.N // +kubebuilder:rbac:groups=deviceplugin.intel.com,resources=fpgadeviceplugins/finalizers,verbs=update // SetupReconciler creates a new reconciler for FpgaDevicePlugin objects. -func SetupReconciler(mgr ctrl.Manager, namespace string, withWebhook bool) error { - c := &controller{scheme: mgr.GetScheme(), ns: namespace} +func SetupReconciler(mgr ctrl.Manager, args controllers.ControllerArgs) error { + c := &controller{scheme: mgr.GetScheme(), args: args} if err := controllers.SetupWithManager(mgr, c, devicepluginv1.GroupVersion.String(), "FpgaDevicePlugin", ownerKey); err != nil { return err } - if withWebhook { + if args.WithWebhook { return (&devicepluginv1.FpgaDevicePlugin{}).SetupWebhookWithManager(mgr) } @@ -58,7 +59,7 @@ func SetupReconciler(mgr ctrl.Manager, namespace string, withWebhook bool) error type controller struct { controllers.DefaultServiceAccountFactory scheme *runtime.Scheme - ns string + args controllers.ControllerArgs } func (c *controller) CreateEmptyObject() client.Object { @@ -84,7 +85,13 @@ func (c *controller) NewDaemonSet(rawObj client.Object) *apps.DaemonSet { daemonSet.Spec.Template.Spec.Tolerations = devicePlugin.Spec.Tolerations } - daemonSet.ObjectMeta.Namespace = c.ns + daemonSet.ObjectMeta.Namespace = c.args.Namespace + + if len(c.args.Secret) > 0 { + daemonSet.Spec.Template.Spec.ImagePullSecrets = []v1.LocalObjectReference{ + {Name: c.args.Secret}, + } + } daemonSet.Spec.Template.Spec.Containers[0].Args = getPodArgs(devicePlugin) daemonSet.Spec.Template.Spec.Containers[0].Image = devicePlugin.Spec.Image diff --git a/pkg/controllers/fpga/controller_test.go b/pkg/controllers/fpga/controller_test.go index b0ca45b81..c3ce2620e 100644 --- a/pkg/controllers/fpga/controller_test.go +++ b/pkg/controllers/fpga/controller_test.go @@ -42,13 +42,13 @@ func (c *controller) newDaemonSetExpected(rawObj client.Object) *apps.DaemonSet maxUnavailable := intstr.FromInt(1) maxSurge := intstr.FromInt(0) - return &apps.DaemonSet{ + ds := &apps.DaemonSet{ TypeMeta: metav1.TypeMeta{ Kind: "DaemonSet", APIVersion: "apps/v1", }, ObjectMeta: metav1.ObjectMeta{ - Namespace: c.ns, + Namespace: c.args.Namespace, Name: appLabel + "-" + devicePlugin.Name, Labels: map[string]string{ "app": appLabel, @@ -198,6 +198,14 @@ func (c *controller) newDaemonSetExpected(rawObj client.Object) *apps.DaemonSet }, }, } + + if len(c.args.Secret) > 0 { + ds.Spec.Template.Spec.ImagePullSecrets = []v1.LocalObjectReference{ + {Name: c.args.Secret}, + } + } + + return ds } // Test that FPGA daemonset created by using go:embed is @@ -218,4 +226,12 @@ func TestNewDaemonSetFPGA(t *testing.T) { if !reflect.DeepEqual(expected, actual) { t.Errorf("expected and actuall daemonsets differ: %+s", diff.ObjectGoPrintDiff(expected, actual)) } + + c.args.Secret = "mysecret" + + expected = c.newDaemonSetExpected(plugin) + actual = c.NewDaemonSet(plugin) + if !reflect.DeepEqual(expected, actual) { + t.Errorf("expected and actual daemonsets with secret differ: %+s", diff.ObjectGoPrintDiff(expected, actual)) + } } diff --git a/pkg/controllers/gpu/controller.go b/pkg/controllers/gpu/controller.go index 3c943f526..492ae4b73 100644 --- a/pkg/controllers/gpu/controller.go +++ b/pkg/controllers/gpu/controller.go @@ -49,13 +49,13 @@ var defaultNodeSelector = deployments.GPUPluginDaemonSet().Spec.Template.Spec.No // +kubebuilder:rbac:groups=deviceplugin.intel.com,resources=gpudeviceplugins/finalizers,verbs=update // SetupReconciler creates a new reconciler for GpuDevicePlugin objects. -func SetupReconciler(mgr ctrl.Manager, namespace string, withWebhook bool) error { - c := &controller{scheme: mgr.GetScheme(), ns: namespace} +func SetupReconciler(mgr ctrl.Manager, args controllers.ControllerArgs) error { + c := &controller{scheme: mgr.GetScheme(), args: args} if err := controllers.SetupWithManager(mgr, c, devicepluginv1.GroupVersion.String(), "GpuDevicePlugin", ownerKey); err != nil { return err } - if withWebhook { + if args.WithWebhook { return (&devicepluginv1.GpuDevicePlugin{}).SetupWebhookWithManager(mgr) } @@ -64,7 +64,7 @@ func SetupReconciler(mgr ctrl.Manager, namespace string, withWebhook bool) error type controller struct { scheme *runtime.Scheme - ns string + args controllers.ControllerArgs } func (c *controller) CreateEmptyObject() client.Object { @@ -80,7 +80,7 @@ func (c *controller) NewSharedServiceAccount() *v1.ServiceAccount { return &v1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ Name: serviceAccountName, - Namespace: c.ns, + Namespace: c.args.Namespace, }, } } @@ -89,13 +89,13 @@ func (c *controller) NewSharedClusterRoleBinding() *rbacv1.ClusterRoleBinding { return &rbacv1.ClusterRoleBinding{ ObjectMeta: metav1.ObjectMeta{ Name: roleBindingName, - Namespace: c.ns, + Namespace: c.args.Namespace, }, Subjects: []rbacv1.Subject{ { Kind: "ServiceAccount", Name: serviceAccountName, - Namespace: c.ns, + Namespace: c.args.Namespace, }, }, RoleRef: rbacv1.RoleRef{ @@ -140,10 +140,16 @@ func (c *controller) NewDaemonSet(rawObj client.Object) *apps.DaemonSet { daemonSet.Spec.Template.Spec.Tolerations = devicePlugin.Spec.Tolerations } - daemonSet.ObjectMeta.Namespace = c.ns + daemonSet.ObjectMeta.Namespace = c.args.Namespace daemonSet.Spec.Template.Spec.Containers[0].Args = getPodArgs(devicePlugin) daemonSet.Spec.Template.Spec.Containers[0].Image = devicePlugin.Spec.Image + if len(c.args.Secret) > 0 { + daemonSet.Spec.Template.Spec.ImagePullSecrets = []v1.LocalObjectReference{ + {Name: c.args.Secret}, + } + } + if devicePlugin.Spec.InitImage == "" { daemonSet.Spec.Template.Spec.InitContainers = nil daemonSet.Spec.Template.Spec.Volumes = removeVolume(daemonSet.Spec.Template.Spec.Volumes, "nfd-features") diff --git a/pkg/controllers/gpu/controller_test.go b/pkg/controllers/gpu/controller_test.go index 994f0d88f..2256a9fc8 100644 --- a/pkg/controllers/gpu/controller_test.go +++ b/pkg/controllers/gpu/controller_test.go @@ -29,6 +29,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" devicepluginv1 "github.com/intel/intel-device-plugins-for-kubernetes/pkg/apis/deviceplugin/v1" + "github.com/intel/intel-device-plugins-for-kubernetes/pkg/controllers" ) const appLabel = "intel-gpu-plugin" @@ -50,7 +51,7 @@ func (c *controller) newDaemonSetExpected(rawObj client.Object) *apps.DaemonSet APIVersion: "apps/v1", }, ObjectMeta: metav1.ObjectMeta{ - Namespace: c.ns, + Namespace: c.args.Namespace, Name: appLabel + "-" + devicePlugin.Name, Labels: map[string]string{ "app": appLabel, @@ -196,6 +197,12 @@ func (c *controller) newDaemonSetExpected(rawObj client.Object) *apps.DaemonSet addVolumeMountIfMissing(&daemonSet.Spec.Template.Spec, "sysfsdevices", "/sys/devices", true) } + if len(c.args.Secret) > 0 { + daemonSet.Spec.Template.Spec.ImagePullSecrets = []v1.LocalObjectReference{ + {Name: c.args.Secret}, + } + } + return &daemonSet } @@ -272,6 +279,24 @@ func TestNewDamonSetGPU(t *testing.T) { } } +func TestNewDamonSetGPUWithSecret(t *testing.T) { + c := &controller{ + args: controllers.ControllerArgs{ + Secret: "mysecret", + }, + } + + plugin := &devicepluginv1.GpuDevicePlugin{} + plugin.Name = "new-gpu-cr-testing" + + expected := c.newDaemonSetExpected(plugin) + actual := c.NewDaemonSet(plugin) + + if !reflect.DeepEqual(expected, actual) { + t.Errorf("expected and actual daemonsets with secret differ: %+s", diff.ObjectGoPrintDiff(expected, actual)) + } +} + func TestUpdateDamonSetGPU(t *testing.T) { tcases := []struct { name string diff --git a/pkg/controllers/iaa/controller.go b/pkg/controllers/iaa/controller.go index bf2ce865c..9195ed8a7 100644 --- a/pkg/controllers/iaa/controller.go +++ b/pkg/controllers/iaa/controller.go @@ -45,13 +45,13 @@ const ( // +kubebuilder:rbac:groups=deviceplugin.intel.com,resources=iaadeviceplugins/finalizers,verbs=update // SetupReconciler creates a new reconciler for IaaDevicePlugin objects. -func SetupReconciler(mgr ctrl.Manager, namespace string, withWebhook bool) error { - c := &controller{scheme: mgr.GetScheme(), ns: namespace} +func SetupReconciler(mgr ctrl.Manager, args controllers.ControllerArgs) error { + c := &controller{scheme: mgr.GetScheme(), args: args} if err := controllers.SetupWithManager(mgr, c, devicepluginv1.GroupVersion.String(), "IaaDevicePlugin", ownerKey); err != nil { return err } - if withWebhook { + if args.WithWebhook { return (&devicepluginv1.IaaDevicePlugin{}).SetupWebhookWithManager(mgr) } @@ -61,7 +61,7 @@ func SetupReconciler(mgr ctrl.Manager, namespace string, withWebhook bool) error type controller struct { controllers.DefaultServiceAccountFactory scheme *runtime.Scheme - ns string + args controllers.ControllerArgs } func (c *controller) CreateEmptyObject() client.Object { @@ -199,7 +199,7 @@ func (c *controller) NewDaemonSet(rawObj client.Object) *apps.DaemonSet { daemonSet.Spec.Template.Spec.Tolerations = devicePlugin.Spec.Tolerations } - daemonSet.ObjectMeta.Namespace = c.ns + daemonSet.ObjectMeta.Namespace = c.args.Namespace daemonSet.Spec.Template.Spec.Containers[0].Args = getPodArgs(devicePlugin) daemonSet.Spec.Template.Spec.Containers[0].Image = devicePlugin.Spec.Image @@ -208,6 +208,12 @@ func (c *controller) NewDaemonSet(rawObj client.Object) *apps.DaemonSet { addInitContainer(daemonSet, devicePlugin) } + if len(c.args.Secret) > 0 { + daemonSet.Spec.Template.Spec.ImagePullSecrets = []v1.LocalObjectReference{ + {Name: c.args.Secret}, + } + } + return daemonSet } diff --git a/pkg/controllers/iaa/controller_test.go b/pkg/controllers/iaa/controller_test.go index e74ae955f..6dd027a1d 100644 --- a/pkg/controllers/iaa/controller_test.go +++ b/pkg/controllers/iaa/controller_test.go @@ -47,7 +47,7 @@ func (c *controller) newDaemonSetExpected(rawObj client.Object) *apps.DaemonSet APIVersion: "apps/v1", }, ObjectMeta: metav1.ObjectMeta{ - Namespace: c.ns, + Namespace: c.args.Namespace, Name: appLabel + "-" + devicePlugin.Name, Labels: map[string]string{ "app": appLabel, @@ -177,6 +177,12 @@ func (c *controller) newDaemonSetExpected(rawObj client.Object) *apps.DaemonSet addInitContainer(&daemonSet, devicePlugin) } + if len(c.args.Secret) > 0 { + daemonSet.Spec.Template.Spec.ImagePullSecrets = []v1.LocalObjectReference{ + {Name: c.args.Secret}, + } + } + return &daemonSet } @@ -193,4 +199,13 @@ func TestNewDaemonSetIAA(t *testing.T) { if !reflect.DeepEqual(expected, actual) { t.Errorf("expected and actuall daemonsets differ: %+s", diff.ObjectGoPrintDiff(expected, actual)) } + + c.args.Secret = "mysecret" + + expected = c.newDaemonSetExpected(plugin) + actual = c.NewDaemonSet(plugin) + + if !reflect.DeepEqual(expected, actual) { + t.Errorf("expected and actual daemonsets with secret differ: %+s", diff.ObjectGoPrintDiff(expected, actual)) + } } diff --git a/pkg/controllers/qat/controller.go b/pkg/controllers/qat/controller.go index 36153d86d..c554fc7a5 100644 --- a/pkg/controllers/qat/controller.go +++ b/pkg/controllers/qat/controller.go @@ -47,13 +47,13 @@ var defaultNodeSelector = deployments.QATPluginDaemonSet().Spec.Template.Spec.No // +kubebuilder:rbac:groups=deviceplugin.intel.com,resources=qatdeviceplugins/finalizers,verbs=update // SetupReconciler creates a new reconciler for QatDevicePlugin objects. -func SetupReconciler(mgr ctrl.Manager, namespace string, withWebhook bool) error { - c := &controller{scheme: mgr.GetScheme(), ns: namespace} +func SetupReconciler(mgr ctrl.Manager, args controllers.ControllerArgs) error { + c := &controller{scheme: mgr.GetScheme(), args: args} if err := controllers.SetupWithManager(mgr, c, devicepluginv1.GroupVersion.String(), "QatDevicePlugin", ownerKey); err != nil { return err } - if withWebhook { + if args.WithWebhook { return (&devicepluginv1.QatDevicePlugin{}).SetupWebhookWithManager(mgr) } @@ -63,7 +63,7 @@ func SetupReconciler(mgr ctrl.Manager, namespace string, withWebhook bool) error type controller struct { controllers.DefaultServiceAccountFactory scheme *runtime.Scheme - ns string + args controllers.ControllerArgs } func (c *controller) CreateEmptyObject() client.Object { @@ -93,7 +93,13 @@ func (c *controller) NewDaemonSet(rawObj client.Object) *apps.DaemonSet { setInitContainer(&daemonSet.Spec.Template.Spec, devicePlugin.Spec) } - daemonSet.ObjectMeta.Namespace = c.ns + if len(c.args.Secret) > 0 { + daemonSet.Spec.Template.Spec.ImagePullSecrets = []v1.LocalObjectReference{ + {Name: c.args.Secret}, + } + } + + daemonSet.ObjectMeta.Namespace = c.args.Namespace daemonSet.Spec.Template.Spec.Containers[0].Args = getPodArgs(devicePlugin) daemonSet.Spec.Template.Spec.Containers[0].Image = devicePlugin.Spec.Image diff --git a/pkg/controllers/qat/controller_test.go b/pkg/controllers/qat/controller_test.go index 4d81ca610..71663a3be 100644 --- a/pkg/controllers/qat/controller_test.go +++ b/pkg/controllers/qat/controller_test.go @@ -48,7 +48,7 @@ func (c *controller) newDaemonSetExpected(rawObj client.Object) *apps.DaemonSet APIVersion: "apps/v1", }, ObjectMeta: metav1.ObjectMeta{ - Namespace: c.ns, + Namespace: c.args.Namespace, Name: appLabel + "-" + devicePlugin.Name, Labels: map[string]string{ "app": appLabel, @@ -176,6 +176,12 @@ func (c *controller) newDaemonSetExpected(rawObj client.Object) *apps.DaemonSet setInitContainer(&daemonSet.Spec.Template.Spec, devicePlugin.Spec) } + if len(c.args.Secret) > 0 { + daemonSet.Spec.Template.Spec.ImagePullSecrets = []v1.LocalObjectReference{ + {Name: c.args.Secret}, + } + } + return &daemonSet } @@ -194,4 +200,13 @@ func TestNewDaemonSetQAT(t *testing.T) { if !reflect.DeepEqual(expected, actual) { t.Errorf("expected and actuall daemonsets differ: %+s", diff.ObjectGoPrintDiff(expected, actual)) } + + c.args.Secret = "mysecret" + + expected = c.newDaemonSetExpected(plugin) + actual = c.NewDaemonSet(plugin) + + if !reflect.DeepEqual(expected, actual) { + t.Errorf("expected and actual daemonsets with secret differ: %+s", diff.ObjectGoPrintDiff(expected, actual)) + } } diff --git a/pkg/controllers/reconciler.go b/pkg/controllers/reconciler.go index 86879cb3a..a3d29e12c 100644 --- a/pkg/controllers/reconciler.go +++ b/pkg/controllers/reconciler.go @@ -94,6 +94,12 @@ type DevicePluginController interface { Upgrade(ctx context.Context, obj client.Object) (upgrade bool) } +type ControllerArgs struct { + Namespace string + Secret string + WithWebhook bool +} + type reconciler struct { controller DevicePluginController client.Client diff --git a/pkg/controllers/sgx/controller.go b/pkg/controllers/sgx/controller.go index 05a7f1635..85632b6c3 100644 --- a/pkg/controllers/sgx/controller.go +++ b/pkg/controllers/sgx/controller.go @@ -43,13 +43,13 @@ var defaultNodeSelector = deployments.SGXPluginDaemonSet().Spec.Template.Spec.No // +kubebuilder:rbac:groups=deviceplugin.intel.com,resources=sgxdeviceplugins/finalizers,verbs=update // SetupReconciler creates a new reconciler for SgxDevicePlugin objects. -func SetupReconciler(mgr ctrl.Manager, namespace string, withWebhook bool) error { - c := &controller{scheme: mgr.GetScheme(), ns: namespace} +func SetupReconciler(mgr ctrl.Manager, args controllers.ControllerArgs) error { + c := &controller{scheme: mgr.GetScheme(), args: args} if err := controllers.SetupWithManager(mgr, c, devicepluginv1.GroupVersion.String(), "SgxDevicePlugin", ownerKey); err != nil { return err } - if withWebhook { + if args.WithWebhook { return (&devicepluginv1.SgxDevicePlugin{}).SetupWebhookWithManager(mgr) } @@ -59,7 +59,7 @@ func SetupReconciler(mgr ctrl.Manager, namespace string, withWebhook bool) error type controller struct { controllers.DefaultServiceAccountFactory scheme *runtime.Scheme - ns string + args controllers.ControllerArgs } func (c *controller) Upgrade(ctx context.Context, obj client.Object) bool { @@ -126,7 +126,7 @@ func (c *controller) NewDaemonSet(rawObj client.Object) *apps.DaemonSet { daemonSet.Spec.Template.Spec.NodeSelector = devicePlugin.Spec.NodeSelector } - daemonSet.ObjectMeta.Namespace = c.ns + daemonSet.ObjectMeta.Namespace = c.args.Namespace daemonSet.Spec.Template.Spec.Containers[0].Args = getPodArgs(devicePlugin) daemonSet.Spec.Template.Spec.Containers[0].Image = devicePlugin.Spec.Image @@ -136,6 +136,12 @@ func (c *controller) NewDaemonSet(rawObj client.Object) *apps.DaemonSet { setInitContainer(&daemonSet.Spec.Template.Spec, devicePlugin.Spec.InitImage) } + if len(c.args.Secret) > 0 { + daemonSet.Spec.Template.Spec.ImagePullSecrets = []v1.LocalObjectReference{ + {Name: c.args.Secret}, + } + } + return daemonSet } diff --git a/pkg/controllers/sgx/controller_test.go b/pkg/controllers/sgx/controller_test.go index 47f653ed1..0ddf484da 100644 --- a/pkg/controllers/sgx/controller_test.go +++ b/pkg/controllers/sgx/controller_test.go @@ -49,7 +49,7 @@ func (c *controller) newDaemonSetExpected(rawObj client.Object) *apps.DaemonSet APIVersion: "apps/v1", }, ObjectMeta: metav1.ObjectMeta{ - Namespace: c.ns, + Namespace: c.args.Namespace, Name: appLabel + "-" + devicePlugin.Name, Labels: map[string]string{ "app": appLabel, @@ -157,6 +157,12 @@ func (c *controller) newDaemonSetExpected(rawObj client.Object) *apps.DaemonSet setInitContainer(&daemonSet.Spec.Template.Spec, devicePlugin.Spec.InitImage) } + if len(c.args.Secret) > 0 { + daemonSet.Spec.Template.Spec.ImagePullSecrets = []v1.LocalObjectReference{ + {Name: c.args.Secret}, + } + } + return &daemonSet } @@ -173,4 +179,13 @@ func TestNewDaemonSetSGX(t *testing.T) { if !reflect.DeepEqual(expected, actual) { t.Errorf("expected and actuall daemonsets differ: %+s", diff.ObjectGoPrintDiff(expected, actual)) } + + c.args.Secret = "mysecret" + + expected = c.newDaemonSetExpected(plugin) + actual = c.NewDaemonSet(plugin) + + if !reflect.DeepEqual(expected, actual) { + t.Errorf("expected and actual daemonsets with secret differ: %+s", diff.ObjectGoPrintDiff(expected, actual)) + } } diff --git a/test/envtest/suite_test.go b/test/envtest/suite_test.go index 44e4e090c..5664cf245 100644 --- a/test/envtest/suite_test.go +++ b/test/envtest/suite_test.go @@ -113,21 +113,21 @@ func up() { k8sManager, managerErr := ctrl.NewManager(cfg, ctrl.Options{Scheme: scheme.Scheme, Metrics: metricsserver.Options{BindAddress: "0"}, Controller: config.Controller{SkipNameValidation: &yes}}) Expect(managerErr).To(BeNil()) - withWebhook := true + args := ctr.ControllerArgs{Namespace: ns, WithWebhook: false} - Expect(dlbctr.SetupReconciler(k8sManager, ns, !withWebhook)).To(BeNil()) + Expect(dlbctr.SetupReconciler(k8sManager, args)).To(BeNil()) - Expect(dsactr.SetupReconciler(k8sManager, ns, !withWebhook)).To(BeNil()) + Expect(dsactr.SetupReconciler(k8sManager, args)).To(BeNil()) - Expect(fpgactr.SetupReconciler(k8sManager, ns, !withWebhook)).To(BeNil()) + Expect(fpgactr.SetupReconciler(k8sManager, args)).To(BeNil()) - Expect(gpuctr.SetupReconciler(k8sManager, ns, !withWebhook)).To(BeNil()) + Expect(gpuctr.SetupReconciler(k8sManager, args)).To(BeNil()) - Expect(iaactr.SetupReconciler(k8sManager, ns, !withWebhook)).To(BeNil()) + Expect(iaactr.SetupReconciler(k8sManager, args)).To(BeNil()) - Expect(qatctr.SetupReconciler(k8sManager, ns, !withWebhook)).To(BeNil()) + Expect(qatctr.SetupReconciler(k8sManager, args)).To(BeNil()) - Expect(sgxctr.SetupReconciler(k8sManager, ns, !withWebhook)).To(BeNil()) + Expect(sgxctr.SetupReconciler(k8sManager, args)).To(BeNil()) ctx, cancel = context.WithCancel(context.TODO())