From 10155ceace42f6d2021e45a3b6f60f7a75074028 Mon Sep 17 00:00:00 2001 From: Vladimir Nadvornik Date: Mon, 25 Nov 2024 16:13:44 +0100 Subject: [PATCH] Create dedicated postgres container in upgrade and migration --- mgradm/cmd/migrate/podman/utils.go | 11 +++ mgradm/cmd/migrate/shared/flags.go | 1 + mgradm/cmd/support/ptf/podman/podman.go | 1 + mgradm/cmd/support/ptf/podman/utils.go | 8 +- mgradm/cmd/upgrade/podman/utils.go | 9 ++- mgradm/cmd/upgrade/shared/flags.go | 1 + mgradm/shared/kubernetes/dbFinalize.go | 1 - mgradm/shared/kubernetes/services.go | 1 - mgradm/shared/pgsql/pgsql.go | 75 +++++++++++-------- mgradm/shared/podman/podman.go | 70 +++++++++++++++-- .../shared/templates/migrateScriptTemplate.go | 15 ++-- .../shared/templates/pgsqlConfigTemplate.go | 54 ------------- .../templates/pgsqlFinalizeScriptTemplate.go | 27 ------- .../templates/pgsqlMigrateScriptTemplate.go | 52 +++++++++++++ .../pgsqlVersionUpgradeScriptTemplate.go | 29 +++---- mgradm/shared/utils/cmd_utils.go | 4 +- mgradm/shared/utils/exec.go | 36 ++++----- mgradm/shared/utils/flags.go | 2 + shared/utils/ports.go | 1 - shared/utils/serverinspector.go | 21 ++++-- shared/utils/volumes.go | 11 ++- 21 files changed, 257 insertions(+), 173 deletions(-) delete mode 100644 mgradm/shared/templates/pgsqlConfigTemplate.go create mode 100644 mgradm/shared/templates/pgsqlMigrateScriptTemplate.go diff --git a/mgradm/cmd/migrate/podman/utils.go b/mgradm/cmd/migrate/podman/utils.go index 769c89f8d..3511d1258 100644 --- a/mgradm/cmd/migrate/podman/utils.go +++ b/mgradm/cmd/migrate/podman/utils.go @@ -14,6 +14,7 @@ import ( migration_shared "github.com/uyuni-project/uyuni-tools/mgradm/cmd/migrate/shared" "github.com/uyuni-project/uyuni-tools/mgradm/shared/coco" "github.com/uyuni-project/uyuni-tools/mgradm/shared/hub" + "github.com/uyuni-project/uyuni-tools/mgradm/shared/pgsql" "github.com/uyuni-project/uyuni-tools/mgradm/shared/podman" "github.com/uyuni-project/uyuni-tools/mgradm/shared/saline" "github.com/uyuni-project/uyuni-tools/shared" @@ -94,6 +95,16 @@ func migrateToPodman( } } + if err := podman_utils.SetupNetwork(false); err != nil { + return err + } + + if err := pgsql.Upgrade( + systemd, authFile, flags.Pgsql, + ); err != nil { + return err + } + schemaUpdateRequired := oldPgVersion != newPgVersion if err := podman.RunPgsqlFinalizeScript(preparedImage, schemaUpdateRequired, true); err != nil { return utils.Errorf(err, L("cannot run PostgreSQL finalize script")) diff --git a/mgradm/cmd/migrate/shared/flags.go b/mgradm/cmd/migrate/shared/flags.go index 22fdeae02..f19f488bb 100644 --- a/mgradm/cmd/migrate/shared/flags.go +++ b/mgradm/cmd/migrate/shared/flags.go @@ -17,6 +17,7 @@ func AddMigrateFlags(cmd *cobra.Command) { utils.AddSCCFlag(cmd) utils.AddImageFlag(cmd) utils.AddDBUpgradeImageFlag(cmd) + utils.AddUpgradePgsqlFlags(cmd) utils.AddUpgradeCocoFlag(cmd) utils.AddUpgradeHubXmlrpcFlags(cmd) utils.AddUpgradeSalineFlag(cmd) diff --git a/mgradm/cmd/support/ptf/podman/podman.go b/mgradm/cmd/support/ptf/podman/podman.go index 1728a0184..e5950fe82 100644 --- a/mgradm/cmd/support/ptf/podman/podman.go +++ b/mgradm/cmd/support/ptf/podman/podman.go @@ -22,6 +22,7 @@ type podmanPTFFlags struct { Coco adm_utils.CocoFlags Hubxmlrpc adm_utils.HubXmlrpcFlags Saline adm_utils.SalineFlags + Pgsql adm_utils.PgsqlFlags } func newCmd(globalFlags *types.GlobalFlags, run utils.CommandFunc[podmanPTFFlags]) *cobra.Command { diff --git a/mgradm/cmd/support/ptf/podman/utils.go b/mgradm/cmd/support/ptf/podman/utils.go index 3e5ff3655..5e6fe297d 100644 --- a/mgradm/cmd/support/ptf/podman/utils.go +++ b/mgradm/cmd/support/ptf/podman/utils.go @@ -44,7 +44,13 @@ func ptfForPodman( return err } - return podman.Upgrade(systemd, authFile, "", flags.Image, dummyImage, flags.Coco, flags.Hubxmlrpc, flags.Saline) + return podman.Upgrade(systemd, authFile, "", + flags.Image, dummyImage, + flags.Coco, + flags.Hubxmlrpc, + flags.Saline, + flags.Pgsql, + ) } // variables for unit testing. diff --git a/mgradm/cmd/upgrade/podman/utils.go b/mgradm/cmd/upgrade/podman/utils.go index 88fed1112..97d0f9835 100644 --- a/mgradm/cmd/upgrade/podman/utils.go +++ b/mgradm/cmd/upgrade/podman/utils.go @@ -28,6 +28,13 @@ func upgradePodman(_ *types.GlobalFlags, flags *podmanUpgradeFlags, _ *cobra.Com defer cleaner() return podman.Upgrade( - systemd, authFile, flags.Image.Registry, flags.Image, flags.DBUpgradeImage, flags.Coco, flags.HubXmlrpc, flags.Saline, + systemd, authFile, + flags.Image.Registry, + flags.Image, + flags.DBUpgradeImage, + flags.Coco, + flags.HubXmlrpc, + flags.Saline, + flags.Pgsql, ) } diff --git a/mgradm/cmd/upgrade/shared/flags.go b/mgradm/cmd/upgrade/shared/flags.go index 500f5adca..7f0182dbd 100644 --- a/mgradm/cmd/upgrade/shared/flags.go +++ b/mgradm/cmd/upgrade/shared/flags.go @@ -18,6 +18,7 @@ func AddUpgradeFlags(cmd *cobra.Command) { utils.AddUpgradeCocoFlag(cmd) utils.AddUpgradeHubXmlrpcFlags(cmd) utils.AddUpgradeSalineFlag(cmd) + utils.AddUpgradePgsqlFlags(cmd) } // AddUpgradeListFlags add upgrade list flags to a command. diff --git a/mgradm/shared/kubernetes/dbFinalize.go b/mgradm/shared/kubernetes/dbFinalize.go index b096f9872..e776ba122 100644 --- a/mgradm/shared/kubernetes/dbFinalize.go +++ b/mgradm/shared/kubernetes/dbFinalize.go @@ -53,7 +53,6 @@ func getDBFinalizeJob( // Prepare the script scriptData := templates.FinalizePostgresTemplateData{ - RunAutotune: true, RunReindex: migration, RunSchemaUpdate: schemaUpdateRequired, Migration: migration, diff --git a/mgradm/shared/kubernetes/services.go b/mgradm/shared/kubernetes/services.go index f5fb3b4a4..009ccce7f 100644 --- a/mgradm/shared/kubernetes/services.go +++ b/mgradm/shared/kubernetes/services.go @@ -40,7 +40,6 @@ func CreateServices(namespace string, debug bool) error { // If debug is true, the Java debug ports will be exposed. func GetServices(namespace string, debug bool) []*core.Service { ports := utils.GetServerPorts(debug) - ports = append(ports, utils.DBPorts...) servicesPorts := map[string][]types.PortMap{} for _, port := range ports { diff --git a/mgradm/shared/pgsql/pgsql.go b/mgradm/shared/pgsql/pgsql.go index 95b0f13bd..cabaf96c9 100644 --- a/mgradm/shared/pgsql/pgsql.go +++ b/mgradm/shared/pgsql/pgsql.go @@ -6,8 +6,6 @@ package pgsql import ( "fmt" - "os" - "path/filepath" "github.com/rs/zerolog/log" "github.com/uyuni-project/uyuni-tools/mgradm/shared/templates" @@ -50,25 +48,7 @@ func SetupPgsql( return err } - initdbDir, _, err := utils.TempDir() - if err != nil { - return err - } - - // fixme: for now, we need the script outside of this func, in EnableSSL - // defer cleaner() - - _ = os.Chmod(initdbDir, 0555) - - data := templates.PgsqlConfigTemplateData{} - - scriptName := "pgsqlConfig.sh" - scriptPath := filepath.Join(initdbDir, scriptName) - if err := utils.WriteTemplateToFile(data, scriptPath, 0555, true); err != nil { - return fmt.Errorf(L("failed to generate %s"), scriptName) - } - - if err := generatePgsqlSystemdService(systemd, preparedImage, initdbDir, admin, password); err != nil { + if err := generatePgsqlSystemdService(systemd, preparedImage, admin, password); err != nil { return utils.Errorf(err, L("cannot generate systemd service")) } @@ -82,18 +62,18 @@ func SetupPgsql( if err := cnx.WaitForHealthcheck(); err != nil { return err } - // Now the servisce is up and ready, the admin credentials are no longer needed - if err := generatePgsqlSystemdService(systemd, preparedImage, "", "", ""); err != nil { + if err := generatePgsqlSystemdService(systemd, preparedImage, "", ""); err != nil { return utils.Errorf(err, L("cannot generate systemd service")) } + return nil } // EnableSSL enables ssl in postgres container, as long as the certs are mounted. func EnableSSL(systemd podman.Systemd) error { cnx := shared.NewConnection("podman", podman.PgsqlContainerName, "") - if _, err := cnx.Exec("/docker-entrypoint-initdb.d/pgsqlConfig.sh"); err != nil { + if _, err := cnx.Exec("/docker-entrypoint-initdb.d/uyuni-postgres-config.sh"); err != nil { return err } @@ -126,25 +106,59 @@ func Upgrade( systemd podman.Systemd, authFile string, pgsqlFlags cmd_utils.PgsqlFlags, - admin string, - password string, ) error { - if err := SetupPgsql(systemd, authFile, pgsqlFlags, admin, password); err != nil { + image := pgsqlFlags.Image + currentReplicas := systemd.CurrentReplicaCount(podman.PgsqlService) + log.Debug().Msgf("Current HUB replicas running are %d.", currentReplicas) + + if pgsqlFlags.Replicas == 0 { + log.Debug().Msg("No pgsql requested.") + } + if !pgsqlFlags.IsChanged { + log.Info().Msgf(L("No changes requested for hub. Keep %d replicas."), currentReplicas) + } + + pullEnabled := (pgsqlFlags.Replicas > 0 && pgsqlFlags.IsChanged) || (currentReplicas > 0 && !pgsqlFlags.IsChanged) + + pgsqlImage, err := utils.ComputeImage(pgsqlFlags.Image.Registry, pgsqlFlags.Image.Tag, image) + + if err != nil { + return utils.Errorf(err, L("failed to compute image URL")) + } + + preparedImage, err := podman.PrepareImage(authFile, pgsqlImage, pgsqlFlags.Image.PullPolicy, pullEnabled) + if err != nil { + return err + } + err = podman.RunContainer("uyuni-db-migrate", pgsqlImage, utils.PgsqlRequiredVolumeMounts, []string{}, + []string{"chown", "postgres", "/etc/pki/tls/private/pg-spacewalk.key"}) + if err != nil { return err } + if err := generatePgsqlSystemdService(systemd, preparedImage, "", ""); err != nil { + return utils.Errorf(err, L("cannot generate systemd service")) + } + if err := systemd.ReloadDaemon(false); err != nil { return err } - return systemd.RestartInstantiated(podman.PgsqlService) + if err := EnablePgsql(systemd, 0); err != nil { + return err + } + if err := EnablePgsql(systemd, pgsqlFlags.Replicas); err != nil { + return err + } + + cnx := shared.NewConnection("podman", podman.PgsqlContainerName, "") + return cnx.WaitForHealthcheck() } // generatePgsqlSystemdService creates the Hub XMLRPC systemd files. func generatePgsqlSystemdService( systemd podman.Systemd, image string, - initdb string, admin string, password string, ) error { @@ -162,9 +176,6 @@ func generatePgsqlSystemdService( } environment := fmt.Sprintf("Environment=UYUNI_IMAGE=%s\n", image) - if initdb != "" { - environment += fmt.Sprintf("Environment=PODMAN_EXTRA_ARGS=\"-v %s:/docker-entrypoint-initdb.d:z\"\n", initdb) - } if admin != "" { environment += fmt.Sprintf("Environment=POSTGRES_USER=\"%s\"\n", admin) } diff --git a/mgradm/shared/podman/podman.go b/mgradm/shared/podman/podman.go index c8e75018d..f6ab945d0 100644 --- a/mgradm/shared/podman/podman.go +++ b/mgradm/shared/podman/podman.go @@ -18,6 +18,7 @@ import ( "github.com/spf13/viper" "github.com/uyuni-project/uyuni-tools/mgradm/shared/coco" "github.com/uyuni-project/uyuni-tools/mgradm/shared/hub" + "github.com/uyuni-project/uyuni-tools/mgradm/shared/pgsql" "github.com/uyuni-project/uyuni-tools/mgradm/shared/saline" "github.com/uyuni-project/uyuni-tools/mgradm/shared/templates" adm_utils "github.com/uyuni-project/uyuni-tools/mgradm/shared/utils" @@ -187,7 +188,14 @@ func RunMigration( user string, prepare bool, ) (*utils.InspectResult, error) { - scriptDir, cleaner, err := adm_utils.GenerateMigrationScript(sourceFqdn, user, false, prepare) + scriptDir, cleaner, err := adm_utils.GenerateMigrationScript( + sourceFqdn, + user, + false, + prepare, + "uyuni-pgsql-server.mgr.internal", + "uyuni-pgsql-server.mgr.internal", + ) if err != nil { return nil, utils.Errorf(err, L("cannot generate migration script")) } @@ -209,7 +217,7 @@ func RunMigration( } log.Info().Msg(L("Migrating server")) - if err := podman.RunContainer("uyuni-migration", preparedImage, utils.ServerVolumeMounts, extraArgs, + if err := podman.RunContainer("uyuni-migration", preparedImage, utils.ServerMigrationVolumeMounts, extraArgs, []string{"/var/lib/uyuni-tools/migrate.sh"}); err != nil { return nil, utils.Errorf(err, L("cannot run uyuni migration container")) } @@ -285,7 +293,7 @@ func RunPgsqlVersionUpgrade( return utils.Errorf(err, L("cannot generate PostgreSQL database version upgrade script")) } - err = podman.RunContainer(pgsqlVersionUpgradeContainer, preparedImage, utils.ServerVolumeMounts, extraArgs, + err = podman.RunContainer(pgsqlVersionUpgradeContainer, preparedImage, utils.PgsqlRequiredVolumeMounts, extraArgs, []string{"/var/lib/uyuni-tools/" + pgsqlVersionUpgradeScriptName}) if err != nil { return err @@ -305,10 +313,11 @@ func RunPgsqlFinalizeScript(serverImage string, schemaUpdateRequired bool, migra extraArgs := []string{ "-v", scriptDir + ":/var/lib/uyuni-tools/", "--security-opt", "label=disable", + "--network", podman.UyuniNetwork, } pgsqlFinalizeContainer := "uyuni-finalize-pgsql" pgsqlFinalizeScriptName, err := adm_utils.GenerateFinalizePostgresScript( - scriptDir, true, schemaUpdateRequired, true, migration, false, + scriptDir, true, schemaUpdateRequired, migration, false, ) if err != nil { return utils.Errorf(err, L("cannot generate PostgreSQL finalization script")) @@ -355,6 +364,7 @@ func Upgrade( cocoFlags adm_utils.CocoFlags, hubXmlrpcFlags adm_utils.HubXmlrpcFlags, salineFlags adm_utils.SalineFlags, + pgsqlFlags adm_utils.PgsqlFlags, ) error { if err := CallCloudGuestRegistryAuth(); err != nil { return err @@ -395,6 +405,22 @@ func Upgrade( defer func() { err = systemd.StartService(podman.ServerService) }() + + if inspectedValues.CurrentPgVersionNotMigrated != "" || + inspectedValues.DBHost == "localhost" || + inspectedValues.ReportDBHost == "localhost" { + log.Info().Msgf(L("Configuring external postgresql %s %s"), + inspectedValues.CurrentPgVersion, inspectedValues.CurrentPgVersionNotMigrated) + + if err := RunPgsqlContainerMigration( + preparedImage, "uyuni-pgsql-server.mgr.internal", "uyuni-pgsql-server.mgr.internal", + ); err != nil { + return utils.Errorf(err, L("cannot run PostgreSQL version upgrade script")) + } + inspectedValues.CurrentPgVersion = inspectedValues.CurrentPgVersionNotMigrated + pgsqlFlags.Replicas = 1 // migrating pgsql to separate container + } + if inspectedValues.ImagePgVersion > inspectedValues.CurrentPgVersion { log.Info().Msgf( L("Previous postgresql is %[1]s, instead new one is %[2]s. Performing a DB version upgradeā€¦"), @@ -414,6 +440,12 @@ func Upgrade( ) } + if err := pgsql.Upgrade( + systemd, authFile, pgsqlFlags, + ); err != nil { + return err + } + schemaUpdateRequired := inspectedValues.CurrentPgVersion != inspectedValues.ImagePgVersion if err := RunPgsqlFinalizeScript(preparedImage, schemaUpdateRequired, false); err != nil { return utils.Errorf(err, L("cannot run PostgreSQL finalize script")) @@ -506,7 +538,7 @@ func Inspect(preparedImage string) (*utils.ServerInspectData, error) { "--security-opt", "label=disable", } - err = podman.RunContainer("uyuni-inspect", preparedImage, utils.ServerVolumeMounts, podmanArgs, + err = podman.RunContainer("uyuni-inspect", preparedImage, utils.ServerMigrationVolumeMounts, podmanArgs, []string{utils.InspectContainerDirectory + "/" + utils.InspectScriptFilename}) if err != nil { return nil, err @@ -520,6 +552,34 @@ func Inspect(preparedImage string) (*utils.ServerInspectData, error) { return inspectResult, err } +// RunPgsqlContainerMigration migrate to separate postgres container. +func RunPgsqlContainerMigration(serverImage string, dbHost string, reportDBHost string) error { + scriptDir, cleaner, err := utils.TempDir() + if err != nil { + return err + } + defer cleaner() + + data := templates.PgsqlMigrateScriptTemplateData{ + DBHost: dbHost, + ReportDBHost: reportDBHost, + } + + scriptPath := filepath.Join(scriptDir, "pgmigrate.sh") + if err = utils.WriteTemplateToFile(data, scriptPath, 0555, true); err != nil { + return utils.Errorf(err, L("failed to generate postgresql migration script")) + } + + podmanArgs := []string{ + "-v", scriptDir + ":" + scriptDir, + "--security-opt", "label=disable", + } + err = podman.RunContainer("uyuni-db-migrate", serverImage, utils.ServerMigrationVolumeMounts, podmanArgs, + []string{scriptPath}) + + return err +} + // CallCloudGuestRegistryAuth calls cloudguestregistryauth if it is available. func CallCloudGuestRegistryAuth() error { cloudguestregistryauth := "cloudguestregistryauth" diff --git a/mgradm/shared/templates/migrateScriptTemplate.go b/mgradm/shared/templates/migrateScriptTemplate.go index fbdf3c86b..0fd5fb194 100644 --- a/mgradm/shared/templates/migrateScriptTemplate.go +++ b/mgradm/shared/templates/migrateScriptTemplate.go @@ -140,7 +140,8 @@ $SSH {{ .SourceFqdn }} sh -c "systemctl list-unit-files | grep hub-xmlrpc-api | (test $($SSH {{ .SourceFqdn }} grep jdwp -r /etc/tomcat/conf.d/ /etc/rhn/taskomatic.conf | wc -l) -gt 0 && echo debug=true || echo debug=false) >>/var/lib/uyuni-tools/data echo "Altering configuration for domain resolution..." -sed 's/report_db_host = {{ .SourceFqdn }}/report_db_host = localhost/' -i /etc/rhn/rhn.conf; +sed 's/^db_host = .*/db_host = {{ .DBHost }}/' -i /etc/rhn/rhn.conf; +sed 's/^report_db_host = .*/report_db_host = {{ .ReportDBHost }}/' -i /etc/rhn/rhn.conf; if ! grep -q '^java.hostname *=' /etc/rhn/rhn.conf; then sed 's/server\.jabber_server/java\.hostname/' -i /etc/rhn/rhn.conf; fi @@ -199,11 +200,13 @@ echo "DONE"` // MigrateScriptTemplateData represents migration information used to create migration script. type MigrateScriptTemplateData struct { - Volumes []types.VolumeMount - SourceFqdn string - User string - Kubernetes bool - Prepare bool + Volumes []types.VolumeMount + SourceFqdn string + User string + Kubernetes bool + Prepare bool + DBHost string + ReportDBHost string } // Render will create migration script. diff --git a/mgradm/shared/templates/pgsqlConfigTemplate.go b/mgradm/shared/templates/pgsqlConfigTemplate.go deleted file mode 100644 index e4855c76c..000000000 --- a/mgradm/shared/templates/pgsqlConfigTemplate.go +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-FileCopyrightText: 2024 SUSE LLC -// -// SPDX-License-Identifier: Apache-2.0 - -package templates - -import ( - "io" - "text/template" - // "github.com/uyuni-project/uyuni-tools/shared/types" -) - -const pgsqlConfigTemplate = `#!/bin/sh -x -POSTGRESQL=/var/lib/pgsql/data/postgresql.conf -SSL_CERT=/etc/pki/tls/certs/spacewalk.crt -SSL_KEY=/etc/pki/tls/private/pg-spacewalk.key - -postgres_reconfig() { - if grep -E "^$1[[:space:]]*=" $POSTGRESQL >/dev/null; then - sed -i "s|^$1[[:space:]]*=.*|$1 = $2|" $POSTGRESQL - else - echo "$1 = $2" >> $POSTGRESQL - fi -} - - -postgres_reconfig effective_cache_size 1152MB -postgres_reconfig maintenance_work_mem 96MB -postgres_reconfig max_connections 600 -postgres_reconfig shared_buffers 384MB -postgres_reconfig wal_buffers 4MB -postgres_reconfig work_mem 2560kB -postgres_reconfig jit off - -if [ -f $SSL_KEY ] ; then - chown postgres $SSL_KEY - chmod 400 $SSL_KEY - postgres_reconfig "ssl" "on" - postgres_reconfig "ssl_cert_file" "'$SSL_CERT'" - postgres_reconfig "ssl_key_file" "'$SSL_KEY'" -fi - -echo "postgresql.conf updated" -` - -// PgsqlConfigTemplateData POD information to create systemd file. -type PgsqlConfigTemplateData struct { -} - -// Render will create the systemd configuration file. -func (data PgsqlConfigTemplateData) Render(wr io.Writer) error { - t := template.Must(template.New("script").Parse(pgsqlConfigTemplate)) - return t.Execute(wr, data) -} diff --git a/mgradm/shared/templates/pgsqlFinalizeScriptTemplate.go b/mgradm/shared/templates/pgsqlFinalizeScriptTemplate.go index 723a6a5f8..cd6df01b3 100644 --- a/mgradm/shared/templates/pgsqlFinalizeScriptTemplate.go +++ b/mgradm/shared/templates/pgsqlFinalizeScriptTemplate.go @@ -13,24 +13,6 @@ import ( const postgresFinalizeScriptTemplate = `#!/bin/bash set -e -echo "Temporarily disable SSL in the posgresql configuration" -cp /var/lib/pgsql/data/postgresql.conf /var/lib/pgsql/data/postgresql.conf.bak -sed 's/^ssl/#ssl/' -i /var/lib/pgsql/data/postgresql.conf - -{{ if .Migration }} -echo "Adding database access for other containers..." -db_user=$(sed -n '/^db_user/{s/^.*=[ \t]\+\(.*\)$/\1/ ; p}' /etc/rhn/rhn.conf) -db_name=$(sed -n '/^db_name/{s/^.*=[ \t]\+\(.*\)$/\1/ ; p}' /etc/rhn/rhn.conf) -ip=$(ip -o -4 addr show up scope global | head -1 | awk '{print $4}' || true) -echo "host $db_name $db_user $ip scram-sha-256" >> /var/lib/pgsql/data/pg_hba.conf -{{ end }} - -{{ if .RunAutotune }} -echo "Running smdba system-check autotuning..." -smdba system-check autotuning -{{ end }} -echo "Starting Postgresql..." -HOME=/var/lib/pgsql PG_DATA=/var/lib/pgsql/data su -s /bin/bash -p postgres -c "/usr/share/postgresql/postgresql-script start" {{ if .RunReindex }} echo "Reindexing database. This may take a while, please do not cancel it!" database=$(sed -n "s/^\s*db_name\s*=\s*\([^ ]*\)\s*$/\1/p" /etc/rhn/rhn.conf) @@ -60,19 +42,10 @@ where not exists (select 1 from rhntaskorun r join rhntaskotemplate t on r.templ join rhntaskobunch b on t.bunch_id = b.id where b.name='update-system-overview-bunch' limit 1); EOT {{ end }} - -echo "Stopping Postgresql..." -HOME=/var/lib/pgsql PG_DATA=/var/lib/pgsql/data su -s /bin/bash -p postgres -c "/usr/share/postgresql/postgresql-script stop" - -echo "Enable SSL again" -cp /var/lib/pgsql/data/postgresql.conf.bak /var/lib/pgsql/data/postgresql.conf - -echo "DONE" ` // FinalizePostgresTemplateData represents information used to create PostgreSQL migration script. type FinalizePostgresTemplateData struct { - RunAutotune bool RunReindex bool RunSchemaUpdate bool Migration bool diff --git a/mgradm/shared/templates/pgsqlMigrateScriptTemplate.go b/mgradm/shared/templates/pgsqlMigrateScriptTemplate.go new file mode 100644 index 000000000..84cea9ef3 --- /dev/null +++ b/mgradm/shared/templates/pgsqlMigrateScriptTemplate.go @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2024 SUSE LLC +// +// SPDX-License-Identifier: Apache-2.0 + +package templates + +import ( + "io" + "text/template" +) + +//nolint:lll +const pgsqlMigrationScriptTemplate = `#!/bin/bash +set -e -x + +if [ -d /var/lib/pgsql/data/data ] ; then + shopt -s dotglob + mv /var/lib/pgsql/data/data/* /var/lib/pgsql/data + rmdir /var/lib/pgsql/data/data + + echo "Adding database access for other containers..." + db_user=$(sed -n '/^db_user/{s/^.*=[ \t]\+\(.*\)$/\1/ ; p}' /etc/rhn/rhn.conf) + db_name=$(sed -n '/^db_name/{s/^.*=[ \t]\+\(.*\)$/\1/ ; p}' /etc/rhn/rhn.conf) + ip=$(ip -o -4 addr show up scope global | head -1 | awk '{print $4}' || true) + echo "host $db_name $db_user all scram-sha-256" >> /var/lib/pgsql/data/pg_hba.conf + + ls -la /var/lib/pgsql/data + +fi + +{{ if .ReportDBHost }} +sed 's/^report_db_host = .*/report_db_host = {{ .ReportDBHost }}/' -i /etc/rhn/rhn.conf; +{{ end }} + +{{ if .DBHost }} +sed 's/^db_host = .*/db_host = {{ .DBHost }}/' -i /etc/rhn/rhn.conf; +{{ end }} + + +echo "DONE"` + +// MigrateScriptTemplateData represents migration information used to create migration script. +type PgsqlMigrateScriptTemplateData struct { + DBHost string + ReportDBHost string +} + +// Render will create migration script. +func (data PgsqlMigrateScriptTemplateData) Render(wr io.Writer) error { + t := template.Must(template.New("script").Parse(pgsqlMigrationScriptTemplate)) + return t.Execute(wr, data) +} diff --git a/mgradm/shared/templates/pgsqlVersionUpgradeScriptTemplate.go b/mgradm/shared/templates/pgsqlVersionUpgradeScriptTemplate.go index ed9d7a90f..277bcadc7 100644 --- a/mgradm/shared/templates/pgsqlVersionUpgradeScriptTemplate.go +++ b/mgradm/shared/templates/pgsqlVersionUpgradeScriptTemplate.go @@ -14,21 +14,24 @@ const postgreSQLVersionUpgradeScriptTemplate = `#!/bin/bash set -e echo "PostgreSQL version upgrade" +ls -la /var/lib/pgsql/data/ OLD_VERSION={{ .OldVersion }} NEW_VERSION={{ .NewVersion }} -FAST_UPGRADE=--link +FAST_UPGRADE= #--link echo "Testing presence of postgresql$NEW_VERSION..." test -d /usr/lib/postgresql$NEW_VERSION/bin echo "Testing presence of postgresql$OLD_VERSION..." test -d /usr/lib/postgresql$OLD_VERSION/bin -# Create a backup copy of the data to prepare DB upgrade. -echo "Backing up the database files ..." -mv /var/lib/pgsql/data /var/lib/pgsql/data-pg$OLD_VERSION +echo "Create a backup at /var/lib/pgsql/data-backup..." +mkdir -p /var/lib/pgsql/data-backup +chown postgres:postgres /var/lib/pgsql/data-backup +chmod 700 /var/lib/pgsql/data-backup +shopt -s dotglob +mv /var/lib/pgsql/data/* /var/lib/pgsql/data-backup echo "Create new database directory..." -mkdir -p /var/lib/pgsql/data chown -R postgres:postgres /var/lib/pgsql if [ -e /etc/pki/tls/private/pg-spacewalk.key ]; then @@ -51,18 +54,18 @@ su -s /bin/bash - postgres -c "initdb -D /var/lib/pgsql/data --locale=$POSTGRES_ echo "Successfully initialized new postgresql $NEW_VERSION database." echo "Temporarily disable SSL in the old posgresql configuration" -cp /var/lib/pgsql/data-pg$OLD_VERSION/postgresql.conf /var/lib/pgsql/data-pg$OLD_VERSION/postgresql.conf.bak -sed 's/^ssl/#ssl/' -i /var/lib/pgsql/data-pg$OLD_VERSION/postgresql.conf +cp /var/lib/pgsql/data-backup/postgresql.conf /var/lib/pgsql/data-backup/postgresql.conf.bak +sed 's/^ssl/#ssl/' -i /var/lib/pgsql/data-backup/postgresql.conf -su -s /bin/bash - postgres -c "pg_upgrade --old-bindir=/usr/lib/postgresql$OLD_VERSION/bin --new-bindir=/usr/lib/postgresql$NEW_VERSION/bin --old-datadir=/var/lib/pgsql/data-pg$OLD_VERSION --new-datadir=/var/lib/pgsql/data $FAST_UPGRADE" +su -s /bin/bash - postgres -c "pg_upgrade --old-bindir=/usr/lib/postgresql$OLD_VERSION/bin --new-bindir=/usr/lib/postgresql$NEW_VERSION/bin --old-datadir=/var/lib/pgsql/data-backup --new-datadir=/var/lib/pgsql/data $FAST_UPGRADE" echo "Enable SSL again" -cp /var/lib/pgsql/data-pg$OLD_VERSION/postgresql.conf.bak /var/lib/pgsql/data-pg$OLD_VERSION/postgresql.conf +cp /var/lib/pgsql/data-backup/postgresql.conf.bak /var/lib/pgsql/data-backup/postgresql.conf -cp /var/lib/pgsql/data-pg$OLD_VERSION/pg_hba.conf /var/lib/pgsql/data -mv /var/lib/pgsql/data-pg$OLD_VERSION/pg_hba.conf /var/lib/pgsql/data-pg$OLD_VERSION/pg_hba.conf.migrated -cp /var/lib/pgsql/data-pg$OLD_VERSION/postgresql.conf /var/lib/pgsql/data/ -mv /var/lib/pgsql/data-pg$OLD_VERSION/postgresql.conf /var/lib/pgsql/data-pg$OLD_VERSION/postgresql.conf.migrated +cp /var/lib/pgsql/data-backup/pg_hba.conf /var/lib/pgsql/data +mv /var/lib/pgsql/data-backup/pg_hba.conf /var/lib/pgsql/data-backup/pg_hba.conf.migrated +cp /var/lib/pgsql/data-backup/postgresql.conf /var/lib/pgsql/data/ +mv /var/lib/pgsql/data-backup/postgresql.conf /var/lib/pgsql/data-backup/postgresql.conf.migrated echo "DONE"` diff --git a/mgradm/shared/utils/cmd_utils.go b/mgradm/shared/utils/cmd_utils.go index 5c8290fe1..2cf9d7420 100644 --- a/mgradm/shared/utils/cmd_utils.go +++ b/mgradm/shared/utils/cmd_utils.go @@ -213,7 +213,7 @@ Leave it unset if you want to keep the previous number of replicas. // AddPgsqlFlags adds hub XML-RPC related parameters to cmd. func AddPgsqlFlags(cmd *cobra.Command) { _ = utils.AddFlagHelpGroup(cmd, &utils.Group{ID: "pgsql-container", Title: L("Postgresql Database Container Flags")}) - AddContainerImageFlags(cmd, "pgsql", L("Postgresql Database"), "pgsql-container", "suse/postgres") + AddContainerImageFlags(cmd, "pgsql", L("Postgresql Database"), "pgsql-container", "server-postgres") cmd.Flags().Int("pgsql-replicas", 1, L("How many replicas of the Postgresql service container should be started.")) _ = utils.AddFlagToHelpGroupID(cmd, "pgsql-replicas", "pgsql-container") } @@ -221,7 +221,7 @@ func AddPgsqlFlags(cmd *cobra.Command) { // AddUpgradePgsqlFlags adds hub XML-RPC related parameters to cmd upgrade. func AddUpgradePgsqlFlags(cmd *cobra.Command) { _ = utils.AddFlagHelpGroup(cmd, &utils.Group{ID: "pgsql-container", Title: L("Postgresql Database Container Flags")}) - AddContainerImageFlags(cmd, "pgsql", L("Postgresql Database"), "pgsql-container", "pgsql-container") + AddContainerImageFlags(cmd, "pgsql", L("Postgresql Database"), "pgsql-container", "server-postgres") cmd.Flags().Int("pgsql-replicas", 0, L(`How many replicas of the Postgresql service container should be started. Leave it unset if you want to keep the previous number of replicas.`)) diff --git a/mgradm/shared/utils/exec.go b/mgradm/shared/utils/exec.go index 8ea2130b5..6b9987121 100644 --- a/mgradm/shared/utils/exec.go +++ b/mgradm/shared/utils/exec.go @@ -5,7 +5,6 @@ package utils import ( - "errors" "fmt" "os/exec" "path/filepath" @@ -71,10 +70,9 @@ func GeneratePgsqlVersionUpgradeScript( // GenerateFinalizePostgresScript generates the script to finalize PostgreSQL upgrade. func GenerateFinalizePostgresScript( - scriptDir string, runAutotune bool, runReindex bool, runSchemaUpdate bool, migration bool, kubernetes bool, + scriptDir string, runReindex bool, runSchemaUpdate bool, migration bool, kubernetes bool, ) (string, error) { data := templates.FinalizePostgresTemplateData{ - RunAutotune: runAutotune, RunReindex: runReindex, RunSchemaUpdate: runSchemaUpdate, Migration: migration, @@ -112,18 +110,27 @@ func RunMigration(cnx *shared.Connection, scriptName string) error { } // GenerateMigrationScript generates the script that perform migration. -func GenerateMigrationScript(sourceFqdn string, user string, kubernetes bool, prepare bool) (string, func(), error) { +func GenerateMigrationScript( + sourceFqdn string, + user string, + kubernetes bool, + prepare bool, + dbHost string, + reportDBHost string, +) (string, func(), error) { scriptDir, cleaner, err := utils.TempDir() if err != nil { return "", nil, err } data := templates.MigrateScriptTemplateData{ - Volumes: utils.ServerVolumeMounts, - SourceFqdn: sourceFqdn, - User: user, - Kubernetes: kubernetes, - Prepare: prepare, + Volumes: append(utils.ServerVolumeMounts, utils.VarPgsqlDataVolumeMount), + SourceFqdn: sourceFqdn, + User: user, + Kubernetes: kubernetes, + Prepare: prepare, + DBHost: dbHost, + ReportDBHost: reportDBHost, } scriptPath := filepath.Join(scriptDir, "migrate.sh") @@ -188,16 +195,5 @@ func SanityCheck( } } } - - // Perform PostgreSQL version checks. - if inspectedValues.ImagePgVersion == "" { - return fmt.Errorf(L("cannot fetch PostgreSQL version from %s"), serverImage) - } - log.Debug().Msgf("Image %s has PostgreSQL %s", serverImage, inspectedValues.ImagePgVersion) - if inspectedValues.CurrentPgVersion == "" { - return errors.New(L("PostgreSQL is not installed in the current deployment")) - } - log.Debug().Msgf("Current deployment has PostgreSQL %s", inspectedValues.CurrentPgVersion) - return nil } diff --git a/mgradm/shared/utils/flags.go b/mgradm/shared/utils/flags.go index 9fc7da453..6c51e2512 100644 --- a/mgradm/shared/utils/flags.go +++ b/mgradm/shared/utils/flags.go @@ -65,6 +65,8 @@ func (flags *InstallationFlags) CheckParameters(cmd *cobra.Command, command stri flags.ReportDB.Password = utils.GetRandomBase64(30) } + utils.AskPasswordIfMissing(&flags.DB.Admin.Password, cmd.Flag("db-admin-password").Usage, 5, 48) + // Make sure we have all the required 3rd party flags or none flags.SSL.CheckParameters() diff --git a/shared/utils/ports.go b/shared/utils/ports.go index 01b2e16a5..60a4f7bf6 100644 --- a/shared/utils/ports.go +++ b/shared/utils/ports.go @@ -111,7 +111,6 @@ var TftpPorts = []types.PortMap{ func GetServerPorts(debug bool) []types.PortMap { ports := []types.PortMap{} ports = appendPorts(ports, debug, WebPorts...) - ports = appendPorts(ports, debug, ReportDBPorts...) ports = appendPorts(ports, debug, SaltPorts...) ports = appendPorts(ports, debug, CobblerPorts...) ports = appendPorts(ports, debug, TaskoPorts...) diff --git a/shared/utils/serverinspector.go b/shared/utils/serverinspector.go index a0bf2b01c..f5cfe10b3 100644 --- a/shared/utils/serverinspector.go +++ b/shared/utils/serverinspector.go @@ -33,6 +33,8 @@ func NewServerInspector(scriptDir string) ServerInspector { "rpm -qa --qf '%{VERSION}\\n' 'name=postgresql[0-8][0-9]-server' | cut -d. -f1 | sort -n | tail -1 || true"), types.NewInspectData("current_pg_version", "(test -e /var/lib/pgsql/data/PG_VERSION && cat /var/lib/pgsql/data/PG_VERSION) || true"), + types.NewInspectData("current_pg_version_not_migrated", + "(test -e /var/lib/pgsql/data/data/PG_VERSION && cat /var/lib/pgsql/data/data/PG_VERSION) || true"), types.NewInspectData("db_user", "cat /etc/rhn/rhn.conf 2>/dev/null | grep -m1 '^db_user' | cut -d' ' -f3 || true"), types.NewInspectData("db_password", @@ -41,6 +43,10 @@ func NewServerInspector(scriptDir string) ServerInspector { "cat /etc/rhn/rhn.conf 2>/dev/null | grep -m1 '^db_name' | cut -d' ' -f3 || true"), types.NewInspectData("db_port", "cat /etc/rhn/rhn.conf 2>/dev/null | grep -m1 '^db_port' | cut -d' ' -f3 || true"), + types.NewInspectData("db_host", + "cat /etc/rhn/rhn.conf 2>/dev/null | grep -m1 '^db_host' | cut -d' ' -f3 || true"), + types.NewInspectData("report_db_host", + "cat /etc/rhn/rhn.conf 2>/dev/null | grep -m1 '^report_db_host' | cut -d' ' -f3 || true"), }, ScriptDir: scriptDir, DataPath: path.Join(InspectContainerDirectory, inspectDataFile), @@ -52,12 +58,15 @@ func NewServerInspector(scriptDir string) ServerInspector { // CommonInspectData are data common between the migration source inspect and server inspector results. type CommonInspectData struct { - CurrentPgVersion string `mapstructure:"current_pg_version"` - ImagePgVersion string `mapstructure:"image_pg_version"` - DBUser string `mapstructure:"db_user"` - DBPassword string `mapstructure:"db_password"` - DBName string `mapstructure:"db_name"` - DBPort int `mapstructure:"db_port"` + CurrentPgVersion string `mapstructure:"current_pg_version"` + CurrentPgVersionNotMigrated string `mapstructure:"current_pg_version_not_migrated"` + ImagePgVersion string `mapstructure:"image_pg_version"` + DBUser string `mapstructure:"db_user"` + DBPassword string `mapstructure:"db_password"` + DBName string `mapstructure:"db_name"` + DBPort int `mapstructure:"db_port"` + DBHost string `mapstructure:"db_host"` + ReportDBHost string `mapstructure:"report_db_host"` } // ServerInspectData are the data extracted by a server inspector. diff --git a/shared/utils/volumes.go b/shared/utils/volumes.go index 3b8285d06..7e2b35c99 100644 --- a/shared/utils/volumes.go +++ b/shared/utils/volumes.go @@ -9,13 +9,13 @@ import "github.com/uyuni-project/uyuni-tools/shared/types" // EtcRhnVolumeMount defines the /etc/rhn volume mount. var EtcRhnVolumeMount = types.VolumeMount{MountPath: "/etc/rhn", Name: "etc-rhn", Size: "1Mi"} -// VarPgsqlDataVolumeMount defines the /var/lib/pgsql volume mount. +// VarPgsqlDataVolumeMount defines the /var/lib/pgsql/data volume mount. var VarPgsqlDataVolumeMount = types.VolumeMount{MountPath: "/var/lib/pgsql/data", Name: "var-pgsql", Size: "50Gi"} // RootVolumeMount defines the /root volume mount. var RootVolumeMount = types.VolumeMount{MountPath: "/root", Name: "root", Size: "1Mi"} -// PgsqlRequiredSharedVolumeMounts represents shared volumes mount used by PostgreSQL. +// PgsqlRequiredSharedVolumeMounts represents volumes shared between Server and PostgreSQL. var PgsqlRequiredSharedVolumeMounts = []types.VolumeMount{ {MountPath: "/etc/pki/tls", Name: "etc-tls", Size: "1Mi"}, {MountPath: "/etc/pki/spacewalk-tls", Name: "tls-key"}, @@ -37,7 +37,9 @@ var etcServerVolumeMounts = []types.VolumeMount{ {MountPath: "/etc/sssd", Name: "etc-sssd", Size: "1Mi"}, } -var etcAndPgsqlVolumeMounts = append(PgsqlRequiredSharedVolumeMounts, etcServerVolumeMounts[:]...) +var etcAndPgsqlVolumeMounts = append(append(PgsqlRequiredSharedVolumeMounts, + EtcRhnVolumeMount), + etcServerVolumeMounts[:]...) // ServerVolumeMounts should match the volumes mapping from the container definition in both // the helm chart and the systemctl services definitions. @@ -60,6 +62,9 @@ var ServerVolumeMounts = append([]types.VolumeMount{ {MountPath: "/run/salt/master", Name: "run-salt-master"}, }, etcAndPgsqlVolumeMounts[:]...) +// ServerMigrationVolumeMounts match server + postgres volume mounts, used for migration. +var ServerMigrationVolumeMounts = append(ServerVolumeMounts, VarPgsqlDataVolumeMount, EtcRhnVolumeMount) + // HubXmlrpcVolumeMounts represents volumes used by Hub Xmlrpc container. var HubXmlrpcVolumeMounts = []types.VolumeMount{ {MountPath: "/etc/pki/trust/anchors", Name: "ca-cert"},