diff --git a/.github/workflows/merge.yml b/.github/workflows/merge.yml index 999468187d..3533bdad78 100644 --- a/.github/workflows/merge.yml +++ b/.github/workflows/merge.yml @@ -260,6 +260,21 @@ jobs: echo "✅ Created and pushed tag: $NEW_TAG" echo "appcat-tag=$NEW_TAG" >> $GITHUB_OUTPUT + - name: Trigger Release Workflow + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + await github.rest.actions.createWorkflowDispatch({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: 'release.yml', + ref: 'master', + inputs: { + tag: '${{ steps.tag.outputs.appcat-tag }}' + } + }); + - name: Clone and patch component repo run: | COMPONENT_BRANCH="${{ needs.check-conditions.outputs.comp-feature-branch }}" @@ -311,7 +326,7 @@ jobs: gh pr merge -R "$COMPONENT_REPO" ${{ needs.check-conditions.outputs.comp-pr-number }} --merge --delete-branch merge-hotfix-update-develop: - needs: merge-hotfix + needs: [merge-hotfix, check-conditions] runs-on: ubuntu-latest steps: - name: Create PR to merge master into develop in appcat repo @@ -322,7 +337,7 @@ jobs: --repo "$APPCAT_REPO" \ --base develop \ --head master \ - --reviewer ${{ needs.check-conditions.outputs.author }} \ \ + --reviewer ${{ needs.check-conditions.outputs.author }} \ --title "🔀 Merge master into develop (sync hotfixes)" \ --body "This PR synchronizes the hotfixes from master back into develop." || true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b671c253d1..462021983f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,6 +4,12 @@ on: push: tags: - "*" + workflow_dispatch: + inputs: + tag: + description: 'Tag to release' + required: true + type: string env: APP_NAME: appcat diff --git a/pkg/comp-functions/functions/common/maintenance/maintenance.go b/pkg/comp-functions/functions/common/maintenance/maintenance.go index 5d65dad6a3..85116f6203 100644 --- a/pkg/comp-functions/functions/common/maintenance/maintenance.go +++ b/pkg/comp-functions/functions/common/maintenance/maintenance.go @@ -253,6 +253,10 @@ func (m *Maintenance) createMaintenanceJob(_ context.Context, cronSchedule strin Name: "RELEASE_MANAGEMENT_ENABLED", Value: m.svc.Config.Data["releaseManagementEnabled"], }, + { + Name: "MAINTENANCE_URL", + Value: m.svc.Config.Data["maintenanceURL"], + }, } job := &batchv1.CronJob{ diff --git a/pkg/comp-functions/functions/vshnkeycloak/deploy.go b/pkg/comp-functions/functions/vshnkeycloak/deploy.go index e88cf1f890..9e682e623a 100644 --- a/pkg/comp-functions/functions/vshnkeycloak/deploy.go +++ b/pkg/comp-functions/functions/vshnkeycloak/deploy.go @@ -1090,7 +1090,7 @@ func copyKeycloakCredentials(comp *vshnv1.VSHNKeycloak, svc *runtime.ServiceRunt Containers: []v1.Container{ { Name: "copyjob", - Image: "bitnami/kubectl:latest", + Image: svc.Config.Data["kubectl_image"], Command: []string{"sh", "-c"}, Args: []string{keycloakCredentialsCopyJobScript}, Env: []v1.EnvVar{ diff --git a/pkg/comp-functions/functions/vshnmariadb/mariadb_deploy.go b/pkg/comp-functions/functions/vshnmariadb/mariadb_deploy.go index 205b7f2a93..d979bb4020 100644 --- a/pkg/comp-functions/functions/vshnmariadb/mariadb_deploy.go +++ b/pkg/comp-functions/functions/vshnmariadb/mariadb_deploy.go @@ -244,6 +244,20 @@ func newValues(ctx context.Context, svc *runtime.ServiceRuntime, comp *vshnv1.VS } } + if imageRepositoryPrefix := svc.Config.Data["imageRepositoryPrefix"]; imageRepositoryPrefix != "" { + if err := common.SetNestedObjectValue(values, []string{"image"}, map[string]any{ + "repository": fmt.Sprintf("%s/mariadb-galera", imageRepositoryPrefix), + }); err != nil { + return nil, err + } + + if err := common.SetNestedObjectValue(values, []string{"metrics", "image"}, map[string]any{ + "repository": fmt.Sprintf("%s/mysqld-exporter", imageRepositoryPrefix), + }); err != nil { + return nil, err + } + } + return values, nil } diff --git a/pkg/comp-functions/functions/vshnpostgres/postgresql_deploy.go b/pkg/comp-functions/functions/vshnpostgres/postgresql_deploy.go index 001966d3e5..367b1f82a1 100644 --- a/pkg/comp-functions/functions/vshnpostgres/postgresql_deploy.go +++ b/pkg/comp-functions/functions/vshnpostgres/postgresql_deploy.go @@ -664,7 +664,7 @@ func createCopyJob(comp *vshnv1.VSHNPostgreSQL, svc *runtime.ServiceRuntime) err Containers: []v1.Container{ { Name: "copyjob", - Image: "bitnami/kubectl:latest", + Image: svc.Config.Data["kubectl_image"], Command: []string{"sh", "-c"}, Args: []string{postgresqlCopyJobScript}, Env: []v1.EnvVar{ diff --git a/pkg/comp-functions/functions/vshnredis/backup.go b/pkg/comp-functions/functions/vshnredis/backup.go index bd5e6e3128..bfa3300db4 100644 --- a/pkg/comp-functions/functions/vshnredis/backup.go +++ b/pkg/comp-functions/functions/vshnredis/backup.go @@ -71,17 +71,17 @@ func updateRelease(ctx context.Context, svc *runtime.ServiceRuntime) error { } l.Info("Adding the PVC k8up annotations") - if err := backup.AddPVCAnnotationToValues(values, "master", "persistence", "annotations"); err != nil { + if err := backup.AddPVCAnnotationToValues(values, "replica", "persistence", "annotations"); err != nil { return err } l.Info("Adding the Pod k8up annotations") - if err := backup.AddPodAnnotationToValues(values, "/scripts/backup.sh", ".tar", "master", "podAnnotations"); err != nil { + if err := backup.AddPodAnnotationToValues(values, "/scripts/backup.sh", ".tar", "replica", "podAnnotations"); err != nil { return err } l.Info("Mounting CM into pod") - if err := backup.AddBackupCMToValues(values, []string{"master", "extraVolumes"}, []string{"master", "extraVolumeMounts"}); err != nil { + if err := backup.AddBackupCMToValues(values, []string{"replica", "extraVolumes"}, []string{"replica", "extraVolumeMounts"}); err != nil { return err } diff --git a/pkg/comp-functions/functions/vshnredis/pvcresize.go b/pkg/comp-functions/functions/vshnredis/pvcresize.go index a9f0ce18d9..b0fdcfae91 100644 --- a/pkg/comp-functions/functions/vshnredis/pvcresize.go +++ b/pkg/comp-functions/functions/vshnredis/pvcresize.go @@ -115,7 +115,7 @@ func ResizePVCs(ctx context.Context, comp *vshnv1.VSHNRedis, svc *runtime.Servic } func needReleasePatch(comp *vshnv1.VSHNRedis, values map[string]interface{}) (bool, *xfnproto.Result) { - releaseSizeValue, found, err := unstructured.NestedString(values, "master", "persistence", "size") + releaseSizeValue, found, err := unstructured.NestedString(values, "replica", "persistence", "size") if !found { return false, runtime.NewFatalResult(fmt.Errorf("disk size not found in release")) } @@ -178,12 +178,12 @@ func addDeletionJob(svc *runtime.ServiceRuntime, comp *vshnv1.VSHNRedis) error { Containers: []corev1.Container{ { Name: "sts-deleter", - Image: "bitnami/kubectl", + Image: svc.Config.Data["kubectl_image"], ImagePullPolicy: corev1.PullIfNotPresent, Env: []corev1.EnvVar{ { Name: "STS_NAME", - Value: "redis-master", + Value: "redis-node", }, { Name: "STS_NAMESPACE", @@ -212,17 +212,17 @@ func addDeletionJob(svc *runtime.ServiceRuntime, comp *vshnv1.VSHNRedis) error { }, } - return svc.SetDesiredKubeObject(job, comp.Name+"-sts-deleter") + return svc.SetDesiredKubeObject(job, comp.Name+"-sts-deleter", runtime.KubeOptionAllowDeletion) } func addStsObserver(svc *runtime.ServiceRuntime, comp *vshnv1.VSHNRedis) error { statefulset := &appsv1.StatefulSet{ ObjectMeta: metav1.ObjectMeta{ - Name: "redis-master", + Name: "redis-node", Namespace: getInstanceNamespace(comp), }, } - return svc.SetDesiredKubeObject(statefulset, comp.Name+"-sts-observer", runtime.KubeOptionObserve) + return svc.SetDesiredKubeObject(statefulset, comp.Name+"-sts-observer", runtime.KubeOptionObserve, runtime.KubeOptionAllowDeletion) } diff --git a/pkg/comp-functions/functions/vshnredis/pvcresize_test.go b/pkg/comp-functions/functions/vshnredis/pvcresize_test.go index 403ce9d9b9..d8a1bacd25 100644 --- a/pkg/comp-functions/functions/vshnredis/pvcresize_test.go +++ b/pkg/comp-functions/functions/vshnredis/pvcresize_test.go @@ -63,7 +63,7 @@ func Test_needReleasePatch(t *testing.T) { }, }, values: map[string]interface{}{ - "master": map[string]interface{}{ + "replica": map[string]interface{}{ "persistence": map[string]interface{}{ "size": "15Gi", }, @@ -85,7 +85,7 @@ func Test_needReleasePatch(t *testing.T) { }, }, values: map[string]interface{}{ - "master": map[string]interface{}{ + "replica": map[string]interface{}{ "persistence": map[string]interface{}{ "size": "15Gi", }, @@ -107,7 +107,7 @@ func Test_needReleasePatch(t *testing.T) { }, }, values: map[string]interface{}{ - "master": map[string]interface{}{ + "replica": map[string]interface{}{ "persistence": map[string]interface{}{ "size": "15Gi", }, @@ -130,7 +130,7 @@ func Test_needReleasePatch(t *testing.T) { }, }, values: map[string]interface{}{ - "master": map[string]interface{}{ + "replica": map[string]interface{}{ "persistence": map[string]interface{}{ "size": "15Gi", }, @@ -153,7 +153,7 @@ func Test_needReleasePatch(t *testing.T) { }, }, values: map[string]interface{}{ - "master": map[string]interface{}{ + "replica": map[string]interface{}{ "persistence": map[string]interface{}{ "size": "foo", }, @@ -176,7 +176,7 @@ func Test_needReleasePatch(t *testing.T) { }, }, values: map[string]interface{}{ - "master": map[string]interface{}{ + "replica": map[string]interface{}{ "persistence": map[string]interface{}{}, }, }, diff --git a/pkg/comp-functions/functions/vshnredis/redis_deploy.go b/pkg/comp-functions/functions/vshnredis/redis_deploy.go index 09156be2f9..a29bc3657e 100644 --- a/pkg/comp-functions/functions/vshnredis/redis_deploy.go +++ b/pkg/comp-functions/functions/vshnredis/redis_deploy.go @@ -273,6 +273,34 @@ func newValues(ctx context.Context, svc *runtime.ServiceRuntime, comp *vshnv1.VS if registry := svc.Config.Data["imageRegistry"]; registry != "" { _ = common.SetNestedObjectValue(values, []string{"global", "imageRegistry"}, registry) } + + if imageRepositoryPrefix := svc.Config.Data["imageRepositoryPrefix"]; imageRepositoryPrefix != "" { + if err := common.SetNestedObjectValue(values, []string{"image"}, map[string]any{ + "repository": fmt.Sprintf("%s/redis", imageRepositoryPrefix), + }); err != nil { + return nil, err + } + + if err := common.SetNestedObjectValue(values, []string{"sentinel", "image"}, map[string]any{ + "repository": fmt.Sprintf("%s/redis-sentinel", imageRepositoryPrefix), + }); err != nil { + return nil, err + } + + if err := common.SetNestedObjectValue(values, []string{"metrics", "image"}, map[string]any{ + "repository": fmt.Sprintf("%s/redis-exporter", imageRepositoryPrefix), + }); err != nil { + return nil, err + } + + if err := common.SetNestedObjectValue(values, []string{"kubectl", "image"}, map[string]any{ + "repository": fmt.Sprintf("%s/kubectl", imageRepositoryPrefix), + }); err != nil { + return nil, err + } + + } + return values, nil } @@ -412,7 +440,7 @@ func migrateRedis(ctx context.Context, svc *runtime.ServiceRuntime, comp *vshnv1 Containers: []corev1.Container{ { Name: "migrationjob", - Image: "bitnami/kubectl:latest", + Image: svc.Config.Data["kubectl_image"], Command: []string{"sh", "-c"}, Args: []string{redisScalingScript}, Env: []corev1.EnvVar{ diff --git a/pkg/comp-functions/functions/vshnredis/restore.go b/pkg/comp-functions/functions/vshnredis/restore.go index a1cd6efd61..7dedabcafa 100644 --- a/pkg/comp-functions/functions/vshnredis/restore.go +++ b/pkg/comp-functions/functions/vshnredis/restore.go @@ -89,7 +89,7 @@ func addPrepareRestoreJob(ctx context.Context, comp *vshnv1.VSHNRedis, svc *runt Containers: []corev1.Container{ { Name: "copyjob", - Image: "bitnami/kubectl:latest", + Image: svc.Config.Data["kubectl_image"], Command: []string{ "bash", "-c", @@ -140,7 +140,7 @@ func addRestoreJob(ctx context.Context, comp *vshnv1.VSHNRedis, svc *runtime.Ser Name: "data", VolumeSource: corev1.VolumeSource{ PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{ - ClaimName: "redis-data-redis-master-0", + ClaimName: "redis-data-redis-node-0", }, }, }, @@ -236,6 +236,13 @@ func addRestoreJob(ctx context.Context, comp *vshnv1.VSHNRedis, svc *runtime.Ser }, } + if !svc.GetBoolFromCompositionConfig("isOpenshift") { + fsGroup := int64(1001) + job.Spec.Template.Spec.SecurityContext = &corev1.PodSecurityContext{ + FSGroup: &fsGroup, + } + } + return svc.SetDesiredKubeObject(job, restoreJobName) } @@ -259,7 +266,7 @@ func addCleanUpJob(ctx context.Context, comp *vshnv1.VSHNRedis, svc *runtime.Ser Containers: []corev1.Container{ { Name: "copyjob", - Image: "bitnami/kubectl:latest", + Image: svc.Config.Data["kubectl_image"], Command: []string{ "bash", "-c", diff --git a/pkg/comp-functions/functions/vshnredis/script/cleanupRestore.sh b/pkg/comp-functions/functions/vshnredis/script/cleanupRestore.sh index 52ece84238..081a99178c 100644 --- a/pkg/comp-functions/functions/vshnredis/script/cleanupRestore.sh +++ b/pkg/comp-functions/functions/vshnredis/script/cleanupRestore.sh @@ -56,7 +56,7 @@ EOF fi echo "scaling up redis" -kubectl -n "${TARGET_NAMESPACE}" scale statefulset redis-master --replicas "${NUM_REPLICAS}" +kubectl -n "${TARGET_NAMESPACE}" scale statefulset redis-node --replicas "${NUM_REPLICAS}" echo "cleanup secret" diff --git a/pkg/comp-functions/functions/vshnredis/script/prepRestore.sh b/pkg/comp-functions/functions/vshnredis/script/prepRestore.sh index eaab246ee0..295be50007 100644 --- a/pkg/comp-functions/functions/vshnredis/script/prepRestore.sh +++ b/pkg/comp-functions/functions/vshnredis/script/prepRestore.sh @@ -14,14 +14,14 @@ restic_password=$(kubectl -n "${source_namespace}" get secret k8up-repository-pa restic_repository=$(kubectl -n "${source_namespace}" get snapshots.k8up.io "${BACKUP_NAME}" -o jsonpath='{.spec.repository}') backup_path=$(kubectl -n "${source_namespace}" get snapshots.k8up.io "${BACKUP_NAME}" -o jsonpath='{.spec.paths[0]}') backup_name=$(kubectl -n "${source_namespace}" get snapshots.k8up.io "${BACKUP_NAME}" -o jsonpath='{.spec.id}') -num_replicas=$(kubectl -n "${TARGET_NAMESPACE}" get statefulset redis-master -o jsonpath='{.spec.replicas}') +num_replicas=$(kubectl -n "${TARGET_NAMESPACE}" get statefulset redis-node -o jsonpath='{.spec.replicas}') kubectl -n "${TARGET_NAMESPACE}" create secret generic "restore-credentials-${BACKUP_NAME}" --from-literal AWS_ACCESS_KEY_ID="${access_key}" --from-literal AWS_SECRET_ACCESS_KEY="${secret_key}" --from-literal RESTIC_PASSWORD="${restic_password}" --from-literal RESTIC_REPOSITORY="${restic_repository}" --from-literal BACKUP_PATH="${backup_path}" --from-literal BACKUP_NAME="${backup_name}" kubectl create secret generic "statefulset-replicas-${SOURCE_CLAIM_NAME}-${BACKUP_NAME}" --from-literal NUM_REPLICAS="${num_replicas}" echo "scaling down redis" -until kubectl -n "${TARGET_NAMESPACE}" get statefulset redis-master > /dev/null 2>&1 +until kubectl -n "${TARGET_NAMESPACE}" get statefulset redis-node > /dev/null 2>&1 do sleep 1 done -kubectl -n "${TARGET_NAMESPACE}" scale statefulset redis-master --replicas 0 +kubectl -n "${TARGET_NAMESPACE}" scale statefulset redis-node --replicas 0 \ No newline at end of file diff --git a/pkg/comp-functions/functions/vshnredis/script/recreate.sh b/pkg/comp-functions/functions/vshnredis/script/recreate.sh index 1e67bcc95f..35667edaef 100644 --- a/pkg/comp-functions/functions/vshnredis/script/recreate.sh +++ b/pkg/comp-functions/functions/vshnredis/script/recreate.sh @@ -19,15 +19,15 @@ if [[ $foundsize != "$size" ]]; then # deletion with orphan doesn't go through and the sts is stuck with an orphan finalizer. # So if the delete hasn't returned after 5s we forcefully patch away the finalizer. kubectl -n "$namespace" delete sts "$name" --cascade=orphan --ignore-not-found --wait=true --timeout 5s || true - kubectl -n "$namespace" patch sts redis-master -p '{"metadata":{"finalizers":null}}' || true + kubectl -n "$namespace" patch sts "$name" -p '{"metadata":{"finalizers":null}}' || true # Poke the release so it tries again to create the sts # We first set it to garbage to ensure that the release is in an invalid state, we use an invalid state so it doesn't # actually deploy anything. # Then we patch the right size to enforce an upgrade # This is necessary as provider-helm doesn't actually retry failed helm deployments unless the values change. echo "Triggering sts re-creation" - kubectl patch release "$release" --type merge -p "{\"spec\":{\"forProvider\":{\"values\":{\"master\":{\"persistence\":{\"size\":\"foo\"}}}}}}" - kubectl patch release "$release" --type merge -p "{\"spec\":{\"forProvider\":{\"values\":{\"master\":{\"persistence\":{\"size\":\"$size\"}}}}}}" + kubectl patch release "$release" --type merge -p "{\"spec\":{\"forProvider\":{\"values\":{\"replica\":{\"persistence\":{\"size\":\"foo\"}}}}}}" + kubectl patch release "$release" --type merge -p "{\"spec\":{\"forProvider\":{\"values\":{\"replica\":{\"persistence\":{\"size\":\"$size\"}}}}}}" count=0 while ! kubectl -n "$namespace" get sts "$name" && [[ count -lt 300 ]]; do echo "waiting for sts to re-appear" diff --git a/pkg/comp-functions/functions/vshnredis/script/restore.sh b/pkg/comp-functions/functions/vshnredis/script/restore.sh index 9170db0f99..2ed3aec5c5 100644 --- a/pkg/comp-functions/functions/vshnredis/script/restore.sh +++ b/pkg/comp-functions/functions/vshnredis/script/restore.sh @@ -2,10 +2,20 @@ set -euo pipefail -rm -rf /data/* -restic dump "${BACKUP_NAME}" "${BACKUP_PATH}" > /data/restore.tar -cd /data -tar xvf restore.tar -mv data/* . -rmdir data -rm restore.tar +DEST="/data" + +echo "Starting restore process" + +echo "Removing existing files in ${DEST}" +rm -rf "${DEST:?}/"* + +echo "Dumping restic backup '${BACKUP_NAME}' path '${BACKUP_PATH}' to ${DEST}/restore.tar" +restic dump "${BACKUP_NAME}" "${BACKUP_PATH}" > "${DEST}/restore.tar" + +echo "Extracting files from restore.tar into ${DEST}" +tar xvf "${DEST}/restore.tar" --strip-components=1 -C "${DEST}" + +echo "Removing temporary archive ${DEST}/restore.tar" +rm "${DEST}/restore.tar" + +echo "Restore completed successfully" diff --git a/pkg/maintenance/forgejo.go b/pkg/maintenance/forgejo.go index 0e957d620b..b73f182f63 100644 --- a/pkg/maintenance/forgejo.go +++ b/pkg/maintenance/forgejo.go @@ -2,18 +2,15 @@ package maintenance import ( "context" - "github.com/vshn/appcat/v4/pkg/maintenance/release" "net/http" + "github.com/vshn/appcat/v4/pkg/maintenance/release" + "github.com/go-logr/logr" "github.com/vshn/appcat/v4/pkg/maintenance/helm" "sigs.k8s.io/controller-runtime/pkg/client" ) -const ( - forgejoURL = "https://codeberg.org/v2/forgejo/forgejo/tags/list" -) - // Forgejo contains all necessary dependencies to successfully run a Forgejo maintenance type Forgejo struct { k8sClient client.Client @@ -34,7 +31,12 @@ func NewForgejo(c client.Client, hc *http.Client, vh release.VersionHandler, log // DoMaintenance will run forgejo's maintenance script. func (f *Forgejo) DoMaintenance(ctx context.Context) error { + maintenanceURL, err := getMaintenanceURL() + if err != nil { + return err + } + patcher := helm.NewImagePatcher(f.k8sClient, f.httpClient, f.log) valuesPath := helm.NewValuePath("image", "tag") - return patcher.DoMaintenance(ctx, forgejoURL, valuesPath, helm.SemVerPatchesOnly(true)) + return patcher.DoMaintenance(ctx, maintenanceURL, valuesPath, helm.SemVerPatchesOnly(true)) } diff --git a/pkg/maintenance/keycloak.go b/pkg/maintenance/keycloak.go index d420f5b549..6846b510c9 100644 --- a/pkg/maintenance/keycloak.go +++ b/pkg/maintenance/keycloak.go @@ -11,10 +11,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" ) -const ( - keycloakURL = "https://docker-registry.inventage.com:10121/v2/keycloak-competence-center/keycloak-managed/tags/list" -) - // Keycloak contains all necessary dependencies to successfully run a Keycloak maintenance type Keycloak struct { k8sClient client.Client @@ -35,7 +31,12 @@ func NewKeycloak(c client.Client, hc *http.Client, vh release.VersionHandler, lo // DoMaintenance will run minios's maintenance script. func (k *Keycloak) DoMaintenance(ctx context.Context) error { + maintenanceURL, err := getMaintenanceURL() + if err != nil { + return err + } + patcher := helm.NewImagePatcher(k.k8sClient, k.httpClient, k.log) valuesPath := helm.NewValuePath("image", "tag") - return patcher.DoMaintenance(ctx, keycloakURL, valuesPath, helm.SemVerMinorAndPatches(true)) + return patcher.DoMaintenance(ctx, maintenanceURL, valuesPath, helm.SemVerMinorAndPatches(true)) } diff --git a/pkg/maintenance/mariadb.go b/pkg/maintenance/mariadb.go index 3e590602cc..561af4353a 100644 --- a/pkg/maintenance/mariadb.go +++ b/pkg/maintenance/mariadb.go @@ -2,18 +2,14 @@ package maintenance import ( "context" - "github.com/vshn/appcat/v4/pkg/maintenance/release" "net/http" "github.com/go-logr/logr" "github.com/vshn/appcat/v4/pkg/maintenance/helm" + "github.com/vshn/appcat/v4/pkg/maintenance/release" "sigs.k8s.io/controller-runtime/pkg/client" ) -const ( - mariaDBURL = "https://hub.docker.com/v2/repositories/bitnami/mariadb-galera/tags/?page_size=100" -) - // MariaDB holds all the necessary objects to do a MariaDB maintenance type MariaDB struct { k8sClient client.Client @@ -22,7 +18,7 @@ type MariaDB struct { release.VersionHandler } -// NewMariaDB returns a new Redis maintenance job runner +// NewMariaDB returns a new MariaDB maintenance job runner func NewMariaDB(c client.Client, hc *http.Client, vh release.VersionHandler, logger logr.Logger) *MariaDB { return &MariaDB{ k8sClient: c, @@ -32,8 +28,13 @@ func NewMariaDB(c client.Client, hc *http.Client, vh release.VersionHandler, log } } -// DoMaintenance will run redis' maintenance script. +// DoMaintenance will run MariaDB's maintenance script. func (m *MariaDB) DoMaintenance(ctx context.Context) error { + maintenanceURL, err := getMaintenanceURL() + if err != nil { + return err + } + patcher := helm.NewImagePatcher(m.k8sClient, m.httpClient, m.log) - return patcher.DoMaintenance(ctx, mariaDBURL, helm.NewValuePath("image", "tag"), helm.SemVerPatchesOnly(false)) + return patcher.DoMaintenance(ctx, maintenanceURL, helm.NewValuePath("image", "tag"), helm.SemVerPatchesOnly(false)) } diff --git a/pkg/maintenance/minio.go b/pkg/maintenance/minio.go index b211e7728a..eb5afc0d1b 100644 --- a/pkg/maintenance/minio.go +++ b/pkg/maintenance/minio.go @@ -4,11 +4,12 @@ import ( "context" "encoding/json" "fmt" - "github.com/vshn/appcat/v4/pkg/maintenance/release" "net/http" "regexp" "time" + "github.com/vshn/appcat/v4/pkg/maintenance/release" + "github.com/go-logr/logr" "github.com/spf13/viper" "github.com/vshn/appcat/v4/pkg/maintenance/helm" @@ -17,7 +18,6 @@ import ( ) const ( - minioURL = "https://hub.docker.com/v2/repositories/minio/minio/tags/?page_size=100" dateRegex = minioTagPrefix + `(?P.*Z$)` minioTimeLayout = "2006-01-02T15-04-05Z07:00" minioTagPrefix = "RELEASE." @@ -44,14 +44,18 @@ func NewMinio(c client.Client, hc *http.Client, vh release.VersionHandler, logge // DoMaintenance will run minio's maintenance script. func (m *Minio) DoMaintenance(ctx context.Context) error { + maintenanceURL, err := getMaintenanceURL() + if err != nil { + return err + } + patcher := helm.NewImagePatcher(m.k8sClient, m.httpClient, m.log) valuesPath := helm.NewValuePath("image", "tag") - err := m.ensureTagIsNotNil(ctx, valuesPath) - if err != nil { + if err := m.ensureTagIsNotNil(ctx, valuesPath); err != nil { return fmt.Errorf("could not ensure tag exists: %w", err) } - return patcher.DoMaintenance(ctx, minioURL, valuesPath, compareMinioVersions) + return patcher.DoMaintenance(ctx, maintenanceURL, valuesPath, compareMinioVersions) } // compareMinioVersions specifically checks for new Minio versions diff --git a/pkg/maintenance/nextcloud.go b/pkg/maintenance/nextcloud.go index 38a4b3b317..65cf684d49 100644 --- a/pkg/maintenance/nextcloud.go +++ b/pkg/maintenance/nextcloud.go @@ -2,18 +2,15 @@ package maintenance import ( "context" - "github.com/vshn/appcat/v4/pkg/maintenance/release" "net/http" + "github.com/vshn/appcat/v4/pkg/maintenance/release" + "github.com/go-logr/logr" "github.com/vshn/appcat/v4/pkg/maintenance/helm" "sigs.k8s.io/controller-runtime/pkg/client" ) -const ( - nextcloudURL = "https://hub.docker.com/v2/namespaces/library/repositories/nextcloud/tags?page_size=100" -) - // Nextcloud contains all necessary dependencies to successfully run a Nextcloud maintenance type Nextcloud struct { k8sClient client.Client @@ -34,7 +31,12 @@ func NewNextcloud(c client.Client, hc *http.Client, vh release.VersionHandler, l // DoMaintenance will run minios's maintenance script. func (n *Nextcloud) DoMaintenance(ctx context.Context) error { + maintenanceURL, err := getMaintenanceURL() + if err != nil { + return err + } + patcher := helm.NewImagePatcher(n.k8sClient, n.httpClient, n.log) valuesPath := helm.NewValuePath("image", "tag") - return patcher.DoMaintenance(ctx, nextcloudURL, valuesPath, helm.SemVerPatchesOnly(true)) + return patcher.DoMaintenance(ctx, maintenanceURL, valuesPath, helm.SemVerPatchesOnly(true)) } diff --git a/pkg/maintenance/redis.go b/pkg/maintenance/redis.go index 16284e80a5..07786ba947 100644 --- a/pkg/maintenance/redis.go +++ b/pkg/maintenance/redis.go @@ -2,17 +2,14 @@ package maintenance import ( "context" + "net/http" + "github.com/go-logr/logr" "github.com/vshn/appcat/v4/pkg/maintenance/helm" "github.com/vshn/appcat/v4/pkg/maintenance/release" - "net/http" "sigs.k8s.io/controller-runtime/pkg/client" ) -const ( - redisURL = "https://hub.docker.com/v2/repositories/bitnami/redis/tags/?page_size=100" -) - // Redis holds all the necessary objects to do a Redis maintenance type Redis struct { k8sClient client.Client @@ -33,6 +30,11 @@ func NewRedis(c client.Client, hc *http.Client, vh release.VersionHandler, logge // DoMaintenance will run redis' maintenance script. func (r *Redis) DoMaintenance(ctx context.Context) error { + maintenanceURL, err := getMaintenanceURL() + if err != nil { + return err + } + patcher := helm.NewImagePatcher(r.k8sClient, r.httpClient, r.log) - return patcher.DoMaintenance(ctx, redisURL, helm.NewValuePath("image", "tag"), helm.SemVerPatchesOnly(false)) + return patcher.DoMaintenance(ctx, maintenanceURL, helm.NewValuePath("image", "tag"), helm.SemVerPatchesOnly(false)) } diff --git a/pkg/maintenance/redis_test.go b/pkg/maintenance/redis_test.go index 9fcaba0573..4acc637ae7 100644 --- a/pkg/maintenance/redis_test.go +++ b/pkg/maintenance/redis_test.go @@ -3,11 +3,12 @@ package maintenance import ( "context" "encoding/json" - "github.com/go-logr/logr" - "github.com/vshn/appcat/v4/pkg/maintenance/release" "net/http" "testing" + "github.com/go-logr/logr" + "github.com/vshn/appcat/v4/pkg/maintenance/release" + "github.com/spf13/viper" "github.com/stretchr/testify/assert" "github.com/vshn/appcat/v4/apis/helm/release/v1beta1" @@ -68,6 +69,7 @@ func TestRedis_DoMaintenance(t *testing.T) { // GIVEN t.Setenv("INSTANCE_NAMESPACE", "test-namespace") + t.Setenv("MAINTENANCE_URL", "https://hub.docker.com/v2/repositories/bitnamilegacy/redis/tags/?page_size=100") viper.AutomaticEnv() fClient := fake.NewClientBuilder(). WithScheme(pkg.SetupScheme()). diff --git a/pkg/maintenance/url.go b/pkg/maintenance/url.go new file mode 100644 index 0000000000..788981756f --- /dev/null +++ b/pkg/maintenance/url.go @@ -0,0 +1,15 @@ +package maintenance + +import ( + "fmt" + "os" +) + +// getMaintenanceURL reads the MAINTENANCE_URL environment variable. +func getMaintenanceURL() (string, error) { + const envKey = "MAINTENANCE_URL" + if url := os.Getenv(envKey); url != "" { + return url, nil + } + return "", fmt.Errorf("%s environment variable not set", envKey) +} diff --git a/test/functions/vshnredis/pvcresize/01_default.yaml b/test/functions/vshnredis/pvcresize/01_default.yaml index f1b55df0db..44a3c32adc 100644 --- a/test/functions/vshnredis/pvcresize/01_default.yaml +++ b/test/functions/vshnredis/pvcresize/01_default.yaml @@ -42,7 +42,7 @@ desired: image: repository: bitnami/redis tag: 7.0.11 - master: + replica: containerSecurityContext: enabled: true persistence: @@ -115,7 +115,7 @@ observed: image: repository: bitnami/redis tag: "7.0" - master: + replica: containerSecurityContext: enabled: true extraVolumes: [] diff --git a/test/functions/vshnredis/pvcresize/01_job.yaml b/test/functions/vshnredis/pvcresize/01_job.yaml index 72e9fc7970..f9880937ef 100644 --- a/test/functions/vshnredis/pvcresize/01_job.yaml +++ b/test/functions/vshnredis/pvcresize/01_job.yaml @@ -42,7 +42,7 @@ desired: image: repository: bitnami/redis tag: 7.0.11 - master: + replica: containerSecurityContext: enabled: true persistence: @@ -169,7 +169,7 @@ observed: image: repository: bitnami/redis tag: "7.0" - master: + replica: containerSecurityContext: enabled: true extraVolumes: [] diff --git a/test/functions/vshnredis/restore/01-GivenNoRestoreConfig.yaml b/test/functions/vshnredis/restore/01-GivenNoRestoreConfig.yaml index d07bdbbafb..e602f467ea 100644 --- a/test/functions/vshnredis/restore/01-GivenNoRestoreConfig.yaml +++ b/test/functions/vshnredis/restore/01-GivenNoRestoreConfig.yaml @@ -39,7 +39,7 @@ desired: image: repository: bitnami/redis tag: dummy - master: + replica: containerSecurityContext: enabled: true persistence: diff --git a/test/functions/vshnredis/restore/01-GivenRestoreConfig.yaml b/test/functions/vshnredis/restore/01-GivenRestoreConfig.yaml index 1778c6d7cb..ac23ef8632 100644 --- a/test/functions/vshnredis/restore/01-GivenRestoreConfig.yaml +++ b/test/functions/vshnredis/restore/01-GivenRestoreConfig.yaml @@ -53,7 +53,7 @@ desired: image: repository: bitnami/redis tag: dummy - master: + replica: containerSecurityContext: enabled: true persistence: diff --git a/test/functions/vshnredis/restore/01-GivenRestoreConfigNoBN.yaml b/test/functions/vshnredis/restore/01-GivenRestoreConfigNoBN.yaml index d07bdbbafb..e602f467ea 100644 --- a/test/functions/vshnredis/restore/01-GivenRestoreConfigNoBN.yaml +++ b/test/functions/vshnredis/restore/01-GivenRestoreConfigNoBN.yaml @@ -39,7 +39,7 @@ desired: image: repository: bitnami/redis tag: dummy - master: + replica: containerSecurityContext: enabled: true persistence: diff --git a/test/functions/vshnredis/restore/01-GivenRestoreConfigNoCN.yaml b/test/functions/vshnredis/restore/01-GivenRestoreConfigNoCN.yaml index d07bdbbafb..e602f467ea 100644 --- a/test/functions/vshnredis/restore/01-GivenRestoreConfigNoCN.yaml +++ b/test/functions/vshnredis/restore/01-GivenRestoreConfigNoCN.yaml @@ -39,7 +39,7 @@ desired: image: repository: bitnami/redis tag: dummy - master: + replica: containerSecurityContext: enabled: true persistence: