From bc9ffe0ae970118d5de7eddcec2a754a63c72ea0 Mon Sep 17 00:00:00 2001 From: Simon Emms Date: Mon, 25 Oct 2021 17:48:08 +0100 Subject: [PATCH] [installer]: trigger a migration job when DB is ready --- installer/pkg/common/common.go | 4 ++ installer/pkg/components/components.go | 2 + .../pkg/components/migrations/constants.go | 9 ++++ installer/pkg/components/migrations/job.go | 53 +++++++++++++++++++ .../pkg/components/migrations/objects.go | 15 ++++++ .../pkg/components/migrations/rolebinding.go | 35 ++++++++++++ installer/pkg/components/mysql/configmap.go | 1 + .../init/00-create-and-init-sessions-db.sql | 3 ++ 8 files changed, 122 insertions(+) create mode 100644 installer/pkg/components/migrations/constants.go create mode 100644 installer/pkg/components/migrations/job.go create mode 100644 installer/pkg/components/migrations/objects.go create mode 100644 installer/pkg/components/migrations/rolebinding.go diff --git a/installer/pkg/common/common.go b/installer/pkg/common/common.go index c41fd2f2d23dac..51b03cb096d7cd 100644 --- a/installer/pkg/common/common.go +++ b/installer/pkg/common/common.go @@ -466,6 +466,10 @@ var ( APIVersion: "v1", Kind: "ResourceQuota", } + TypeMetaBatchJob = metav1.TypeMeta{ + APIVersion: "batch/v1", + Kind: "Job", + } ) type TLS struct { diff --git a/installer/pkg/components/components.go b/installer/pkg/components/components.go index 05bc8a58b9881d..cbf160e61583f3 100644 --- a/installer/pkg/components/components.go +++ b/installer/pkg/components/components.go @@ -15,6 +15,7 @@ import ( "github.com/gitpod-io/gitpod/installer/pkg/components/gitpod" imagebuildermk3 "github.com/gitpod-io/gitpod/installer/pkg/components/image-builder-mk3" jaegeroperator "github.com/gitpod-io/gitpod/installer/pkg/components/jaeger-operator" + "github.com/gitpod-io/gitpod/installer/pkg/components/migrations" "github.com/gitpod-io/gitpod/installer/pkg/components/minio" "github.com/gitpod-io/gitpod/installer/pkg/components/mysql" openvsxproxy "github.com/gitpod-io/gitpod/installer/pkg/components/openvsx-proxy" @@ -35,6 +36,7 @@ var MetaObjects = common.CompositeRenderFunc( proxy.Objects, dashboard.Objects, imagebuildermk3.Objects, + migrations.Objects, mysql.Objects, openvsxproxy.Objects, rabbitmq.Objects, diff --git a/installer/pkg/components/migrations/constants.go b/installer/pkg/components/migrations/constants.go new file mode 100644 index 00000000000000..209fe55a195d6c --- /dev/null +++ b/installer/pkg/components/migrations/constants.go @@ -0,0 +1,9 @@ +// Copyright (c) 2021 Gitpod GmbH. All rights reserved. +// Licensed under the GNU Affero General Public License (AGPL). +// See License-AGPL.txt in the project root for license information. + +package migrations + +const ( + Component = "migrations" +) diff --git a/installer/pkg/components/migrations/job.go b/installer/pkg/components/migrations/job.go new file mode 100644 index 00000000000000..d3cac368582d1c --- /dev/null +++ b/installer/pkg/components/migrations/job.go @@ -0,0 +1,53 @@ +// Copyright (c) 2021 Gitpod GmbH. All rights reserved. +// Licensed under the GNU Affero General Public License (AGPL). +// See License-AGPL.txt in the project root for license information. + +package migrations + +import ( + "github.com/gitpod-io/gitpod/installer/pkg/common" + batchv1 "k8s.io/api/batch/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/utils/pointer" +) + +func job(ctx *common.RenderContext) ([]runtime.Object, error) { + objectMeta := metav1.ObjectMeta{ + Name: Component, + Namespace: ctx.Namespace, + Labels: common.DefaultLabels(Component), + } + + return []runtime.Object{&batchv1.Job{ + TypeMeta: common.TypeMetaBatchJob, + ObjectMeta: objectMeta, + Spec: batchv1.JobSpec{ + Template: corev1.PodTemplateSpec{ + ObjectMeta: objectMeta, + Spec: corev1.PodSpec{ + Affinity: &corev1.Affinity{}, + RestartPolicy: corev1.RestartPolicyNever, + ServiceAccountName: Component, + EnableServiceLinks: pointer.Bool(false), + // The init container is designed to emulate Helm hooks + InitContainers: []corev1.Container{*common.DatabaseWaiterContainer(ctx)}, + Containers: []corev1.Container{{ + Name: Component, + Image: common.ImageName(ctx.Config.Repository, "db-migrations", ctx.VersionManifest.Components.DBMigrations.Version), + ImagePullPolicy: corev1.PullIfNotPresent, + Env: common.MergeEnv( + common.DatabaseEnv(&ctx.Config), + ), + Command: []string{ + "sh", + "-c", + "cd /app/node_modules/@gitpod/gitpod-db && yarn run wait-for-db && yarn run typeorm migrations:run", + }, + }}, + }, + }, + }, + }}, nil +} diff --git a/installer/pkg/components/migrations/objects.go b/installer/pkg/components/migrations/objects.go new file mode 100644 index 00000000000000..e5256c380aef36 --- /dev/null +++ b/installer/pkg/components/migrations/objects.go @@ -0,0 +1,15 @@ +// Copyright (c) 2021 Gitpod GmbH. All rights reserved. +// Licensed under the GNU Affero General Public License (AGPL). +// See License-AGPL.txt in the project root for license information. + +package migrations + +import ( + "github.com/gitpod-io/gitpod/installer/pkg/common" +) + +var Objects = common.CompositeRenderFunc( + job, + rolebinding, + common.DefaultServiceAccount(Component), +) diff --git a/installer/pkg/components/migrations/rolebinding.go b/installer/pkg/components/migrations/rolebinding.go new file mode 100644 index 00000000000000..b4daefb875e374 --- /dev/null +++ b/installer/pkg/components/migrations/rolebinding.go @@ -0,0 +1,35 @@ +// Copyright (c) 2021 Gitpod GmbH. All rights reserved. +// Licensed under the GNU Affero General Public License (AGPL). +// See License-AGPL.txt in the project root for license information. + +package migrations + +import ( + "fmt" + "github.com/gitpod-io/gitpod/installer/pkg/common" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +func rolebinding(ctx *common.RenderContext) ([]runtime.Object, error) { + labels := common.DefaultLabels(Component) + + return []runtime.Object{&rbacv1.RoleBinding{ + TypeMeta: common.TypeMetaRoleBinding, + ObjectMeta: metav1.ObjectMeta{ + Name: Component, + Namespace: ctx.Namespace, + Labels: labels, + }, + RoleRef: rbacv1.RoleRef{ + Kind: "ClusterRole", + Name: fmt.Sprintf("%s-ns-psp:restricted-root-user", ctx.Namespace), + APIGroup: "rbac.authorization.k8s.io", + }, + Subjects: []rbacv1.Subject{{ + Kind: "ServiceAccount", + Name: Component, + }}, + }}, nil +} diff --git a/installer/pkg/components/mysql/configmap.go b/installer/pkg/components/mysql/configmap.go index 40a55754321245..fb9ebb7954e868 100644 --- a/installer/pkg/components/mysql/configmap.go +++ b/installer/pkg/components/mysql/configmap.go @@ -40,6 +40,7 @@ func configmap(ctx *common.RenderContext) ([]runtime.Object, error) { fileStr := string(file) // Replace variables in the script fileStr = strings.Replace(fileStr, "__GITPOD_DB_NAME__", Database, -1) + fileStr = strings.Replace(fileStr, "__GITPOD_USERNAME__", Username, -1) // Add the file name for debugging purposes initScriptData += fmt.Sprintf("-- %s\n\n%s", script.Name(), fileStr) diff --git a/installer/pkg/components/mysql/init/00-create-and-init-sessions-db.sql b/installer/pkg/components/mysql/init/00-create-and-init-sessions-db.sql index ffe04f00e855bd..f25ce59d4416e6 100644 --- a/installer/pkg/components/mysql/init/00-create-and-init-sessions-db.sql +++ b/installer/pkg/components/mysql/init/00-create-and-init-sessions-db.sql @@ -14,3 +14,6 @@ CREATE TABLE IF NOT EXISTS sessions ( `_lastModified` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), PRIMARY KEY (`session_id`) ); + +-- Grant privileges +GRANT ALL ON `gitpod-sessions`.* TO "__GITPOD_USERNAME__"@"%";