diff --git a/CHANGES/1060.feature b/CHANGES/1060.feature new file mode 100644 index 000000000..7b4520ee3 --- /dev/null +++ b/CHANGES/1060.feature @@ -0,0 +1 @@ +Added a job to handle `ALLOWED_CONTENT_CHECKSUMS` modifications. diff --git a/apis/repo-manager.pulpproject.org/v1beta2/pulp_types.go b/apis/repo-manager.pulpproject.org/v1beta2/pulp_types.go index 1039fad80..1e9e47b50 100644 --- a/apis/repo-manager.pulpproject.org/v1beta2/pulp_types.go +++ b/apis/repo-manager.pulpproject.org/v1beta2/pulp_types.go @@ -338,6 +338,12 @@ type PulpSpec struct { // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:hidden"} PulpSecretKey string `json:"pulp_secret_key,omitempty"` + // List of allowed checksum algorithms used to verify repository's integrity. + // Valid options: ["md5","sha1","sha256","sha512"]. + // +kubebuilder:validation:Optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:advanced"} + AllowedContentChecksums []string `json:"allowed_content_checksums,omitempty"` + // Protocol used by pulp-web service when ingress_type==loadbalancer // +kubebuilder:validation:Enum:=http;https // +kubebuilder:validation:Optional @@ -881,6 +887,10 @@ type PulpStatus struct { TelemetryEnabled bool `json:"telemetry_enabled,omitempty"` // Name of the Secret to provide Django cryptographic signing. PulpSecretKey string `json:"pulp_secret_key,omitempty"` + // List of allowed checksum algorithms used to verify repository's integrity. + AllowedContentChecksums string `json:"allowed_content_checksums,omitempty"` + // Controller status to keep tracking of deployment updates + LastDeploymentUpdate string `json:"last_deployment_update,omitempty"` } // Pulp is the Schema for the pulps API diff --git a/apis/repo-manager.pulpproject.org/v1beta2/zz_generated.deepcopy.go b/apis/repo-manager.pulpproject.org/v1beta2/zz_generated.deepcopy.go index a40793d98..fcd63356b 100644 --- a/apis/repo-manager.pulpproject.org/v1beta2/zz_generated.deepcopy.go +++ b/apis/repo-manager.pulpproject.org/v1beta2/zz_generated.deepcopy.go @@ -573,6 +573,11 @@ func (in *PulpSpec) DeepCopyInto(out *PulpSpec) { } in.AdminPasswordJob.DeepCopyInto(&out.AdminPasswordJob) in.MigrationJob.DeepCopyInto(&out.MigrationJob) + if in.AllowedContentChecksums != nil { + in, out := &in.AllowedContentChecksums, &out.AllowedContentChecksums + *out = make([]string, len(*in)) + copy(*out, *in) + } in.Telemetry.DeepCopyInto(&out.Telemetry) } diff --git a/bundle/manifests/pulp-operator.clusterserviceversion.yaml b/bundle/manifests/pulp-operator.clusterserviceversion.yaml index d77d409b4..7207a6e4c 100644 --- a/bundle/manifests/pulp-operator.clusterserviceversion.yaml +++ b/bundle/manifests/pulp-operator.clusterserviceversion.yaml @@ -164,7 +164,7 @@ metadata: capabilities: Full Lifecycle categories: Integration & Delivery containerImage: quay.io/pulp/pulp-operator:devel - createdAt: "2023-08-24T11:17:51Z" + createdAt: "2023-08-29T13:45:26Z" description: Pulp is a platform for managing repositories of software packages and making them available to a large number of consumers. operators.operatorframework.io/builder: operator-sdk-v1.29.0 @@ -301,6 +301,12 @@ spec: x-descriptors: - urn:alm:descriptor:io.kubernetes:Secret - urn:alm:descriptor:com.tectonic.ui:advanced + - description: 'List of allowed checksum algorithms used to verify repository''s + integrity. Valid options: ["md5","sha1","sha256","sha512"].' + displayName: Allowed Content Checksums + path: allowed_content_checksums + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:advanced - description: Api defines desired state of pulpcore-api resources displayName: Api path: api diff --git a/bundle/manifests/repo-manager.pulpproject.org_pulps.yaml b/bundle/manifests/repo-manager.pulpproject.org_pulps.yaml index 54d6266ac..72878086f 100644 --- a/bundle/manifests/repo-manager.pulpproject.org_pulps.yaml +++ b/bundle/manifests/repo-manager.pulpproject.org_pulps.yaml @@ -101,6 +101,12 @@ spec: description: 'Secret where the administrator password can be found. Default: + "-admin-password"' type: string + allowed_content_checksums: + description: 'List of allowed checksum algorithms used to verify repository''s + integrity. Valid options: ["md5","sha1","sha256","sha512"].' + items: + type: string + type: array api: default: replicas: 1 @@ -8627,6 +8633,10 @@ spec: admin_password_secret: description: Secret where the administrator password can be found type: string + allowed_content_checksums: + description: List of allowed checksum algorithms used to verify repository's + integrity. + type: string conditions: items: description: "Condition contains details for one aspect of the current @@ -8718,6 +8728,9 @@ spec: ingress_type: description: The ingress type to use to reach the deployed instance type: string + last_deployment_update: + description: Controller status to keep tracking of deployment updates + type: string object_storage_azure_secret: description: The secret for Azure compliant object storage configuration. type: string diff --git a/config/crd/bases/repo-manager.pulpproject.org_pulps.yaml b/config/crd/bases/repo-manager.pulpproject.org_pulps.yaml index 87c3319fc..908506e11 100644 --- a/config/crd/bases/repo-manager.pulpproject.org_pulps.yaml +++ b/config/crd/bases/repo-manager.pulpproject.org_pulps.yaml @@ -102,6 +102,12 @@ spec: description: 'Secret where the administrator password can be found. Default: + "-admin-password"' type: string + allowed_content_checksums: + description: 'List of allowed checksum algorithms used to verify repository''s + integrity. Valid options: ["md5","sha1","sha256","sha512"].' + items: + type: string + type: array api: default: replicas: 1 @@ -8628,6 +8634,10 @@ spec: admin_password_secret: description: Secret where the administrator password can be found type: string + allowed_content_checksums: + description: List of allowed checksum algorithms used to verify repository's + integrity. + type: string conditions: items: description: "Condition contains details for one aspect of the current @@ -8719,6 +8729,9 @@ spec: ingress_type: description: The ingress type to use to reach the deployed instance type: string + last_deployment_update: + description: Controller status to keep tracking of deployment updates + type: string object_storage_azure_secret: description: The secret for Azure compliant object storage configuration. type: string diff --git a/config/manifests/bases/pulp-operator.clusterserviceversion.yaml b/config/manifests/bases/pulp-operator.clusterserviceversion.yaml index d419c26e8..b00ac353d 100644 --- a/config/manifests/bases/pulp-operator.clusterserviceversion.yaml +++ b/config/manifests/bases/pulp-operator.clusterserviceversion.yaml @@ -301,6 +301,12 @@ spec: x-descriptors: - urn:alm:descriptor:io.kubernetes:Secret - urn:alm:descriptor:com.tectonic.ui:advanced + - description: 'List of allowed checksum algorithms used to verify repository''s + integrity. Valid options: ["md5","sha1","sha256","sha512"].' + displayName: Allowed Content Checksums + path: allowed_content_checksums + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:advanced - description: Api defines desired state of pulpcore-api resources displayName: Api path: api diff --git a/controllers/deployment.go b/controllers/deployment.go index 75aadf1dd..c8cc86eea 100644 --- a/controllers/deployment.go +++ b/controllers/deployment.go @@ -949,6 +949,10 @@ func (d *CommonDeployment) setAnnotations(pulp repomanagerpulpprojectorgv1beta2. "kubectl.kubernetes.io/default-container": strings.ToLower(pulpcoreType), } + if pulp.Status.LastDeploymentUpdate != "" { + d.podAnnotations["repo-manager.pulpproject.org/restartedAt"] = pulp.Status.LastDeploymentUpdate + } + d.deploymentAnnotations = map[string]string{ "email": "pulp-dev@redhat.com", "ignore-check.kube-linter.io/no-node-affinity": "Do not check node affinity", diff --git a/controllers/repo_manager/README.md b/controllers/repo_manager/README.md index 15ac375d1..e8a50a2ba 100644 --- a/controllers/repo_manager/README.md +++ b/controllers/repo_manager/README.md @@ -214,6 +214,7 @@ PulpSpec defines the desired state of Pulp | admin_password_job | Job to reset pulp admin password | [PulpJob](#pulpjob) | false | | migration_job | Job to run django migrations | [PulpJob](#pulpjob) | false | | pulp_secret_key | Name of the Secret to provide Django cryptographic signing. Default: \"pulp-secret-key\" | string | false | +| allowed_content_checksums | List of allowed checksum algorithms used to verify repository's integrity. Valid options: [\"md5\",\"sha1\",\"sha256\",\"sha512\"]. | []string | false | | loadbalancer_protocol | Protocol used by pulp-web service when ingress_type==loadbalancer | string | false | | loadbalancer_port | Port exposed by pulp-web service when ingress_type==loadbalancer | int32 | false | | telemetry | Telemetry defines the OpenTelemetry configuration | [Telemetry](#telemetry) | false | @@ -239,6 +240,8 @@ PulpStatus defines the observed state of Pulp | external_cache_secret | Name of the secret with the parameters to connect to an external Redis cluster | string | false | | telemetry_enabled | Pulp metrics collection enabled | bool | false | | pulp_secret_key | Name of the Secret to provide Django cryptographic signing. | string | false | +| allowed_content_checksums | List of allowed checksum algorithms used to verify repository's integrity. | string | false | +| last_deployment_update | Controller status to keep tracking of deployment updates | string | false | [Back to Custom Resources](#custom-resources) diff --git a/controllers/repo_manager/api.go b/controllers/repo_manager/api.go index 0748b747e..65118acb3 100644 --- a/controllers/repo_manager/api.go +++ b/controllers/repo_manager/api.go @@ -176,14 +176,8 @@ func (r *RepoManagerReconciler) pulpApiController(ctx context.Context, pulp *rep r.Get(ctx, types.NamespacedName{Name: pulp.Name + "-server", Namespace: pulp.Namespace}, serverSecret) expectedServerSecret := pulpServerSecret(funcResources) if requeue, err := controllers.ReconcileObject(funcResources, expectedServerSecret, serverSecret, conditionType, controllers.PulpSecret{}); err != nil || requeue { - log.Info("Reprovisioning pulpcore-api pods to get the new settings ...") - // when requeue==true it means the secret changed so we need to redeploy api and content pods to get the new settings.py - r.restartPods(pulp, apiDeployment) - contentDeployment := &appsv1.Deployment{} - r.Get(ctx, types.NamespacedName{Name: pulp.Name + "-content", Namespace: pulp.Namespace}, contentDeployment) - log.Info("Reprovisioning pulpcore-content pods to get the new settings ...") - r.restartPods(pulp, contentDeployment) - + // restart pulpcore pods if the secret has changed + r.restartPulpCorePods(pulp) return ctrl.Result{Requeue: requeue}, err } diff --git a/controllers/repo_manager/controller.go b/controllers/repo_manager/controller.go index 585c20ba4..67d4902b9 100644 --- a/controllers/repo_manager/controller.go +++ b/controllers/repo_manager/controller.go @@ -173,6 +173,9 @@ func (r *RepoManagerReconciler) Reconcile(ctx context.Context, req ctrl.Request) // create the job to reset pulp admin password in case admin_password_secret has changed r.updateAdminPasswordJob(ctx, pulp) + // create the job to update the allowed_content_checksums + r.updateContentChecksumsJob(ctx, pulp) + // if this is the first reconciliation loop (.status.ingress_type == "") OR // if there is no update in ingressType field if len(pulp.Status.IngressType) == 0 || pulp.Status.IngressType == pulp.Spec.IngressType { diff --git a/controllers/repo_manager/job.go b/controllers/repo_manager/job.go index e4e89f416..842011beb 100644 --- a/controllers/repo_manager/job.go +++ b/controllers/repo_manager/job.go @@ -18,13 +18,17 @@ package repo_manager import ( "context" + "encoding/json" + "reflect" + "time" repomanagerpulpprojectorgv1beta2 "github.com/pulp/pulp-operator/apis/repo-manager.pulpproject.org/v1beta2" "github.com/pulp/pulp-operator/controllers" - jobs "k8s.io/api/batch/v1" + batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" ) const ( @@ -56,13 +60,13 @@ func (r *RepoManagerReconciler) updateAdminPasswordJob(ctx context.Context, pulp jobTTL := int32(3600) // job definition - job := &jobs.Job{ + job := &batchv1.Job{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "reset-admin-password-", Namespace: pulp.Namespace, Labels: labels, }, - Spec: jobs.JobSpec{ + Spec: batchv1.JobSpec{ BackoffLimit: &backOffLimit, TTLSecondsAfterFinished: &jobTTL, Template: corev1.PodTemplateSpec{ @@ -214,13 +218,13 @@ func (r *RepoManagerReconciler) migrationJob(ctx context.Context, pulp *repomana jobTTL := int32(3600) // job definition - job := &jobs.Job{ + job := &batchv1.Job{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "pulpcore-migration-", Namespace: pulp.Namespace, Labels: labels, }, - Spec: jobs.JobSpec{ + Spec: batchv1.JobSpec{ BackoffLimit: &backOffLimit, TTLSecondsAfterFinished: &jobTTL, Template: corev1.PodTemplateSpec{ @@ -275,3 +279,113 @@ func jobLabels(pulp repomanagerpulpprojectorgv1beta2.Pulp) map[string]string { "pulp_cr": pulp.Name, } } + +// updateContentChecksumsJob creates a k8s Job to update the list of allowed content checksums +func (r *RepoManagerReconciler) updateContentChecksumsJob(ctx context.Context, pulp *repomanagerpulpprojectorgv1beta2.Pulp) { + log := r.RawLogger + + if !contentChecksumsModified(pulp) { + return + } + + labels := jobLabels(*pulp) + labels["app.kubernetes.io/component"] = "allowed-content-checksums" + containers := []corev1.Container{contentChecksumsContainer(pulp)} + volumes := pulpcoreVolumes(pulp, "") + backOffLimit := int32(2) + jobTTL := int32(60) + + // job definition + job := &batchv1.Job{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "update-content-checksums-", + Namespace: pulp.Namespace, + Labels: labels, + }, + Spec: batchv1.JobSpec{ + BackoffLimit: &backOffLimit, + TTLSecondsAfterFinished: &jobTTL, + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + RestartPolicy: "Never", + Containers: containers, + Volumes: volumes, + ServiceAccountName: pulp.Name, + }, + }, + }, + } + + // create the Job + log.Info("Creating a new update content checksums Job") + if err := r.Create(ctx, job); err != nil { + log.Error(err, "Failed to create update content checksums Job!") + } + + // update .status + settings, _ := json.Marshal(pulp.Spec.AllowedContentChecksums) + pulp.Status.AllowedContentChecksums = string(settings) + r.Status().Update(ctx, pulp) +} + +// contentChecksumsContainer defines the container spec for the updateContentChecksums Job +func contentChecksumsContainer(pulp *repomanagerpulpprojectorgv1beta2.Pulp) corev1.Container { + // env vars + envVars := controllers.GetPostgresEnvVars(*pulp) + + // volume mounts + volumeMounts := pulpcoreVolumeMounts(pulp) + + // resource requirements + resources := pulp.Spec.MigrationJob.PulpContainer.ResourceRequirements + + return corev1.Container{ + Name: "update-checksum", + Image: pulp.Spec.Image + ":" + pulp.Spec.ImageVersion, + ImagePullPolicy: "Always", + Env: envVars, + Command: []string{"/bin/sh"}, + Args: []string{ + "-c", + `/usr/bin/wait_on_postgres.py + /usr/bin/wait_on_database_migrations.sh + pulpcore-manager handle-artifact-checksums`, + }, + Resources: resources, + VolumeMounts: volumeMounts, + } +} + +// contentChecksumsModified returns true if +// .status.AllowedContentChecksums != pulp.Spec.AllowedContentChecksums +func contentChecksumsModified(pulp *repomanagerpulpprojectorgv1beta2.Pulp) bool { + var statusAllowedChecksum []string + json.Unmarshal([]byte(pulp.Status.AllowedContentChecksums), &statusAllowedChecksum) + return !reflect.DeepEqual(pulp.Spec.AllowedContentChecksums, statusAllowedChecksum) +} + +// waitJobFinishes wait until content-checksums job completes +func waitJobFinishes(resources RepoManagerReconciler, pulp *repomanagerpulpprojectorgv1beta2.Pulp, timeout time.Duration) { + labels := map[string]string{ + "app.kubernetes.io/component": "allowed-content-checksums", + } + listOpts := []client.ListOption{ + client.InNamespace(pulp.Namespace), + client.MatchingLabels(labels), + } + +TIMEOUT: + for i := 0; i < int(timeout.Seconds()); i++ { + jobList := &batchv1.JobList{} + if err := resources.Client.List(context.TODO(), jobList, listOpts...); err != nil { + resources.RawLogger.Error(err, "Failed to find content-checksum Jobs") + return + } + for _, p := range jobList.Items { + if p.Status.CompletionTime != nil { + break TIMEOUT + } + } + time.Sleep(time.Second) + } +} diff --git a/controllers/repo_manager/precheck.go b/controllers/repo_manager/precheck.go index e0a56fe93..625b67de5 100644 --- a/controllers/repo_manager/precheck.go +++ b/controllers/repo_manager/precheck.go @@ -18,6 +18,7 @@ package repo_manager import ( "context" + "encoding/json" "strings" "github.com/go-logr/logr" @@ -73,6 +74,11 @@ func prechecks(ctx context.Context, r *RepoManagerReconciler, pulp *repomanagerp return reconcile, nil } + // verify inconsistency in allowed_content_checksums definition + if reconcile := checkAllowedContentChecksums(ctx, r, pulp); reconcile != nil { + return reconcile, nil + } + return nil, nil } @@ -211,3 +217,33 @@ func checkFileStorage(ctx context.Context, r *RepoManagerReconciler, pulp *repom func hasFileStorageDefinition(pulp *repomanagerpulpprojectorgv1beta2.Pulp) bool { return len(pulp.Spec.FileStorageAccessMode) > 0 || len(pulp.Spec.FileStorageSize) > 0 } + +// checkAllowedContentChecksums verifies the following conditions for allowed_content_checksums: +// * deprecated checksums algorithms +// * mandatory checksums present (for now, only sha256 is required) +// * checksums provided are valid +func checkAllowedContentChecksums(ctx context.Context, r *RepoManagerReconciler, pulp *repomanagerpulpprojectorgv1beta2.Pulp) *ctrl.Result { + logger := controllers.CustomZapLogger() + + if len(pulp.Spec.AllowedContentChecksums) == 0 { + return nil + } + + for _, v := range pulp.Spec.AllowedContentChecksums { + if ok := verifyChecksum(v, validContentChecksums); !ok { + logger.Error("Checksum " + v + " is not valid!") + return &ctrl.Result{} + } + + if deprecated := verifyChecksum(v, deprecatedContentChecksum); deprecated { + logger.Warn("Checksum " + v + " is deprecated by some Pulp plugins, it is not recommended using it in production.") + } + } + + if missing, ok := requiredContentChecksums(pulp.Spec.AllowedContentChecksums); !ok { + missingJson, _ := json.Marshal(missing) + logger.Error("Missing required checksum(s): " + string(missingJson)) + return &ctrl.Result{} + } + return nil +} diff --git a/controllers/repo_manager/secret.go b/controllers/repo_manager/secret.go index c4fbb7f93..bd764ebe0 100644 --- a/controllers/repo_manager/secret.go +++ b/controllers/repo_manager/secret.go @@ -67,6 +67,9 @@ func pulpServerSecret(resources controllers.FunctionResources) client.Object { // django SECRET_KEY secretKeySettings(resources, &pulp_settings) + // allowed content checksum + allowedContentChecksumsSettings(resources, &pulp_settings) + // add custom settings to the secret addCustomPulpSettings(pulp, &pulp_settings) @@ -373,6 +376,16 @@ func secretKeySettings(resources controllers.FunctionResources, pulpSettings *st *pulpSettings = *pulpSettings + fmt.Sprintln("SECRET_KEY = \""+secretKey["secret_key"]+"\"") } +// allowedContentChecksumsSettings appends the allowed_content_checksums into pulpSettings +func allowedContentChecksumsSettings(resources controllers.FunctionResources, pulpSettings *string) { + pulp := resources.Pulp + if len(pulp.Spec.AllowedContentChecksums) == 0 { + return + } + settings, _ := json.Marshal(pulp.Spec.AllowedContentChecksums) + *pulpSettings = *pulpSettings + fmt.Sprintln("ALLOWED_CONTENT_CHECKSUMS = ", string(settings)) +} + // addCustomPulpSettings appends custom settings defined in Pulp CR into pulpSettings func addCustomPulpSettings(pulp *repomanagerpulpprojectorgv1beta2.Pulp, pulpSettings *string) { settings := pulp.Spec.PulpSettings.Raw diff --git a/controllers/repo_manager/status.go b/controllers/repo_manager/status.go index 01068a11c..d67c6e73a 100644 --- a/controllers/repo_manager/status.go +++ b/controllers/repo_manager/status.go @@ -251,6 +251,12 @@ func (r *RepoManagerReconciler) pulpStatus(ctx context.Context, pulp *repomanage r.Status().Update(ctx, pulp) } + // remove .status.allowed_content_checksums field in case it is not defined anymore + if len(pulp.Spec.AllowedContentChecksums) == 0 { + pulp.Status.AllowedContentChecksums = "" + r.Status().Update(ctx, pulp) + } + return ctrl.Result{}, nil } diff --git a/controllers/repo_manager/utils.go b/controllers/repo_manager/utils.go index e8f11c699..78db603fe 100644 --- a/controllers/repo_manager/utils.go +++ b/controllers/repo_manager/utils.go @@ -472,6 +472,9 @@ func (r *RepoManagerReconciler) findPulpDependentSecrets(secret client.Object) [ return []reconcile.Request{} } +// [DEPRECATED] this is not working because the r.Patch modification will be +// reconciled by the controller. The reconciliation is triggered because in +// the expected deployment there isn't a "repo-manager.pulpproject.org/restartedAt" annotation. // restartPods modifies a deployment template field (`.annotations`) which will // start a new rollout of pods func (r *RepoManagerReconciler) restartPods(pulp *repomanagerpulpprojectorgv1beta2.Pulp, obj client.Object) { @@ -487,6 +490,14 @@ func (r *RepoManagerReconciler) restartPods(pulp *repomanagerpulpprojectorgv1bet } } +// restartPulpCorePods will redeploy all pulpcore (API,content,worker) pods. +func (r *RepoManagerReconciler) restartPulpCorePods(pulp *repomanagerpulpprojectorgv1beta2.Pulp) { + log := r.RawLogger + log.Info("Reprovisioning pulpcore pods to get the new settings ...") + pulp.Status.LastDeploymentUpdate = time.Now().Format(time.RFC3339) + r.Status().Update(context.TODO(), pulp) +} + // runMigration deploys a k8s Job to run django migrations in case of pulpcore image change func (r *RepoManagerReconciler) runMigration(ctx context.Context, pulp *repomanagerpulpprojectorgv1beta2.Pulp) { if !r.needsMigration(ctx, pulp) { @@ -531,3 +542,54 @@ func hasActiveJob(jobList batchv1.JobList, pulp *repomanagerpulpprojectorgv1beta } return false } + +// validContentChecksums returns a map of the checksums algorithms supported and +// required by Pulp (only sha256 is required in the current Pulp version). +func validContentChecksums() map[string]bool { + return map[string]bool{ + "md5": false, + "sha1": false, + "sha256": true, + "sha512": false, + } +} + +// requiredContentChecksums verifies if all the required checksums are in the +// checksums list provided and, if not, returns the list of missing checksums +func requiredContentChecksums(cs []string) ([]string, bool) { + missing := []string{} + currentChecksums := map[string]bool{} + for _, v := range cs { + currentChecksums[v] = true + } + + for checksum, required := range validContentChecksums() { + if !required { + continue + } + if _, ok := currentChecksums[checksum]; !ok { + missing = append(missing, checksum) + } + } + + if len(missing) > 0 { + return missing, false + } + return []string{}, true +} + +// deprecatedContentChecksum returns a map of the checksums algorithms that are +// supported by Pulp but deprecated by some Pulp plugin. +func deprecatedContentChecksum() map[string]bool { + return map[string]bool{ + "md5": true, + "sha1": true, + } +} + +// verifyChecksum verifies if the provided checksum algorithm is supported and/or +// deprecated (depending on the validateFunction provided). +func verifyChecksum(checksum string, validateFunction func() map[string]bool) bool { + _, isValid := validateFunction()[checksum] + return isValid +} diff --git a/docs/configuring/content_checksums.md b/docs/configuring/content_checksums.md new file mode 100644 index 000000000..dda175f7f --- /dev/null +++ b/docs/configuring/content_checksums.md @@ -0,0 +1,24 @@ +# Configuring Pulp Allowed Content Checksums + +During repositories synchronization, Pulp checks the downloaded files against a list +of checksums algorithms. Together with a valid (and trusted) release file signature this will guarantee the integrity of the synchronized repository. + +The list of checksums algorithms is defined using the `ALLOWED_CONTENT_CHECKSUMS` setting. +For more information on how `Pulp` uses the checksums check: [https://docs.pulpproject.org/pulp_deb/workflows/checksums.html](https://docs.pulpproject.org/pulp_deb/workflows/checksums.html) + + +To set the `ALLOWED_CONTENT_CHECKSUMS` in Pulp Operator, update Pulp CR with: +```yaml +spec: + allowed_content_checksums: + - sha256 +``` + +!!! note + `sha256` is a mandatory checksum. + The possible checksums are: `md5`, `sha1`,`sha256`,`sha512`. + +After modifying the `allowed_content_checksums` field in Pulp CR, the operator will create a kubernetes job to run the `pulpcore-manager handle-artifact-checksums` command to ensure database consistency. + +!!! note + Missing checksums will need to be recalculated for all your artifacts which can take some time. \ No newline at end of file diff --git a/main.go b/main.go index 5925c925a..761c41b01 100644 --- a/main.go +++ b/main.go @@ -170,7 +170,7 @@ func main() { os.Exit(1) } - setupLog.Info("pulp-operator version: 1.0.3-beta.1") + setupLog.Info("pulp-operator version: 1.0.4-beta.1") setupLog.Info("starting manager") if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { setupLog.Error(err, "problem running manager") diff --git a/mkdocs.yml b/mkdocs.yml index ec446ae05..099ef612e 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -54,6 +54,7 @@ nav: - Disabling Reconciliation: configuring/unmanaged.md - Galaxy: configuring/galaxy.md - Telemetry: configuring/telemetry.md + - Content Checksums: configuring/content_checksums.md - Backup and Restore: - Overview: backup_and_restore/overview.md - Configuring and Running: backup_and_restore/config_running.md