diff --git a/DEVEL.md b/DEVEL.md index 900dc6337..74e1dc90b 100644 --- a/DEVEL.md +++ b/DEVEL.md @@ -132,6 +132,8 @@ Check if the fields mentioned below in the [base CSV manifest file](deployments/ - metadata.annotations.containerImage - metadata.annotations.createdAT +Check if [manager yaml file](deployments/operator/manager/manager.yaml) `spec.template.spec.containers.env` has correct sha256 digest for each plugin image. + Fork the [Community Operators](https://github.com/k8s-operatorhub/community-operators) repo and clone it: ``` $ git clone https://github.com//community-operators diff --git a/Makefile b/Makefile index 454f33e43..82c70e162 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,7 @@ BUNDLE_DEFAULT_CHANNEL := --default-channel=$(DEFAULT_CHANNEL) endif BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL) OLM_MANIFESTS = deployments/operator/manifests +BUNDLE_GEN_FLAGS ?= -q --overwrite --version $(TAG) $(BUNDLE_METADATA_OPTS) --kustomize-dir $(OLM_MANIFESTS) --output-dir . --use-image-digests BUNDLE_DIR = community-operators/operators/intel-device-plugins-operator/$(TAG) TESTDATA_DIR = pkg/topology/testdata @@ -120,7 +121,7 @@ bundle: rm -rf $(BUNDLE_DIR) mkdir -p $(BUNDLE_DIR) $(OPERATOR_SDK) generate kustomize manifests -q --input-dir $(OLM_MANIFESTS) --output-dir $(OLM_MANIFESTS) --apis-dir pkg/apis - $(KUSTOMIZE) build $(OLM_MANIFESTS) | sed "s|intel-deviceplugin-operator:devel|intel-deviceplugin-operator:$(TAG)|" | $(OPERATOR_SDK) generate bundle -q --overwrite --kustomize-dir $(OLM_MANIFESTS) --version $(TAG) $(BUNDLE_METADATA_OPTS) --output-dir . + $(KUSTOMIZE) build $(OLM_MANIFESTS) | sed "s|intel-deviceplugin-operator:devel|intel-deviceplugin-operator:$(TAG)|" | $(OPERATOR_SDK) generate bundle $(BUNDLE_GEN_FLAGS) # Remove unneeded resources rm manifests/*service.yaml rm manifests/*clusterrole.yaml diff --git a/cmd/operator/README.md b/cmd/operator/README.md index 22da75113..3b4a5c46e 100644 --- a/cmd/operator/README.md +++ b/cmd/operator/README.md @@ -109,11 +109,13 @@ The upgrade of the deployed plugins can be done by simply installing a new relea The operator auto-upgrades operator-managed plugins (CR images and thus corresponding deployed daemonsets) to the current release of the operator. -During upgrade the tag in the image path is updated (e.g. docker.io/intel/intel-sgx-plugin:tag), but the rest of the path is left intact. +From `0.28.0` release, each version of the operator can have a set of images in `deployments/operator/manager/manager.yaml` as env variables. -No upgrade is done for: -- Non-operator managed deployments -- Operator deployments without numeric tags +When env variables are set for specific plugins (and their initcontainers), plugins are upgraded to the images set as env variables and all user input is ignored. + +The name of env variables is capitalized image with '_SHA' ending (e.g. in case of the image for `intel-sgx-plugin`, the env variable is `INTEL_SGX_PLUGIN_SHA`). + +The value of env variables is the full path of the image (e.g. `docker.io/intel/intel-sgx-plugin@sha256:`). ## Limiting Supported Devices diff --git a/pkg/controllers/dlb/controller.go b/pkg/controllers/dlb/controller.go index 964bbc0b8..8e250ba3d 100644 --- a/pkg/controllers/dlb/controller.go +++ b/pkg/controllers/dlb/controller.go @@ -68,7 +68,7 @@ func (c *controller) CreateEmptyObject() client.Object { func (c *controller) Upgrade(ctx context.Context, obj client.Object) bool { dp := obj.(*devicepluginv1.DlbDevicePlugin) - return controllers.UpgradeImages(&dp.Spec.Image, &dp.Spec.InitImage) + return controllers.UpgradeImages(ctx, &dp.Spec.Image, &dp.Spec.InitImage) } func (c *controller) GetTotalObjectCount(ctx context.Context, clnt client.Client) (int, error) { diff --git a/pkg/controllers/dsa/controller.go b/pkg/controllers/dsa/controller.go index 7bd4e9d94..4cd504019 100644 --- a/pkg/controllers/dsa/controller.go +++ b/pkg/controllers/dsa/controller.go @@ -71,7 +71,7 @@ func (c *controller) CreateEmptyObject() client.Object { func (c *controller) Upgrade(ctx context.Context, obj client.Object) bool { dp := obj.(*devicepluginv1.DsaDevicePlugin) - return controllers.UpgradeImages(&dp.Spec.Image, &dp.Spec.InitImage) + return controllers.UpgradeImages(ctx, &dp.Spec.Image, &dp.Spec.InitImage) } func (c *controller) GetTotalObjectCount(ctx context.Context, clnt client.Client) (int, error) { diff --git a/pkg/controllers/fpga/controller.go b/pkg/controllers/fpga/controller.go index d6e21d284..19488714c 100644 --- a/pkg/controllers/fpga/controller.go +++ b/pkg/controllers/fpga/controller.go @@ -67,7 +67,7 @@ func (c *controller) CreateEmptyObject() client.Object { func (c *controller) Upgrade(ctx context.Context, obj client.Object) bool { dp := obj.(*devicepluginv1.FpgaDevicePlugin) - return controllers.UpgradeImages(&dp.Spec.Image, &dp.Spec.InitImage) + return controllers.UpgradeImages(ctx, &dp.Spec.Image, &dp.Spec.InitImage) } func (c *controller) GetTotalObjectCount(ctx context.Context, clnt client.Client) (int, error) { diff --git a/pkg/controllers/gpu/controller.go b/pkg/controllers/gpu/controller.go index dca852d35..ca408b52d 100644 --- a/pkg/controllers/gpu/controller.go +++ b/pkg/controllers/gpu/controller.go @@ -72,7 +72,7 @@ func (c *controller) CreateEmptyObject() client.Object { func (c *controller) Upgrade(ctx context.Context, obj client.Object) bool { dp := obj.(*devicepluginv1.GpuDevicePlugin) - return controllers.UpgradeImages(&dp.Spec.Image, &dp.Spec.InitImage) + return controllers.UpgradeImages(ctx, &dp.Spec.Image, &dp.Spec.InitImage) } func (c *controller) GetTotalObjectCount(ctx context.Context, clnt client.Client) (int, error) { diff --git a/pkg/controllers/iaa/controller.go b/pkg/controllers/iaa/controller.go index 9cbf4248b..b9aa05fc4 100644 --- a/pkg/controllers/iaa/controller.go +++ b/pkg/controllers/iaa/controller.go @@ -69,7 +69,7 @@ func (c *controller) CreateEmptyObject() client.Object { func (c *controller) Upgrade(ctx context.Context, obj client.Object) bool { dp := obj.(*devicepluginv1.IaaDevicePlugin) - return controllers.UpgradeImages(&dp.Spec.Image, &dp.Spec.InitImage) + return controllers.UpgradeImages(ctx, &dp.Spec.Image, &dp.Spec.InitImage) } func (c *controller) GetTotalObjectCount(ctx context.Context, clnt client.Client) (int, error) { diff --git a/pkg/controllers/qat/controller.go b/pkg/controllers/qat/controller.go index 422c088f4..e1b8718f7 100644 --- a/pkg/controllers/qat/controller.go +++ b/pkg/controllers/qat/controller.go @@ -72,7 +72,7 @@ func (c *controller) CreateEmptyObject() client.Object { func (c *controller) Upgrade(ctx context.Context, obj client.Object) bool { dp := obj.(*devicepluginv1.QatDevicePlugin) - return controllers.UpgradeImages(&dp.Spec.Image, &dp.Spec.InitImage) + return controllers.UpgradeImages(ctx, &dp.Spec.Image, &dp.Spec.InitImage) } func (c *controller) GetTotalObjectCount(ctx context.Context, clnt client.Client) (int, error) { diff --git a/pkg/controllers/reconciler.go b/pkg/controllers/reconciler.go index b9bcdfd97..4a3d41c33 100644 --- a/pkg/controllers/reconciler.go +++ b/pkg/controllers/reconciler.go @@ -17,6 +17,8 @@ package controllers import ( "context" + "os" + "path/filepath" "strings" "sync" @@ -167,7 +169,7 @@ func (r *reconciler) createObjects(ctx context.Context, return result, nil } -func UpgradeImages(image *string, initimage *string) (upgrade bool) { +func UpgradeImages(ctx context.Context, image *string, initimage *string) (upgrade bool) { for _, s := range []*string{image, initimage} { if s == nil { continue @@ -175,6 +177,18 @@ func UpgradeImages(image *string, initimage *string) (upgrade bool) { if parts := strings.SplitN(*s, ":", 2); len(parts) == 2 && len(parts[0]) > 0 { name, version := parts[0], parts[1] + + envVarValue := os.Getenv(strings.ReplaceAll(strings.ToUpper(filepath.Base(name)), "-", "_") + "_SHA") + + if envVarValue != "" && *s != envVarValue { + log.FromContext(ctx).Info("env var for the image: " + name + " is already set; user input of the image is ignored") + + *s = envVarValue + upgrade = true + + continue + } + if ver, err := versionutil.ParseSemantic(version); err == nil && ver.LessThan(ImageMinVersion) { *s = name + ":" + ImageMinVersion.String() upgrade = true diff --git a/pkg/controllers/reconciler_test.go b/pkg/controllers/reconciler_test.go index 7d3348e6f..56bb400c6 100644 --- a/pkg/controllers/reconciler_test.go +++ b/pkg/controllers/reconciler_test.go @@ -15,6 +15,7 @@ package controllers import ( + "context" "testing" ) @@ -63,7 +64,7 @@ func TestUpgrade(test *testing.T) { for i := range tests { t := tests[i] - upgrade := UpgradeImages(&t.image, &t.initimage) + upgrade := UpgradeImages(context.Background(), &t.image, &t.initimage) if !(upgrade == t.upgrade && t.image == t.expectedImage && t.initimage == t.expectedInitimage) { test.Errorf("expectedUpgrade: %v, received: %v", t.upgrade, upgrade) diff --git a/pkg/controllers/sgx/controller.go b/pkg/controllers/sgx/controller.go index ce3084159..e60d14cfe 100644 --- a/pkg/controllers/sgx/controller.go +++ b/pkg/controllers/sgx/controller.go @@ -64,7 +64,7 @@ type controller struct { func (c *controller) Upgrade(ctx context.Context, obj client.Object) bool { dp := obj.(*devicepluginv1.SgxDevicePlugin) - return controllers.UpgradeImages(&dp.Spec.Image, &dp.Spec.InitImage) + return controllers.UpgradeImages(ctx, &dp.Spec.Image, &dp.Spec.InitImage) } func (c *controller) CreateEmptyObject() client.Object {