Skip to content

Commit

Permalink
Allow mgrpxy install to use stored configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
rjpmestre committed Feb 17, 2025
1 parent 6ea5f93 commit 5b57bf8
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 27 deletions.
4 changes: 2 additions & 2 deletions mgrpxy/cmd/install/podman/podman.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2024 SUSE LLC
// SPDX-FileCopyrightText: 2025 SUSE LLC
//
// SPDX-License-Identifier: Apache-2.0

Expand Down Expand Up @@ -27,7 +27,7 @@ The install podman command assumes podman is installed locally.
NOTE: for now installing on a remote podman is not supported!
`),
Args: cobra.ExactArgs(1),
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
var flags podman.PodmanProxyFlags
return shared_utils.CommandHelper(globalFlags, cmd, args, &flags, nil, run)
Expand Down
4 changes: 2 additions & 2 deletions mgrpxy/cmd/install/podman/utils.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2024 SUSE LLC
// SPDX-FileCopyrightText: 2025 SUSE LLC
//
// SPDX-License-Identifier: Apache-2.0

Expand Down Expand Up @@ -40,7 +40,7 @@ func installForPodman(

configPath := utils.GetConfigPath(args)
if err := podman.UnpackConfig(configPath); err != nil {
return shared_utils.Errorf(err, L("failed to extract proxy config from %s file"), configPath)
return shared_utils.Errorf(err, L("failed to retrieve proxy config files"))
}

hostData, err := shared_podman.InspectHost()
Expand Down
61 changes: 39 additions & 22 deletions mgrpxy/shared/podman/podman.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2024 SUSE LLC
// SPDX-FileCopyrightText: 2025 SUSE LLC
//
// SPDX-License-Identifier: Apache-2.0

Expand Down Expand Up @@ -193,44 +193,61 @@ func GetContainerImage(authFile string, flags *utils.ProxyImageFlags, name strin

// UnpackConfig uncompress the config.tar.gz containing proxy configuration.
func UnpackConfig(configPath string) error {
log.Info().Msgf(L("Setting up proxy with configuration %s"), configPath)
const proxyConfigDir = "/etc/uyuni/proxy"
if err := os.MkdirAll(proxyConfigDir, 0755); err != nil {
return err
}

if err := shared_utils.ExtractTarGz(configPath, proxyConfigDir); err != nil {
// Create dir if it doesn't exist & check perms
if err := os.MkdirAll(proxyConfigDir, 0755); err != nil {
return err
}

proxyConfigDirInfo, err := os.Stat(proxyConfigDir)
if err != nil {
if err := checkPermissions(proxyConfigDir, 0005|0050|0500); err != nil {
return err
}

dirMode := proxyConfigDirInfo.Mode()

if !(dirMode&0005 != 0 && dirMode&0050 != 0 && dirMode&0500 != 0) {
return errors.New(
L("/etc/uyuni/proxy directory has no read and write permissions for all users. Check your umask settings."),
)
// Extract the tarball, if provided
if configPath != "" {
log.Info().Msgf(L("Setting up proxy with configuration %s"), configPath)
if err := shared_utils.ExtractTarGz(configPath, proxyConfigDir); err != nil {
return shared_utils.Errorf(err, L("failed to extract proxy config from %s file"), configPath)
}
} else {
log.Info().Msg(L("No tarball provided. Will check existing configuration files."))
}

if err := shared_utils.ExtractTarGz(configPath, proxyConfigDir); err != nil {
return err
}
return validateInstallYamlFiles(proxyConfigDir)
}

proxyConfigInfo, err := os.Stat(path.Join(proxyConfigDir, "config.yaml"))
// checkPermissions checks if a directory or file has a required permissions.
func checkPermissions(path string, requiredMode os.FileMode) error {
info, err := os.Stat(path)
if err != nil {
return err
}
if info.Mode()&requiredMode != requiredMode {
if info.IsDir() {
return fmt.Errorf(L("%s directory has no required permissions. Check your umask settings"), path)
}
return fmt.Errorf(L("%s file has no required permissions. Check your umask settings"), path)
}
return nil
}

mode := proxyConfigInfo.Mode()
// validateYamlFiles validates if the required configuration files.
func validateInstallYamlFiles(dir string) error {
yamlFiles := []string{"httpd.yaml", "ssh.yaml", "config.yaml"}

if !(mode&0004 != 0 && mode&0040 != 0 && mode&0400 != 0) {
return errors.New(L("/etc/uyuni/proxy/config.yaml has no read permissions for all users. Check your umask settings."))
for _, file := range yamlFiles {
filePath := path.Join(dir, file)
_, err := os.Stat(filePath)
if err != nil {
return fmt.Errorf(L("missing required configuration file: %s"), filePath)
}
if file == "config.yaml" {
if err := checkPermissions(filePath, 0004|0040|0400); err != nil {
return err
}
}
}

return nil
}

Expand Down
57 changes: 57 additions & 0 deletions mgrpxy/shared/podman/podman_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// SPDX-FileCopyrightText: 2025 SUSE LLC
//
// SPDX-License-Identifier: Apache-2.0

package podman

import (
"os"
"path"
"testing"
)

func TestCheckDirPermissions(t *testing.T) {
tempDir := t.TempDir()
if err := os.MkdirAll(tempDir, 0755); err != nil {
t.Fatal(err)
}
if err := checkPermissions(tempDir, 0005|0050|0500); err != nil {
t.Errorf("Expected no error, got %v", err)
}
}

func TestValidateYamlFiles(t *testing.T) {
tempDir := t.TempDir()
testFiles := []string{"httpd.yaml", "ssh.yaml", "config.yaml"}
for _, file := range testFiles {
filePath := path.Join(tempDir, file)
if _, err := os.Create(filePath); err != nil {
t.Fatalf("Failed to create test file %s: %v", filePath, err)
}
}

// Test: when all files are present and have correct permissions
if err := validateInstallYamlFiles(tempDir); err != nil {
t.Errorf("Expected no error, got %v", err)
}

// Change the permission of config.yaml to 0600 to simulate a permission error
configFilePath := path.Join(tempDir, "config.yaml")
if err := os.Chmod(configFilePath, 0600); err != nil {
t.Fatalf("Failed to change permissions for %s: %v", configFilePath, err)
}
if err := validateInstallYamlFiles(tempDir); err == nil {
t.Errorf("Expected an error due to incorrect permissions on config.yaml, but got none")
}

// Restore the correct permissions for the next test run
if err := os.Chmod(configFilePath, 0644); err != nil {
t.Fatalf("Failed to restore permissions for %s: %v", configFilePath, err)
}

// Test: Missing file scenario, remove one file and expect an error
os.Remove(path.Join(tempDir, "httpd.yaml"))
if err := validateInstallYamlFiles(tempDir); err == nil {
t.Errorf("Expected an error due to missing httpd.yaml, but got none")
}
}
5 changes: 4 additions & 1 deletion mgrpxy/shared/utils/cmd.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2024 SUSE LLC
// SPDX-FileCopyrightText: 2025 SUSE LLC
//
// SPDX-License-Identifier: Apache-2.0

Expand All @@ -12,6 +12,9 @@ import (

// GetConfigPath returns the configuration path if exists.
func GetConfigPath(args []string) string {
if len(args) == 0 {
return ""
}
configPath := args[0]
if !utils.FileExists(configPath) {
log.Fatal().Msgf(L("argument is not an existing file: %s"), configPath)
Expand Down
1 change: 1 addition & 0 deletions uyuni-tools.changes.rjpmestre.mgrpxy-install-stored-conf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Allow mgrpxy install to use stored configuration

0 comments on commit 5b57bf8

Please sign in to comment.