Skip to content

Commit

Permalink
Split the inspection scripts based on their usage
Browse files Browse the repository at this point in the history
It doesn't make sense to try to extract all the values for both
containers and hosts. This commit introduces Inspector objects that are
responsible for generating the inspection script and parsing it into a
structure.

While at it, the extracted values that were not used have been removed.
This gains quite some time at each execution since extracting the
SCC registration status was quite long.

While doing this we could also drop the InspectData proxyHost flag as
SCC credentials are extracted for both server and proxy hosts.
  • Loading branch information
cbosdo committed Jul 16, 2024
1 parent 8d6aea5 commit 03a0910
Show file tree
Hide file tree
Showing 17 changed files with 499 additions and 235 deletions.
2 changes: 1 addition & 1 deletion mgradm/cmd/migrate/kubernetes/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func migrateToKubernetes(
return utils.Errorf(err, L("cannot run migration"))
}

extractedData, err := adm_utils.ReadContainerData(scriptDir)
extractedData, err := utils.ReadInspectData[utils.InspectResult](path.Join(scriptDir, "data"))
if err != nil {
return utils.Errorf(err, L("cannot read data from container"))
}
Expand Down
18 changes: 9 additions & 9 deletions mgradm/shared/kubernetes/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,8 @@ func Upgrade(
return err
}

fqdn, exist := inspectedValues["fqdn"]
if !exist {
fqdn := inspectedValues.Fqdn
if fqdn == "" {
return fmt.Errorf(L("inspect function did non return fqdn value"))
}

Expand Down Expand Up @@ -182,23 +182,23 @@ func Upgrade(
err = kubernetes.ReplicasTo(kubernetes.ServerApp, 1)
}
}()
if inspectedValues["image_pg_version"] > inspectedValues["current_pg_version"] {
if inspectedValues.ImagePgVersion > inspectedValues.CurrentPgVersion {
log.Info().Msgf(L("Previous PostgreSQL is %[1]s, new one is %[2]s. Performing a DB version upgrade…"),
inspectedValues["current_pg_version"], inspectedValues["image_pg_version"])
inspectedValues.CurrentPgVersion, inspectedValues.ImagePgVersion)

if err := RunPgsqlVersionUpgrade(*image, *upgradeImage, nodeName,
inspectedValues["current_pg_version"], inspectedValues["image_pg_version"],
inspectedValues.CurrentPgVersion, inspectedValues.ImagePgVersion,
); err != nil {
return utils.Errorf(err, L("cannot run PostgreSQL version upgrade script"))
}
} else if inspectedValues["image_pg_version"] == inspectedValues["current_pg_version"] {
log.Info().Msgf(L("Upgrading to %s without changing PostgreSQL version"), inspectedValues["uyuni_release"])
} else if inspectedValues.ImagePgVersion == inspectedValues.CurrentPgVersion {
log.Info().Msgf(L("Upgrading to %s without changing PostgreSQL version"), inspectedValues.UyuniRelease)
} else {
return fmt.Errorf(L("trying to downgrade PostgreSQL from %[1]s to %[2]s"),
inspectedValues["current_pg_version"], inspectedValues["image_pg_version"])
inspectedValues.CurrentPgVersion, inspectedValues.ImagePgVersion)
}

schemaUpdateRequired := inspectedValues["current_pg_version"] != inspectedValues["image_pg_version"]
schemaUpdateRequired := inspectedValues.CurrentPgVersion != inspectedValues.ImagePgVersion
if err := RunPgsqlFinalizeScript(serverImage, image.PullPolicy, nodeName, schemaUpdateRequired, false); err != nil {
return utils.Errorf(err, L("cannot run PostgreSQL finalize script"))
}
Expand Down
43 changes: 19 additions & 24 deletions mgradm/shared/podman/podman.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"os/exec"
"path"
"path/filepath"
"strconv"
"strings"

"github.com/rs/zerolog"
Expand Down Expand Up @@ -204,7 +203,7 @@ func RunMigration(preparedImage string, sshAuthSocket string, sshConfigPath stri
[]string{"/var/lib/uyuni-tools/migrate.sh"}); err != nil {
return nil, utils.Errorf(err, L("cannot run uyuni migration container"))
}
extractedData, err := adm_utils.ReadContainerData(scriptDir)
extractedData, err := utils.ReadInspectData[utils.InspectResult](path.Join(scriptDir, "data"))

if err != nil {
return nil, utils.Errorf(err, L("cannot read extracted data"))
Expand Down Expand Up @@ -361,20 +360,20 @@ func Upgrade(
defer func() {
err = podman.StartService(podman.ServerService)
}()
if inspectedValues["image_pg_version"] > inspectedValues["current_pg_version"] {
log.Info().Msgf(L("Previous postgresql is %[1]s, instead new one is %[2]s. Performing a DB version upgrade…"), inspectedValues["current_pg_version"], inspectedValues["image_pg_version"])
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…"), inspectedValues.CurrentPgVersion, inspectedValues.ImagePgVersion)
if err := RunPgsqlVersionUpgrade(
authFile, image, upgradeImage, inspectedValues["current_pg_version"], inspectedValues["image_pg_version"],
authFile, image, upgradeImage, inspectedValues.CurrentPgVersion, inspectedValues.ImagePgVersion,
); err != nil {
return utils.Errorf(err, L("cannot run PostgreSQL version upgrade script"))
}
} else if inspectedValues["image_pg_version"] == inspectedValues["current_pg_version"] {
log.Info().Msgf(L("Upgrading to %s without changing PostgreSQL version"), inspectedValues["uyuni_release"])
} else if inspectedValues.ImagePgVersion == inspectedValues.CurrentPgVersion {
log.Info().Msgf(L("Upgrading to %s without changing PostgreSQL version"), inspectedValues.UyuniRelease)
} else {
return fmt.Errorf(L("trying to downgrade PostgreSQL from %[1]s to %[2]s"), inspectedValues["current_pg_version"], inspectedValues["image_pg_version"])
return fmt.Errorf(L("trying to downgrade PostgreSQL from %[1]s to %[2]s"), inspectedValues.CurrentPgVersion, inspectedValues.ImagePgVersion)
}

schemaUpdateRequired := inspectedValues["current_pg_version"] != inspectedValues["image_pg_version"]
schemaUpdateRequired := inspectedValues.CurrentPgVersion != inspectedValues.ImagePgVersion
if err := RunPgsqlFinalizeScript(preparedImage, schemaUpdateRequired, false); err != nil {
return utils.Errorf(err, L("cannot run PostgreSQL finalize script"))
}
Expand All @@ -388,13 +387,8 @@ func Upgrade(
}
log.Info().Msg(L("Waiting for the server to start…"))

dbPort, err := strconv.Atoi(inspectedValues["db_port"])
if err != nil {
return utils.Errorf(err, L("error %s is not a valid port number."), inspectedValues["db_port"])
}

err = coco.Upgrade(cocoImage, image,
dbPort, inspectedValues["db_name"], inspectedValues["db_user"], inspectedValues["db_password"])
inspectedValues.DbPort, inspectedValues.DbName, inspectedValues.DbUser, inspectedValues.DbPassword)
if err != nil {
return utils.Errorf(err, L("error upgrading confidential computing service."))
}
Expand All @@ -403,31 +397,32 @@ func Upgrade(
}

// Inspect check values on a given image and deploy.
func Inspect(preparedImage string) (map[string]string, error) {
func Inspect(preparedImage string) (*utils.ServerInspectData, error) {
scriptDir, err := os.MkdirTemp("", "mgradm-*")
defer os.RemoveAll(scriptDir)
if err != nil {
return map[string]string{}, utils.Errorf(err, L("failed to create temporary directory"))
return nil, utils.Errorf(err, L("failed to create temporary directory"))
}

if err := utils.GenerateInspectContainerScript(scriptDir); err != nil {
return map[string]string{}, err
inspector := utils.NewServerInspector(scriptDir)
if err := inspector.GenerateScript(); err != nil {
return nil, err
}

podmanArgs := []string{
"-v", scriptDir + ":" + utils.InspectOutputFile.Directory,
"-v", scriptDir + ":" + utils.InspectContainerDirectory,
"--security-opt", "label=disable",
}

err = podman.RunContainer("uyuni-inspect", preparedImage, utils.ServerVolumeMounts, podmanArgs,
[]string{utils.InspectOutputFile.Directory + "/" + utils.InspectScriptFilename})
[]string{utils.InspectContainerDirectory + "/" + utils.InspectScriptFilename})
if err != nil {
return map[string]string{}, err
return nil, err
}

inspectResult, err := utils.ReadInspectData(scriptDir)
inspectResult, err := inspector.ReadInspectData()
if err != nil {
return map[string]string{}, utils.Errorf(err, L("cannot inspect data"))
return nil, utils.Errorf(err, L("cannot inspect data"))
}

return inspectResult, err
Expand Down
67 changes: 29 additions & 38 deletions mgradm/shared/utils/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
package utils

import (
"bytes"
"errors"
"fmt"
"os"
Expand All @@ -15,7 +14,6 @@ import (

"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"github.com/spf13/viper"
"github.com/uyuni-project/uyuni-tools/mgradm/shared/templates"
"github.com/uyuni-project/uyuni-tools/shared"
"github.com/uyuni-project/uyuni-tools/shared/kubernetes"
Expand Down Expand Up @@ -100,25 +98,6 @@ func GeneratePostUpgradeScript(scriptDir string, cobblerHost string) (string, er
return scriptName, nil
}

// ReadContainerData returns values used to perform migration.
func ReadContainerData(scriptDir string) (*utils.InspectResult, error) {
data, err := os.ReadFile(filepath.Join(scriptDir, "data"))
if err != nil {
return nil, errors.New(L("failed to read data extracted from source host"))
}

viper.SetConfigType("env")
if err := viper.MergeConfig(bytes.NewBuffer(data)); err != nil {
return nil, utils.Errorf(err, L("cannot read config"))
}

var results utils.InspectResult
if err := viper.Unmarshal(&results); err != nil {
return nil, utils.Errorf(err, L("failed to unmarshall data extracted from source host"))
}
return &results, nil
}

// RunMigration execute the migration script.
func RunMigration(cnx *shared.Connection, tmpPath string, scriptName string) error {
log.Info().Msg(L("Migrating server"))
Expand Down Expand Up @@ -183,20 +162,26 @@ func RunningImage(cnx *shared.Connection, containerName string) (string, error)
}

// SanityCheck verifies if an upgrade can be run.
func SanityCheck(cnx *shared.Connection, inspectedValues map[string]string, serverImage string) error {
func SanityCheck(cnx *shared.Connection, inspectedValues *utils.ServerInspectData, serverImage string) error {
isUyuni, err := isUyuni(cnx)
if err != nil {
return utils.Errorf(err, L("cannot check server release"))
}
_, isCurrentUyuni := inspectedValues["uyuni_release"]
_, isCurrentSuma := inspectedValues["suse_manager_release"]
isCurrentUyuni := inspectedValues.UyuniRelease != ""
isCurrentSuma := inspectedValues.SuseManagerRelease != ""

if isUyuni && isCurrentSuma {
return fmt.Errorf(L("currently SUSE Manager %s is installed, instead the image is Uyuni. Upgrade is not supported"), inspectedValues["suse_manager_release"])
return fmt.Errorf(
L("currently SUSE Manager %s is installed, instead the image is Uyuni. Upgrade is not supported"),
inspectedValues.SuseManagerRelease,
)
}

if !isUyuni && isCurrentUyuni {
return fmt.Errorf(L("currently Uyuni %s is installed, instead the image is SUSE Manager. Upgrade is not supported"), inspectedValues["uyuni_release"])
return fmt.Errorf(
L("currently Uyuni %s is installed, instead the image is SUSE Manager. Upgrade is not supported"),
inspectedValues.UyuniRelease,
)
}

if isUyuni {
Expand All @@ -206,12 +191,15 @@ func SanityCheck(cnx *shared.Connection, inspectedValues map[string]string, serv
return utils.Errorf(err, L("failed to read current uyuni release"))
}
log.Debug().Msgf("Current release is %s", string(current_uyuni_release))
if (len(inspectedValues["uyuni_release"])) <= 0 {
if inspectedValues.UyuniRelease != "" {
return fmt.Errorf(L("cannot fetch release from image %s"), serverImage)
}
log.Debug().Msgf("Image %s is %s", serverImage, inspectedValues["uyuni_release"])
if utils.CompareVersion(inspectedValues["uyuni_release"], string(current_uyuni_release)) < 0 {
return fmt.Errorf(L("cannot downgrade from version %[1]s to %[2]s"), string(current_uyuni_release), inspectedValues["uyuni_release"])
log.Debug().Msgf("Image %s is %s", serverImage, inspectedValues.UyuniRelease)
if utils.CompareVersion(inspectedValues.UyuniRelease, string(current_uyuni_release)) < 0 {
return fmt.Errorf(
L("cannot downgrade from version %[1]s to %[2]s"),
string(current_uyuni_release), inspectedValues.UyuniRelease,
)
}
} else {
cnx_args := []string{"s/SUSE Manager release //g", "/etc/susemanager-release"}
Expand All @@ -220,23 +208,26 @@ func SanityCheck(cnx *shared.Connection, inspectedValues map[string]string, serv
return utils.Errorf(err, L("failed to read current susemanager release"))
}
log.Debug().Msgf("Current release is %s", string(current_suse_manager_release))
if (len(inspectedValues["suse_manager_release"])) <= 0 {
if inspectedValues.SuseManagerRelease != "" {
return fmt.Errorf(L("cannot fetch release from image %s"), serverImage)
}
log.Debug().Msgf("Image %s is %s", serverImage, inspectedValues["suse_manager_release"])
if utils.CompareVersion(inspectedValues["suse_manager_release"], string(current_suse_manager_release)) < 0 {
return fmt.Errorf(L("cannot downgrade from version %[1]s to %[2]s"), string(current_suse_manager_release), inspectedValues["suse_manager_release"])
log.Debug().Msgf("Image %s is %s", serverImage, inspectedValues.SuseManagerRelease)
if utils.CompareVersion(inspectedValues.SuseManagerRelease, string(current_suse_manager_release)) < 0 {
return fmt.Errorf(
L("cannot downgrade from version %[1]s to %[2]s"),
string(current_suse_manager_release), inspectedValues.SuseManagerRelease,
)
}
}

if (len(inspectedValues["image_pg_version"])) <= 0 {
if inspectedValues.ImagePgVersion != "" {
return fmt.Errorf(L("cannot fetch postgresql version from %s"), serverImage)
}
log.Debug().Msgf("Image %s has PostgreSQL %s", serverImage, inspectedValues["image_pg_version"])
if (len(inspectedValues["current_pg_version"])) <= 0 {
log.Debug().Msgf("Image %s has PostgreSQL %s", serverImage, inspectedValues.ImagePgVersion)
if inspectedValues.CurrentPgVersion != "" {
return fmt.Errorf(L("posgresql is not installed in the current deployment"))
}
log.Debug().Msgf("Current deployment has PostgreSQL %s", inspectedValues["current_pg_version"])
log.Debug().Msgf("Current deployment has PostgreSQL %s", inspectedValues.CurrentPgVersion)

return nil
}
Expand Down
25 changes: 13 additions & 12 deletions shared/kubernetes/k3s.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,36 +52,37 @@ func UninstallK3sTraefikConfig(dryRun bool) {
}

// InspectKubernetes check values on a given image and deploy.
func InspectKubernetes(serverImage string, pullPolicy string) (map[string]string, error) {
func InspectKubernetes(serverImage string, pullPolicy string) (*utils.ServerInspectData, error) {
for _, binary := range []string{"kubectl", "helm"} {
if _, err := exec.LookPath(binary); err != nil {
return map[string]string{}, fmt.Errorf(L("install %s before running this command"), binary)
return nil, fmt.Errorf(L("install %s before running this command"), binary)
}
}

scriptDir, err := os.MkdirTemp("", "mgradm-*")
defer os.RemoveAll(scriptDir)
if err != nil {
return map[string]string{}, utils.Errorf(err, L("failed to create temporary directory"))
return nil, utils.Errorf(err, L("failed to create temporary directory"))
}

if err := utils.GenerateInspectContainerScript(scriptDir); err != nil {
return map[string]string{}, err
inspector := utils.NewServerInspector(scriptDir)
if err := inspector.GenerateScript(); err != nil {
return nil, err
}

command := path.Join(utils.InspectOutputFile.Directory, utils.InspectScriptFilename)
command := path.Join(utils.InspectContainerDirectory, utils.InspectScriptFilename)

const podName = "inspector"

//delete pending pod and then check the node, because in presence of more than a pod GetNode return is wrong
if err := DeletePod(podName, ServerFilter); err != nil {
return map[string]string{}, utils.Errorf(err, L("cannot delete %s"), podName)
return nil, utils.Errorf(err, L("cannot delete %s"), podName)
}

//this is needed because folder with script needs to be mounted
nodeName, err := GetNode("uyuni")
if err != nil {
return map[string]string{}, utils.Errorf(err, L("cannot find node running uyuni"))
return nil, utils.Errorf(err, L("cannot find node running uyuni"))
}

//generate deploy data
Expand All @@ -105,16 +106,16 @@ func InspectKubernetes(serverImage string, pullPolicy string) (map[string]string
//transform deploy data in JSON
override, err := GenerateOverrideDeployment(deployData)
if err != nil {
return map[string]string{}, err
return nil, err
}
err = RunPod(podName, ServerFilter, serverImage, pullPolicy, command, override)
if err != nil {
return map[string]string{}, utils.Errorf(err, L("cannot run inspect pod"))
return nil, utils.Errorf(err, L("cannot run inspect pod"))
}

inspectResult, err := utils.ReadInspectData(scriptDir)
inspectResult, err := inspector.ReadInspectData()
if err != nil {
return map[string]string{}, utils.Errorf(err, L("cannot inspect data"))
return nil, utils.Errorf(err, L("cannot inspect data"))
}

return inspectResult, err
Expand Down
7 changes: 1 addition & 6 deletions shared/kubernetes/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,24 +230,19 @@ func waitForReplica(podname string, replica uint) error {
}
cmdArgs := []string{"get", "pod", podname, "--output=custom-columns=STATUS:.status.phase", "--no-headers"}

var err error

for i := 0; i < waitSeconds; i++ {
out, err := utils.RunCmdOutput(zerolog.DebugLevel, "kubectl", cmdArgs...)
outStr := strings.TrimSuffix(string(out), "\n")
if err != nil {
return utils.Errorf(err, L("cannot execute %s"), strings.Join(cmdArgs, string(" ")))
}
outStr := strings.TrimSuffix(string(out), "\n")
if string(outStr) == "Running" {
log.Debug().Msgf("%s pod replica is now %d", podname, replica)
break
}
log.Debug().Msgf("Pod %s replica is %s in %d seconds.", podname, string(out), i)
time.Sleep(1 * time.Second)
}
if err != nil {
return utils.Errorf(err, L("pod %[1]s replicas have not reached %[2]d in %[3]s seconds"), podname, replica, strconv.Itoa(waitSeconds))
}
return nil
}

Expand Down
Loading

0 comments on commit 03a0910

Please sign in to comment.