Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dedicated container for database #482

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions mgradm/cmd/install/podman/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
install_shared "github.com/uyuni-project/uyuni-tools/mgradm/cmd/install/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/shared"
. "github.com/uyuni-project/uyuni-tools/shared/l10n"
Expand Down Expand Up @@ -110,6 +111,18 @@ func installForPodman(
"CERT_PASS": caPassword,
}

if flags.ReportDB.Host == "" {
flags.ReportDB.Host = "uyuni-pgsql-server.mgr.internal"
}

if flags.DB.Host == "" {
flags.DB.Host = "uyuni-pgsql-server.mgr.internal"

if err := pgsql.SetupPgsql(systemd, authFile, flags.Pgsql, flags.DB.Admin.User, flags.DB.Admin.Password); err != nil {
return err
}
}

log.Info().Msg(L("Run setup command in the container"))

if err := install_shared.RunSetup(cnx, &flags.InstallFlags, fqdn, env); err != nil {
Expand All @@ -119,6 +132,11 @@ func installForPodman(
return err
}

log.Info().Msg(L("Enabling SSL in the postgres container"))
if err := pgsql.EnableSSL(systemd); err != nil {
return err
}

if path, err := exec.LookPath("uyuni-payg-extract-data"); err == nil {
// the binary is installed
err = utils.RunCmdStdMapping(zerolog.DebugLevel, path)
Expand Down
12 changes: 8 additions & 4 deletions mgradm/cmd/install/shared/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ type InstallFlags struct {
Scc types.SCCCredentials
Debug DebugFlags
Image types.ImageFlags `mapstructure:",squash"`
Pgsql cmd_utils.PgsqlFlags
Coco cmd_utils.CocoFlags
HubXmlrpc cmd_utils.HubXmlrpcFlags
Admin apiTypes.User
Expand Down Expand Up @@ -100,6 +101,7 @@ func (flags *InstallFlags) CheckParameters(cmd *cobra.Command, command string) {
if flags.TZ == "" {
flags.TZ = utils.GetLocalTimezone()
}
utils.AskPasswordIfMissing(&flags.DB.Admin.Password, cmd.Flag("db-admin-password").Usage, 5, 48)

utils.AskIfMissing(&flags.Email, cmd.Flag("email").Usage, 1, 128, emailChecker)
utils.AskIfMissing(&flags.EmailFrom, cmd.Flag("emailfrom").Usage, 0, 0, emailChecker)
Expand Down Expand Up @@ -129,11 +131,11 @@ func AddInstallFlags(cmd *cobra.Command) {
cmd.Flags().String("db-user", "spacewalk", L("Database user"))
cmd.Flags().String("db-password", "", L("Database password. Randomly generated by default"))
cmd.Flags().String("db-name", "susemanager", L("Database name"))
cmd.Flags().String("db-host", "localhost", L("Database host"))
cmd.Flags().String("db-host", "", L("Database host"))
cmd.Flags().Int("db-port", 5432, L("Database port"))
cmd.Flags().String("db-protocol", "tcp", L("Database protocol"))
cmd.Flags().String("db-admin-user", "", L("External database admin user name"))
cmd.Flags().String("db-admin-password", "", L("External database admin password"))
cmd.Flags().String("db-admin-user", "postgres", L("Database admin user name"))
cmd.Flags().String("db-admin-password", "", L("Database admin password"))
cmd.Flags().String("db-provider", "", L("External database provider. Possible values 'aws'"))

_ = utils.AddFlagHelpGroup(cmd, &utils.Group{ID: "db", Title: L("Database Flags")})
Expand All @@ -149,7 +151,7 @@ func AddInstallFlags(cmd *cobra.Command) {

cmd.Flags().Bool("tftp", true, L("Enable TFTP"))
cmd.Flags().String("reportdb-name", "reportdb", L("Report database name"))
cmd.Flags().String("reportdb-host", "localhost", L("Report database host"))
cmd.Flags().String("reportdb-host", "", L("Report database host"))
cmd.Flags().Int("reportdb-port", 5432, L("Report database port"))
cmd.Flags().String("reportdb-user", "pythia_susemanager", L("Report Database username"))
cmd.Flags().String("reportdb-password", "", L("Report database password. Randomly generated by default"))
Expand Down Expand Up @@ -200,6 +202,8 @@ func AddInstallFlags(cmd *cobra.Command) {

cmd_utils.AddHubXmlrpcFlags(cmd)

cmd_utils.AddPgsqlFlags(cmd)

cmd.Flags().String("admin-login", "admin", L("Administrator user name"))
cmd.Flags().String("admin-password", "", L("Administrator password"))
cmd.Flags().String("admin-firstName", "Administrator", L("First name of the administrator"))
Expand Down
5 changes: 5 additions & 0 deletions mgradm/cmd/uninstall/podman.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ func uninstallForPodman(
podman.GetServiceImage(podman.ServerService),
podman.GetServiceImage(podman.ServerAttestationService + "@"),
podman.GetServiceImage(podman.HubXmlrpcService),
podman.GetServiceImage(podman.PgsqlService),
}

// Uninstall the service
Expand All @@ -35,6 +36,7 @@ func uninstallForPodman(

systemd.UninstallInstantiatedService(podman.ServerAttestationService, !flags.Force)
systemd.UninstallInstantiatedService(podman.HubXmlrpcService, !flags.Force)
systemd.UninstallInstantiatedService(podman.PgsqlService, !flags.Force)

// Remove the volumes
if flags.Purge.Volumes {
Expand All @@ -43,6 +45,9 @@ func uninstallForPodman(
for _, volume := range utils.ServerVolumeMounts {
volumes = append(volumes, volume.Name)
}
for _, volume := range utils.PgsqlRequiredVolumeMounts {
volumes = append(volumes, volume.Name)
}
for _, volume := range volumes {
if err := podman.DeleteVolume(volume, !flags.Force); err != nil {
log.Warn().Err(err).Msgf(L("Failed to remove volume %s"), volume)
Expand Down
180 changes: 180 additions & 0 deletions mgradm/shared/pgsql/pgsql.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
// SPDX-FileCopyrightText: 2024 SUSE LLC
//
// SPDX-License-Identifier: Apache-2.0

package pgsql

import (
"fmt"
"os"
"path/filepath"

"github.com/rs/zerolog/log"
"github.com/uyuni-project/uyuni-tools/mgradm/shared/templates"
cmd_utils "github.com/uyuni-project/uyuni-tools/mgradm/shared/utils"
"github.com/uyuni-project/uyuni-tools/shared"
. "github.com/uyuni-project/uyuni-tools/shared/l10n"
"github.com/uyuni-project/uyuni-tools/shared/podman"
"github.com/uyuni-project/uyuni-tools/shared/utils"
)

// SetupPgsql prepares the systemd service and starts it if needed.
func SetupPgsql(
systemd podman.Systemd,
authFile string,
pgsqlFlags cmd_utils.PgsqlFlags,
admin string,
password string,
) error {
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
}

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 {
return utils.Errorf(err, L("cannot generate systemd service"))
}

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, "")
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 {
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 {
return err
}

if err := systemd.RestartInstantiated(podman.PgsqlService); err != nil {
return utils.Errorf(err, L("cannot restart service"))
}

if err := cnx.WaitForHealthcheck(); err != nil {
return err
}
return nil
}

// EnablePgsql enables the hub xmlrpc service if the number of replicas is 1.
// This function is meant for installation or migration, to enable or disable the service after, use ScaleService.
func EnablePgsql(systemd podman.Systemd, replicas int) error {
if replicas > 1 {
log.Warn().Msg(L("Multiple Hub XML-RPC container replicas are not currently supported, setting up only one."))
replicas = 1
}

if err := systemd.ScaleService(replicas, podman.PgsqlService); err != nil {
return utils.Errorf(err, L("cannot enable service"))
}
return nil
}

// Upgrade updates the systemd service files and restarts the containers if needed.
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 {
return err
}

if err := systemd.ReloadDaemon(false); err != nil {
return err
}

return systemd.RestartInstantiated(podman.PgsqlService)
}

// generatePgsqlSystemdService creates the Hub XMLRPC systemd files.
func generatePgsqlSystemdService(
systemd podman.Systemd,
image string,
initdb string,
admin string,
password string,
) error {
pgsqlData := templates.PgsqlServiceTemplateData{
Volumes: utils.PgsqlRequiredVolumeMounts,
Ports: utils.PgsqlPorts,
NamePrefix: "uyuni",
Network: podman.UyuniNetwork,
Image: image,
}
if err := utils.WriteTemplateToFile(
pgsqlData, podman.GetServicePath(podman.PgsqlService+"@"), 0555, true,
); err != nil {
return utils.Errorf(err, L("failed to generate systemd service unit file"))
}

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)
}
if password != "" {
environment += fmt.Sprintf("Environment=POSTGRES_PASSWORD=\"%s\"\n", password)
}

if err := podman.GenerateSystemdConfFile(podman.PgsqlService+"@", "generated.conf", environment, true); err != nil {
return utils.Errorf(err, L("cannot generate systemd conf file"))
}

return systemd.ReloadDaemon(false)
}
10 changes: 8 additions & 2 deletions mgradm/shared/templates/mgrSetupScriptTemplate.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,24 @@ import (
)

//nolint:lll
const mgrSetupScriptTemplate = `#!/bin/sh
const mgrSetupScriptTemplate = `#!/bin/sh -x
{{- range $name, $value := .Env }}
export {{ $name }}='{{ $value }}'
{{- end }}
sed -i -e "s|/bin/bash|/bin/bash -x|" /usr/bin/uyuni-setup-reportdb
sed -i -e "s|verify-full|disable|" /usr/lib/perl5/vendor_perl/5.26.1/Spacewalk/Setup.pm
sed -i -e "s|CREATE EXTENSION pgcrypto;||" /usr/share/susemanager/db/postgres/main.sql
sed -i -e "s|create extension dblink;||" /usr/share/susemanager/db/postgres/main.sql
sed -i -e "s|create extension dblink;||" /usr/share/susemanager/db/reportdb/main.sql

{{- if .DebugJava }}
echo 'JAVA_OPTS=" $JAVA_OPTS -Xdebug -Xrunjdwp:transport=dt_socket,address=*:8003,server=y,suspend=n" ' >> /etc/tomcat/conf.d/remote_debug.conf
echo 'JAVA_OPTS=" $JAVA_OPTS -Xdebug -Xrunjdwp:transport=dt_socket,address=*:8001,server=y,suspend=n" ' >> /etc/rhn/taskomatic.conf
echo 'JAVA_OPTS=" $JAVA_OPTS -Xdebug -Xrunjdwp:transport=dt_socket,address=*:8002,server=y,suspend=n" ' >> /usr/share/rhn/config-defaults/rhn_search_daemon.conf
{{- end }}

/usr/lib/susemanager/bin/mgr-setup -s -n
#sed -i -e "s|EXTERNALDB=0|EXTERNALDB=1|" /usr/lib/susemanager/bin/mgr-setup
/bin/bash -x /usr/lib/susemanager/bin/mgr-setup -s -n
RESULT=$?

# clean before leaving
Expand Down
54 changes: 54 additions & 0 deletions mgradm/shared/templates/pgsqlConfigTemplate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// 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)
}
Loading
Loading