├── .tito ├── packages │ └── uyuni-tools └── tito.props ├── uyuni-tools.changes.cbosdo.pxy-ptf ├── pre-commit-build.sh ├── .vscode └── settings.json ├── .gitignore ├── install-hooks.sh ├── shared ├── utils │ ├── conf_test │ │ ├── firstConfFile.yaml │ │ └── secondConfFile.yaml │ ├── nokubernetes.go │ ├── kubernetes.go │ ├── slices.go │ ├── validationUtils.go │ ├── ports_test.go │ ├── inspector.go │ ├── dbinspector.go │ ├── template.go │ ├── inspector_test.go │ └── support_test.go ├── types │ ├── global.go │ ├── networks.go │ ├── chart.go │ ├── inspect.go │ ├── uyuniservice.go │ ├── ssl.go │ ├── distro.go │ ├── images.go │ └── runner.go ├── api │ ├── types │ │ ├── user.go │ │ └── organization.go │ ├── mocks │ │ └── mocks.go │ ├── api_test.go │ ├── org │ │ ├── getDetails.go │ │ └── createFirst.go │ ├── proxy │ │ ├── model.go │ │ ├── containerConfig.go │ │ └── mapping.go │ └── types.go ├── podman │ ├── selinux.go │ ├── selinux_test.go │ ├── utils_test.go │ └── hostinspector_test.go ├── kubernetes │ ├── uninstall.go │ ├── deploy.go │ ├── converters.go │ ├── k3s_test.go │ ├── inspect.go │ ├── rke2NginxTemplate.go │ ├── k3sTraefikTemplate.go │ ├── pvc_test.go │ └── deploy_test.go ├── testutils │ ├── flagstests │ │ ├── podman.go │ │ ├── scc.go │ │ ├── api.go │ │ └── ssl.go │ └── files.go ├── l10n │ ├── gettext.go │ └── utils │ │ └── defaultfs.go ├── templates │ └── inspectTemplate.go ├── completion │ └── completion.go └── ssl │ └── testdata │ └── chain2 │ └── RHN-ORG-TRUSTED-SSL-CERT ├── setup.sh ├── mgradm ├── cmd │ ├── install │ │ ├── kubernetes │ │ │ ├── nobuild.go │ │ │ └── kubernetes_test.go │ │ └── install.go │ ├── migrate │ │ ├── kubernetes │ │ │ └── nobuild.go │ │ ├── shared │ │ │ └── flags.go │ │ ├── migrate.go │ │ └── podman │ │ │ ├── utils.go │ │ │ └── podman_test.go │ ├── upgrade │ │ ├── kubernetes │ │ │ ├── nobuild.go │ │ │ └── utils.go │ │ ├── shared │ │ │ └── flags.go │ │ ├── upgrade.go │ │ └── podman │ │ │ └── utils.go │ ├── support │ │ ├── ptf │ │ │ ├── noptf.go │ │ │ └── ptf.go │ │ ├── support.go │ │ ├── config │ │ │ ├── config_test.go │ │ │ └── config.go │ │ └── sql │ │ │ └── sql_cmd_test.go │ ├── server │ │ ├── rename │ │ │ ├── nobuild.go │ │ │ └── kubernetes.go │ │ └── server.go │ ├── inspect │ │ ├── nobuild.go │ │ └── inspect_test.go │ ├── stop │ │ ├── podman.go │ │ ├── nokubernetes.go │ │ ├── kubernetes.go │ │ ├── stop_test.go │ │ └── stop.go │ ├── start │ │ ├── podman.go │ │ ├── nokubernetes.go │ │ ├── kubernetes.go │ │ ├── start_test.go │ │ └── start.go │ ├── uninstall │ │ ├── nokubernetes.go │ │ ├── uninstall_test.go │ │ └── uninstall.go │ ├── scale │ │ ├── kubernetes.go │ │ ├── nokubernetes.go │ │ ├── podman.go │ │ └── scale_test.go │ ├── status │ │ ├── nokubernetes.go │ │ ├── status.go │ │ └── kubernetes.go │ ├── restart │ │ ├── nokubernetes.go │ │ ├── podman.go │ │ ├── kubernetes.go │ │ ├── restart_test.go │ │ └── restart.go │ ├── hub │ │ ├── hub.go │ │ └── register │ │ │ └── register_test.go │ ├── gpg │ │ ├── gpg.go │ │ ├── list │ │ │ └── gpg_test.go │ │ └── add │ │ │ └── gpg_test.go │ └── distro │ │ └── distro_test.go ├── shared │ ├── cmd_test.go │ ├── kubernetes │ │ ├── ports.go │ │ ├── flags.go │ │ ├── namespace.go │ │ ├── node.go │ │ ├── deployment_test.go │ │ ├── certificates_test.go │ │ └── postUpgradeJob.go │ ├── templates │ │ ├── tlsSecret.go │ │ ├── pgsqlMigrateScriptTemplate.go │ │ └── postUpgradeScriptTemplate.go │ ├── utils │ │ └── flags_test.go │ └── podman │ │ └── startstop.go └── main.go ├── .github ├── workflows │ ├── git-checks.yml │ ├── reuse.yml │ ├── check_l10n.yml │ ├── vulncheck.yml │ ├── prebuilt_devcontainer.yml │ └── mingo_build.yml └── dependabot.yml ├── mgrpxy ├── cmd │ ├── support │ │ ├── ptf │ │ │ ├── noptf.go │ │ │ ├── kubernetes │ │ │ │ ├── utils.go │ │ │ │ └── kubernetes_test.go │ │ │ ├── ptf.go │ │ │ └── podman │ │ │ │ └── podman_test.go │ │ ├── support.go │ │ └── config │ │ │ ├── config_test.go │ │ │ ├── config.go │ │ │ └── extractor.go │ ├── upgrade │ │ ├── kubernetes │ │ │ ├── utils.go │ │ │ ├── kubernetes_test.go │ │ │ └── kubernetes.go │ │ ├── podman │ │ │ ├── utils.go │ │ │ ├── podman_test.go │ │ │ └── podman.go │ │ └── upgrade.go │ ├── stop │ │ ├── podman.go │ │ ├── kubernetes.go │ │ ├── stop_test.go │ │ └── stop.go │ ├── start │ │ ├── podman.go │ │ ├── kubernetes.go │ │ ├── start_test.go │ │ └── start.go │ ├── restart │ │ ├── podman.go │ │ ├── kubernetes.go │ │ ├── restart_test.go │ │ └── restart.go │ ├── cache │ │ ├── squid.go │ │ ├── podman.go │ │ ├── kubernetes.go │ │ └── clear.go │ ├── install │ │ ├── install.go │ │ ├── kubernetes │ │ │ └── kubernetes_test.go │ │ └── podman │ │ │ └── podman_test.go │ ├── status │ │ ├── podman.go │ │ ├── kubernetes.go │ │ └── status.go │ ├── logs │ │ ├── podman.go │ │ └── logs_test.go │ └── uninstall │ │ ├── uninstall_test.go │ │ └── uninstall.go ├── shared │ ├── utils │ │ └── cmd.go │ └── kubernetes │ │ └── cmd.go └── main.go ├── mgrctl ├── cmd │ ├── api │ │ ├── api_test.go │ │ ├── get.go │ │ └── login.go │ ├── proxy │ │ ├── utils.go │ │ ├── proxy.go │ │ └── utils_test.go │ └── term │ │ ├── term.go │ │ └── term_test.go └── main.go ├── .vimrc ├── update-copyright-year.sh ├── REUSE.toml ├── .devcontainer ├── devcontainer.json └── Dockerfile ├── locale └── build.sh ├── LICENSES └── MIT.txt ├── extract_strings ├── push.sh ├── .golangci.yml └── .pre-commit-config.yaml /.tito/packages/uyuni-tools: -------------------------------------------------------------------------------- 1 | 5.2.3-0 ./ 2 | -------------------------------------------------------------------------------- /uyuni-tools.changes.cbosdo.pxy-ptf: -------------------------------------------------------------------------------- 1 | - Fix images handling in mgrpxy support ptf (bsc#1250940) 2 | -------------------------------------------------------------------------------- /pre-commit-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # SPDX-FileCopyrightText: 2024 SUSE LLC 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | go build $* ./... 6 | go test $* ./... 7 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | { 5 | "gopls": { "ui.semanticTokens": true } 6 | } 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 SUSE LLC 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | bin 6 | vendor.tar.gz 7 | *.pyc 8 | __pycache__ 9 | **/tags 10 | *.mo 11 | -------------------------------------------------------------------------------- /install-hooks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # SPDX-FileCopyrightText: 2024 SUSE LLC 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | pre-commit install --hook-type pre-commit --hook-type pre-push 6 | -------------------------------------------------------------------------------- /shared/utils/conf_test/firstConfFile.yaml: -------------------------------------------------------------------------------- 1 | #SPDX-FileCopyrightText: 2024 SUSE LLC 2 | 3 | #SPDX-License-Identifier: Apache-2.0 4 | secondConf: firstConfFile 5 | thirdConf: firstConfFile 6 | -------------------------------------------------------------------------------- /shared/utils/conf_test/secondConfFile.yaml: -------------------------------------------------------------------------------- 1 | #SPDX-FileCopyrightText: 2024 SUSE LLC 2 | 3 | #SPDX-License-Identifier: Apache-2.0 4 | thirdConf: SecondConfFile 5 | fourthConf: SecondConfFile 6 | -------------------------------------------------------------------------------- /shared/utils/nokubernetes.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | //go:build nok8s 6 | 7 | package utils 8 | 9 | const KubernetesBuilt = false 10 | -------------------------------------------------------------------------------- /.tito/tito.props: -------------------------------------------------------------------------------- 1 | [buildconfig] 2 | builder = custom.SuseGitExtraGenerationBuilder 3 | tagger = tito.tagger.SUSETagger 4 | changelog_with_email = 0 5 | changelog_do_not_remove_cherrypick = 0 6 | no_default_changelog = 1 7 | lib_dir=.tito/custom 8 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 SUSE LLC 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | set -euxo pipefail 6 | 7 | go mod vendor && tar czvf vendor.tar.gz vendor >/dev/null && rm -rf vendor 8 | 9 | echo "vendor.tar.gz" 10 | -------------------------------------------------------------------------------- /shared/types/global.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package types 6 | 7 | // GlobalFlags represents the flags used by all commands. 8 | type GlobalFlags struct { 9 | ConfigPath string 10 | LogLevel string 11 | } 12 | -------------------------------------------------------------------------------- /shared/types/networks.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package types 6 | 7 | // PortMap describes a port. 8 | type PortMap struct { 9 | Service string 10 | Name string 11 | Exposed int 12 | Port int 13 | Protocol string 14 | } 15 | -------------------------------------------------------------------------------- /shared/utils/kubernetes.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | //go:build !nok8s 6 | 7 | package utils 8 | 9 | // KubernetesBuilt is a flag for compiling kubernetes code. True when go:build !nok8s, False when go:build nok8s. 10 | const KubernetesBuilt = true 11 | -------------------------------------------------------------------------------- /shared/types/chart.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package types 6 | 7 | // ChartFlags represents the flags required by charts. 8 | type ChartFlags struct { 9 | Namespace string 10 | Chart string 11 | Version string 12 | Values string 13 | } 14 | -------------------------------------------------------------------------------- /shared/api/types/user.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package types 6 | 7 | // User describes an Uyuni user in the API. 8 | type User struct { 9 | Login string 10 | Password string 11 | FirstName string 12 | LastName string 13 | Email string 14 | } 15 | -------------------------------------------------------------------------------- /mgradm/cmd/install/kubernetes/nobuild.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | //go:build nok8s 6 | 7 | package kubernetes 8 | 9 | import ( 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/shared/types" 12 | ) 13 | 14 | func NewCommand(_ *types.GlobalFlags) *cobra.Command { 15 | return nil 16 | } 17 | -------------------------------------------------------------------------------- /mgradm/cmd/migrate/kubernetes/nobuild.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | //go:build nok8s 6 | 7 | package kubernetes 8 | 9 | import ( 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/shared/types" 12 | ) 13 | 14 | func NewCommand(_ *types.GlobalFlags) *cobra.Command { 15 | return nil 16 | } 17 | -------------------------------------------------------------------------------- /mgradm/cmd/upgrade/kubernetes/nobuild.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | //go:build nok8s 6 | 7 | package kubernetes 8 | 9 | import ( 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/shared/types" 12 | ) 13 | 14 | func NewCommand(_ *types.GlobalFlags) *cobra.Command { 15 | return nil 16 | } 17 | -------------------------------------------------------------------------------- /shared/utils/slices.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package utils 6 | 7 | // Contains returns true if a string is contained in a string slice. 8 | func Contains(slice []string, needle string) bool { 9 | for _, item := range slice { 10 | if item == needle { 11 | return true 12 | } 13 | } 14 | return false 15 | } 16 | -------------------------------------------------------------------------------- /.github/workflows/git-checks.yml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2019 Brad Erickson 2 | # 3 | # SPDX-License-Identifier: MIT 4 | 5 | name: Git Checks 6 | 7 | on: [pull_request] 8 | 9 | jobs: 10 | block-fixup: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v2.0.0 15 | - name: Block Fixup Commit Merge 16 | uses: 13rac1/block-fixup-merge-action@v2.0.0 17 | -------------------------------------------------------------------------------- /mgradm/cmd/support/ptf/noptf.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | //go:build !ptf 5 | 6 | package ptf 7 | 8 | import ( 9 | "github.com/spf13/cobra" 10 | "github.com/uyuni-project/uyuni-tools/shared/types" 11 | ) 12 | 13 | // NewCommand is the command for creates supportptf. 14 | func NewCommand(_ *types.GlobalFlags) *cobra.Command { 15 | return nil 16 | } 17 | -------------------------------------------------------------------------------- /mgrpxy/cmd/support/ptf/noptf.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | //go:build !ptf 5 | 6 | package ptf 7 | 8 | import ( 9 | "github.com/spf13/cobra" 10 | "github.com/uyuni-project/uyuni-tools/shared/types" 11 | ) 12 | 13 | // NewCommand is the command for creates supportptf. 14 | func NewCommand(_ *types.GlobalFlags) *cobra.Command { 15 | return nil 16 | } 17 | -------------------------------------------------------------------------------- /mgradm/cmd/server/rename/nobuild.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | //go:build nok8s 6 | 7 | package rename 8 | 9 | import ( 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/shared/types" 12 | ) 13 | 14 | func renameForKubernetes(_ *types.GlobalFlags, _ *renameFlags, _ *cobra.Command, _ []string) error { 15 | return nil 16 | } 17 | -------------------------------------------------------------------------------- /shared/podman/selinux.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package podman 6 | 7 | import "github.com/rs/zerolog" 8 | 9 | // IsSELinuxEnabled reports whether SELinux is enabled or not. 10 | // It relies on selinuxenabled tool. 11 | func IsSELinuxEnabled() bool { 12 | _, err := runCmdOutput(zerolog.DebugLevel, "selinuxenabled") 13 | return err == nil 14 | } 15 | -------------------------------------------------------------------------------- /mgrctl/cmd/api/api_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package api 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/uyuni-project/uyuni-tools/shared/types" 11 | ) 12 | 13 | func TestNewCommand(t *testing.T) { 14 | var globalflags types.GlobalFlags 15 | cmd := NewCommand(&globalflags) 16 | if cmd == nil { 17 | t.Error("Unexpected nil command") 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.vimrc: -------------------------------------------------------------------------------- 1 | " SPDX-FileCopyrightText: 2023 SUSE LLC 2 | " 3 | " SPDX-License-Identifier: Apache-2.0 4 | 5 | " Local vim configuration loaded by https://github.com/LucHermitte/local_vimrc 6 | " For local_vimrc to use this file, ensure .vimrc is in the g:local_vimrc 7 | " list. You can set it like the following in the vim or neovim config: 8 | " 9 | " let g:local_vimrc = ['.vimrc'] 10 | 11 | " Set make command 12 | set makeprg=go\ build\ ./... 13 | -------------------------------------------------------------------------------- /mgradm/cmd/inspect/nobuild.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | //go:build nok8s 6 | 7 | package inspect 8 | 9 | import ( 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/shared/types" 12 | ) 13 | 14 | func kuberneteInspect( 15 | _ *types.GlobalFlags, 16 | _ *inspectFlags, 17 | _ *cobra.Command, 18 | _ []string, 19 | ) error { 20 | return nil 21 | } 22 | -------------------------------------------------------------------------------- /update-copyright-year.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # SPDX-FileCopyrightText: 2025 SUSE LLC 4 | # 5 | # SPDX-License-Identifier: Apache-2.0 6 | 7 | current_year=$(date +%Y) 8 | for changed_file in $@; do 9 | sed -i -E "s/\/\/ SPDX-FileCopyrightText: [0-9]{4}/\/\/ SPDX-FileCopyrightText: $current_year/" $changed_file 10 | done 11 | 12 | if test $(git status --porcelain | wc -l) -ne 0 ; then 13 | echo "✨ Copyright year adjusted, please commit" 14 | fi 15 | -------------------------------------------------------------------------------- /shared/api/mocks/mocks.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package mocks 6 | 7 | import "net/http" 8 | 9 | // MockClient is a mocked api.HTTPClient. 10 | type MockClient struct { 11 | DoFunc func(req *http.Request) (*http.Response, error) 12 | } 13 | 14 | // Do fulfills the api.HTTPClient interface. 15 | func (m *MockClient) Do(req *http.Request) (*http.Response, error) { 16 | return m.DoFunc(req) 17 | } 18 | -------------------------------------------------------------------------------- /mgradm/shared/cmd_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package shared 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/uyuni-project/uyuni-tools/mgradm/cmd" 11 | ) 12 | 13 | func TestSubCommandsHaveGroup(t *testing.T) { 14 | mgradmCmd, _ := cmd.NewUyuniadmCommand() 15 | if !mgradmCmd.AllChildCommandsHaveGroup() { 16 | t.Errorf("There's at least one mgradm subcommand without group") 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /mgradm/cmd/stop/podman.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package stop 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/mgradm/shared/podman" 10 | "github.com/uyuni-project/uyuni-tools/shared/types" 11 | ) 12 | 13 | func podmanStop( 14 | _ *types.GlobalFlags, 15 | _ *stopFlags, 16 | _ *cobra.Command, 17 | _ []string, 18 | ) error { 19 | return podman.StopServices() 20 | } 21 | -------------------------------------------------------------------------------- /mgradm/cmd/start/podman.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package start 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/mgradm/shared/podman" 10 | "github.com/uyuni-project/uyuni-tools/shared/types" 11 | ) 12 | 13 | func podmanStart( 14 | _ *types.GlobalFlags, 15 | _ *startFlags, 16 | _ *cobra.Command, 17 | _ []string, 18 | ) error { 19 | return podman.StartServices() 20 | } 21 | -------------------------------------------------------------------------------- /shared/utils/validationUtils.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package utils 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | ) 10 | 11 | // MarkMandatoryFlags ensures that the specified flags are marked as required for the given command. 12 | func MarkMandatoryFlags(cmd *cobra.Command, fields []string) { 13 | for _, field := range fields { 14 | if err := cmd.MarkFlagRequired(field); err != nil { 15 | return 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /mgradm/cmd/uninstall/nokubernetes.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | //go:build nok8s 6 | 7 | package uninstall 8 | 9 | import ( 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/shared/types" 12 | "github.com/uyuni-project/uyuni-tools/shared/utils" 13 | ) 14 | 15 | func uninstallForKubernetes( 16 | _ *types.GlobalFlags, 17 | _ *utils.UninstallFlags, 18 | _ *cobra.Command, 19 | _ []string, 20 | ) error { 21 | return nil 22 | } 23 | -------------------------------------------------------------------------------- /mgradm/cmd/server/rename/kubernetes.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | //go:build !nok8s 5 | 6 | package rename 7 | 8 | import ( 9 | "errors" 10 | 11 | "github.com/spf13/cobra" 12 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 13 | "github.com/uyuni-project/uyuni-tools/shared/types" 14 | ) 15 | 16 | func renameForKubernetes(_ *types.GlobalFlags, _ *renameFlags, _ *cobra.Command, _ []string) error { 17 | return errors.New(L("not implemented yet")) 18 | } 19 | -------------------------------------------------------------------------------- /mgrpxy/cmd/upgrade/kubernetes/utils.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package kubernetes 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/mgrpxy/shared/kubernetes" 10 | "github.com/uyuni-project/uyuni-tools/shared/types" 11 | ) 12 | 13 | func upgradeKubernetes(_ *types.GlobalFlags, 14 | flags *kubernetes.KubernetesProxyUpgradeFlags, cmd *cobra.Command, args []string, 15 | ) error { 16 | return kubernetes.Upgrade(flags, cmd, args) 17 | } 18 | -------------------------------------------------------------------------------- /mgrpxy/cmd/stop/podman.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package stop 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/shared/podman" 10 | "github.com/uyuni-project/uyuni-tools/shared/types" 11 | ) 12 | 13 | var systemd podman.Systemd = podman.NewSystemd() 14 | 15 | func podmanStop( 16 | _ *types.GlobalFlags, 17 | _ *stopFlags, 18 | _ *cobra.Command, 19 | _ []string, 20 | ) error { 21 | return systemd.StopService(podman.ProxyService) 22 | } 23 | -------------------------------------------------------------------------------- /mgrpxy/cmd/start/podman.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package start 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/shared/podman" 10 | "github.com/uyuni-project/uyuni-tools/shared/types" 11 | ) 12 | 13 | var systemd podman.Systemd = podman.NewSystemd() 14 | 15 | func podmanStart( 16 | _ *types.GlobalFlags, 17 | _ *startFlags, 18 | _ *cobra.Command, 19 | _ []string, 20 | ) error { 21 | return systemd.StartService(podman.ProxyService) 22 | } 23 | -------------------------------------------------------------------------------- /shared/types/inspect.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package types 6 | 7 | /* InspectData represents CLI command to run in the container 8 | * and the variable where the output is stored. 9 | */ 10 | type InspectData struct { 11 | Variable string 12 | CLI string 13 | } 14 | 15 | // NewInspectData creates an InspectData instance. 16 | func NewInspectData(variable string, cli string) InspectData { 17 | return InspectData{ 18 | Variable: variable, 19 | CLI: cli, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /mgradm/cmd/scale/kubernetes.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | //go:build !nok8s 6 | 7 | package scale 8 | 9 | import ( 10 | "errors" 11 | 12 | "github.com/spf13/cobra" 13 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 14 | "github.com/uyuni-project/uyuni-tools/shared/types" 15 | ) 16 | 17 | func kubernetesScale( 18 | _ *types.GlobalFlags, 19 | _ *scaleFlags, 20 | _ *cobra.Command, 21 | _ []string, 22 | ) error { 23 | return errors.New(L("kubernetes not supported yet")) 24 | } 25 | -------------------------------------------------------------------------------- /mgradm/cmd/stop/nokubernetes.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | //go:build nok8s 6 | 7 | package stop 8 | 9 | import ( 10 | "errors" 11 | 12 | "github.com/spf13/cobra" 13 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 14 | "github.com/uyuni-project/uyuni-tools/shared/types" 15 | ) 16 | 17 | func kubernetesStop( 18 | _ *types.GlobalFlags, 19 | _ *stopFlags, 20 | _ *cobra.Command, 21 | _ []string, 22 | ) error { 23 | return errors.New(L("built without kubernetes support")) 24 | } 25 | -------------------------------------------------------------------------------- /mgradm/cmd/scale/nokubernetes.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | //go:build nok8s 6 | 7 | package scale 8 | 9 | import ( 10 | "errors" 11 | 12 | "github.com/spf13/cobra" 13 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 14 | "github.com/uyuni-project/uyuni-tools/shared/types" 15 | ) 16 | 17 | func kubernetesScale( 18 | _ *types.GlobalFlags, 19 | _ *scaleFlags, 20 | _ *cobra.Command, 21 | _ []string, 22 | ) error { 23 | return errors.New(L("built without kubernetes support")) 24 | } 25 | -------------------------------------------------------------------------------- /mgradm/cmd/start/nokubernetes.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | //go:build nok8s 6 | 7 | package start 8 | 9 | import ( 10 | "errors" 11 | 12 | "github.com/spf13/cobra" 13 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 14 | "github.com/uyuni-project/uyuni-tools/shared/types" 15 | ) 16 | 17 | func kubernetesStart( 18 | _ *types.GlobalFlags, 19 | _ *startFlags, 20 | _ *cobra.Command, 21 | _ []string, 22 | ) error { 23 | return errors.New(L("built without kubernetes support")) 24 | } 25 | -------------------------------------------------------------------------------- /mgradm/cmd/status/nokubernetes.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | //go:build nok8s 6 | 7 | package status 8 | 9 | import ( 10 | "errors" 11 | 12 | "github.com/spf13/cobra" 13 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 14 | "github.com/uyuni-project/uyuni-tools/shared/types" 15 | ) 16 | 17 | func kubernetesStatus( 18 | _ *types.GlobalFlags, 19 | _ *statusFlags, 20 | _ *cobra.Command, 21 | _ []string, 22 | ) error { 23 | return errors.New(L("built without kubernetes support")) 24 | } 25 | -------------------------------------------------------------------------------- /mgrctl/cmd/proxy/utils.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package proxy 6 | 7 | import ( 8 | "strings" 9 | ) 10 | 11 | // GetFilename returns the filename to save a configuration file to. 12 | // If an output filename is not specified, then the filename is based on the proxy name. 13 | func GetFilename(output string, proxyName string) string { 14 | filename := output 15 | if filename == "" { 16 | filename = strings.Split(proxyName, ".")[0] + "-config" 17 | } 18 | return filename + ".tar.gz" 19 | } 20 | -------------------------------------------------------------------------------- /mgrpxy/cmd/restart/podman.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package restart 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/shared/podman" 10 | "github.com/uyuni-project/uyuni-tools/shared/types" 11 | ) 12 | 13 | var systemd podman.Systemd = podman.NewSystemd() 14 | 15 | func podmanRestart( 16 | _ *types.GlobalFlags, 17 | _ *restartFlags, 18 | _ *cobra.Command, 19 | _ []string, 20 | ) error { 21 | return systemd.RestartService(podman.ProxyService) 22 | } 23 | -------------------------------------------------------------------------------- /mgradm/cmd/restart/nokubernetes.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | //go:build nok8s 6 | 7 | package restart 8 | 9 | import ( 10 | "errors" 11 | 12 | "github.com/spf13/cobra" 13 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 14 | "github.com/uyuni-project/uyuni-tools/shared/types" 15 | ) 16 | 17 | func kubernetesRestart( 18 | _ *types.GlobalFlags, 19 | _ *restartFlags, 20 | _ *cobra.Command, 21 | _ []string, 22 | ) error { 23 | return errors.New(L("built without kubernetes support")) 24 | } 25 | -------------------------------------------------------------------------------- /mgrpxy/cmd/support/ptf/kubernetes/utils.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | //go:build ptf 5 | 6 | package kubernetes 7 | 8 | import ( 9 | "github.com/spf13/cobra" 10 | "github.com/uyuni-project/uyuni-tools/mgrpxy/shared/kubernetes" 11 | "github.com/uyuni-project/uyuni-tools/shared/types" 12 | ) 13 | 14 | func ptfForKubernetes(_ *types.GlobalFlags, 15 | flags *kubernetesPTFFlags, 16 | cmd *cobra.Command, 17 | args []string, 18 | ) error { 19 | return kubernetes.Upgrade(&flags.UpgradeFlags, cmd, args) 20 | } 21 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 SUSE LLC 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | # To get started with Dependabot version updates, you'll need to specify which 6 | # package ecosystems to update and where the package manifests are located. 7 | # Please see the documentation for all configuration options: 8 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 9 | 10 | version: 2 11 | updates: 12 | - package-ecosystem: "github-actions" 13 | directory: "/" 14 | schedule: 15 | interval: "daily" 16 | -------------------------------------------------------------------------------- /.github/workflows/reuse.yml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 Free Software Foundation Europe e.V. 2 | # 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | name: REUSE Compliance Check 6 | 7 | on: 8 | push: 9 | branches: 10 | - main 11 | pull_request: 12 | types: 13 | - opened 14 | - reopened 15 | - synchronize 16 | 17 | jobs: 18 | test: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 22 | - name: REUSE Compliance Check 23 | uses: fsfe/reuse-action@bb774aa972c2a89ff34781233d275075cbddf542 #v5.0.0 24 | -------------------------------------------------------------------------------- /mgradm/cmd/upgrade/kubernetes/utils.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | //go:build !nok8s 6 | 7 | package kubernetes 8 | 9 | import ( 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/mgradm/shared/kubernetes" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | ) 14 | 15 | func upgradeKubernetes( 16 | _ *types.GlobalFlags, 17 | flags *kubernetes.KubernetesServerFlags, 18 | cmd *cobra.Command, 19 | _ []string, 20 | ) error { 21 | flags.Installation.CheckUpgradeParameters(cmd, "kubectl") 22 | return kubernetes.Reconcile(flags, "") 23 | } 24 | -------------------------------------------------------------------------------- /mgradm/shared/kubernetes/ports.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | //go:build !nok8s 6 | 7 | package kubernetes 8 | 9 | import ( 10 | "github.com/uyuni-project/uyuni-tools/shared/types" 11 | "github.com/uyuni-project/uyuni-tools/shared/utils" 12 | ) 13 | 14 | // getPortList returns compiled lists of tcp and udp ports.. 15 | func getPortList(hub bool, debug bool) []types.PortMap { 16 | ports := utils.GetServerPorts(debug) 17 | ports = append(ports, utils.ReportDBPorts...) 18 | if hub { 19 | ports = append(ports, utils.HubXmlrpcPorts...) 20 | } 21 | 22 | return ports 23 | } 24 | -------------------------------------------------------------------------------- /mgradm/shared/kubernetes/flags.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | //go:build !nok8s 6 | 7 | package kubernetes 8 | 9 | import "github.com/uyuni-project/uyuni-tools/mgradm/shared/utils" 10 | 11 | // KubernetesServerFlags is the aggregation of all flags for install, upgrade and migrate. 12 | type KubernetesServerFlags struct { 13 | utils.ServerFlags `mapstructure:",squash"` 14 | Kubernetes utils.KubernetesFlags 15 | Volumes utils.VolumesFlags 16 | // SSH defines the SSH configuration to use to connect to the source server to migrate. 17 | SSH utils.SSHFlags 18 | } 19 | -------------------------------------------------------------------------------- /mgrpxy/shared/utils/cmd.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package utils 6 | 7 | import ( 8 | "github.com/rs/zerolog/log" 9 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 10 | "github.com/uyuni-project/uyuni-tools/shared/utils" 11 | ) 12 | 13 | // GetConfigPath returns the configuration path if exists. 14 | func GetConfigPath(args []string) string { 15 | if len(args) == 0 { 16 | return "" 17 | } 18 | configPath := args[0] 19 | if !utils.FileExists(configPath) { 20 | log.Fatal().Msgf(L("argument is not an existing file: %s"), configPath) 21 | } 22 | return configPath 23 | } 24 | -------------------------------------------------------------------------------- /REUSE.toml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023-2024 SUSE LLC 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | version = 1 5 | SPDX-PackageName = "uyuni-tools" 6 | SPDX-PackageSupplier = "Uyuni Project <>" 7 | SPDX-PackageDownloadLocation = "https://github.com/uyuni-project/uyuni-tools" 8 | 9 | [[annotations]] 10 | path = ["shared/ssl/testdata/**", "go.mod", "go.sum", "uyuni-tools.changes*", "uyuni-tools.spec", ".tito/**"] 11 | precedence = "aggregate" 12 | SPDX-FileCopyrightText = "2023-2024 SUSE LLC" 13 | SPDX-License-Identifier = "Apache-2.0" 14 | 15 | [[annotations]] 16 | path = "locale/**" 17 | precedence = "override" 18 | SPDX-FileCopyrightText = "2024 SUSE LLC" 19 | SPDX-License-Identifier = "Apache-2.0" 20 | -------------------------------------------------------------------------------- /mgrpxy/cmd/upgrade/podman/utils.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package podman 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/mgrpxy/shared/podman" 10 | shared_podman "github.com/uyuni-project/uyuni-tools/shared/podman" 11 | "github.com/uyuni-project/uyuni-tools/shared/types" 12 | ) 13 | 14 | var systemd shared_podman.Systemd = shared_podman.NewSystemd() 15 | 16 | func upgradePodman( 17 | globalFlags *types.GlobalFlags, 18 | flags *podman.PodmanProxyFlags, 19 | cmd *cobra.Command, 20 | args []string, 21 | ) error { 22 | return podman.Upgrade(systemd, globalFlags, flags, cmd, args) 23 | } 24 | -------------------------------------------------------------------------------- /shared/kubernetes/uninstall.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2023 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package kubernetes 6 | 7 | import ( 8 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 9 | ) 10 | 11 | // UninstallHelp returns the message appended in the uninstall commands for kubernetes. 12 | func UninstallHelp() string { 13 | return L(` 14 | Note that removing the volumes could also be handled automatically depending on the StorageClass used 15 | when installed on a kubernetes cluster. 16 | 17 | For instance on a default K3S install, the local-path-provider storage volumes will 18 | be automatically removed when deleting the deployment even if --purge-volumes argument is not used.`) 19 | } 20 | -------------------------------------------------------------------------------- /shared/types/uyuniservice.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package types 6 | 7 | type UyuniServiceOption struct { 8 | Name string 9 | Value interface{} 10 | Description string 11 | } 12 | 13 | type UyuniServiceReplicas struct { 14 | Max uint 15 | Min uint 16 | Default uint 17 | } 18 | 19 | type UyuniService struct { 20 | Name string 21 | Image ImageFlags 22 | Description string 23 | Replicas UyuniServiceReplicas 24 | Options []UyuniServiceOption 25 | } 26 | 27 | var SingleMandatoryReplica = UyuniServiceReplicas{Max: 1, Min: 1, Default: 1} 28 | var SingleOptionalReplica = UyuniServiceReplicas{Max: 1, Min: 0, Default: 0} 29 | -------------------------------------------------------------------------------- /shared/utils/ports_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package utils 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 11 | ) 12 | 13 | func TestGetServerPorts(t *testing.T) { 14 | allPorts := len(WebPorts) + len(SaltPorts) + len(CobblerPorts) + 15 | len(TaskoPorts) + len(TomcatPorts) + len(SearchPorts) + len(TftpPorts) + len(DBExporterPorts) 16 | 17 | ports := GetServerPorts(false) 18 | testutils.AssertEquals(t, "Wrong number of ports without debug ones", allPorts-3, len(ports)) 19 | 20 | ports = GetServerPorts(true) 21 | testutils.AssertEquals(t, "Wrong number of ports with debug ones", allPorts, len(ports)) 22 | } 23 | -------------------------------------------------------------------------------- /shared/testutils/flagstests/podman.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package flagstests 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/uyuni-project/uyuni-tools/shared/podman" 11 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 12 | ) 13 | 14 | // PodmanFlagsTestArgs is the values for PodmanFlagsTestArgs. 15 | var PodmanFlagsTestArgs = []string{ 16 | "--podman-arg", "arg1", 17 | "--podman-arg", "arg2", 18 | } 19 | 20 | // AssertPodmanInstallFlags checks that all podman flags are parsed correctly. 21 | func AssertPodmanInstallFlags(t *testing.T, flags *podman.PodmanFlags) { 22 | testutils.AssertEquals(t, "Error parsing --podman-arg", []string{"arg1", "arg2"}, flags.Args) 23 | } 24 | -------------------------------------------------------------------------------- /shared/api/types/organization.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package types 6 | 7 | // Organization describe an organization in the API. 8 | type Organization struct { 9 | ID int 10 | Name string 11 | ActiveUsers int `mapstructure:"active_users"` 12 | Systems int 13 | Trusts int 14 | SystemGroups int `mapstructure:"system_groups"` 15 | ActivationKeys int `mapstructure:"activation_keys"` 16 | KickstartProfiles int `mapstructure:"kickstart_profiles"` 17 | ConfigurationChannels int `mapstructure:"configuration_channels"` 18 | StagingContentEnabled bool `mapstructure:"staging_content_enabled"` 19 | } 20 | -------------------------------------------------------------------------------- /.github/workflows/check_l10n.yml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 SUSE LLC 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | name: l10n-check 6 | on: 7 | push: 8 | branches: 9 | - main 10 | pull_request: 11 | 12 | permissions: 13 | contents: read 14 | 15 | jobs: 16 | l10n-check: 17 | name: localizable 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 21 | - name: Check localizable strings 22 | shell: bash -x {0} 23 | run: ./check_localizable 24 | - uses: cbosdo/gettext-go-lint@118d756ec8dc7b45cd5e560dcaaecf45fd17d891 # gettext-go-lint-0.1.1-0 25 | name: Localizable strings linter 26 | with: 27 | keywords: L,NL,PL 28 | -------------------------------------------------------------------------------- /mgradm/cmd/server/server.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package server 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/mgradm/cmd/server/rename" 10 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 11 | "github.com/uyuni-project/uyuni-tools/shared/types" 12 | ) 13 | 14 | // NewCommand creates a sub command for all server-related actions. 15 | func NewCommand(globalFlags *types.GlobalFlags) *cobra.Command { 16 | cmd := &cobra.Command{ 17 | Use: "server", 18 | GroupID: "tool", 19 | Short: L("Server management utilities"), 20 | Args: cobra.ExactArgs(1), 21 | } 22 | 23 | cmd.AddCommand(rename.NewCommand(globalFlags)) 24 | return cmd 25 | } 26 | -------------------------------------------------------------------------------- /mgradm/cmd/upgrade/shared/flags.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package shared 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | adm_utils "github.com/uyuni-project/uyuni-tools/mgradm/shared/utils" 10 | ) 11 | 12 | // AddUpgradeFlags add upgrade flags to a command. 13 | func AddUpgradeFlags(cmd *cobra.Command) { 14 | adm_utils.AddServerFlags(cmd) 15 | 16 | adm_utils.AddDBUpgradeImageFlag(cmd) 17 | adm_utils.AddUpgradeCocoFlag(cmd) 18 | adm_utils.AddUpgradeHubXmlrpcFlags(cmd) 19 | adm_utils.AddUpgradeSalineFlag(cmd) 20 | } 21 | 22 | // AddUpgradeListFlags add upgrade list flags to a command. 23 | func AddUpgradeListFlags(cmd *cobra.Command) { 24 | adm_utils.AddImageFlag(cmd) 25 | adm_utils.AddSCCFlag(cmd) 26 | } 27 | -------------------------------------------------------------------------------- /mgrpxy/cmd/cache/squid.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package cache 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 10 | "github.com/uyuni-project/uyuni-tools/shared/types" 11 | ) 12 | 13 | // NewCommand entry command for managing cache. 14 | // Setup for subcommand to clear (the cache). 15 | func NewCommand(globalFlags *types.GlobalFlags) *cobra.Command { 16 | var cacheCmd = &cobra.Command{ 17 | Use: "cache", 18 | Short: L("Manage proxy cache"), 19 | Long: L("Manage proxy cache"), 20 | Run: func(cmd *cobra.Command, _ []string) { 21 | _ = cmd.Help() 22 | }, 23 | } 24 | 25 | cacheCmd.AddCommand(NewClearCmd(globalFlags)) 26 | return cacheCmd 27 | } 28 | -------------------------------------------------------------------------------- /mgrctl/main.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package main 6 | 7 | import ( 8 | "os" 9 | 10 | "github.com/chai2010/gettext-go" 11 | "github.com/spf13/cobra" 12 | "github.com/uyuni-project/uyuni-tools/mgrctl/cmd" 13 | l10n_utils "github.com/uyuni-project/uyuni-tools/shared/l10n/utils" 14 | "github.com/uyuni-project/uyuni-tools/shared/utils" 15 | ) 16 | 17 | // Run runs the `mgrctl` root command. 18 | func Run() error { 19 | gettext.BindLocale(gettext.New("mgrctl", utils.LocaleRoot, l10n_utils.New(utils.LocaleRoot))) 20 | cobra.EnableCaseInsensitive = true 21 | run := cmd.NewUyunictlCommand() 22 | 23 | return run.Execute() 24 | } 25 | 26 | func main() { 27 | if err := Run(); err != nil { 28 | os.Exit(1) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /mgradm/cmd/support/ptf/ptf.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | //go:build ptf 5 | 6 | package ptf 7 | 8 | import ( 9 | "github.com/spf13/cobra" 10 | "github.com/uyuni-project/uyuni-tools/mgradm/cmd/support/ptf/podman" 11 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | "github.com/uyuni-project/uyuni-tools/shared/utils" 14 | ) 15 | 16 | // NewCommand is the command for creates supportptf. 17 | func NewCommand(globalFlags *types.GlobalFlags) *cobra.Command { 18 | ptfCmd := &cobra.Command{ 19 | Use: "ptf", 20 | Short: L("Install a PTF"), 21 | } 22 | 23 | utils.AddBackendFlag(ptfCmd) 24 | 25 | ptfCmd.AddCommand(podman.NewCommand(globalFlags)) 26 | 27 | return ptfCmd 28 | } 29 | -------------------------------------------------------------------------------- /shared/testutils/flagstests/scc.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package flagstests 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 11 | "github.com/uyuni-project/uyuni-tools/shared/types" 12 | ) 13 | 14 | // SCCFlagTestArgs is the expected values for AssertSccFlag. 15 | var SCCFlagTestArgs = []string{ 16 | "--scc-user", "mysccuser", 17 | "--scc-password", "mysccpass", 18 | } 19 | 20 | // AssertSCCFlag checks that all SCC flags are parsed correctly. 21 | func AssertSCCFlag(t *testing.T, flags *types.SCCCredentials) { 22 | testutils.AssertEquals(t, "Error parsing --scc-user", "mysccuser", flags.User) 23 | testutils.AssertEquals(t, "Error parsing --scc-password", "mysccpass", flags.Password) 24 | } 25 | -------------------------------------------------------------------------------- /mgradm/shared/kubernetes/namespace.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | //go:build !nok8s 6 | 7 | package kubernetes 8 | 9 | import ( 10 | "github.com/uyuni-project/uyuni-tools/shared/kubernetes" 11 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 12 | core "k8s.io/api/core/v1" 13 | meta "k8s.io/apimachinery/pkg/apis/meta/v1" 14 | "k8s.io/apimachinery/pkg/runtime" 15 | ) 16 | 17 | // CreateNamespace creates a kubernetes namespace. 18 | func CreateNamespace(namespace string) error { 19 | ns := core.Namespace{ 20 | TypeMeta: meta.TypeMeta{Kind: "Namespace", APIVersion: "v1"}, 21 | ObjectMeta: meta.ObjectMeta{ 22 | Name: namespace, 23 | }, 24 | } 25 | return kubernetes.Apply([]runtime.Object{&ns}, L("failed to create the namespace")) 26 | } 27 | -------------------------------------------------------------------------------- /mgradm/cmd/restart/podman.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package restart 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/shared/podman" 10 | "github.com/uyuni-project/uyuni-tools/shared/types" 11 | "github.com/uyuni-project/uyuni-tools/shared/utils" 12 | ) 13 | 14 | var systemd podman.Systemd = podman.NewSystemd() 15 | 16 | func podmanRestart( 17 | _ *types.GlobalFlags, 18 | _ *restartFlags, 19 | _ *cobra.Command, 20 | _ []string, 21 | ) error { 22 | return utils.JoinErrors( 23 | systemd.RestartService(podman.DBService), 24 | systemd.RestartService(podman.ServerService), 25 | systemd.RestartInstantiated(podman.ServerAttestationService), 26 | systemd.RestartInstantiated(podman.HubXmlrpcService), 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /mgradm/main.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package main 6 | 7 | import ( 8 | "os" 9 | 10 | "github.com/chai2010/gettext-go" 11 | "github.com/spf13/cobra" 12 | "github.com/uyuni-project/uyuni-tools/mgradm/cmd" 13 | l10n_utils "github.com/uyuni-project/uyuni-tools/shared/l10n/utils" 14 | "github.com/uyuni-project/uyuni-tools/shared/utils" 15 | ) 16 | 17 | // Run runs the `mgradm` root command. 18 | func Run() error { 19 | gettext.BindLocale(gettext.New("mgradm", utils.LocaleRoot, l10n_utils.New(utils.LocaleRoot))) 20 | cobra.EnableCaseInsensitive = true 21 | run, err := cmd.NewUyuniadmCommand() 22 | if err != nil { 23 | return err 24 | } 25 | return run.Execute() 26 | } 27 | 28 | func main() { 29 | if err := Run(); err != nil { 30 | os.Exit(1) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /mgrpxy/main.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package main 6 | 7 | import ( 8 | "os" 9 | 10 | "github.com/chai2010/gettext-go" 11 | "github.com/spf13/cobra" 12 | "github.com/uyuni-project/uyuni-tools/mgrpxy/cmd" 13 | l10n_utils "github.com/uyuni-project/uyuni-tools/shared/l10n/utils" 14 | "github.com/uyuni-project/uyuni-tools/shared/utils" 15 | ) 16 | 17 | // Run runs the `mgrpxy` root command. 18 | func Run() error { 19 | gettext.BindLocale(gettext.New("mgrpxy", utils.LocaleRoot, l10n_utils.New(utils.LocaleRoot))) 20 | cobra.EnableCaseInsensitive = true 21 | run, err := cmd.NewUyuniproxyCommand() 22 | if err != nil { 23 | return err 24 | } 25 | return run.Execute() 26 | } 27 | 28 | func main() { 29 | if err := Run(); err != nil { 30 | os.Exit(1) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /mgradm/cmd/hub/hub.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package hub 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/mgradm/cmd/hub/register" 10 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 11 | "github.com/uyuni-project/uyuni-tools/shared/types" 12 | ) 13 | 14 | // NewCommand command for Hub management. 15 | func NewCommand(globalFlags *types.GlobalFlags) *cobra.Command { 16 | hubCmd := &cobra.Command{ 17 | Use: "hub", 18 | GroupID: "management", 19 | Short: L("Hub management"), 20 | Long: L("Tools and utilities for Hub management"), 21 | Aliases: []string{"hub"}, 22 | } 23 | 24 | hubCmd.SetUsageTemplate(hubCmd.UsageTemplate()) 25 | hubCmd.AddCommand(register.NewCommand(globalFlags)) 26 | return hubCmd 27 | } 28 | -------------------------------------------------------------------------------- /shared/api/api_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package api 6 | 7 | import "testing" 8 | 9 | func TestRedactHeaders(t *testing.T) { 10 | data := [][]string{ 11 | { 12 | `"JSESSIONID=supersecret; Path=/; Secure; HttpOnly; HttpOnly;HttpOnly;Secure"`, 13 | `"JSESSIONID=; Path=/; Secure; HttpOnly; HttpOnly;HttpOnly;Secure"`, 14 | }, 15 | { 16 | `"pxt-session-cookie=supersecret; Max-Age=0;"`, 17 | `"pxt-session-cookie=; Max-Age=0;"`, 18 | }, 19 | } 20 | 21 | for i, testCase := range data { 22 | input := testCase[0] 23 | expected := testCase[1] 24 | 25 | actual := redactHeaders(input) 26 | 27 | if actual != expected { 28 | t.Errorf("Testcase %d: Expected %s got %s when redacting %s", i, expected, actual, input) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /mgradm/shared/kubernetes/node.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | //go:build !nok8s 6 | 7 | package kubernetes 8 | 9 | import ( 10 | "github.com/uyuni-project/uyuni-tools/shared/kubernetes" 11 | ) 12 | 13 | // deployNodeConfig deploy configuration files on the node. 14 | func deployNodeConfig( 15 | namespace string, 16 | clusterInfos *kubernetes.ClusterInfos, 17 | needsHub bool, 18 | debug bool, 19 | ) error { 20 | // If installing on k3s, install the traefik helm config in manifests 21 | isK3s := clusterInfos.IsK3s() 22 | IsRke2 := clusterInfos.IsRke2() 23 | ports := getPortList(needsHub, debug) 24 | if isK3s { 25 | return kubernetes.InstallK3sTraefikConfig(ports) 26 | } else if IsRke2 { 27 | return kubernetes.InstallRke2NginxConfig(ports, namespace) 28 | } 29 | return nil 30 | } 31 | -------------------------------------------------------------------------------- /shared/l10n/gettext.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package l10n 6 | 7 | import "github.com/chai2010/gettext-go" 8 | 9 | // L localizes a string using the set up gettext domain and locale. 10 | // This is an alias for gettext.Gettext(). 11 | func L(message string) string { 12 | return gettext.Gettext(message) 13 | } 14 | 15 | // NL returns a localized message depending on the value of count. 16 | // This is an alias for gettext.NGettext(). 17 | func NL(message string, plural string, count int) string { 18 | return gettext.NGettext(message, plural, count) 19 | } 20 | 21 | // PL localizes a string using the set up gettext domain and locale, but adding a context. 22 | // This is an alias for gettext.PGettext(). 23 | func PL(context string, message string) string { 24 | return gettext.PGettext(context, message) 25 | } 26 | -------------------------------------------------------------------------------- /mgrpxy/cmd/stop/kubernetes.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package stop 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/shared" 10 | "github.com/uyuni-project/uyuni-tools/shared/kubernetes" 11 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | "github.com/uyuni-project/uyuni-tools/shared/utils" 14 | ) 15 | 16 | func kubernetesStop( 17 | _ *types.GlobalFlags, 18 | _ *stopFlags, 19 | _ *cobra.Command, 20 | _ []string, 21 | ) error { 22 | cnx := shared.NewConnection("kubectl", "", kubernetes.ProxyFilter) 23 | namespace, err := cnx.GetNamespace("") 24 | if err != nil { 25 | return utils.Errorf(err, L("failed retrieving namespace")) 26 | } 27 | return kubernetes.Stop(namespace, kubernetes.ProxyApp) 28 | } 29 | -------------------------------------------------------------------------------- /mgrpxy/cmd/start/kubernetes.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package start 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/shared" 10 | "github.com/uyuni-project/uyuni-tools/shared/kubernetes" 11 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | "github.com/uyuni-project/uyuni-tools/shared/utils" 14 | ) 15 | 16 | func kubernetesStart( 17 | _ *types.GlobalFlags, 18 | _ *startFlags, 19 | _ *cobra.Command, 20 | _ []string, 21 | ) error { 22 | cnx := shared.NewConnection("kubectl", "", kubernetes.ProxyFilter) 23 | namespace, err := cnx.GetNamespace("") 24 | if err != nil { 25 | return utils.Errorf(err, L("failed retrieving namespace")) 26 | } 27 | return kubernetes.Start(namespace, kubernetes.ProxyApp) 28 | } 29 | -------------------------------------------------------------------------------- /shared/podman/selinux_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package podman 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | "testing" 11 | 12 | "github.com/rs/zerolog" 13 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 14 | ) 15 | 16 | func TestIsSELinuxEnabled(t *testing.T) { 17 | type testType struct { 18 | err error 19 | expected bool 20 | } 21 | 22 | cases := []testType{ 23 | {nil, true}, 24 | {errors.New("no such program selinuxenabled"), false}, 25 | } 26 | 27 | for i, testCase := range cases { 28 | runCmdOutput = func(_ zerolog.Level, _ string, _ ...string) ([]byte, error) { 29 | return []byte(""), testCase.err 30 | } 31 | caseString := fmt.Sprintf("case %d: ", i) 32 | testutils.AssertEquals(t, caseString+"unexpected return value", testCase.expected, IsSELinuxEnabled()) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /mgrpxy/cmd/restart/kubernetes.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package restart 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/shared" 10 | "github.com/uyuni-project/uyuni-tools/shared/kubernetes" 11 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | "github.com/uyuni-project/uyuni-tools/shared/utils" 14 | ) 15 | 16 | func kubernetesRestart( 17 | _ *types.GlobalFlags, 18 | _ *restartFlags, 19 | _ *cobra.Command, 20 | _ []string, 21 | ) error { 22 | cnx := shared.NewConnection("kubectl", "", kubernetes.ProxyFilter) 23 | namespace, err := cnx.GetNamespace("") 24 | if err != nil { 25 | return utils.Errorf(err, L("failed retrieving namespace")) 26 | } 27 | return kubernetes.Restart(namespace, kubernetes.ProxyApp) 28 | } 29 | -------------------------------------------------------------------------------- /mgrpxy/cmd/upgrade/upgrade.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package upgrade 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/mgrpxy/cmd/upgrade/kubernetes" 10 | "github.com/uyuni-project/uyuni-tools/mgrpxy/cmd/upgrade/podman" 11 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | ) 14 | 15 | // NewCommand install a new proxy from scratch. 16 | func NewCommand(globalFlags *types.GlobalFlags) *cobra.Command { 17 | upgradeCmd := &cobra.Command{ 18 | Use: "upgrade", 19 | GroupID: "deploy", 20 | Short: L("Upgrade a proxy"), 21 | Long: L("Upgrade a proxy"), 22 | } 23 | upgradeCmd.AddCommand(podman.NewCommand(globalFlags)) 24 | upgradeCmd.AddCommand(kubernetes.NewCommand(globalFlags)) 25 | 26 | return upgradeCmd 27 | } 28 | -------------------------------------------------------------------------------- /mgradm/cmd/gpg/gpg.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package gpg 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | gpgadd "github.com/uyuni-project/uyuni-tools/mgradm/cmd/gpg/add" 10 | gpglist "github.com/uyuni-project/uyuni-tools/mgradm/cmd/gpg/list" 11 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | ) 14 | 15 | // NewCommand import gpg keys from 3rd party repository. 16 | func NewCommand(globalFlags *types.GlobalFlags) *cobra.Command { 17 | gpgKeyCmd := &cobra.Command{ 18 | Use: "gpg", 19 | GroupID: "tool", 20 | Short: L("Manage GPG keys for 3rd party repositories"), 21 | Args: cobra.ExactArgs(1), 22 | } 23 | 24 | gpgKeyCmd.AddCommand(gpgadd.NewCommand(globalFlags)) 25 | gpgKeyCmd.AddCommand(gpglist.NewCommand(globalFlags)) 26 | 27 | return gpgKeyCmd 28 | } 29 | -------------------------------------------------------------------------------- /mgradm/cmd/stop/kubernetes.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | //go:build !nok8s 6 | 7 | package stop 8 | 9 | import ( 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/shared" 12 | "github.com/uyuni-project/uyuni-tools/shared/kubernetes" 13 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 14 | "github.com/uyuni-project/uyuni-tools/shared/types" 15 | "github.com/uyuni-project/uyuni-tools/shared/utils" 16 | ) 17 | 18 | func kubernetesStop( 19 | _ *types.GlobalFlags, 20 | _ *stopFlags, 21 | _ *cobra.Command, 22 | _ []string, 23 | ) error { 24 | cnx := shared.NewConnection("kubectl", "", kubernetes.ServerFilter) 25 | namespace, err := cnx.GetNamespace("") 26 | if err != nil { 27 | return utils.Errorf(err, L("failed retrieving namespace")) 28 | } 29 | return kubernetes.Stop(namespace, kubernetes.ServerApp) 30 | } 31 | -------------------------------------------------------------------------------- /mgradm/cmd/start/kubernetes.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | //go:build !nok8s 6 | 7 | package start 8 | 9 | import ( 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/shared" 12 | "github.com/uyuni-project/uyuni-tools/shared/kubernetes" 13 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 14 | "github.com/uyuni-project/uyuni-tools/shared/types" 15 | "github.com/uyuni-project/uyuni-tools/shared/utils" 16 | ) 17 | 18 | func kubernetesStart( 19 | _ *types.GlobalFlags, 20 | _ *startFlags, 21 | _ *cobra.Command, 22 | _ []string, 23 | ) error { 24 | cnx := shared.NewConnection("kubectl", "", kubernetes.ServerFilter) 25 | namespace, err := cnx.GetNamespace("") 26 | if err != nil { 27 | return utils.Errorf(err, L("failed retrieving namespace")) 28 | } 29 | return kubernetes.Start(namespace, kubernetes.ServerApp) 30 | } 31 | -------------------------------------------------------------------------------- /shared/utils/inspector.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package utils 6 | 7 | import ( 8 | "bytes" 9 | 10 | "github.com/spf13/viper" 11 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 12 | ) 13 | 14 | // ReadInspectData returns an unmarshalled object of type T from the data as a string. 15 | // 16 | // This function is most likely to be used for the implementation of the inspectors, but can also be used directly. 17 | func ReadInspectData[T any](data []byte) (*T, error) { 18 | viper.SetConfigType("env") 19 | if err := viper.MergeConfig(bytes.NewBuffer(data)); err != nil { 20 | return nil, Error(err, L("cannot read config")) 21 | } 22 | 23 | var inspectResult T 24 | if err := viper.Unmarshal(&inspectResult); err != nil { 25 | return nil, Error(err, L("failed to unmarshal the inspected data")) 26 | } 27 | return &inspectResult, nil 28 | } 29 | -------------------------------------------------------------------------------- /mgrpxy/cmd/support/ptf/ptf.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | //go:build ptf 5 | 6 | package ptf 7 | 8 | import ( 9 | "github.com/spf13/cobra" 10 | "github.com/uyuni-project/uyuni-tools/mgrpxy/cmd/support/ptf/kubernetes" 11 | "github.com/uyuni-project/uyuni-tools/mgrpxy/cmd/support/ptf/podman" 12 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 13 | "github.com/uyuni-project/uyuni-tools/shared/types" 14 | ) 15 | 16 | // NewCommand is the command for creates supportptf. 17 | func NewCommand(globalFlags *types.GlobalFlags) *cobra.Command { 18 | ptfCmd := &cobra.Command{ 19 | Use: "ptf", 20 | Short: L("Install a PTF"), 21 | } 22 | 23 | ptfCmd.AddCommand(podman.NewCommand(globalFlags)) 24 | 25 | if kubernetesCmd := kubernetes.NewCommand(globalFlags); kubernetesCmd != nil { 26 | ptfCmd.AddCommand(kubernetesCmd) 27 | } 28 | 29 | return ptfCmd 30 | } 31 | -------------------------------------------------------------------------------- /mgradm/cmd/restart/kubernetes.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | //go:build !nok8s 6 | 7 | package restart 8 | 9 | import ( 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/shared" 12 | "github.com/uyuni-project/uyuni-tools/shared/kubernetes" 13 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 14 | "github.com/uyuni-project/uyuni-tools/shared/types" 15 | "github.com/uyuni-project/uyuni-tools/shared/utils" 16 | ) 17 | 18 | func kubernetesRestart( 19 | _ *types.GlobalFlags, 20 | _ *restartFlags, 21 | _ *cobra.Command, 22 | _ []string, 23 | ) error { 24 | cnx := shared.NewConnection("kubectl", "", kubernetes.ServerFilter) 25 | namespace, err := cnx.GetNamespace("") 26 | if err != nil { 27 | return utils.Errorf(err, L("failed retrieving namespace")) 28 | } 29 | return kubernetes.Restart(namespace, kubernetes.ServerApp) 30 | } 31 | -------------------------------------------------------------------------------- /shared/utils/dbinspector.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package utils 6 | 7 | import ( 8 | "github.com/uyuni-project/uyuni-tools/shared/templates" 9 | "github.com/uyuni-project/uyuni-tools/shared/types" 10 | ) 11 | 12 | // NewDBInspector creates a new templates.InspectTemplateData for the database info. 13 | func NewDBInspector() templates.InspectTemplateData { 14 | return templates.InspectTemplateData{ 15 | Values: []types.InspectData{ 16 | types.NewInspectData("image_pg_version", 17 | "echo $PG_MAJOR || true"), 18 | types.NewInspectData("image_libc_version", "ldd --version | head -n1 | sed 's/^ldd (GNU libc) //'"), 19 | }, 20 | } 21 | } 22 | 23 | // DBInspectData are data of the DB data. 24 | type DBInspectData struct { 25 | ImagePgVersion string `mapstructure:"image_pg_version"` 26 | ImageLibcVersion string `mapstructure:"image_libc_version"` 27 | } 28 | -------------------------------------------------------------------------------- /mgrpxy/cmd/install/install.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package install 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/mgrpxy/cmd/install/kubernetes" 10 | "github.com/uyuni-project/uyuni-tools/mgrpxy/cmd/install/podman" 11 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | ) 14 | 15 | // NewCommand install a new proxy from scratch. 16 | func NewCommand(globalFlags *types.GlobalFlags) *cobra.Command { 17 | installCmd := &cobra.Command{ 18 | Use: "install [fqdn]", 19 | GroupID: "deploy", 20 | Short: L("Install a new proxy from scratch"), 21 | Long: L("Install a new proxy from scratch"), 22 | } 23 | installCmd.AddCommand(podman.NewCommand(globalFlags)) 24 | installCmd.AddCommand(kubernetes.NewCommand(globalFlags)) 25 | 26 | return installCmd 27 | } 28 | -------------------------------------------------------------------------------- /mgradm/cmd/migrate/shared/flags.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package shared 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | adm_utils "github.com/uyuni-project/uyuni-tools/mgradm/shared/utils" 10 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 11 | ) 12 | 13 | // AddMigrateFlags add migration flags to a command. 14 | func AddMigrateFlags(cmd *cobra.Command) { 15 | cmd.Flags().Bool("prepare", false, L("Prepare the migration - copy the data without stopping the source server.")) 16 | 17 | cmd.Flags().String("user", "root", 18 | L("User on the source server. Non-root user must have passwordless sudo privileges (NOPASSWD tag in /etc/sudoers)."), 19 | ) 20 | adm_utils.AddServerFlags(cmd) 21 | 22 | adm_utils.AddDBUpgradeImageFlag(cmd) 23 | adm_utils.AddUpgradeCocoFlag(cmd) 24 | adm_utils.AddUpgradeHubXmlrpcFlags(cmd) 25 | adm_utils.AddUpgradeSalineFlag(cmd) 26 | } 27 | -------------------------------------------------------------------------------- /mgrpxy/cmd/cache/podman.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package cache 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/shared" 10 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 11 | "github.com/uyuni-project/uyuni-tools/shared/podman" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | "github.com/uyuni-project/uyuni-tools/shared/utils" 14 | ) 15 | 16 | var systemd podman.Systemd = podman.NewSystemd() 17 | 18 | func podmanCacheClear( 19 | _ *types.GlobalFlags, 20 | _ *cacheClearFlags, 21 | _ *cobra.Command, 22 | _ []string, 23 | ) error { 24 | cnx := shared.NewConnection("podman", "uyuni-proxy-squid", "") 25 | 26 | if _, err := cnx.Exec("sh", "-c", "rm -rf /var/cache/squid/*"); err != nil { 27 | return utils.Errorf(err, L("failed to remove cached data")) 28 | } 29 | 30 | return systemd.RestartService(podman.ProxyService) 31 | } 32 | -------------------------------------------------------------------------------- /mgradm/cmd/install/install.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package install 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/mgradm/cmd/install/kubernetes" 10 | "github.com/uyuni-project/uyuni-tools/mgradm/cmd/install/podman" 11 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | ) 14 | 15 | // NewCommand for installation. 16 | func NewCommand(globalFlags *types.GlobalFlags) *cobra.Command { 17 | installCmd := &cobra.Command{ 18 | Use: "install", 19 | GroupID: "deploy", 20 | Short: L("Install a new server"), 21 | Long: L("Install a new server"), 22 | } 23 | installCmd.AddCommand(podman.NewCommand(globalFlags)) 24 | 25 | if kubernetesCmd := kubernetes.NewCommand(globalFlags); kubernetesCmd != nil { 26 | installCmd.AddCommand(kubernetesCmd) 27 | } 28 | 29 | return installCmd 30 | } 31 | -------------------------------------------------------------------------------- /mgrpxy/cmd/support/support.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package support 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/mgrpxy/cmd/support/config" 10 | "github.com/uyuni-project/uyuni-tools/mgrpxy/cmd/support/ptf" 11 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | ) 14 | 15 | // NewCommand to export supportconfig. 16 | func NewCommand(globalFlags *types.GlobalFlags) *cobra.Command { 17 | supportCmd := &cobra.Command{ 18 | Use: "support", 19 | GroupID: "tool", 20 | Short: L("Commands for support operations"), 21 | Long: L("Commands for support operations"), 22 | } 23 | 24 | supportCmd.AddCommand(config.NewCommand(globalFlags)) 25 | if ptfCommand := ptf.NewCommand(globalFlags); ptfCommand != nil { 26 | supportCmd.AddCommand(ptfCommand) 27 | } 28 | 29 | return supportCmd 30 | } 31 | -------------------------------------------------------------------------------- /mgradm/cmd/upgrade/upgrade.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | package upgrade 5 | 6 | import ( 7 | "github.com/spf13/cobra" 8 | "github.com/uyuni-project/uyuni-tools/mgradm/cmd/upgrade/kubernetes" 9 | "github.com/uyuni-project/uyuni-tools/mgradm/cmd/upgrade/podman" 10 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 11 | "github.com/uyuni-project/uyuni-tools/shared/types" 12 | ) 13 | 14 | // NewCommand for upgrading a local server. 15 | func NewCommand(globalFlags *types.GlobalFlags) *cobra.Command { 16 | upgradeCmd := &cobra.Command{ 17 | Use: "upgrade server", 18 | GroupID: "deploy", 19 | Short: L("Upgrade local server"), 20 | Long: L("Upgrade local server"), 21 | } 22 | upgradeCmd.AddCommand(podman.NewCommand(globalFlags)) 23 | 24 | if kubernetesCmd := kubernetes.NewCommand(globalFlags); kubernetesCmd != nil { 25 | upgradeCmd.AddCommand(kubernetesCmd) 26 | } 27 | 28 | return upgradeCmd 29 | } 30 | -------------------------------------------------------------------------------- /mgrpxy/cmd/start/start_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package start 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | ) 14 | 15 | func TestParamsParsing(t *testing.T) { 16 | args := []string{ 17 | "--backend", "kubectl", 18 | } 19 | 20 | // Test function asserting that the args are properly parsed 21 | tester := func(_ *types.GlobalFlags, flags *startFlags, _ *cobra.Command, _ []string) error { 22 | testutils.AssertEquals(t, "Error parsing --backend", "kubectl", flags.Backend) 23 | return nil 24 | } 25 | 26 | globalFlags := types.GlobalFlags{} 27 | cmd := newCmd(&globalFlags, tester) 28 | 29 | testutils.AssertHasAllFlags(t, cmd, args) 30 | 31 | cmd.SetArgs(args) 32 | if err := cmd.Execute(); err != nil { 33 | t.Errorf("command failed with error: %s", err) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /.github/workflows/vulncheck.yml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 SUSE LLC 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | name: Vulnerability check 6 | 7 | on: 8 | pull_request: 9 | types: 10 | - opened 11 | - reopened 12 | - synchronize 13 | 14 | jobs: 15 | govulncheck: 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 20 | with: 21 | fetch-tags: true 22 | fetch-depth: 0 23 | 24 | - name: Setup Go ${{ matrix.go-version }} 25 | uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 #v5.5.0 26 | with: 27 | go-version: '1.23' 28 | check-latest: true 29 | 30 | - name: Install govulncheck 31 | run: go install golang.org/x/vuln/cmd/govulncheck@latest 32 | shell: bash 33 | 34 | - id: govulncheck 35 | name: Run govulncheck 36 | run: govulncheck -tags ptf ./... 37 | shell: bash 38 | -------------------------------------------------------------------------------- /mgrpxy/cmd/stop/stop_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package stop 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | ) 14 | 15 | func TestParamsParsing(t *testing.T) { 16 | args := []string{ 17 | "--backend", "kubectl", 18 | } 19 | 20 | // Test function asserting that the args are properly parsed 21 | tester := func(_ *types.GlobalFlags, flags *stopFlags, 22 | _ *cobra.Command, _ []string, 23 | ) error { 24 | testutils.AssertEquals(t, "Error parsing --backend", "kubectl", flags.Backend) 25 | return nil 26 | } 27 | 28 | globalFlags := types.GlobalFlags{} 29 | cmd := newCmd(&globalFlags, tester) 30 | 31 | testutils.AssertHasAllFlags(t, cmd, args) 32 | 33 | cmd.SetArgs(args) 34 | if err := cmd.Execute(); err != nil { 35 | t.Errorf("command failed with error: %s", err) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /mgrpxy/cmd/restart/restart_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package restart 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | ) 14 | 15 | func TestParamsParsing(t *testing.T) { 16 | args := []string{ 17 | "--backend", "kubectl", 18 | } 19 | 20 | // Test function asserting that the args are properly parsed 21 | tester := func(_ *types.GlobalFlags, flags *restartFlags, 22 | _ *cobra.Command, _ []string, 23 | ) error { 24 | testutils.AssertEquals(t, "Error parsing --backend", "kubectl", flags.Backend) 25 | return nil 26 | } 27 | 28 | globalFlags := types.GlobalFlags{} 29 | cmd := newCmd(&globalFlags, tester) 30 | 31 | testutils.AssertHasAllFlags(t, cmd, args) 32 | 33 | cmd.SetArgs(args) 34 | if err := cmd.Execute(); err != nil { 35 | t.Errorf("command failed with error: %s", err) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /shared/utils/template.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package utils 6 | 7 | import ( 8 | "fmt" 9 | "io" 10 | "os" 11 | 12 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 13 | ) 14 | 15 | // Template is an interface for implementing Render function. 16 | type Template interface { 17 | Render(wr io.Writer) error 18 | } 19 | 20 | // WriteTemplateToFile writes a template to a file. 21 | func WriteTemplateToFile(template Template, path string, perm os.FileMode, overwrite bool) error { 22 | // Check if the file is existing 23 | if !overwrite { 24 | if FileExists(path) { 25 | return fmt.Errorf(L("%s file already present, not overwriting"), path) 26 | } 27 | } 28 | 29 | // Write the configuration 30 | file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) 31 | if err != nil { 32 | return Errorf(err, L("failed to open %s for writing"), path) 33 | } 34 | defer file.Close() 35 | 36 | return template.Render(file) 37 | } 38 | -------------------------------------------------------------------------------- /mgradm/cmd/migrate/migrate.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package migrate 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/mgradm/cmd/migrate/kubernetes" 10 | "github.com/uyuni-project/uyuni-tools/mgradm/cmd/migrate/podman" 11 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | ) 14 | 15 | // NewCommand for migration. 16 | func NewCommand(globalFlags *types.GlobalFlags) *cobra.Command { 17 | migrateCmd := &cobra.Command{ 18 | Use: "migrate [source server FQDN]", 19 | GroupID: "deploy", 20 | Short: L("Migrate a remote server to containers"), 21 | Long: L("Migrate a remote server to containers"), 22 | } 23 | migrateCmd.AddCommand(podman.NewCommand(globalFlags)) 24 | 25 | if kubernetesCmd := kubernetes.NewCommand(globalFlags); kubernetesCmd != nil { 26 | migrateCmd.AddCommand(kubernetesCmd) 27 | } 28 | 29 | return migrateCmd 30 | } 31 | -------------------------------------------------------------------------------- /mgradm/shared/kubernetes/deployment_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | //go:build !nok8s 6 | 7 | package kubernetes 8 | 9 | import ( 10 | "errors" 11 | "fmt" 12 | "testing" 13 | 14 | "github.com/rs/zerolog" 15 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 16 | ) 17 | 18 | func TestGetRunningServerImage(t *testing.T) { 19 | type dataType struct { 20 | err error 21 | out string 22 | expected string 23 | } 24 | data := []dataType{ 25 | {nil, "registry.opensuse.org/uyuni/server:latest\n", "registry.opensuse.org/uyuni/server:latest"}, 26 | {errors.New("deployment not found"), "", ""}, 27 | } 28 | 29 | for i, test := range data { 30 | runCmdOutput = func(_ zerolog.Level, _ string, _ ...string) ([]byte, error) { 31 | return []byte(test.out), test.err 32 | } 33 | actual := getRunningServerImage("myns") 34 | testutils.AssertEquals(t, fmt.Sprintf("test %d: unexpected result", i), test.expected, actual) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | { 5 | "name": "uyuni-tools-devcontainer", 6 | "build": { "dockerfile": "Dockerfile" }, 7 | 8 | // Configure tool-specific properties. 9 | "customizations": { 10 | "vscode": { 11 | "extensions": [ 12 | "aldijav.golangwithdidi", 13 | "golang.go", 14 | "NeonXP.gotools", 15 | "honnamkuan.golang-snippets", 16 | "RVSmartPorting.rpm-spec-ext", 17 | "ms-vscode-remote.remote-containers" 18 | ] 19 | } 20 | }, 21 | "postCreateCommand": "curl -fLo \"${XDG_DATA_HOME:-$HOME/.local/share}\"/nvim/site/autoload/plug.vim --create-dirs https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim && echo \"alias vim='nvim -u .devcontainer/init.vim'\" >> ~/.bashrc && nvim -u ${containerWorkspaceFolder}/.devcontainer/init.vim +PlugInstall +qall && cd ${containerWorkspaceFolder} && go mod download && pre-commit install-hooks && ./install-hooks.sh" 22 | } 23 | -------------------------------------------------------------------------------- /locale/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # SPDX-FileCopyrightText: 2024 SUSE LLC 4 | # 5 | # SPDX-License-Identifier: Apache-2.0 6 | 7 | PREFIX=$1 8 | locales_dir=$(dirname $0)/ 9 | if test "x${PREFIX}" == "x"; then 10 | PREFIX=${locales_dir} 11 | fi 12 | 13 | for domain in mgrctl mgradm mgrpxy; do 14 | for po_file in `ls ${locales_dir}/${domain}/*.po`; do 15 | lang=$(basename ${po_file} | sed 's/\.po$//') 16 | locale_dir=${PREFIX}${lang}/LC_MESSAGES 17 | install -vd -m 0755 ${locale_dir} 18 | 19 | if test -e ${locales_dir}/shared/${lang}.po; then 20 | msgcat -o ${locale_dir}/${domain}.po ${po_file} ${locales_dir}/shared/${lang}.po 21 | else 22 | cp ${po_file} ${locale_dir}/${domain}.po 23 | fi 24 | msgfmt -c -o ${locale_dir}/${domain}.mo ${locale_dir}/${domain}.po 25 | if test $? -ne 0; 26 | then 27 | echo "Broken ${po_file}" 28 | exit 1 29 | fi 30 | rm ${locale_dir}/${domain}.po 31 | done 32 | done 33 | -------------------------------------------------------------------------------- /mgrpxy/cmd/cache/kubernetes.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package cache 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/shared" 10 | "github.com/uyuni-project/uyuni-tools/shared/kubernetes" 11 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | "github.com/uyuni-project/uyuni-tools/shared/utils" 14 | ) 15 | 16 | func kubernetesCacheClear( 17 | _ *types.GlobalFlags, 18 | _ *cacheClearFlags, 19 | _ *cobra.Command, 20 | _ []string, 21 | ) error { 22 | cnx := shared.NewConnection("kubectl", "squid", kubernetes.ProxyFilter) 23 | namespace, err := cnx.GetNamespace("") 24 | if err != nil { 25 | return utils.Errorf(err, L("failed retrieving namespace")) 26 | } 27 | 28 | if _, err := cnx.Exec("find", "/var/cache/squid", "-mindepth", "1", "-delete"); err != nil { 29 | return utils.Errorf(err, L("failed to remove cached data")) 30 | } 31 | 32 | return kubernetes.Restart(namespace, kubernetes.ProxyApp) 33 | } 34 | -------------------------------------------------------------------------------- /mgradm/cmd/gpg/list/gpg_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package gpglist 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | ) 14 | 15 | func TestParamsParsing(t *testing.T) { 16 | args := []string{ 17 | "--system", 18 | "--backend", "kubectl", 19 | } 20 | 21 | // Test function asserting that the args are properly parsed 22 | tester := func(_ *types.GlobalFlags, flags *gpgListFlags, _ *cobra.Command, _ []string) error { 23 | testutils.AssertTrue(t, "Error parsing --system", flags.System) 24 | testutils.AssertEquals(t, "Error parsing --backend", "kubectl", flags.Backend) 25 | return nil 26 | } 27 | 28 | globalFlags := types.GlobalFlags{} 29 | cmd := newCmd(&globalFlags, tester) 30 | 31 | testutils.AssertHasAllFlags(t, cmd, args) 32 | 33 | cmd.SetArgs(args) 34 | if err := cmd.Execute(); err != nil { 35 | t.Errorf("command failed with error: %s", err) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /mgrctl/cmd/proxy/proxy.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package proxy 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 10 | "github.com/uyuni-project/uyuni-tools/shared/types" 11 | ) 12 | 13 | // NewCommand entry command for managing cache. 14 | // Setup for subcommand to clear (the cache). 15 | func NewCommand(globalFlags *types.GlobalFlags) *cobra.Command { 16 | var cmd = &cobra.Command{ 17 | Use: "proxy", 18 | Short: L("Manage proxy configurations"), 19 | Long: L("Manage proxy configurations"), 20 | Run: func(cmd *cobra.Command, _ []string) { 21 | _ = cmd.Help() 22 | }, 23 | } 24 | 25 | var createCmd = &cobra.Command{ 26 | Use: "create", 27 | Short: L("Create proxy configurations"), 28 | Long: L("Create proxy configurations"), 29 | Run: func(cmd *cobra.Command, _ []string) { 30 | _ = cmd.Help() 31 | }, 32 | } 33 | 34 | createCmd.AddCommand(NewConfigCommand(globalFlags)) 35 | 36 | cmd.AddCommand(createCmd) 37 | return cmd 38 | } 39 | -------------------------------------------------------------------------------- /mgradm/cmd/support/support.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package support 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/mgradm/cmd/support/config" 10 | "github.com/uyuni-project/uyuni-tools/mgradm/cmd/support/ptf" 11 | "github.com/uyuni-project/uyuni-tools/mgradm/cmd/support/sql" 12 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 13 | "github.com/uyuni-project/uyuni-tools/shared/types" 14 | ) 15 | 16 | // NewCommand to export supportconfig. 17 | func NewCommand(globalFlags *types.GlobalFlags) *cobra.Command { 18 | supportCmd := &cobra.Command{ 19 | Use: "support", 20 | GroupID: "tool", 21 | Short: L("Commands for support operations"), 22 | Long: L("Commands for support operations"), 23 | } 24 | supportCmd.AddCommand(config.NewCommand(globalFlags)) 25 | supportCmd.AddCommand(sql.NewCommand(globalFlags)) 26 | if ptfCommand := ptf.NewCommand(globalFlags); ptfCommand != nil { 27 | supportCmd.AddCommand(ptfCommand) 28 | } 29 | 30 | return supportCmd 31 | } 32 | -------------------------------------------------------------------------------- /mgradm/shared/kubernetes/certificates_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | //go:build !nok8s 6 | 7 | package kubernetes 8 | 9 | import ( 10 | "errors" 11 | "fmt" 12 | "testing" 13 | 14 | "github.com/rs/zerolog" 15 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 16 | ) 17 | 18 | func TestHasIssuer(t *testing.T) { 19 | type testType struct { 20 | out string 21 | err error 22 | expected bool 23 | } 24 | 25 | data := []testType{ 26 | { 27 | out: "issuer.cert-manager.io/someissuer\n", 28 | err: nil, 29 | expected: true, 30 | }, 31 | { 32 | out: "any error\n", 33 | err: errors.New("Any error"), 34 | expected: false, 35 | }, 36 | } 37 | 38 | for i, test := range data { 39 | runCmdOutput = func(_ zerolog.Level, _ string, _ ...string) ([]byte, error) { 40 | return []byte(test.out), test.err 41 | } 42 | testutils.AssertEquals(t, fmt.Sprintf("test %d: unexpected result", i+1), test.expected, 43 | HasIssuer("somens", "someissuer"), 44 | ) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /mgrctl/cmd/proxy/utils_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package proxy 6 | 7 | import ( 8 | "path" 9 | "testing" 10 | 11 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 12 | ) 13 | 14 | // Test getFilename function. 15 | func TestGetFilename(t *testing.T) { 16 | // Test when output is empty 17 | filename := GetFilename("", "testProxy.domain.com") 18 | testutils.AssertEquals(t, "", "testProxy-config.tar.gz", filename) 19 | 20 | // Test when output is provided 21 | filename = GetFilename("customOutput", "testProxy.domain.com") 22 | testutils.AssertEquals(t, "", "customOutput.tar.gz", filename) 23 | 24 | // Test when output is provided 25 | filename = GetFilename("/var/customOutputWitPath", "testProxy.domain.com") 26 | testutils.AssertEquals(t, "", "/var/customOutputWitPath.tar.gz", filename) 27 | } 28 | 29 | func createTestFile(dir string, filename string, content string, t *testing.T) string { 30 | filepath := path.Join(dir, filename) 31 | testutils.WriteFile(t, filepath, content) 32 | return filepath 33 | } 34 | -------------------------------------------------------------------------------- /mgradm/cmd/gpg/add/gpg_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package gpgadd 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | ) 14 | 15 | func TestParamsParsing(t *testing.T) { 16 | args := []string{ 17 | "--force", 18 | "--backend", "kubectl", 19 | "path/to/key", 20 | } 21 | 22 | // Test function asserting that the args are properly parsed 23 | tester := func(_ *types.GlobalFlags, flags *gpgAddFlags, _ *cobra.Command, _ []string) error { 24 | testutils.AssertTrue(t, "Error parsing --force", flags.Force) 25 | testutils.AssertEquals(t, "Error parsing --backend", "kubectl", flags.Backend) 26 | return nil 27 | } 28 | 29 | globalFlags := types.GlobalFlags{} 30 | cmd := newCmd(&globalFlags, tester) 31 | 32 | testutils.AssertHasAllFlags(t, cmd, args) 33 | 34 | cmd.SetArgs(args) 35 | if err := cmd.Execute(); err != nil { 36 | t.Errorf("command failed with error: %s", err) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /mgrpxy/shared/kubernetes/cmd.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package kubernetes 6 | 7 | import ( 8 | "fmt" 9 | 10 | "github.com/spf13/cobra" 11 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | "github.com/uyuni-project/uyuni-tools/shared/utils" 14 | ) 15 | 16 | // HelmFlags it's used for helm chart flags. 17 | type HelmFlags struct { 18 | Proxy types.ChartFlags 19 | } 20 | 21 | // AddHelmFlags add helm flags to a command. 22 | func AddHelmFlags(cmd *cobra.Command) { 23 | defaultChart := fmt.Sprintf("oci://%s/%s", utils.DefaultHelmRegistry, utils.DefaultProxyChart) 24 | 25 | cmd.Flags().String("helm-proxy-namespace", "default", L("Kubernetes namespace where to install the proxy")) 26 | cmd.Flags().String("helm-proxy-chart", defaultChart, L("URL to the proxy helm chart")) 27 | cmd.Flags().String("helm-proxy-version", "", L("Version of the proxy helm chart")) 28 | cmd.Flags().String("helm-proxy-values", "", L("Path to a values YAML file to use for proxy helm install")) 29 | } 30 | -------------------------------------------------------------------------------- /mgradm/cmd/scale/podman.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package scale 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | 11 | "github.com/spf13/cobra" 12 | 13 | "github.com/uyuni-project/uyuni-tools/shared/podman" 14 | "github.com/uyuni-project/uyuni-tools/shared/types" 15 | 16 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 17 | ) 18 | 19 | var systemd podman.Systemd = podman.NewSystemd() 20 | 21 | func podmanScale( 22 | _ *types.GlobalFlags, 23 | flags *scaleFlags, 24 | _ *cobra.Command, 25 | args []string, 26 | ) error { 27 | newReplicas := flags.Replicas 28 | service := args[0] 29 | if service == podman.ServerAttestationService { 30 | return systemd.ScaleService(newReplicas, service) 31 | } 32 | if service == podman.HubXmlrpcService || service == podman.SalineService { 33 | if newReplicas > 1 { 34 | return errors.New(L("Multiple container replicas are not currently supported.")) 35 | } 36 | return systemd.ScaleService(newReplicas, service) 37 | } 38 | return fmt.Errorf(L("service not allowing to be scaled: %s"), service) 39 | } 40 | -------------------------------------------------------------------------------- /mgrpxy/cmd/status/podman.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package status 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | 11 | "github.com/rs/zerolog" 12 | "github.com/rs/zerolog/log" 13 | "github.com/spf13/cobra" 14 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 15 | "github.com/uyuni-project/uyuni-tools/shared/types" 16 | "github.com/uyuni-project/uyuni-tools/shared/utils" 17 | ) 18 | 19 | func podmanStatus( 20 | _ *types.GlobalFlags, 21 | _ *statusFlags, 22 | _ *cobra.Command, 23 | _ []string, 24 | ) error { 25 | var returnErr error 26 | services := []string{"httpd", "salt-broker", "squid", "ssh", "tftpd", "pod"} 27 | for _, service := range services { 28 | serviceName := fmt.Sprintf("uyuni-proxy-%s", service) 29 | if err := utils.RunCmdStdMapping(zerolog.DebugLevel, "systemctl", "status", "--no-pager", serviceName); err != nil { 30 | log.Error().Err(err).Msgf(L("Failed to get status of the %s service"), serviceName) 31 | returnErr = errors.New(L("failed to get the status of at least one service")) 32 | } 33 | } 34 | return returnErr 35 | } 36 | -------------------------------------------------------------------------------- /shared/api/org/getDetails.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package org 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | 11 | "github.com/uyuni-project/uyuni-tools/shared/api" 12 | "github.com/uyuni-project/uyuni-tools/shared/api/types" 13 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 14 | "github.com/uyuni-project/uyuni-tools/shared/utils" 15 | ) 16 | 17 | // GetOrganizationDetails gets details of organization based on organization name. 18 | func GetOrganizationDetails(cnxDetails *api.ConnectionDetails, orgName string) (*types.Organization, error) { 19 | client, err := api.Init(cnxDetails) 20 | if err == nil { 21 | err = client.Login() 22 | } 23 | if err != nil { 24 | return nil, utils.Errorf(err, L("failed to connect to the server")) 25 | } 26 | res, err := api.Get[types.Organization](client, fmt.Sprintf("org/getDetails?name=%s", orgName)) 27 | if err != nil { 28 | return nil, utils.Errorf(err, L("failed to get organization details")) 29 | } 30 | if !res.Success { 31 | return nil, errors.New(res.Message) 32 | } 33 | 34 | return &res.Result, nil 35 | } 36 | -------------------------------------------------------------------------------- /LICENSES/MIT.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Brad Erickson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /mgradm/cmd/start/start_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package start 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | "github.com/uyuni-project/uyuni-tools/shared/utils" 14 | ) 15 | 16 | func TestParamsParsing(t *testing.T) { 17 | args := []string{} 18 | if utils.KubernetesBuilt { 19 | args = append(args, "--backend", "kubectl") 20 | } 21 | 22 | // Test function asserting that the args are properly parsed 23 | tester := func(_ *types.GlobalFlags, flags *startFlags, _ *cobra.Command, _ []string) error { 24 | if utils.KubernetesBuilt { 25 | testutils.AssertEquals(t, "Error parsing --backend", "kubectl", flags.Backend) 26 | } 27 | return nil 28 | } 29 | 30 | globalFlags := types.GlobalFlags{} 31 | cmd := newCmd(&globalFlags, tester) 32 | 33 | testutils.AssertHasAllFlags(t, cmd, args) 34 | 35 | cmd.SetArgs(args) 36 | if err := cmd.Execute(); err != nil { 37 | t.Errorf("command failed with error: %s", err) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /mgradm/shared/templates/tlsSecret.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package templates 6 | 7 | import ( 8 | "io" 9 | "text/template" 10 | 11 | "github.com/uyuni-project/uyuni-tools/shared/kubernetes" 12 | ) 13 | 14 | // Deploy self-signed issuer or CA Certificate and key. 15 | const tlsSecretTemplate = `apiVersion: v1 16 | kind: Secret 17 | type: kubernetes.io/tls 18 | metadata: 19 | name: {{ .Name }} 20 | namespace: {{ .Namespace }} 21 | labels: 22 | app: ` + kubernetes.ServerApp + ` 23 | data: 24 | ca.crt: {{ .RootCa }} 25 | tls.crt: {{ .Certificate }} 26 | tls.key: {{ .Key }} 27 | ` 28 | 29 | // TLSSecretTemplateData contains information to create secret configuration file. 30 | type TLSSecretTemplateData struct { 31 | Name string 32 | Namespace string 33 | RootCa string 34 | Certificate string 35 | Key string 36 | } 37 | 38 | // Render creates secret configuration file. 39 | func (data TLSSecretTemplateData) Render(wr io.Writer) error { 40 | t := template.Must(template.New("secret").Parse(tlsSecretTemplate)) 41 | return t.Execute(wr, data) 42 | } 43 | -------------------------------------------------------------------------------- /shared/api/proxy/model.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package proxy 6 | 7 | // Models/Schemas for the proxy API. 8 | 9 | // ProxyConfigRequest is the request schema for the proxy/containerConfig endpoint when 10 | // user has proxy certificates. 11 | type ProxyConfigRequest struct { 12 | ProxyName string 13 | ProxyPort int 14 | Server string 15 | MaxCache int 16 | Email string 17 | RootCA string 18 | ProxyCrt string 19 | ProxyKey string 20 | IntermediateCAs []string 21 | } 22 | 23 | // ProxyConfigGenerateRequest is the request schema for the proxy/containerConfig endpoint when 24 | // user wants to generate proxy certificates. 25 | type ProxyConfigGenerateRequest struct { 26 | ProxyName string 27 | ProxyPort int 28 | Server string 29 | MaxCache int 30 | Email string 31 | CaCrt string 32 | CaKey string 33 | CaPassword string 34 | Cnames []string 35 | Country string 36 | State string 37 | City string 38 | Org string 39 | OrgUnit string 40 | SSLEmail string 41 | } 42 | -------------------------------------------------------------------------------- /mgradm/cmd/stop/stop_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package stop 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | "github.com/uyuni-project/uyuni-tools/shared/utils" 14 | ) 15 | 16 | func TestParamsParsing(t *testing.T) { 17 | args := []string{} 18 | if utils.KubernetesBuilt { 19 | args = append(args, "--backend", "kubectl") 20 | } 21 | 22 | // Test function asserting that the args are properly parsed 23 | tester := func(_ *types.GlobalFlags, flags *stopFlags, 24 | _ *cobra.Command, _ []string, 25 | ) error { 26 | if utils.KubernetesBuilt { 27 | testutils.AssertEquals(t, "Error parsing --backend", "kubectl", flags.Backend) 28 | } 29 | return nil 30 | } 31 | 32 | globalFlags := types.GlobalFlags{} 33 | cmd := newCmd(&globalFlags, tester) 34 | 35 | testutils.AssertHasAllFlags(t, cmd, args) 36 | 37 | cmd.SetArgs(args) 38 | if err := cmd.Execute(); err != nil { 39 | t.Errorf("command failed with error: %s", err) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /mgradm/cmd/support/config/config_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package config 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | ) 14 | 15 | func TestParamsParsing(t *testing.T) { 16 | args := []string{ 17 | "--output", "path/to/output.tar.gz", 18 | "--backend", "kubectl", 19 | } 20 | 21 | // Test function asserting that the args are properly parsed 22 | tester := func(_ *types.GlobalFlags, flags *configFlags, 23 | _ *cobra.Command, _ []string, 24 | ) error { 25 | testutils.AssertEquals(t, "Error parsing --output", "path/to/output.tar.gz", flags.Output) 26 | testutils.AssertEquals(t, "Error parsing --backend", "kubectl", flags.Backend) 27 | return nil 28 | } 29 | 30 | globalFlags := types.GlobalFlags{} 31 | cmd := newCmd(&globalFlags, tester) 32 | 33 | testutils.AssertHasAllFlags(t, cmd, args) 34 | 35 | cmd.SetArgs(args) 36 | if err := cmd.Execute(); err != nil { 37 | t.Errorf("command failed with error: %s", err) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /mgrpxy/cmd/support/config/config_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package config 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | ) 14 | 15 | func TestParamsParsing(t *testing.T) { 16 | args := []string{ 17 | "--output", "path/to/output.tar.gz", 18 | "--backend", "kubectl", 19 | } 20 | 21 | // Test function asserting that the args are properly parsed 22 | tester := func(_ *types.GlobalFlags, flags *configFlags, 23 | _ *cobra.Command, _ []string, 24 | ) error { 25 | testutils.AssertEquals(t, "Error parsing --output", "path/to/output.tar.gz", flags.Output) 26 | testutils.AssertEquals(t, "Error parsing --backend", "kubectl", flags.Backend) 27 | return nil 28 | } 29 | 30 | globalFlags := types.GlobalFlags{} 31 | cmd := newCmd(&globalFlags, tester) 32 | 33 | testutils.AssertHasAllFlags(t, cmd, args) 34 | 35 | cmd.SetArgs(args) 36 | if err := cmd.Execute(); err != nil { 37 | t.Errorf("command failed with error: %s", err) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /mgradm/cmd/restart/restart_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package restart 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | "github.com/uyuni-project/uyuni-tools/shared/utils" 14 | ) 15 | 16 | func TestParamsParsing(t *testing.T) { 17 | args := []string{} 18 | if utils.KubernetesBuilt { 19 | args = append(args, "--backend", "kubectl") 20 | } 21 | 22 | // Test function asserting that the args are properly parsed 23 | tester := func(_ *types.GlobalFlags, flags *restartFlags, 24 | _ *cobra.Command, _ []string, 25 | ) error { 26 | if utils.KubernetesBuilt { 27 | testutils.AssertEquals(t, "Error parsing --backend", "kubectl", flags.Backend) 28 | } 29 | return nil 30 | } 31 | 32 | globalFlags := types.GlobalFlags{} 33 | cmd := newCmd(&globalFlags, tester) 34 | 35 | testutils.AssertHasAllFlags(t, cmd, args) 36 | 37 | cmd.SetArgs(args) 38 | if err := cmd.Execute(); err != nil { 39 | t.Errorf("command failed with error: %s", err) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /shared/testutils/flagstests/api.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package flagstests 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/uyuni-project/uyuni-tools/shared/api" 11 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 12 | ) 13 | 14 | // APIFlagsTestArgs is the slice of parameters to use with AssertAPIFlags. 15 | var APIFlagsTestArgs = []string{ 16 | "--api-server", "mysrv", 17 | "--api-user", "apiuser", 18 | "--api-password", "api-pass", 19 | "--api-cacert", "path/to/ca.crt", 20 | "--api-insecure", 21 | } 22 | 23 | // AssertAPIFlags checks that all API parameters are parsed correctly. 24 | func AssertAPIFlags(t *testing.T, flags *api.ConnectionDetails) { 25 | testutils.AssertEquals(t, "Error parsing --api-server", "mysrv", flags.Server) 26 | testutils.AssertEquals(t, "Error parsing --api-user", "apiuser", flags.User) 27 | testutils.AssertEquals(t, "Error parsing --api-password", "api-pass", flags.Password) 28 | testutils.AssertEquals(t, "Error parsing --api-cacert", "path/to/ca.crt", flags.CApath) 29 | testutils.AssertTrue(t, "Error parsing --api-insecure", flags.Insecure) 30 | } 31 | -------------------------------------------------------------------------------- /mgradm/shared/utils/flags_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package utils 6 | 7 | import "testing" 8 | 9 | func TestIdChecker(t *testing.T) { 10 | data := map[string]bool{ 11 | "foo": true, 12 | "foo bar": false, 13 | "\u798f": false, 14 | "foo123._-": true, 15 | "foo+": false, 16 | "foo&": false, 17 | "foo'": false, 18 | "foo\"": false, 19 | "foo`": false, 20 | "foo=": false, 21 | "foo#": false, 22 | } 23 | for value, expected := range data { 24 | actual := idChecker(value) 25 | if actual != expected { 26 | t.Errorf("%s: expected %v got %v", value, expected, actual) 27 | } 28 | } 29 | } 30 | 31 | func TestEmailChecker(t *testing.T) { 32 | data := map[string]bool{ 33 | "root@localhost": true, 34 | "joe.hacker@foo.bar.com": true, 35 | "": false, 36 | "fooo": false, 37 | } 38 | for value, expected := range data { 39 | actual := emailChecker(value) 40 | if actual != expected { 41 | t.Errorf("%s: expected %v got %v", value, expected, actual) 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /shared/templates/inspectTemplate.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package templates 6 | 7 | import ( 8 | "io" 9 | "strings" 10 | "text/template" 11 | 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | ) 14 | 15 | const inspectTemplate = ` 16 | # inspect.sh, generated by mgradm 17 | {{- range .Values }} 18 | echo "{{ .Variable }}=$({{ .CLI }})" 19 | {{- end }} 20 | exit 0 21 | ` 22 | 23 | // InspectTemplateData represents information used to create inspect script. 24 | type InspectTemplateData struct { 25 | Values []types.InspectData 26 | } 27 | 28 | // Render will create inspect script. 29 | func (data InspectTemplateData) Render(wr io.Writer) error { 30 | t := template.Must(template.New("inspect").Parse(inspectTemplate)) 31 | return t.Execute(wr, data) 32 | } 33 | 34 | // GenerateScriptString creates the inspector script and returns it as a string. 35 | func (data InspectTemplateData) GenerateScript() (string, error) { 36 | scriptBuilder := new(strings.Builder) 37 | if err := data.Render(scriptBuilder); err != nil { 38 | return "", err 39 | } 40 | 41 | return scriptBuilder.String(), nil 42 | } 43 | -------------------------------------------------------------------------------- /mgrctl/cmd/term/term.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package term 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/mgrctl/cmd/exec" 10 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 11 | "github.com/uyuni-project/uyuni-tools/shared/types" 12 | "github.com/uyuni-project/uyuni-tools/shared/utils" 13 | ) 14 | 15 | var newExecCmd = exec.NewCommand 16 | 17 | // NewCommand returns a new cobra.Command for term. 18 | func NewCommand(globalFlags *types.GlobalFlags) *cobra.Command { 19 | cmd := &cobra.Command{ 20 | Use: "term", 21 | Short: L("Run a terminal inside the server container"), 22 | RunE: func(cmd *cobra.Command, _ []string) error { 23 | execCmd := newExecCmd(globalFlags) 24 | execArgs := []string{"-i", "-t"} 25 | backend, err := cmd.Flags().GetString("backend") 26 | if err == nil { 27 | execArgs = append(execArgs, "--backend", backend) 28 | } 29 | if err := execCmd.Flags().Parse(execArgs); err != nil { 30 | return err 31 | } 32 | return execCmd.RunE(execCmd, []string{"bash"}) 33 | }, 34 | } 35 | 36 | utils.AddBackendFlag(cmd) 37 | return cmd 38 | } 39 | -------------------------------------------------------------------------------- /shared/kubernetes/deploy.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package kubernetes 6 | 7 | import ( 8 | "strconv" 9 | "strings" 10 | 11 | "github.com/rs/zerolog" 12 | ) 13 | 14 | // HasDeployment returns true when a deployment matching the kubectl get filter is existing in the namespace. 15 | func HasDeployment(namespace string, filter string) bool { 16 | out, err := runCmdOutput(zerolog.DebugLevel, "kubectl", "get", "deploy", "-n", namespace, filter, "-o", "name") 17 | if err == nil && strings.TrimSpace(string(out)) != "" { 18 | return true 19 | } 20 | return false 21 | } 22 | 23 | // GetReplicas return the number of replicas of a deployment. 24 | // 25 | // If no such deployment exists, 0 will be returned as if there was a deployment scaled down to 0. 26 | func GetReplicas(namespace string, name string) int { 27 | out, err := runCmdOutput(zerolog.DebugLevel, 28 | "kubectl", "get", "deploy", "-n", namespace, name, "-o", "jsonpath={.status.replicas}", 29 | ) 30 | if err != nil { 31 | return 0 32 | } 33 | replicas, err := strconv.Atoi(strings.TrimSpace(string(out))) 34 | if err != nil { 35 | return 0 36 | } 37 | return replicas 38 | } 39 | -------------------------------------------------------------------------------- /shared/kubernetes/converters.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package kubernetes 6 | 7 | import ( 8 | "github.com/uyuni-project/uyuni-tools/shared/types" 9 | core "k8s.io/api/core/v1" 10 | ) 11 | 12 | // ConvertVolumeMounts converts the internal volume mounts into Kubernetes' ones. 13 | func ConvertVolumeMounts(mounts []types.VolumeMount) []core.VolumeMount { 14 | res := []core.VolumeMount{} 15 | 16 | for _, mount := range mounts { 17 | converted := core.VolumeMount{ 18 | Name: mount.Name, 19 | MountPath: mount.MountPath, 20 | } 21 | res = append(res, converted) 22 | } 23 | 24 | return res 25 | } 26 | 27 | // ConvertPortMaps converts the internal port maps to Kubernetes ContainerPorts. 28 | func ConvertPortMaps(ports []types.PortMap) []core.ContainerPort { 29 | res := []core.ContainerPort{} 30 | 31 | for _, port := range ports { 32 | protocol := core.ProtocolTCP 33 | if port.Protocol == "udp" { 34 | protocol = core.ProtocolUDP 35 | } 36 | converted := core.ContainerPort{ 37 | ContainerPort: int32(port.Exposed), 38 | Protocol: protocol, 39 | } 40 | res = append(res, converted) 41 | } 42 | return res 43 | } 44 | -------------------------------------------------------------------------------- /mgradm/cmd/distro/distro_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package distro 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 12 | "github.com/uyuni-project/uyuni-tools/shared/testutils/flagstests" 13 | "github.com/uyuni-project/uyuni-tools/shared/types" 14 | ) 15 | 16 | func TestParamsParsing(t *testing.T) { 17 | args := []string{ 18 | "copy", 19 | "--channel", "parent-channel", 20 | } 21 | 22 | args = append(args, flagstests.APIFlagsTestArgs...) 23 | 24 | // Test function asserting that the args are properly parsed 25 | tester := func(_ *types.GlobalFlags, flags *flagpole, _ *cobra.Command, _ []string) error { 26 | testutils.AssertEquals(t, "Error parsing --channel", "parent-channel", flags.ChannelLabel) 27 | flagstests.AssertAPIFlags(t, &flags.ConnectionDetails) 28 | return nil 29 | } 30 | 31 | globalFlags := types.GlobalFlags{} 32 | cmd, _ := newCmd(&globalFlags, tester) 33 | 34 | testutils.AssertHasAllFlags(t, cmd, args) 35 | 36 | cmd.SetArgs(args) 37 | if err := cmd.Execute(); err != nil { 38 | t.Errorf("command failed with error: %s", err) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /shared/kubernetes/k3s_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package kubernetes 6 | 7 | import ( 8 | "testing" 9 | "time" 10 | 11 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 12 | "github.com/uyuni-project/uyuni-tools/shared/utils" 13 | ) 14 | 15 | // Test that the generated endpoints are valid for traefik. 16 | func TestGetTraefikEndpointName(t *testing.T) { 17 | ports := utils.GetServerPorts(true) 18 | ports = append(ports, utils.HubXmlrpcPorts...) 19 | ports = append(ports, utils.GetProxyPorts()...) 20 | 21 | for _, port := range ports { 22 | actual := GetTraefikEndpointName(port) 23 | // Traefik would fail if the name is longer than 15 characters 24 | if len(actual) > 15 { 25 | t.Errorf("Traefik endpoint name has more than 15 characters: %s", actual) 26 | } 27 | } 28 | } 29 | 30 | func TestWaitForTraefik(t *testing.T) { 31 | // Test that the time zone is properly handled 32 | installTime := time.Now().In(time.UTC).Add(time.Second * 42) 33 | newRunner = testutils.FakeRunnerGenerator(installTime.Format("2006-01-02T15:04:05Z"), nil) 34 | if err := waitForTraefik(); err != nil { 35 | t.Errorf("Unexpected error: %s", err) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /shared/testutils/files.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package testutils 6 | 7 | import ( 8 | "os" 9 | "testing" 10 | ) 11 | 12 | // WriteFile writes the content in a file at the given path and fails if anything wrong happens. 13 | func WriteFile(t *testing.T, path string, content string) { 14 | if err := os.WriteFile(path, []byte(content), 0755); err != nil { 15 | t.Fatalf("failed to write test file %s: %s", path, err) 16 | } 17 | } 18 | 19 | // ReadFile returns the content of a file as a string and fails is anything wrong happens. 20 | func ReadFile(t *testing.T, path string) string { 21 | content, err := os.ReadFile(path) 22 | if err != nil { 23 | t.Fatalf("failed to read file %s: %s", path, err) 24 | } 25 | return string(content) 26 | } 27 | 28 | // ReadFileAsBinary returns the content of a file as a slice of int8. 29 | func ReadFileAsBinary(t *testing.T, path string) []int8 { 30 | content, err := os.ReadFile(path) 31 | if err != nil { 32 | t.Fatalf("failed to read file %s: %s", path, err) 33 | } 34 | 35 | int8Content := make([]int8, len(content)) 36 | for i, b := range content { 37 | int8Content[i] = int8(b) 38 | } 39 | 40 | return int8Content 41 | } 42 | -------------------------------------------------------------------------------- /mgrpxy/cmd/logs/podman.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package logs 6 | 7 | import ( 8 | "fmt" 9 | 10 | "github.com/rs/zerolog" 11 | "github.com/spf13/cobra" 12 | "github.com/uyuni-project/uyuni-tools/shared/podman" 13 | "github.com/uyuni-project/uyuni-tools/shared/types" 14 | "github.com/uyuni-project/uyuni-tools/shared/utils" 15 | ) 16 | 17 | func podmanLogs( 18 | _ *types.GlobalFlags, 19 | flags *logsFlags, 20 | _ *cobra.Command, 21 | args []string, 22 | ) error { 23 | commandArgs := []string{"logs"} 24 | if flags.Follow { 25 | commandArgs = append(commandArgs, "-f") 26 | } 27 | 28 | if flags.Tail != -1 { 29 | commandArgs = append(commandArgs, "--tail="+fmt.Sprintf("%d", flags.Tail)) 30 | } 31 | 32 | if flags.Timestamps { 33 | commandArgs = append(commandArgs, "--timestamps") 34 | } 35 | 36 | if flags.Since != "" { 37 | commandArgs = append(commandArgs, fmt.Sprintf("--since=%s", flags.Since)) 38 | } 39 | 40 | if len(flags.Containers) == 0 { 41 | commandArgs = append(commandArgs, podman.ProxyContainerNames...) 42 | } else { 43 | commandArgs = append(commandArgs, args...) 44 | } 45 | 46 | return utils.RunCmdStdMapping(zerolog.DebugLevel, "podman", commandArgs...) 47 | } 48 | -------------------------------------------------------------------------------- /mgrpxy/cmd/cache/clear.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package cache 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/shared" 10 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 11 | "github.com/uyuni-project/uyuni-tools/shared/types" 12 | "github.com/uyuni-project/uyuni-tools/shared/utils" 13 | ) 14 | 15 | type cacheClearFlags struct { 16 | } 17 | 18 | // NewClearCmd creates the command to clear the cache. 19 | func NewClearCmd(globalFlags *types.GlobalFlags) *cobra.Command { 20 | var clearCmd = &cobra.Command{ 21 | Use: "clear", 22 | Short: L("Clear the cache"), 23 | Long: L("Clear the cache"), 24 | RunE: func(cmd *cobra.Command, args []string) error { 25 | var flags cacheClearFlags 26 | return utils.CommandHelper(globalFlags, cmd, args, &flags, nil, clearCmd) 27 | }, 28 | } 29 | 30 | return clearCmd 31 | } 32 | 33 | func clearCmd(globalFlags *types.GlobalFlags, flags *cacheClearFlags, cmd *cobra.Command, args []string) error { 34 | fn, err := shared.ChooseProxyPodmanOrKubernetes(cmd.Flags(), podmanCacheClear, kubernetesCacheClear) 35 | if err != nil { 36 | return err 37 | } 38 | 39 | return fn(globalFlags, flags, cmd, args) 40 | } 41 | -------------------------------------------------------------------------------- /mgradm/shared/templates/pgsqlMigrateScriptTemplate.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package templates 6 | 7 | import ( 8 | "io" 9 | "text/template" 10 | ) 11 | 12 | //nolint:lll 13 | const pgsqlMigrationScriptTemplate = ` 14 | set -e -x 15 | 16 | if [ -d /var/lib/pgsql/data/data ] ; then 17 | shopt -s dotglob 18 | rsync -a --exclude=/var/lib/pgsql/data/data/pg_hba.conf /var/lib/pgsql/data/data/ /var/lib/pgsql/data/ 2>/dev/null 19 | rm -rf /var/lib/pgsql/data/data 20 | fi 21 | 22 | {{ if .ReportDBHost }} 23 | sed 's/^report_db_host = .*/report_db_host = {{ .ReportDBHost }}/' -i /etc/rhn/rhn.conf; 24 | {{ end }} 25 | 26 | {{ if .DBHost }} 27 | sed 's/^db_host = .*/db_host = {{ .DBHost }}/' -i /etc/rhn/rhn.conf; 28 | {{ end }} 29 | 30 | echo "DONE"` 31 | 32 | // MigrateScriptTemplateData represents migration information used to create migration script. 33 | type PgsqlMigrateScriptTemplateData struct { 34 | DBHost string 35 | ReportDBHost string 36 | } 37 | 38 | // Render will create migration script. 39 | func (data PgsqlMigrateScriptTemplateData) Render(wr io.Writer) error { 40 | t := template.Must(template.New("script").Parse(pgsqlMigrationScriptTemplate)) 41 | return t.Execute(wr, data) 42 | } 43 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 SUSE LLC 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | FROM registry.opensuse.org/opensuse/tumbleweed:latest 6 | 7 | RUN set -euo pipefail; \ 8 | curl -o uyuni-tools.gpg https://build.opensuse.org/projects/systemsmanagement:Uyuni:Utils/signing_keys/download?kind=gpg && \ 9 | rpm --import uyuni-tools.gpg && \ 10 | zypper ar https://download.opensuse.org/repositories/systemsmanagement:/Uyuni:/Utils/openSUSE_Tumbleweed/ uyuni-utils && \ 11 | zypper -n in \ 12 | awk \ 13 | bash-completion \ 14 | curl \ 15 | gettext-tools \ 16 | git-core \ 17 | go1.23 \ 18 | go1.23-doc \ 19 | gpg2 \ 20 | grep \ 21 | less \ 22 | neovim \ 23 | openssh \ 24 | python313 \ 25 | python313-pre-commit \ 26 | sed \ 27 | uyuni-releng-tools \ 28 | util-linux 29 | 30 | RUN curl -sSfL https://github.com/golangci/golangci-lint/releases/download/v1.64.8/golangci-lint-1.64.8-linux-amd64.tar.gz | tar -xz && \ 31 | mv golangci-lint-1.64.8-linux-amd64/golangci-lint /usr/local/bin/ && \ 32 | rm -rf golangci-lint-1.64.8-linux-amd64 33 | 34 | RUN set -euo pipefail; zypper -n clean -a; \ 35 | rm -rf {/target,}/var/log/{alternatives.log,lastlog,tallylog,zypper.log,zypp/history,YaST2} 36 | -------------------------------------------------------------------------------- /mgrpxy/cmd/support/ptf/kubernetes/kubernetes_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | //go:build ptf 5 | 6 | package kubernetes 7 | 8 | import ( 9 | "testing" 10 | 11 | "github.com/spf13/cobra" 12 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 13 | "github.com/uyuni-project/uyuni-tools/shared/testutils/flagstests" 14 | "github.com/uyuni-project/uyuni-tools/shared/types" 15 | ) 16 | 17 | func TestParamsParsing(t *testing.T) { 18 | args := []string{} 19 | 20 | args = append(args, flagstests.ImageProxyFlagsTestArgs...) 21 | args = append(args, flagstests.ProxyHelmFlagsTestArgs...) 22 | 23 | // Test function asserting that the args are properly parsed 24 | tester := func(_ *types.GlobalFlags, flags *kubernetesPTFFlags, 25 | _ *cobra.Command, _ []string, 26 | ) error { 27 | flagstests.AssertProxyImageFlags(t, &flags.UpgradeFlags.ProxyImageFlags) 28 | flagstests.AssertProxyHelmFlags(t, &flags.UpgradeFlags.Helm) 29 | return nil 30 | } 31 | 32 | globalFlags := types.GlobalFlags{} 33 | cmd := newCmd(&globalFlags, tester) 34 | 35 | testutils.AssertHasAllFlags(t, cmd, args) 36 | 37 | cmd.SetArgs(args) 38 | if err := cmd.Execute(); err != nil { 39 | t.Errorf("command failed with error: %s", err) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /shared/kubernetes/inspect.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | //go:build !nok8s 6 | 7 | package kubernetes 8 | 9 | import ( 10 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 11 | "github.com/uyuni-project/uyuni-tools/shared/types" 12 | "github.com/uyuni-project/uyuni-tools/shared/utils" 13 | ) 14 | 15 | // InspectServer check values on a given image and deploy. 16 | func InspectServer( 17 | namespace string, 18 | serverImage string, 19 | pullPolicy string, 20 | pullSecret string, 21 | ) (*utils.ServerInspectData, error) { 22 | podName := "uyuni-image-inspector" 23 | 24 | inspector := utils.NewServerInspector() 25 | script, err := inspector.GenerateScript() 26 | if err != nil { 27 | return nil, err 28 | } 29 | 30 | out, err := RunPodLogs( 31 | namespace, podName, serverImage, pullPolicy, pullSecret, 32 | []types.VolumeMount{utils.EtcRhnVolumeMount, utils.VarPgsqlDataVolumeMount}, 33 | "sh", "-c", script, 34 | ) 35 | if err != nil { 36 | return nil, err 37 | } 38 | 39 | // Parse the data 40 | inspectedData, err := utils.ReadInspectData[utils.ServerInspectData]([]byte(out)) 41 | if err != nil { 42 | return nil, utils.Errorf(err, L("failed to parse the inspected data")) 43 | } 44 | return inspectedData, nil 45 | } 46 | -------------------------------------------------------------------------------- /shared/kubernetes/rke2NginxTemplate.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package kubernetes 6 | 7 | import ( 8 | "io" 9 | "text/template" 10 | 11 | "github.com/uyuni-project/uyuni-tools/shared/types" 12 | ) 13 | 14 | const rke2NginxConfigTemplate = `apiVersion: helm.cattle.io/v1 15 | kind: HelmChartConfig 16 | metadata: 17 | name: rke2-ingress-nginx 18 | namespace: kube-system 19 | spec: 20 | valuesContent: |- 21 | controller: 22 | config: 23 | hsts: "false" 24 | tcp: 25 | {{- range .TCPPorts }} 26 | {{ .Exposed }}: "{{ $.Namespace }}/uyuni-tcp:{{ .Port }}" 27 | {{- end }} 28 | udp: 29 | {{- range .UDPPorts }} 30 | {{ .Exposed }}: "{{ $.Namespace }}/uyuni-udp:{{ .Port }}" 31 | {{- end }} 32 | ` 33 | 34 | // Rke2NginxConfigTemplateData represents information used to create Rke2 Ngix helm chart. 35 | type Rke2NginxConfigTemplateData struct { 36 | Namespace string 37 | TCPPorts []types.PortMap 38 | UDPPorts []types.PortMap 39 | } 40 | 41 | // Render will create the helm chart configuation for Rke2 Nginx. 42 | func (data Rke2NginxConfigTemplateData) Render(wr io.Writer) error { 43 | t := template.Must(template.New("rke2NginxConfig").Parse(rke2NginxConfigTemplate)) 44 | return t.Execute(wr, data) 45 | } 46 | -------------------------------------------------------------------------------- /shared/types/ssl.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package types 6 | 7 | // SSLCertGenerationFlags stores informations to generate an SSL Certificate. 8 | type SSLCertGenerationFlags struct { 9 | Cnames []string `mapstructure:"cname"` 10 | Country string 11 | State string 12 | City string 13 | Org string 14 | OU string 15 | Password string 16 | Email string 17 | } 18 | 19 | // CaChain is a type to store CA Chain. 20 | type CaChain struct { 21 | Root string 22 | Intermediate []string 23 | // Key is the CA key file in the case of a migration of a self-generate CA. 24 | Key string 25 | } 26 | 27 | // IsThirdParty returns whether the CA chain is a third party one. 28 | func (c *CaChain) IsThirdParty() bool { 29 | return c.IsDefined() && c.Key == "" 30 | } 31 | 32 | // IsDefined returns whether the CA chain is defined. 33 | // At least the CA root certificate is available. 34 | func (c *CaChain) IsDefined() bool { 35 | return c.Root != "" 36 | } 37 | 38 | // SSLPair is a type for SSL Cert and Key. 39 | type SSLPair struct { 40 | Cert string 41 | Key string 42 | } 43 | 44 | // IsDefined returns whether the SSL pair is defined. 45 | func (p *SSLPair) IsDefined() bool { 46 | return p.Cert != "" && p.Key != "" 47 | } 48 | -------------------------------------------------------------------------------- /shared/types/distro.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package types 6 | 7 | // Distribution contains information about the distribution. 8 | type Distribution struct { 9 | TreeLabel string 10 | BasePath string 11 | ChannelLabel string 12 | InstallType string 13 | } 14 | 15 | // DistributionDetails contains distro details passed from the command line. 16 | type DistributionDetails struct { 17 | Name string 18 | Version string 19 | Arch Arch 20 | } 21 | 22 | // ProductMap contains mapping of distro, version arch to the Distribution. 23 | type ProductMap map[string]map[string]map[Arch]Distribution 24 | 25 | // Arch type to store architecture. 26 | type Arch string 27 | 28 | // Constants for supported archhitectures. 29 | const ( 30 | UnknownArch Arch = "unknown" 31 | AMD64 Arch = "x86_64" 32 | AArch64 Arch = "aarch64" 33 | S390X Arch = "s390x" 34 | PPC64LE Arch = "ppc64le" 35 | ) 36 | 37 | // GetArch translates string representation of architecture to Arch type. 38 | func GetArch(a string) Arch { 39 | switch a { 40 | case "x86_64": 41 | return AMD64 42 | case "aarch64": 43 | return AArch64 44 | case "s390x": 45 | return S390X 46 | case "ppc64le": 47 | return PPC64LE 48 | } 49 | return UnknownArch 50 | } 51 | -------------------------------------------------------------------------------- /shared/types/images.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package types 6 | 7 | // ImageFlags represents the flags used by an image. 8 | type ImageFlags struct { 9 | Registry Registry `mapstructure:"registry"` 10 | Name string `mapstructure:"image"` 11 | Tag string `mapstructure:"tag"` 12 | PullPolicy string `mapstructure:"pullPolicy"` 13 | } 14 | 15 | // PgsqlFlags contains settings for Pgsql container. 16 | type PgsqlFlags struct { 17 | Replicas int 18 | Image ImageFlags `mapstructure:",squash"` 19 | IsChanged bool 20 | } 21 | 22 | // ImageMetadata represents the image metadata of an RPM image. 23 | type ImageMetadata struct { 24 | Name string `json:"name"` 25 | Tags []string `json:"tags"` 26 | File string `json:"file"` 27 | } 28 | 29 | // Metadata represents the metadata of an RPM image. 30 | type Metadata struct { 31 | Image ImageMetadata `json:"image"` 32 | } 33 | 34 | // SCCCredentials can store SCC Credentials. 35 | type SCCCredentials struct { 36 | User string `json:"user"` 37 | Password string `json:"password"` 38 | } 39 | 40 | // Registry can store registry information. 41 | type Registry struct { 42 | Host string `json:"host"` 43 | User string `json:"user"` 44 | Password string `json:"password"` 45 | } 46 | -------------------------------------------------------------------------------- /mgradm/cmd/support/config/config.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package config 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 10 | "github.com/uyuni-project/uyuni-tools/shared/types" 11 | "github.com/uyuni-project/uyuni-tools/shared/utils" 12 | ) 13 | 14 | type configFlags struct { 15 | Output string 16 | Backend string 17 | } 18 | 19 | func newCmd(globalFlags *types.GlobalFlags, run utils.CommandFunc[configFlags]) *cobra.Command { 20 | configCmd := &cobra.Command{ 21 | Use: "config", 22 | Short: L("Extract configuration and logs"), 23 | Long: L(`Extract the host or cluster configuration and logs as well as those from 24 | the containers for support to help debugging.`), 25 | RunE: func(cmd *cobra.Command, args []string) error { 26 | var flags configFlags 27 | return utils.CommandHelper(globalFlags, cmd, args, &flags, nil, run) 28 | }, 29 | } 30 | 31 | configCmd.Flags().StringP("output", "o", ".", L("path where to extract the data")) 32 | utils.AddBackendFlag(configCmd) 33 | 34 | return configCmd 35 | } 36 | 37 | // NewCommand is the command for creates supportconfig. 38 | func NewCommand(globalFlags *types.GlobalFlags) *cobra.Command { 39 | return newCmd(globalFlags, extract) 40 | } 41 | -------------------------------------------------------------------------------- /mgrpxy/cmd/support/config/config.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package config 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 10 | "github.com/uyuni-project/uyuni-tools/shared/types" 11 | "github.com/uyuni-project/uyuni-tools/shared/utils" 12 | ) 13 | 14 | type configFlags struct { 15 | Output string 16 | Backend string 17 | } 18 | 19 | func newCmd(globalFlags *types.GlobalFlags, run utils.CommandFunc[configFlags]) *cobra.Command { 20 | configCmd := &cobra.Command{ 21 | Use: "config", 22 | Short: L("Extract configuration and logs"), 23 | Long: L(`Extract the host or cluster configuration and logs as well as those from 24 | the containers for support to help debugging.`), 25 | RunE: func(cmd *cobra.Command, args []string) error { 26 | var flags configFlags 27 | return utils.CommandHelper(globalFlags, cmd, args, &flags, nil, run) 28 | }, 29 | } 30 | 31 | configCmd.Flags().StringP("output", "o", ".", L("path where to extract the data")) 32 | utils.AddBackendFlag(configCmd) 33 | 34 | return configCmd 35 | } 36 | 37 | // NewCommand is the command for creates supportconfig. 38 | func NewCommand(globalFlags *types.GlobalFlags) *cobra.Command { 39 | return newCmd(globalFlags, extract) 40 | } 41 | -------------------------------------------------------------------------------- /mgrpxy/cmd/upgrade/kubernetes/kubernetes_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package kubernetes 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/mgrpxy/shared/kubernetes" 12 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 13 | "github.com/uyuni-project/uyuni-tools/shared/testutils/flagstests" 14 | "github.com/uyuni-project/uyuni-tools/shared/types" 15 | ) 16 | 17 | func TestParamsParsing(t *testing.T) { 18 | args := []string{} 19 | 20 | args = append(args, flagstests.ImageProxyFlagsTestArgs...) 21 | args = append(args, flagstests.ProxyHelmFlagsTestArgs...) 22 | 23 | // Test function asserting that the args are properly parsed 24 | tester := func(_ *types.GlobalFlags, flags *kubernetes.KubernetesProxyUpgradeFlags, 25 | _ *cobra.Command, _ []string, 26 | ) error { 27 | flagstests.AssertProxyImageFlags(t, &flags.ProxyImageFlags) 28 | flagstests.AssertProxyHelmFlags(t, &flags.Helm) 29 | return nil 30 | } 31 | 32 | globalFlags := types.GlobalFlags{} 33 | cmd := newCmd(&globalFlags, tester) 34 | 35 | testutils.AssertHasAllFlags(t, cmd, args) 36 | 37 | cmd.SetArgs(args) 38 | if err := cmd.Execute(); err != nil { 39 | t.Errorf("command failed with error: %s", err) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /shared/utils/inspector_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package utils 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 11 | ) 12 | 13 | func TestReadInspectData(t *testing.T) { 14 | content := `Timezone=Europe/Berlin 15 | image_pg_version=16 16 | current_pg_version=14 17 | db_user=myuser 18 | db_password=mysecret 19 | db_name=mydb 20 | db_port=1234 21 | has_hubxmlrpc=true 22 | ` 23 | 24 | actual, err := ReadInspectData[InspectResult]([]byte(content)) 25 | if err != nil { 26 | t.Fatalf("Unexpected failure: %s", err) 27 | } 28 | 29 | testutils.AssertEquals(t, "Invalid timezone", "Europe/Berlin", actual.Timezone) 30 | testutils.AssertEquals(t, "Invalid current postgresql version", "14", actual.CommonInspectData.CurrentPgVersion) 31 | testutils.AssertEquals(t, "Invalid image postgresql version", "16", actual.DBInspectData.ImagePgVersion) 32 | testutils.AssertEquals(t, "Invalid DB user", "myuser", actual.DBUser) 33 | testutils.AssertEquals(t, "Invalid DB password", "mysecret", actual.DBPassword) 34 | testutils.AssertEquals(t, "Invalid DB name", "mydb", actual.DBName) 35 | testutils.AssertEquals(t, "Invalid DB port", 1234, actual.DBPort) 36 | testutils.AssertTrue(t, "HasHubXmlrpcApi should be true", actual.HasHubXmlrpcAPI) 37 | } 38 | -------------------------------------------------------------------------------- /mgradm/cmd/hub/register/register_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package register 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 12 | "github.com/uyuni-project/uyuni-tools/shared/testutils/flagstests" 13 | "github.com/uyuni-project/uyuni-tools/shared/types" 14 | "github.com/uyuni-project/uyuni-tools/shared/utils" 15 | ) 16 | 17 | func TestParamsParsing(t *testing.T) { 18 | args := []string{} 19 | if utils.KubernetesBuilt { 20 | args = append(args, "--backend", "kubectl") 21 | } 22 | 23 | args = append(args, flagstests.APIFlagsTestArgs...) 24 | 25 | // Test function asserting that the args are properly parsed 26 | tester := func(_ *types.GlobalFlags, flags *registerFlags, _ *cobra.Command, _ []string) error { 27 | if utils.KubernetesBuilt { 28 | testutils.AssertEquals(t, "Error parsing --backend", "kubectl", flags.Backend) 29 | } 30 | flagstests.AssertAPIFlags(t, &flags.ConnectionDetails) 31 | return nil 32 | } 33 | 34 | globalFlags := types.GlobalFlags{} 35 | cmd := newCmd(&globalFlags, tester) 36 | 37 | testutils.AssertHasAllFlags(t, cmd, args) 38 | 39 | cmd.SetArgs(args) 40 | if err := cmd.Execute(); err != nil { 41 | t.Errorf("command failed with error: %s", err) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /mgradm/cmd/scale/scale_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package scale 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | "github.com/uyuni-project/uyuni-tools/shared/utils" 14 | ) 15 | 16 | func TestParamsParsing(t *testing.T) { 17 | args := []string{ 18 | "--replicas", "2", 19 | "some-service", 20 | } 21 | if utils.KubernetesBuilt { 22 | args = append(args, "--backend", "kubectl") 23 | } 24 | 25 | // Test function asserting that the args are properly parsed 26 | tester := func(_ *types.GlobalFlags, flags *scaleFlags, _ *cobra.Command, args []string) error { 27 | testutils.AssertEquals(t, "Error parsing --replicas", 2, flags.Replicas) 28 | testutils.AssertEquals(t, "Error parsing the service name", "some-service", args[0]) 29 | if utils.KubernetesBuilt { 30 | testutils.AssertEquals(t, "Error parsing --backend", "kubectl", flags.Backend) 31 | } 32 | return nil 33 | } 34 | 35 | globalFlags := types.GlobalFlags{} 36 | cmd := newCmd(&globalFlags, tester) 37 | 38 | testutils.AssertHasAllFlags(t, cmd, args) 39 | 40 | cmd.SetArgs(args) 41 | if err := cmd.Execute(); err != nil { 42 | t.Errorf("command failed with error: %s", err) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /mgrpxy/cmd/install/kubernetes/kubernetes_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package kubernetes 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 12 | "github.com/uyuni-project/uyuni-tools/shared/testutils/flagstests" 13 | "github.com/uyuni-project/uyuni-tools/shared/types" 14 | ) 15 | 16 | func TestParamsParsing(t *testing.T) { 17 | args := []string{ 18 | "config.tar.gz", 19 | } 20 | 21 | args = append(args, flagstests.ImageProxyFlagsTestArgs...) 22 | args = append(args, flagstests.ProxyHelmFlagsTestArgs...) 23 | args = append(args, flagstests.SCCFlagTestArgs...) 24 | 25 | // Test function asserting that the args are properly parsed 26 | tester := func(_ *types.GlobalFlags, flags *kubernetesProxyInstallFlags, 27 | _ *cobra.Command, _ []string, 28 | ) error { 29 | flagstests.AssertProxyImageFlags(t, &flags.ProxyImageFlags) 30 | flagstests.AssertProxyHelmFlags(t, &flags.Helm) 31 | flagstests.AssertSCCFlag(t, &flags.SCC) 32 | return nil 33 | } 34 | 35 | globalFlags := types.GlobalFlags{} 36 | cmd := newCmd(&globalFlags, tester) 37 | 38 | testutils.AssertHasAllFlags(t, cmd, args) 39 | 40 | cmd.SetArgs(args) 41 | if err := cmd.Execute(); err != nil { 42 | t.Errorf("command failed with error: %s", err) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /shared/testutils/flagstests/ssl.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package flagstests 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 11 | "github.com/uyuni-project/uyuni-tools/shared/types" 12 | ) 13 | 14 | // SSLGenerationFlagsTestArgs is the slice of command parameters to use with AssertSSLGenerationFlags. 15 | var SSLGenerationFlagsTestArgs = []string{ 16 | "--ssl-cname", "cname1", 17 | "--ssl-cname", "cname2", 18 | "--ssl-country", "OS", 19 | "--ssl-state", "sslstate", 20 | "--ssl-city", "sslcity", 21 | "--ssl-org", "sslorg", 22 | "--ssl-ou", "sslou", 23 | } 24 | 25 | // AssertSSLGenerationFlag checks that all the SSL certificate generation flags are parsed correctly. 26 | func AssertSSLGenerationFlag(t *testing.T, flags *types.SSLCertGenerationFlags) { 27 | testutils.AssertEquals(t, "Error parsing --ssl-cname", []string{"cname1", "cname2"}, flags.Cnames) 28 | testutils.AssertEquals(t, "Error parsing --ssl-country", "OS", flags.Country) 29 | testutils.AssertEquals(t, "Error parsing --ssl-state", "sslstate", flags.State) 30 | testutils.AssertEquals(t, "Error parsing --ssl-city", "sslcity", flags.City) 31 | testutils.AssertEquals(t, "Error parsing --ssl-org", "sslorg", flags.Org) 32 | testutils.AssertEquals(t, "Error parsing --ssl-ou", "sslou", flags.OU) 33 | } 34 | -------------------------------------------------------------------------------- /mgrpxy/cmd/uninstall/uninstall_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package uninstall 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | "github.com/uyuni-project/uyuni-tools/shared/utils" 14 | ) 15 | 16 | func TestParamsParsing(t *testing.T) { 17 | args := []string{ 18 | "--force", 19 | "--purge-volumes", 20 | "--purge-images", 21 | "--backend", "kubectl", 22 | } 23 | 24 | // Test function asserting that the args are properly parsed 25 | tester := func(_ *types.GlobalFlags, flags *utils.UninstallFlags, 26 | _ *cobra.Command, _ []string, 27 | ) error { 28 | testutils.AssertTrue(t, "Error parsing --force", flags.Force) 29 | testutils.AssertTrue(t, "Error parsing --purge-volumes", flags.Purge.Volumes) 30 | testutils.AssertTrue(t, "Error parsing --purge-images", flags.Purge.Images) 31 | testutils.AssertEquals(t, "Error parsing --backend", "kubectl", flags.Backend) 32 | return nil 33 | } 34 | 35 | globalFlags := types.GlobalFlags{} 36 | cmd := newCmd(&globalFlags, tester) 37 | 38 | testutils.AssertHasAllFlags(t, cmd, args) 39 | 40 | cmd.SetArgs(args) 41 | if err := cmd.Execute(); err != nil { 42 | t.Errorf("command failed with error: %s", err) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /extract_strings: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # SPDX-FileCopyrightText: 2024 SUSE LLC 4 | # 5 | # SPDX-License-Identifier: Apache-2.0 6 | 7 | export LC_ALL=C.UTF-8 8 | export LANG=C.UTF-8 9 | for MODULE in mgrctl mgradm mgrpxy shared; do 10 | # Generate the pot file 11 | echo "Generate locale/${MODULE}/${MODULE}.pot" 12 | find ${MODULE} -type f -not -name '*_test.go' -name '*.go' | sort | xargs xgettext --no-wrap --keyword="PL:1c,2" --keyword="NL:1,2" --keyword="L" --language=Javascript --from-code=UTF-8 -o locale/${MODULE}/${MODULE}.pot - 13 | msguniq --no-wrap -o locale/${MODULE}/${MODULE}-uniq.pot locale/${MODULE}/${MODULE}.pot 14 | mv locale/${MODULE}/${MODULE}-uniq.pot locale/${MODULE}/${MODULE}.pot 15 | 16 | # Update the po files 17 | for PO in locale/${MODULE}/*.po; do 18 | echo -n "Update ${PO}" 19 | if msgmerge --previous --no-wrap --update ${PO} locale/${MODULE}/${MODULE}.pot; 20 | then 21 | if test -f ${PO}~; then 22 | rm ${PO}~ 23 | fi 24 | else 25 | echo "msgmerge for ${PO} failed" 26 | fi 27 | done 28 | done 29 | 30 | # Commit the changes 31 | for change in `git diff --numstat | awk '{print $1}'`; do 32 | if [ $change -gt 1 ]; then 33 | git add -u 34 | git commit -m "update strings for translations" 35 | exit 36 | fi 37 | done 38 | git reset --hard 39 | -------------------------------------------------------------------------------- /shared/podman/utils_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package podman 6 | 7 | import ( 8 | "errors" 9 | "testing" 10 | 11 | "github.com/rs/zerolog" 12 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 13 | ) 14 | 15 | func TestGetServiceImage(t *testing.T) { 16 | type dataType struct { 17 | catOut string 18 | catErr error 19 | expected string 20 | } 21 | data := []dataType{ 22 | {"", errors.New("service not existing"), ""}, 23 | {"content with no image defined", nil, ""}, 24 | {`# /etc/systemd/system/uyuni-server-attestation@.service 25 | [Unit] 26 | Description=Uyuni server attestation container service 27 | Wants=network.target 28 | After=network-online.target 29 | [Service] 30 | Environment=PODMAN_SYSTEMD_UNIT=%n 31 | [Install] 32 | WantedBy=multi-user.target default.target 33 | 34 | # /etc/systemd/system/uyuni-server-attestation@.service.d/generated.conf 35 | 36 | [Service] 37 | Environment=UYUNI_IMAGE=myregistry.org/silly/image:tag 38 | `, nil, "myregistry.org/silly/image:tag"}, 39 | } 40 | 41 | for _, testData := range data { 42 | runCmdOutput = func(_ zerolog.Level, _ string, _ ...string) ([]byte, error) { 43 | return []byte(testData.catOut), testData.catErr 44 | } 45 | 46 | testutils.AssertEquals(t, "Wrong image found", testData.expected, GetServiceImage("myservice")) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /mgrpxy/cmd/upgrade/podman/podman_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package podman 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/mgrpxy/shared/podman" 12 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 13 | "github.com/uyuni-project/uyuni-tools/shared/testutils/flagstests" 14 | "github.com/uyuni-project/uyuni-tools/shared/types" 15 | ) 16 | 17 | func TestParamsParsing(t *testing.T) { 18 | args := []string{} 19 | 20 | args = append(args, flagstests.SCCFlagTestArgs...) 21 | args = append(args, flagstests.ImageProxyFlagsTestArgs...) 22 | args = append(args, flagstests.PodmanFlagsTestArgs...) 23 | 24 | // Test function asserting that the args are properly parsed 25 | tester := func(_ *types.GlobalFlags, flags *podman.PodmanProxyFlags, 26 | _ *cobra.Command, _ []string, 27 | ) error { 28 | flagstests.AssertSCCFlag(t, &flags.SCC) 29 | flagstests.AssertPodmanInstallFlags(t, &flags.Podman) 30 | flagstests.AssertProxyImageFlags(t, &flags.ProxyImageFlags) 31 | return nil 32 | } 33 | 34 | globalFlags := types.GlobalFlags{} 35 | cmd := newCmd(&globalFlags, tester) 36 | 37 | testutils.AssertHasAllFlags(t, cmd, args) 38 | 39 | cmd.SetArgs(args) 40 | if err := cmd.Execute(); err != nil { 41 | t.Errorf("command failed with error: %s", err) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /mgrpxy/cmd/logs/logs_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package logs 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | ) 14 | 15 | func TestParamsParsing(t *testing.T) { 16 | args := []string{ 17 | "--follow", 18 | "--timestamps", 19 | "--tail=20", 20 | "--since", "3h", 21 | "container1", "container2", 22 | } 23 | 24 | // Test function asserting that the args are properly parsed 25 | tester := func(_ *types.GlobalFlags, flags *logsFlags, 26 | _ *cobra.Command, _ []string, 27 | ) error { 28 | testutils.AssertTrue(t, "Error parsing --follow", flags.Follow) 29 | testutils.AssertTrue(t, "Error parsing --timestamps", flags.Timestamps) 30 | testutils.AssertEquals(t, "Error parsing --tail", 20, flags.Tail) 31 | testutils.AssertEquals(t, "Error parsing --since", "3h", flags.Since) 32 | testutils.AssertEquals(t, "Error parsing containers", []string{"container1", "container2"}, flags.Containers) 33 | return nil 34 | } 35 | 36 | globalFlags := types.GlobalFlags{} 37 | cmd := newCmd(&globalFlags, tester) 38 | 39 | testutils.AssertHasAllFlags(t, cmd, args) 40 | 41 | cmd.SetArgs(args) 42 | if err := cmd.Execute(); err != nil { 43 | t.Errorf("command failed with error: %s", err) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /mgrpxy/cmd/status/kubernetes.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package status 6 | 7 | import ( 8 | "errors" 9 | 10 | "github.com/rs/zerolog/log" 11 | "github.com/spf13/cobra" 12 | "github.com/uyuni-project/uyuni-tools/shared" 13 | "github.com/uyuni-project/uyuni-tools/shared/kubernetes" 14 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 15 | "github.com/uyuni-project/uyuni-tools/shared/types" 16 | "github.com/uyuni-project/uyuni-tools/shared/utils" 17 | ) 18 | 19 | func kubernetesStatus( 20 | _ *types.GlobalFlags, 21 | _ *statusFlags, 22 | _ *cobra.Command, 23 | _ []string, 24 | ) error { 25 | cnx := shared.NewConnection("kubectl", "", kubernetes.ProxyFilter) 26 | namespace, err := cnx.GetNamespace("") 27 | if err != nil { 28 | return err 29 | } 30 | 31 | // Is the pod running? Do we have all the replicas? 32 | status, err := kubernetes.GetDeploymentStatus(namespace, kubernetes.ProxyApp) 33 | if err != nil { 34 | return utils.Errorf(err, L("failed to get deployment status")) 35 | } 36 | if status.Replicas != status.ReadyReplicas { 37 | log.Warn().Msgf(L("Some replicas are not ready: %[1]d / %[2]d"), status.ReadyReplicas, status.Replicas) 38 | } 39 | 40 | if status.AvailableReplicas == 0 { 41 | return errors.New(L("the pod is not running")) 42 | } 43 | 44 | log.Info().Msg(L("Proxy containers up and running")) 45 | 46 | return nil 47 | } 48 | -------------------------------------------------------------------------------- /push.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | # SPDX-FileCopyrightText: 2025 SUSE LLC 4 | # 5 | # SPDX-License-Identifier: Apache-2.0 6 | 7 | # This script is called by push-packages-to-obs 8 | 9 | OSCAPI=$1 10 | GIT_DIR=$2 11 | PKG_NAME=$3 12 | 13 | SRPM_PKG_DIR=$(dirname "$0") 14 | 15 | pushd ${GIT_DIR} 16 | REMOTE_BRANCH=$(git for-each-ref --format='%(upstream:lstrip=-1)' $(git rev-parse --symbolic-full-name HEAD)) 17 | COMMIT_ID=$(git rev-parse --short HEAD) 18 | popd 19 | 20 | if [ "${OSCAPI}" == "https://api.suse.de" ]; then 21 | VERSION="HEAD" 22 | case ${REMOTE_BRANCH} in Manager-*) 23 | VERSION="${REMOTE_BRANCH#Manager-}" 24 | esac 25 | 26 | # Define the default tag to use 27 | sed 's/^tag=%{!?_default_tag:latest}/tag=5.2.0-alpha1/' -i ${SRPM_PKG_DIR}/uyuni-tools.spec 28 | 29 | sed "s/namespace='%{_default_namespace}'/namespace='%{_default_namespace}\/%{_arch}'/" -i ${SRPM_PKG_DIR}/uyuni-tools.spec 30 | 31 | else 32 | 33 | pushd ${GIT_DIR} 34 | VERSION=$(git tag --points-at HEAD Uyuni-*) 35 | popd 36 | 37 | if test -z "${VERSION}"; then 38 | case ${REMOTE_BRANCH} in Uyuni-*) 39 | VERSION="${REMOTE_BRANCH#Uyuni-}" 40 | esac 41 | 42 | if test -z "${VERSION}"; then 43 | VERSION="Master" 44 | fi 45 | fi 46 | fi 47 | 48 | # Add the version_details value for use in the version tag 49 | sed "/^%global provider_prefix.*$/a%global version_details ${VERSION} $COMMIT_ID" -i ${SRPM_PKG_DIR}/uyuni-tools.spec 50 | -------------------------------------------------------------------------------- /shared/kubernetes/k3sTraefikTemplate.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package kubernetes 6 | 7 | import ( 8 | "io" 9 | "text/template" 10 | 11 | "github.com/uyuni-project/uyuni-tools/shared/types" 12 | ) 13 | 14 | const k3sTraefikConfigTemplate = `apiVersion: helm.cattle.io/v1 15 | kind: HelmChartConfig 16 | metadata: 17 | name: traefik 18 | namespace: kube-system 19 | spec: 20 | valuesContent: |- 21 | ports: 22 | {{- range .Ports }} 23 | {{ .Name }}: 24 | port: {{ .Port }} 25 | {{- if $.ExposeBoolean }} 26 | expose: true 27 | {{- else }} 28 | expose: 29 | default: true 30 | {{- end }} 31 | exposedPort: {{ .Exposed }} 32 | {{- if eq .Protocol "udp" }} 33 | protocol: UDP 34 | {{- else }} 35 | protocol: TCP 36 | {{- end }} 37 | {{- end }} 38 | ` 39 | 40 | // K3sTraefikConfigTemplateData represents information used to create K3s Traefik helm chart. 41 | type K3sTraefikConfigTemplateData struct { 42 | Ports []types.PortMap 43 | // Set to true before traefik chart v27 44 | ExposeBoolean bool 45 | } 46 | 47 | // Render will create the helm chart configuation for K3sTraefik. 48 | func (data K3sTraefikConfigTemplateData) Render(wr io.Writer) error { 49 | t := template.Must(template.New("k3sTraefikConfig").Parse(k3sTraefikConfigTemplate)) 50 | return t.Execute(wr, data) 51 | } 52 | -------------------------------------------------------------------------------- /shared/utils/support_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package utils 6 | 7 | import ( 8 | "strings" 9 | "testing" 10 | ) 11 | 12 | func TestGetSupportConfigPath(t *testing.T) { 13 | data := [][]string{ 14 | {`/var/log/scc_uyuni-server.mgr.internal_240529_1124.txz`, `/var/log/scc_uyuni-server.mgr.internal_240529_1124.txz`}, 15 | {`/var/log/scc_uyuni-server.mgr.internal.txz`, `/var/log/scc_uyuni-server.mgr.internal.txz`}, 16 | {`/var/log/scc_uyuni-server_240529_1124.txz`, `/var/log/scc_uyuni-server_240529_1124.txz`}, 17 | {`/var/log/scc_uyuni-server.txz`, `/var/log/scc_uyuni-server.txz`}, 18 | } 19 | 20 | for i, testCase := range data { 21 | input := testCase[0] 22 | expected := testCase[1] 23 | 24 | actual := GetSupportConfigPath(input) 25 | 26 | if actual != expected { 27 | t.Errorf("Testcase %d: Expected %s got %s when GetSupportConfigPath %s", i, expected, actual, input) 28 | } 29 | } 30 | } 31 | 32 | func TestHostedContainers(t *testing.T) { 33 | data := ` 34 | /etc/systemd/system/uyuni-server.service 35 | /etc/systemd/system/uyuni-server-attestation@.service 36 | ` 37 | 38 | expected := []string{`uyuni-server`, `uyuni-server-attestation@`} 39 | 40 | actual := GetContainersFromSystemdFiles(data) 41 | 42 | if strings.Join(actual, " ") != strings.Join(expected, " ") { 43 | t.Errorf("Testcase: Expected %s got %s ", expected, actual) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /mgrctl/cmd/api/get.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package api 6 | 7 | import ( 8 | "encoding/json" 9 | "fmt" 10 | "strings" 11 | 12 | "github.com/rs/zerolog/log" 13 | "github.com/spf13/cobra" 14 | 15 | "github.com/uyuni-project/uyuni-tools/shared/api" 16 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 17 | "github.com/uyuni-project/uyuni-tools/shared/types" 18 | "github.com/uyuni-project/uyuni-tools/shared/utils" 19 | ) 20 | 21 | func runGet(_ *types.GlobalFlags, flags *apiFlags, _ *cobra.Command, args []string) error { 22 | log.Debug().Msgf("Running GET command %s", args[0]) 23 | client, err := api.Init(&flags.ConnectionDetails) 24 | if err == nil && (client.Details.User != "" || client.Details.InSession) { 25 | err = client.Login() 26 | } 27 | if err != nil { 28 | return utils.Errorf(err, L("unable to login to the server")) 29 | } 30 | path := args[0] 31 | options := args[1:] 32 | 33 | res, err := api.Get[interface{}](client, fmt.Sprintf("%s?%s", path, strings.Join(options, "&"))) 34 | if err != nil { 35 | return utils.Errorf(err, L("error in query '%s'"), path) 36 | } 37 | 38 | // TODO do this only when result is JSON or TEXT. Watchout for binary data 39 | // Decode JSON to the string and pretty print it 40 | out, err := json.MarshalIndent(res.Result, "", " ") 41 | if err != nil { 42 | return err 43 | } 44 | fmt.Print(string(out)) 45 | 46 | return nil 47 | } 48 | -------------------------------------------------------------------------------- /shared/api/org/createFirst.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package org 6 | 7 | import ( 8 | "errors" 9 | 10 | "github.com/uyuni-project/uyuni-tools/shared/api" 11 | "github.com/uyuni-project/uyuni-tools/shared/api/types" 12 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 13 | "github.com/uyuni-project/uyuni-tools/shared/utils" 14 | ) 15 | 16 | // CreateFirst creates the first organization and user after initial setup without authentication. 17 | // 18 | // orgName is the name of the first organization to create and admin the user to create. 19 | func CreateFirst(cnxDetails *api.ConnectionDetails, orgName string, admin *types.User) (*types.Organization, error) { 20 | client, err := api.Init(cnxDetails) 21 | if err != nil { 22 | return nil, utils.Errorf(err, L("unable to prepare API client")) 23 | } 24 | 25 | data := map[string]interface{}{ 26 | "orgName": orgName, 27 | "adminLogin": admin.Login, 28 | "adminPassword": admin.Password, 29 | "firstName": admin.FirstName, 30 | "lastName": admin.LastName, 31 | "email": admin.Email, 32 | } 33 | 34 | res, err := api.Post[types.Organization](client, "org/createFirst", data) 35 | if err != nil { 36 | return nil, utils.Errorf(err, L("failed to create first user and organization")) 37 | } 38 | 39 | if !res.Success { 40 | return nil, errors.New(res.Message) 41 | } 42 | 43 | return &res.Result, nil 44 | } 45 | -------------------------------------------------------------------------------- /mgradm/cmd/uninstall/uninstall_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package uninstall 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | "github.com/uyuni-project/uyuni-tools/shared/utils" 14 | ) 15 | 16 | func TestParamsParsing(t *testing.T) { 17 | args := []string{ 18 | "--force", 19 | "--purge-volumes", 20 | "--purge-images", 21 | } 22 | if utils.KubernetesBuilt { 23 | args = append(args, "--backend", "kubectl") 24 | } 25 | 26 | // Test function asserting that the args are properly parsed 27 | tester := func(_ *types.GlobalFlags, flags *utils.UninstallFlags, _ *cobra.Command, _ []string) error { 28 | testutils.AssertTrue(t, "Error parsing --force", flags.Force) 29 | testutils.AssertTrue(t, "Error parsing --purge-volumes", flags.Purge.Volumes) 30 | testutils.AssertTrue(t, "Error parsing --purge-images", flags.Purge.Images) 31 | if utils.KubernetesBuilt { 32 | testutils.AssertEquals(t, "Error parsing --backend", "kubectl", flags.Backend) 33 | } 34 | return nil 35 | } 36 | 37 | globalFlags := types.GlobalFlags{} 38 | cmd := newCmd(&globalFlags, tester) 39 | 40 | testutils.AssertHasAllFlags(t, cmd, args) 41 | 42 | cmd.SetArgs(args) 43 | if err := cmd.Execute(); err != nil { 44 | t.Errorf("command failed with error: %s", err) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /mgrpxy/cmd/install/podman/podman_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package podman 6 | 7 | import ( 8 | "strings" 9 | "testing" 10 | 11 | "github.com/spf13/cobra" 12 | "github.com/uyuni-project/uyuni-tools/mgrpxy/shared/podman" 13 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 14 | "github.com/uyuni-project/uyuni-tools/shared/testutils/flagstests" 15 | "github.com/uyuni-project/uyuni-tools/shared/types" 16 | ) 17 | 18 | func TestParamsParsing(t *testing.T) { 19 | args := []string{ 20 | "config.tar.gz", 21 | } 22 | args = append(args, flagstests.ImageProxyFlagsTestArgs...) 23 | args = append(args, flagstests.PodmanFlagsTestArgs...) 24 | args = append(args, flagstests.SCCFlagTestArgs...) 25 | 26 | // Test function asserting that the args are properly parsed 27 | tester := func(_ *types.GlobalFlags, flags *podman.PodmanProxyFlags, _ *cobra.Command, _ []string) error { 28 | flagstests.AssertProxyImageFlags(t, &flags.ProxyImageFlags) 29 | flagstests.AssertPodmanInstallFlags(t, &flags.Podman) 30 | flagstests.AssertSCCFlag(t, &flags.SCC) 31 | return nil 32 | } 33 | 34 | globalFlags := types.GlobalFlags{} 35 | cmd := newCmd(&globalFlags, tester) 36 | 37 | testutils.AssertHasAllFlags(t, cmd, args) 38 | 39 | t.Logf("flags: %s", strings.Join(args, " ")) 40 | cmd.SetArgs(args) 41 | if err := cmd.Execute(); err != nil { 42 | t.Errorf("command failed with error: %s", err) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /mgradm/cmd/upgrade/podman/utils.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package podman 6 | 7 | import ( 8 | "errors" 9 | "os/exec" 10 | 11 | "github.com/spf13/cobra" 12 | "github.com/uyuni-project/uyuni-tools/mgradm/shared/podman" 13 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 14 | shared_podman "github.com/uyuni-project/uyuni-tools/shared/podman" 15 | "github.com/uyuni-project/uyuni-tools/shared/types" 16 | ) 17 | 18 | var systemd shared_podman.Systemd = shared_podman.NewSystemd() 19 | 20 | func upgradePodman(_ *types.GlobalFlags, flags *podmanUpgradeFlags, cmd *cobra.Command, _ []string) error { 21 | hostData, err := shared_podman.InspectHost() 22 | if err != nil { 23 | return err 24 | } 25 | 26 | authFile, cleaner, err := shared_podman.PodmanLogin(hostData, flags.Image.Registry, flags.Installation.SCC) 27 | if err != nil { 28 | return err 29 | } 30 | defer cleaner() 31 | 32 | flags.Installation.CheckUpgradeParameters(cmd, "podman") 33 | if _, err := exec.LookPath("podman"); err != nil { 34 | return errors.New(L("install podman before running this command")) 35 | } 36 | 37 | return podman.Upgrade( 38 | systemd, authFile, 39 | flags.Installation.DB, 40 | flags.Installation.ReportDB, 41 | flags.Installation.SSL, 42 | flags.Image, 43 | flags.DBUpgradeImage, 44 | flags.Coco, 45 | flags.HubXmlrpc, 46 | flags.Saline, 47 | flags.Pgsql, 48 | flags.Installation.TZ, 49 | ) 50 | } 51 | -------------------------------------------------------------------------------- /mgrctl/cmd/term/term_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package term 6 | 7 | import ( 8 | "errors" 9 | "testing" 10 | 11 | "github.com/spf13/cobra" 12 | "github.com/uyuni-project/uyuni-tools/mgrctl/cmd/exec" 13 | "github.com/uyuni-project/uyuni-tools/shared/types" 14 | ) 15 | 16 | // Ensure the term command properly delegates to the exec one. 17 | func TestExecute(t *testing.T) { 18 | var globalFlags types.GlobalFlags 19 | 20 | newExecCmd = func(globalFlags *types.GlobalFlags) *cobra.Command { 21 | execCmd := exec.NewCommand(globalFlags) 22 | execCmd.RunE = func(cmd *cobra.Command, _ []string) error { 23 | if interactive, err := cmd.Flags().GetBool("interactive"); err != nil || !interactive { 24 | t.Error("interactive flag not passed") 25 | } 26 | if tty, err := cmd.Flags().GetBool("tty"); err != nil || !tty { 27 | t.Error("tty flag not passed") 28 | } 29 | if backend, err := cmd.Flags().GetString("backend"); err != nil || backend != "mybackend" { 30 | t.Error("backend flag not passed") 31 | } 32 | return errors.New("some error") 33 | } 34 | return execCmd 35 | } 36 | 37 | cmd := NewCommand(&globalFlags) 38 | if err := cmd.Flags().Parse([]string{"--backend", "mybackend"}); err != nil { 39 | t.Errorf("failed to parse flags: %s", err) 40 | } 41 | if err := cmd.RunE(cmd, []string{}); err.Error() != "some error" { 42 | t.Errorf("Unexpected error returned") 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /.github/workflows/prebuilt_devcontainer.yml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 SUSE LLC 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | name: 'pre-built devcontainer' 6 | on: 7 | push: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | devcontainer-build-and-push: 13 | runs-on: ubuntu-latest 14 | permissions: 15 | contents: read 16 | id-token: write 17 | packages: write 18 | steps: 19 | - name: Checkout 20 | id: checkout 21 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 22 | 23 | - name: Compute tag for devcontainer image 24 | id: meta 25 | run: | 26 | tag=$(git rev-parse --short HEAD) 27 | echo "tag=$tag" >> "$GITHUB_OUTPUT" 28 | 29 | - name: Login to GHCR 30 | uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 #v3.4.0 31 | with: 32 | registry: ghcr.io 33 | username: ${{ github.repository_owner }} 34 | password: ${{ secrets.GITHUB_TOKEN }} 35 | 36 | - name: Build and release devcontainer 37 | run: | 38 | npm install -g @devcontainers/cli 39 | devcontainer build \ 40 | --workspace-folder . \ 41 | --image-name ghcr.io/${{ github.repository }}/devcontainer:${{ steps.meta.outputs.tag }} \ 42 | --image-name ghcr.io/${{ github.repository }}/devcontainer:latest \ 43 | --push 44 | env: 45 | BUILDX_NO_DEFAULT_ATTESTATIONS: true 46 | -------------------------------------------------------------------------------- /mgradm/shared/kubernetes/postUpgradeJob.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | //go:build !nok8s 6 | 7 | package kubernetes 8 | 9 | import ( 10 | "github.com/rs/zerolog/log" 11 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 12 | 13 | "github.com/uyuni-project/uyuni-tools/mgradm/shared/templates" 14 | "github.com/uyuni-project/uyuni-tools/shared/kubernetes" 15 | batch "k8s.io/api/batch/v1" 16 | "k8s.io/apimachinery/pkg/runtime" 17 | ) 18 | 19 | // PostUpgradeJobName is the name of the job apply the database changes after the upgrade. 20 | const PostUpgradeJobName = "uyuni-post-upgrade" 21 | 22 | // StartPostUpgradeJob starts the job applying the database changes after the upgrade. 23 | func StartPostUpgradeJob(namespace string, image string, pullPolicy string, pullSecret string) (string, error) { 24 | log.Info().Msg(L("Performing post upgrade changes…")) 25 | 26 | job, err := getPostUpgradeJob(namespace, image, pullPolicy, pullSecret) 27 | if err != nil { 28 | return "", err 29 | } 30 | 31 | return job.ObjectMeta.Name, kubernetes.Apply([]runtime.Object{job}, L("failed to run the post upgrade job")) 32 | } 33 | 34 | func getPostUpgradeJob(namespace string, image string, pullPolicy string, pullSecret string) (*batch.Job, error) { 35 | scriptData := templates.PostUpgradeTemplateData{} 36 | mounts := GetServerMounts() 37 | 38 | return kubernetes.GetScriptJob(namespace, PostUpgradeJobName, image, pullPolicy, pullSecret, mounts, scriptData) 39 | } 40 | -------------------------------------------------------------------------------- /mgradm/shared/podman/startstop.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package podman 6 | 7 | import ( 8 | "github.com/uyuni-project/uyuni-tools/shared/podman" 9 | "github.com/uyuni-project/uyuni-tools/shared/utils" 10 | ) 11 | 12 | func StartServices() error { 13 | var dbErr error 14 | if systemd.HasService(podman.DBService) { 15 | dbErr = systemd.StartService(podman.DBService) 16 | } 17 | errs := utils.JoinErrors( 18 | dbErr, 19 | systemd.StartInstantiated(podman.ServerAttestationService), 20 | systemd.StartInstantiated(podman.HubXmlrpcService), 21 | systemd.StartInstantiated(podman.SalineService), 22 | systemd.StartService(podman.ServerService), 23 | ) 24 | 25 | if systemd.HasService(podman.SalineService + "@") { 26 | errs = utils.JoinErrors(errs, systemd.StartInstantiated(podman.SalineService)) 27 | } 28 | 29 | return errs 30 | } 31 | 32 | func StopServices() error { 33 | errs := utils.JoinErrors( 34 | systemd.StopInstantiated(podman.ServerAttestationService), 35 | systemd.StopInstantiated(podman.HubXmlrpcService), 36 | systemd.StopInstantiated(podman.SalineService), 37 | systemd.StopService(podman.ServerService), 38 | ) 39 | 40 | if systemd.HasService(podman.DBService) { 41 | errs = utils.JoinErrors(errs, systemd.StopService(podman.DBService)) 42 | } 43 | 44 | if systemd.HasService(podman.SalineService + "@") { 45 | errs = utils.JoinErrors(errs, systemd.StopInstantiated(podman.SalineService)) 46 | } 47 | return errs 48 | } 49 | -------------------------------------------------------------------------------- /shared/types/runner.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package types 6 | 7 | import ( 8 | "bytes" 9 | 10 | "github.com/rs/zerolog" 11 | ) 12 | 13 | // Runner is an interface to execute system calls. 14 | type Runner interface { 15 | // Log sets the log level of the output. 16 | Log(logLevel zerolog.Level) Runner 17 | 18 | // Spinner sets a spinner with its message. 19 | // If no message is passed, the command will be used. 20 | Spinner(message string) Runner 21 | 22 | // StdMapping maps the process output and error streams to the standard ones. 23 | // This is useful to show the process output in the console and the logs and can be combined with Log(). 24 | StdMapping() Runner 25 | 26 | // Std maps the process output to the out bytes buffer. 27 | // This is useful to get process output for backgrounds tasks. 28 | Std(out *bytes.Buffer) Runner 29 | 30 | // Wait waits for the command running in the background to ends. 31 | Wait() error 32 | 33 | // InputString adds a string as input of the process. 34 | InputString(input string) Runner 35 | 36 | // Env sets environment variables to use for the command. 37 | Env(env []string) Runner 38 | 39 | // Exec really executes the command and returns its output and error. 40 | // The error output to used as error message if the StdMapping() function wasn't called. 41 | Exec() ([]byte, error) 42 | 43 | // Start starts the command, particularly for commands to run in the background. 44 | Start() error 45 | } 46 | -------------------------------------------------------------------------------- /mgrpxy/cmd/stop/stop.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package stop 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/shared" 10 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 11 | "github.com/uyuni-project/uyuni-tools/shared/types" 12 | "github.com/uyuni-project/uyuni-tools/shared/utils" 13 | ) 14 | 15 | type stopFlags struct { 16 | Backend string 17 | } 18 | 19 | func newCmd(globalFlags *types.GlobalFlags, run utils.CommandFunc[stopFlags]) *cobra.Command { 20 | stopCmd := &cobra.Command{ 21 | Use: "stop", 22 | GroupID: "management", 23 | Short: L("Stop the proxy"), 24 | Long: L("Stop the proxy"), 25 | Args: cobra.ExactArgs(0), 26 | RunE: func(cmd *cobra.Command, args []string) error { 27 | var flags stopFlags 28 | return utils.CommandHelper(globalFlags, cmd, args, &flags, nil, run) 29 | }, 30 | } 31 | 32 | stopCmd.SetUsageTemplate(stopCmd.UsageTemplate()) 33 | 34 | utils.AddBackendFlag(stopCmd) 35 | 36 | return stopCmd 37 | } 38 | 39 | // NewCommand to stop server. 40 | func NewCommand(globalFlags *types.GlobalFlags) *cobra.Command { 41 | return newCmd(globalFlags, stop) 42 | } 43 | 44 | func stop(globalFlags *types.GlobalFlags, flags *stopFlags, cmd *cobra.Command, args []string) error { 45 | fn, err := shared.ChooseProxyPodmanOrKubernetes(cmd.Flags(), podmanStop, kubernetesStop) 46 | if err != nil { 47 | return err 48 | } 49 | 50 | return fn(globalFlags, flags, cmd, args) 51 | } 52 | -------------------------------------------------------------------------------- /shared/l10n/utils/defaultfs.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package l10n 6 | 7 | import "github.com/chai2010/gettext-go" 8 | 9 | // DefaultFS providing a empty data if no data is found. 10 | type DefaultFS struct { 11 | osFs gettext.FileSystem 12 | gettext.FileSystem 13 | } 14 | 15 | // New creates a new DefaultFS delegating to an OS FileSystem. 16 | func New(path string) *DefaultFS { 17 | return &DefaultFS{ 18 | osFs: gettext.OS(path), 19 | } 20 | } 21 | 22 | // LocaleList gets the list of locales from the underlying os FileSystem. 23 | func (f *DefaultFS) LocaleList() []string { 24 | return f.osFs.LocaleList() 25 | } 26 | 27 | // LoadMessagesFile loads a messages or returns the content of an empty json file. 28 | func (f *DefaultFS) LoadMessagesFile(domain, lang, ext string) ([]byte, error) { 29 | osFile, err := f.osFs.LoadMessagesFile(domain, lang, ext) 30 | // Return an empty file by default 31 | if err != nil { 32 | return []byte("[]"), nil 33 | } 34 | return osFile, nil 35 | } 36 | 37 | // LoadResourceFile loads the resource file or returns empty data. 38 | func (f *DefaultFS) LoadResourceFile(domain, lang, ext string) ([]byte, error) { 39 | osFile, err := f.osFs.LoadResourceFile(domain, lang, ext) 40 | // Return an empty file by default 41 | if err != nil { 42 | return []byte{}, nil 43 | } 44 | return osFile, nil 45 | } 46 | 47 | // String returns a name of the FileSystem. 48 | func (f *DefaultFS) String() string { 49 | return "DefaultFS" 50 | } 51 | -------------------------------------------------------------------------------- /.github/workflows/mingo_build.yml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 SUSE LLC 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | name: Build with oldest go 6 | 7 | on: 8 | pull_request: 9 | types: 10 | - opened 11 | - reopened 12 | - synchronize 13 | release: 14 | types: 15 | - published 16 | 17 | jobs: 18 | build: 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2 23 | with: 24 | fetch-tags: true 25 | fetch-depth: 0 26 | 27 | - name: Setup Go ${{ matrix.go-version }} 28 | uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 #v5.3.0 29 | with: 30 | go-version: '1.19' 31 | 32 | - name: Install dependencies 33 | run: | 34 | go get ./... 35 | 36 | - name: Compute version 37 | run: | 38 | tag=$(git describe --tags --abbrev=0) 39 | version=$(git describe --tags --abbrev=0 | cut -f 3 -d '-') 40 | offset=$(git rev-list --count ${tag}..) 41 | echo "VERSION=$tag-$offset" >> "$GITHUB_ENV" 42 | 43 | - name: Build with oldest go 44 | run: | 45 | mkdir -p ./bin 46 | go build \ 47 | -tags nok8s \ 48 | -ldflags "-X github.com/uyuni-project/uyuni-tools/shared/utils.Version=${{ env.VERSION }}" \ 49 | -o ./bin \ 50 | ./... 51 | 52 | - name: Unit tests with all tags 53 | run: go test -tags nok8s ./... 54 | -------------------------------------------------------------------------------- /mgrpxy/cmd/support/config/extractor.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package config 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/shared" 10 | "github.com/uyuni-project/uyuni-tools/shared/kubernetes" 11 | "github.com/uyuni-project/uyuni-tools/shared/podman" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | "github.com/uyuni-project/uyuni-tools/shared/utils" 14 | ) 15 | 16 | var systemd podman.Systemd = podman.NewSystemd() 17 | 18 | func extract(_ *types.GlobalFlags, flags *configFlags, _ *cobra.Command, _ []string) error { 19 | // Copy the generated file locally 20 | tmpDir, cleaner, err := utils.TempDir() 21 | if err != nil { 22 | return err 23 | } 24 | defer cleaner() 25 | 26 | var fileList []string 27 | if systemd.HasService(podman.ProxyService) { 28 | fileList, err = podman.RunSupportConfigOnPodmanHost(systemd, tmpDir) 29 | } 30 | 31 | if utils.IsInstalled("kubectl") && utils.IsInstalled("helm") { 32 | cnx := shared.NewConnection("kubectl", "", kubernetes.ProxyFilter) 33 | var namespace string 34 | namespace, err = cnx.GetNamespace("") 35 | if err != nil { 36 | return err 37 | } 38 | fileList, err = kubernetes.RunSupportConfigOnKubernetesHost(tmpDir, namespace, kubernetes.ProxyFilter) 39 | } 40 | 41 | if err != nil { 42 | return err 43 | } 44 | 45 | if err := utils.CreateSupportConfigTarball(flags.Output, fileList); err != nil { 46 | return err 47 | } 48 | 49 | return nil 50 | } 51 | -------------------------------------------------------------------------------- /mgradm/cmd/support/sql/sql_cmd_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package sql 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | ) 14 | 15 | func TestParamsParsing(t *testing.T) { 16 | args := []string{ 17 | "--database", "reportdb", 18 | "--interactive", 19 | "--force", 20 | "--output", "path/to/output", 21 | "--backend", "kubectl", 22 | } 23 | 24 | // Test function asserting that the args are properly parsed 25 | tester := func(_ *types.GlobalFlags, flags *sqlFlags, 26 | _ *cobra.Command, _ []string, 27 | ) error { 28 | testutils.AssertEquals(t, "Error parsing --dababase", "reportdb", flags.Database) 29 | testutils.AssertTrue(t, "Error parsing --interactive", flags.Interactive) 30 | testutils.AssertTrue(t, "Error parsing --force", flags.ForceOverwrite) 31 | testutils.AssertEquals(t, "Error parsing --dababase", "reportdb", flags.Database) 32 | testutils.AssertEquals(t, "Error parsing --output", "path/to/output", flags.OutputFile) 33 | testutils.AssertEquals(t, "Error parsing --backend", "kubectl", flags.Backend) 34 | return nil 35 | } 36 | 37 | globalFlags := types.GlobalFlags{} 38 | cmd := newCmd(&globalFlags, tester) 39 | 40 | testutils.AssertHasAllFlags(t, cmd, args) 41 | 42 | cmd.SetArgs(args) 43 | if err := cmd.Execute(); err != nil { 44 | t.Errorf("command failed with error: %s", err) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /mgrpxy/cmd/start/start.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package start 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/shared" 10 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 11 | "github.com/uyuni-project/uyuni-tools/shared/types" 12 | "github.com/uyuni-project/uyuni-tools/shared/utils" 13 | ) 14 | 15 | type startFlags struct { 16 | Backend string 17 | } 18 | 19 | func newCmd(globalFlags *types.GlobalFlags, run utils.CommandFunc[startFlags]) *cobra.Command { 20 | startCmd := &cobra.Command{ 21 | Use: "start", 22 | GroupID: "management", 23 | Short: L("Start the proxy"), 24 | Long: L("Start the proxy"), 25 | Args: cobra.ExactArgs(0), 26 | RunE: func(cmd *cobra.Command, args []string) error { 27 | var flags startFlags 28 | return utils.CommandHelper(globalFlags, cmd, args, &flags, nil, run) 29 | }, 30 | } 31 | startCmd.SetUsageTemplate(startCmd.UsageTemplate()) 32 | 33 | utils.AddBackendFlag(startCmd) 34 | 35 | return startCmd 36 | } 37 | 38 | // NewCommand starts the server. 39 | func NewCommand(globalFlags *types.GlobalFlags) *cobra.Command { 40 | return newCmd(globalFlags, start) 41 | } 42 | 43 | func start(globalFlags *types.GlobalFlags, flags *startFlags, cmd *cobra.Command, args []string) error { 44 | fn, err := shared.ChooseProxyPodmanOrKubernetes(cmd.Flags(), podmanStart, kubernetesStart) 45 | if err != nil { 46 | return err 47 | } 48 | 49 | return fn(globalFlags, flags, cmd, args) 50 | } 51 | -------------------------------------------------------------------------------- /shared/api/proxy/containerConfig.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package proxy 6 | 7 | import ( 8 | "errors" 9 | 10 | "github.com/rs/zerolog/log" 11 | "github.com/uyuni-project/uyuni-tools/shared/api" 12 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 13 | "github.com/uyuni-project/uyuni-tools/shared/utils" 14 | ) 15 | 16 | const containerConfigEndpoint = "proxy/containerConfig" 17 | 18 | // ContainerConfig computes and downloads the configuration file for proxy containers with generated certificates. 19 | func ContainerConfig(client *api.APIClient, request ProxyConfigRequest) (*[]int8, error) { 20 | return executeRequest(client, ProxyConfigRequestToMap(request)) 21 | } 22 | 23 | // ContainerConfigGenerate computes and downloads the configuration file for proxy containers. 24 | func ContainerConfigGenerate(client *api.APIClient, request ProxyConfigGenerateRequest) (*[]int8, error) { 25 | return executeRequest(client, ProxyConfigGenerateRequestToMap(request)) 26 | } 27 | 28 | // common method to execute the request. 29 | func executeRequest(client *api.APIClient, data map[string]interface{}) (*[]int8, error) { 30 | log.Trace().Msgf("Creating proxy configuration file with data: %v...", data) 31 | res, err := api.Post[[]int8](client, containerConfigEndpoint, data) 32 | if err != nil { 33 | return nil, utils.Errorf(err, L("failed to create proxy configuration file")) 34 | } 35 | if !res.Success { 36 | return nil, errors.New(res.Message) 37 | } 38 | return &res.Result, nil 39 | } 40 | -------------------------------------------------------------------------------- /shared/kubernetes/pvc_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package kubernetes 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | "testing" 11 | 12 | "github.com/rs/zerolog" 13 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 14 | ) 15 | 16 | func TestHasVolume(t *testing.T) { 17 | type dataType struct { 18 | err error 19 | out string 20 | expected bool 21 | } 22 | data := []dataType{ 23 | {nil, "Bound\n", true}, 24 | {nil, "Pending\n", false}, 25 | {errors.New("PVC not found"), "", false}, 26 | } 27 | 28 | for i, test := range data { 29 | runCmdOutput = func(_ zerolog.Level, _ string, _ ...string) ([]byte, error) { 30 | return []byte(test.out), test.err 31 | } 32 | actual := HasVolume("myns", "thepvc") 33 | testutils.AssertEquals(t, fmt.Sprintf("test %d: unexpected output", i), test.expected, actual) 34 | } 35 | } 36 | 37 | func TestHasPersistentVolumeClaim(t *testing.T) { 38 | type dataType struct { 39 | err error 40 | out string 41 | expected bool 42 | } 43 | data := []dataType{ 44 | {nil, "persistentvolumeclaim/var-pgsql\n", true}, 45 | {errors.New("PVC not found"), "", false}, 46 | } 47 | 48 | for i, test := range data { 49 | runCmdOutput = func(_ zerolog.Level, _ string, _ ...string) ([]byte, error) { 50 | return []byte(test.out), test.err 51 | } 52 | actual := hasPersistentVolumeClaim("myns", "thepvc") 53 | testutils.AssertEquals(t, fmt.Sprintf("test %d: unexpected output", i), test.expected, actual) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 SUSE LLC 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | linters-settings: 6 | stylecheck: 7 | dot-import-whitelist: 8 | - github.com/uyuni-project/uyuni-tools/shared/l10n 9 | initialisms: 10 | # Default 11 | - ACL 12 | - API 13 | - ASCII 14 | - CPU 15 | - DNS 16 | - EOF 17 | - GUID 18 | - HTML 19 | - HTTP 20 | - HTTPS 21 | - ID 22 | - IP 23 | - JSON 24 | - RPC 25 | - SLA 26 | - SMTP 27 | - SQL 28 | - SSH 29 | - TCP 30 | - TLS 31 | - TTL 32 | - UDP 33 | - UI 34 | - GID 35 | - UID 36 | - UUID 37 | - URI 38 | - URL 39 | - UTF8 40 | - VM 41 | - XML 42 | - RTP 43 | - DB 44 | # Added 45 | - SCC 46 | - SSL 47 | gofmt: 48 | simplify: true 49 | gocyclo: 50 | min-complexity: 10 51 | govet: 52 | disable: 53 | - printf 54 | 55 | linters: 56 | enable: 57 | - dupl 58 | - errcheck 59 | - errname 60 | - errorlint 61 | - godot 62 | - gofmt 63 | - goimports 64 | - gosimple 65 | #- gocyclo 66 | - ineffassign 67 | - govet 68 | - lll 69 | - misspell 70 | - revive 71 | - staticcheck 72 | - stylecheck 73 | - unparam 74 | - unused 75 | - whitespace 76 | issues: 77 | exclude-rules: 78 | - linters: 79 | - revive 80 | text: "dot-imports" 81 | - linters: 82 | - revive 83 | text: "stutters" 84 | -------------------------------------------------------------------------------- /mgradm/cmd/stop/stop.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package stop 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/shared" 10 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 11 | "github.com/uyuni-project/uyuni-tools/shared/types" 12 | "github.com/uyuni-project/uyuni-tools/shared/utils" 13 | ) 14 | 15 | type stopFlags struct { 16 | Backend string 17 | } 18 | 19 | func newCmd(globalFlags *types.GlobalFlags, run utils.CommandFunc[stopFlags]) *cobra.Command { 20 | stopCmd := &cobra.Command{ 21 | Use: "stop", 22 | GroupID: "management", 23 | Short: L("Stop the server"), 24 | Long: L("Stop the server"), 25 | Args: cobra.ExactArgs(0), 26 | RunE: func(cmd *cobra.Command, args []string) error { 27 | var flags stopFlags 28 | return utils.CommandHelper(globalFlags, cmd, args, &flags, nil, run) 29 | }, 30 | } 31 | 32 | stopCmd.SetUsageTemplate(stopCmd.UsageTemplate()) 33 | 34 | if utils.KubernetesBuilt { 35 | utils.AddBackendFlag(stopCmd) 36 | } 37 | 38 | return stopCmd 39 | } 40 | 41 | // NewCommand to stop server. 42 | func NewCommand(globalFlags *types.GlobalFlags) *cobra.Command { 43 | return newCmd(globalFlags, stop) 44 | } 45 | 46 | func stop(globalFlags *types.GlobalFlags, flags *stopFlags, cmd *cobra.Command, args []string) error { 47 | fn, err := shared.ChoosePodmanOrKubernetes(cmd.Flags(), podmanStop, kubernetesStop) 48 | if err != nil { 49 | return err 50 | } 51 | 52 | return fn(globalFlags, flags, cmd, args) 53 | } 54 | -------------------------------------------------------------------------------- /mgrpxy/cmd/upgrade/kubernetes/kubernetes.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package kubernetes 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/mgrpxy/shared/kubernetes" 10 | pxy_utils "github.com/uyuni-project/uyuni-tools/mgrpxy/shared/utils" 11 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | "github.com/uyuni-project/uyuni-tools/shared/utils" 14 | ) 15 | 16 | func newCmd( 17 | globalFlags *types.GlobalFlags, 18 | run utils.CommandFunc[kubernetes.KubernetesProxyUpgradeFlags], 19 | ) *cobra.Command { 20 | cmd := &cobra.Command{ 21 | Use: "kubernetes", 22 | Short: L("Upgrade a proxy on a running kubernetes cluster"), 23 | Long: L(`Upgrade a proxy on a running kubernetes cluster. 24 | 25 | The upgrade kubernetes command assumes kubectl is installed locally. 26 | 27 | NOTE: for now upgrading on a remote kubernetes cluster is not supported! 28 | `), 29 | Args: cobra.ExactArgs(0), 30 | RunE: func(cmd *cobra.Command, args []string) error { 31 | var flags kubernetes.KubernetesProxyUpgradeFlags 32 | return utils.CommandHelper(globalFlags, cmd, args, &flags, nil, run) 33 | }, 34 | } 35 | 36 | pxy_utils.AddImageFlags(cmd) 37 | 38 | kubernetes.AddHelmFlags(cmd) 39 | 40 | return cmd 41 | } 42 | 43 | // NewCommand install a new proxy on a running kubernetes cluster. 44 | func NewCommand(globalFlags *types.GlobalFlags) *cobra.Command { 45 | return newCmd(globalFlags, upgradeKubernetes) 46 | } 47 | -------------------------------------------------------------------------------- /mgradm/cmd/start/start.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package start 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/shared" 10 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 11 | "github.com/uyuni-project/uyuni-tools/shared/types" 12 | "github.com/uyuni-project/uyuni-tools/shared/utils" 13 | ) 14 | 15 | type startFlags struct { 16 | Backend string 17 | } 18 | 19 | func newCmd(globalFlags *types.GlobalFlags, run utils.CommandFunc[startFlags]) *cobra.Command { 20 | startCmd := &cobra.Command{ 21 | Use: "start", 22 | GroupID: "management", 23 | Short: L("Start the server"), 24 | Long: L("Start the server"), 25 | Args: cobra.ExactArgs(0), 26 | RunE: func(cmd *cobra.Command, args []string) error { 27 | var flags startFlags 28 | return utils.CommandHelper(globalFlags, cmd, args, &flags, nil, run) 29 | }, 30 | } 31 | startCmd.SetUsageTemplate(startCmd.UsageTemplate()) 32 | 33 | if utils.KubernetesBuilt { 34 | utils.AddBackendFlag(startCmd) 35 | } 36 | 37 | return startCmd 38 | } 39 | 40 | // NewCommand starts the server. 41 | func NewCommand(globalFlags *types.GlobalFlags) *cobra.Command { 42 | return newCmd(globalFlags, start) 43 | } 44 | 45 | func start(globalFlags *types.GlobalFlags, flags *startFlags, cmd *cobra.Command, args []string) error { 46 | fn, err := shared.ChoosePodmanOrKubernetes(cmd.Flags(), podmanStart, kubernetesStart) 47 | if err != nil { 48 | return err 49 | } 50 | 51 | return fn(globalFlags, flags, cmd, args) 52 | } 53 | -------------------------------------------------------------------------------- /mgrpxy/cmd/restart/restart.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package restart 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/shared" 10 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 11 | "github.com/uyuni-project/uyuni-tools/shared/types" 12 | "github.com/uyuni-project/uyuni-tools/shared/utils" 13 | ) 14 | 15 | type restartFlags struct { 16 | Backend string 17 | } 18 | 19 | func newCmd(globalFlags *types.GlobalFlags, run utils.CommandFunc[restartFlags]) *cobra.Command { 20 | restartCmd := &cobra.Command{ 21 | Use: "restart", 22 | GroupID: "management", 23 | Short: L("Restart the proxy"), 24 | Long: L("Restart the proxy"), 25 | Args: cobra.ExactArgs(0), 26 | RunE: func(cmd *cobra.Command, args []string) error { 27 | var flags restartFlags 28 | return utils.CommandHelper(globalFlags, cmd, args, &flags, nil, run) 29 | }, 30 | } 31 | restartCmd.SetUsageTemplate(restartCmd.UsageTemplate()) 32 | 33 | utils.AddBackendFlag(restartCmd) 34 | 35 | return restartCmd 36 | } 37 | 38 | // NewCommand to restart server. 39 | func NewCommand(globalFlags *types.GlobalFlags) *cobra.Command { 40 | return newCmd(globalFlags, restart) 41 | } 42 | 43 | func restart(globalFlags *types.GlobalFlags, flags *restartFlags, cmd *cobra.Command, args []string) error { 44 | fn, err := shared.ChooseProxyPodmanOrKubernetes(cmd.Flags(), podmanRestart, kubernetesRestart) 45 | if err != nil { 46 | return err 47 | } 48 | 49 | return fn(globalFlags, flags, cmd, args) 50 | } 51 | -------------------------------------------------------------------------------- /mgrpxy/cmd/support/ptf/podman/podman_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | //go:build ptf 5 | 6 | package podman 7 | 8 | import ( 9 | "testing" 10 | 11 | "github.com/spf13/cobra" 12 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 13 | "github.com/uyuni-project/uyuni-tools/shared/testutils/flagstests" 14 | "github.com/uyuni-project/uyuni-tools/shared/types" 15 | ) 16 | 17 | func TestParamsParsing(t *testing.T) { 18 | args := []string{ 19 | "--ptf", "ptf123", 20 | "--test", "test123", 21 | "--user", "sccuser", 22 | } 23 | 24 | args = append(args, flagstests.SCCFlagTestArgs...) 25 | args = append(args, flagstests.ImageProxyFlagsTestArgs...) 26 | 27 | // Test function asserting that the args are properly parsed 28 | tester := func(_ *types.GlobalFlags, flags *podmanPTFFlags, 29 | _ *cobra.Command, _ []string, 30 | ) error { 31 | flagstests.AssertSCCFlag(t, &flags.UpgradeFlags.SCC) 32 | flagstests.AssertProxyImageFlags(t, &flags.UpgradeFlags.ProxyImageFlags) 33 | testutils.AssertEquals(t, "Error parsing --ptf", "ptf123", flags.PTFId) 34 | testutils.AssertEquals(t, "Error parsing --test", "test123", flags.TestID) 35 | testutils.AssertEquals(t, "Error parsing --user", "sccuser", flags.CustomerID) 36 | return nil 37 | } 38 | 39 | globalFlags := types.GlobalFlags{} 40 | cmd := newCmd(&globalFlags, tester) 41 | 42 | testutils.AssertHasAllFlags(t, cmd, args) 43 | 44 | cmd.SetArgs(args) 45 | if err := cmd.Execute(); err != nil { 46 | t.Errorf("command failed with error: %s", err) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /shared/api/proxy/mapping.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package proxy 6 | 7 | // Mappings for the models/Schemas in scope of the proxy API 8 | 9 | // ProxyConfigRequestToMap maps the ProxyConfigRequest to a map. 10 | func ProxyConfigRequestToMap(request ProxyConfigRequest) map[string]interface{} { 11 | return map[string]interface{}{ 12 | "proxyName": request.ProxyName, 13 | "proxyPort": request.ProxyPort, 14 | "server": request.Server, 15 | "maxCache": request.MaxCache, 16 | "email": request.Email, 17 | "rootCA": request.RootCA, 18 | "proxyCrt": request.ProxyCrt, 19 | "proxyKey": request.ProxyKey, 20 | "intermediateCAs": request.IntermediateCAs, 21 | } 22 | } 23 | 24 | // ProxyConfigGenerateRequestToMap maps the ProxyConfigGenerateRequest to a map. 25 | func ProxyConfigGenerateRequestToMap(request ProxyConfigGenerateRequest) map[string]interface{} { 26 | return map[string]interface{}{ 27 | "proxyName": request.ProxyName, 28 | "proxyPort": request.ProxyPort, 29 | "server": request.Server, 30 | "maxCache": request.MaxCache, 31 | "email": request.Email, 32 | "caCrt": request.CaCrt, 33 | "caKey": request.CaKey, 34 | "caPassword": request.CaPassword, 35 | "cnames": request.Cnames, 36 | "country": request.Country, 37 | "state": request.State, 38 | "city": request.City, 39 | "org": request.Org, 40 | "orgUnit": request.OrgUnit, 41 | "sslEmail": request.SSLEmail, 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /mgradm/cmd/migrate/podman/utils.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package podman 6 | 7 | import ( 8 | "errors" 9 | "os/exec" 10 | 11 | "github.com/spf13/cobra" 12 | "github.com/uyuni-project/uyuni-tools/mgradm/shared/podman" 13 | podman_utils "github.com/uyuni-project/uyuni-tools/shared/podman" 14 | "github.com/uyuni-project/uyuni-tools/shared/types" 15 | 16 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 17 | ) 18 | 19 | var systemd podman_utils.Systemd = podman_utils.NewSystemd() 20 | 21 | func migrateToPodman( 22 | _ *types.GlobalFlags, 23 | flags *podmanMigrateFlags, 24 | cmd *cobra.Command, 25 | args []string, 26 | ) error { 27 | hostData, err := podman_utils.InspectHost() 28 | if err != nil { 29 | return err 30 | } 31 | 32 | authFile, cleaner, err := podman_utils.PodmanLogin(hostData, flags.Image.Registry, flags.Installation.SCC) 33 | if err != nil { 34 | return err 35 | } 36 | defer cleaner() 37 | 38 | flags.Installation.CheckUpgradeParameters(cmd, "podman") 39 | if _, err := exec.LookPath("podman"); err != nil { 40 | return errors.New(L("install podman before running this command")) 41 | } 42 | 43 | return podman.Migrate( 44 | systemd, authFile, 45 | flags.Installation.DB, 46 | flags.Installation.ReportDB, 47 | flags.Installation.SSL, 48 | flags.Image, 49 | flags.DBUpgradeImage, 50 | flags.Coco, 51 | flags.HubXmlrpc, 52 | flags.Saline, 53 | flags.Pgsql, 54 | flags.Migration.Prepare, 55 | flags.Migration.User, 56 | flags.Mirror, 57 | flags.Podman, 58 | args, 59 | ) 60 | } 61 | -------------------------------------------------------------------------------- /shared/kubernetes/deploy_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package kubernetes 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | "testing" 11 | 12 | "github.com/rs/zerolog" 13 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 14 | ) 15 | 16 | func TestHasDeployment(t *testing.T) { 17 | type dataType struct { 18 | out string 19 | err error 20 | expected bool 21 | } 22 | 23 | data := []dataType{ 24 | {"deployment.apps/traefik\n", nil, true}, 25 | {"\n", nil, false}, 26 | {"Some error", errors.New("Some error"), false}, 27 | } 28 | 29 | for i, test := range data { 30 | runCmdOutput = func(_ zerolog.Level, _ string, _ ...string) ([]byte, error) { 31 | return []byte(test.out), test.err 32 | } 33 | testutils.AssertEquals(t, fmt.Sprintf("test %d: unexpected result", i+1), test.expected, 34 | HasDeployment("kube-system", "-lapp.kubernetes.io/name=traefik"), 35 | ) 36 | } 37 | } 38 | 39 | func TestGetReplicas(t *testing.T) { 40 | type dataType struct { 41 | out string 42 | err error 43 | expected int 44 | } 45 | data := []dataType{ 46 | {"2\n", nil, 2}, 47 | {"no such deploy\n", errors.New("No such deploy"), 0}, 48 | {"invalid output\n", nil, 0}, 49 | } 50 | 51 | for i, test := range data { 52 | runCmdOutput = func(_ zerolog.Level, _ string, _ ...string) ([]byte, error) { 53 | return []byte(test.out), test.err 54 | } 55 | testutils.AssertEquals(t, fmt.Sprintf("test %d: unexpected result", i+1), 56 | test.expected, GetReplicas("uyuni", "uyuni-hub-api")) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /mgradm/cmd/inspect/inspect_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package inspect 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 12 | "github.com/uyuni-project/uyuni-tools/shared/testutils/flagstests" 13 | "github.com/uyuni-project/uyuni-tools/shared/types" 14 | "github.com/uyuni-project/uyuni-tools/shared/utils" 15 | ) 16 | 17 | func TestParamsParsing(t *testing.T) { 18 | args := []string{} 19 | if utils.KubernetesBuilt { 20 | args = append(args, "--backend", "kubectl") 21 | } 22 | 23 | args = append(args, flagstests.ImageFlagsTestArgs...) 24 | args = append(args, flagstests.SCCFlagTestArgs...) 25 | args = append(args, flagstests.PgsqlFlagsTestArgs...) 26 | 27 | // Test function asserting that the args are properly parsed 28 | tester := func(_ *types.GlobalFlags, flags *inspectFlags, _ *cobra.Command, _ []string) error { 29 | flagstests.AssertImageFlag(t, &flags.Image) 30 | flagstests.AssertRegistryFlag(t, &flags.Image.Registry) 31 | flagstests.AssertSCCFlag(t, &flags.SCC) 32 | flagstests.AssertPgsqlFlag(t, &flags.Pgsql) 33 | if utils.KubernetesBuilt { 34 | testutils.AssertEquals(t, "Error parsing --backend", "kubectl", flags.Backend) 35 | } 36 | return nil 37 | } 38 | 39 | globalFlags := types.GlobalFlags{} 40 | cmd := newCmd(&globalFlags, tester) 41 | 42 | testutils.AssertHasAllFlags(t, cmd, args) 43 | 44 | cmd.SetArgs(args) 45 | if err := cmd.Execute(); err != nil { 46 | t.Errorf("command failed with error: %s", err) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /mgradm/cmd/restart/restart.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package restart 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/shared" 10 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 11 | "github.com/uyuni-project/uyuni-tools/shared/types" 12 | "github.com/uyuni-project/uyuni-tools/shared/utils" 13 | ) 14 | 15 | type restartFlags struct { 16 | Backend string 17 | } 18 | 19 | func newCmd(globalFlags *types.GlobalFlags, run utils.CommandFunc[restartFlags]) *cobra.Command { 20 | restartCmd := &cobra.Command{ 21 | Use: "restart", 22 | GroupID: "management", 23 | Short: L("Restart the server"), 24 | Long: L("Restart the server"), 25 | Args: cobra.ExactArgs(0), 26 | RunE: func(cmd *cobra.Command, args []string) error { 27 | var flags restartFlags 28 | return utils.CommandHelper(globalFlags, cmd, args, &flags, nil, run) 29 | }, 30 | } 31 | restartCmd.SetUsageTemplate(restartCmd.UsageTemplate()) 32 | 33 | if utils.KubernetesBuilt { 34 | utils.AddBackendFlag(restartCmd) 35 | } 36 | 37 | return restartCmd 38 | } 39 | 40 | // NewCommand to restart server. 41 | func NewCommand(globalFlags *types.GlobalFlags) *cobra.Command { 42 | return newCmd(globalFlags, restart) 43 | } 44 | 45 | func restart(globalFlags *types.GlobalFlags, flags *restartFlags, cmd *cobra.Command, args []string) error { 46 | fn, err := shared.ChoosePodmanOrKubernetes(cmd.Flags(), podmanRestart, kubernetesRestart) 47 | if err != nil { 48 | return err 49 | } 50 | 51 | return fn(globalFlags, flags, cmd, args) 52 | } 53 | -------------------------------------------------------------------------------- /mgradm/cmd/install/kubernetes/kubernetes_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | //go:build !nok8s 6 | 7 | package kubernetes 8 | 9 | import ( 10 | "testing" 11 | 12 | "github.com/spf13/cobra" 13 | "github.com/uyuni-project/uyuni-tools/mgradm/shared/kubernetes" 14 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 15 | "github.com/uyuni-project/uyuni-tools/shared/testutils/flagstests" 16 | "github.com/uyuni-project/uyuni-tools/shared/types" 17 | ) 18 | 19 | func TestParamsParsing(t *testing.T) { 20 | args := flagstests.InstallFlagsTestArgs() 21 | args = append(args, flagstests.ServerKubernetesFlagsTestArgs...) 22 | args = append(args, flagstests.VolumesFlagsTestExpected...) 23 | args = append(args, flagstests.PgsqlFlagsTestArgs...) 24 | args = append(args, "srv.fq.dn") 25 | 26 | // Test function asserting that the args are properly parsed 27 | tester := func(_ *types.GlobalFlags, flags *kubernetes.KubernetesServerFlags, 28 | _ *cobra.Command, args []string, 29 | ) error { 30 | flagstests.AssertInstallFlags(t, &flags.ServerFlags) 31 | flagstests.AssertServerKubernetesFlags(t, &flags.Kubernetes) 32 | flagstests.AssertVolumesFlags(t, &flags.Volumes) 33 | flagstests.AssertPgsqlFlag(t, &flags.Pgsql) 34 | testutils.AssertEquals(t, "Wrong FQDN", "srv.fq.dn", args[0]) 35 | return nil 36 | } 37 | 38 | globalFlags := types.GlobalFlags{} 39 | cmd := newCmd(&globalFlags, tester) 40 | 41 | testutils.AssertHasAllFlags(t, cmd, args) 42 | 43 | cmd.SetArgs(args) 44 | if err := cmd.Execute(); err != nil { 45 | t.Errorf("command failed with error: %s", err) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /mgradm/cmd/status/status.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package status 6 | 7 | import ( 8 | "errors" 9 | 10 | "github.com/spf13/cobra" 11 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 12 | "github.com/uyuni-project/uyuni-tools/shared/podman" 13 | "github.com/uyuni-project/uyuni-tools/shared/types" 14 | "github.com/uyuni-project/uyuni-tools/shared/utils" 15 | ) 16 | 17 | type statusFlags struct { 18 | } 19 | 20 | func newCmd(globalFlags *types.GlobalFlags, run utils.CommandFunc[statusFlags]) *cobra.Command { 21 | cmd := &cobra.Command{ 22 | Use: "status", 23 | GroupID: "management", 24 | Short: L("Get the server status"), 25 | Long: L("Get the server status"), 26 | Args: cobra.ExactArgs(0), 27 | RunE: func(cmd *cobra.Command, args []string) error { 28 | var flags statusFlags 29 | return utils.CommandHelper(globalFlags, cmd, args, &flags, nil, run) 30 | }, 31 | } 32 | cmd.SetUsageTemplate(cmd.UsageTemplate()) 33 | 34 | return cmd 35 | } 36 | 37 | // NewCommand to get the status of the server. 38 | func NewCommand(globalFlags *types.GlobalFlags) *cobra.Command { 39 | return newCmd(globalFlags, status) 40 | } 41 | 42 | func status(globalFlags *types.GlobalFlags, flags *statusFlags, cmd *cobra.Command, args []string) error { 43 | if systemd.HasService(podman.ServerService) { 44 | return podmanStatus(globalFlags, flags, cmd, args) 45 | } 46 | 47 | if utils.IsInstalled("kubectl") && utils.IsInstalled("helm") { 48 | return kubernetesStatus(globalFlags, flags, cmd, args) 49 | } 50 | 51 | return errors.New(L("no installed server detected")) 52 | } 53 | -------------------------------------------------------------------------------- /shared/completion/completion.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package completion 6 | 7 | import ( 8 | "os" 9 | 10 | "github.com/spf13/cobra" 11 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | "github.com/uyuni-project/uyuni-tools/shared/utils" 14 | ) 15 | 16 | // NewCommand command for generates completion script. 17 | func NewCommand(_ *types.GlobalFlags) *cobra.Command { 18 | shellCompletionCmd := &cobra.Command{ 19 | Use: "completion [bash|zsh|fish|powershell]", 20 | Short: L("Generate shell completion script"), 21 | Long: L("Generate shell completion script"), 22 | DisableFlagsInUseLine: true, 23 | ValidArgs: []string{"bash", "zsh", "fish"}, 24 | Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs), 25 | Hidden: true, 26 | RunE: func(cmd *cobra.Command, args []string) error { 27 | switch args[0] { 28 | case "bash": 29 | if err := cmd.Root().GenBashCompletion(os.Stdout); err != nil { 30 | return utils.Errorf(err, L("cannot generate %s completion"), args[0]) 31 | } 32 | case "zsh": 33 | if err := cmd.Root().GenZshCompletion(os.Stdout); err != nil { 34 | return utils.Errorf(err, L("cannot generate %s completion"), args[0]) 35 | } 36 | case "fish": 37 | if err := cmd.Root().GenFishCompletion(os.Stdout, true); err != nil { 38 | return utils.Errorf(err, L("cannot generate %s completion"), args[0]) 39 | } 40 | } 41 | return nil 42 | }, 43 | } 44 | return shellCompletionCmd 45 | } 46 | -------------------------------------------------------------------------------- /shared/ssl/testdata/chain2/RHN-ORG-TRUSTED-SSL-CERT: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEVjCCAz6gAwIBAgIUA12e94NKtyrGIZpdEYgrqkjHXN8wDQYJKoZIhvcNAQEL 3 | BQAwXTELMAkGA1UEBhMCREUxDjAMBgNVBAgMBVNUQVRFMQ0wCwYDVQQHDARDSVRZ 4 | MQwwCgYDVQQKDANPUkcxEDAOBgNVBAsMB09SR1VOSVQxDzANBgNVBAMMBlJvb3RD 5 | QTAeFw0yMzEwMDYxNTQyMzBaFw0yNjA3MjYxNTQyMzBaMF0xCzAJBgNVBAYTAkRF 6 | MQ4wDAYDVQQIDAVTVEFURTENMAsGA1UEBwwEQ0lUWTEMMAoGA1UECgwDT1JHMRAw 7 | DgYDVQQLDAdPUkdVTklUMQ8wDQYDVQQDDAZSb290Q0EwggEiMA0GCSqGSIb3DQEB 8 | AQUAA4IBDwAwggEKAoIBAQDDbR3+UOxtw6KO8s/XsvkjukqSAFggAjSJxOw+KJL4 9 | tOykM4lBXkC3nLiV6ve5Np2koi9bX1At/nk1Fxftwy37WbeVAFs6wprkI0sDbK6z 10 | ZfT/qRoNChpYnzMFs28VCgftsOv1q5aLEUHfnSgEIK3lH3lMvDaEO6VgTDa84Y3h 11 | DlNbj5bssq3mMHsKE5DRCSM0wXP8ZlnwfY8S/LMxf8FN8S+c3fwg6/+dUKiAHU8Q 12 | goXQliH/NvZZPvvYTiADTY+xt6fEeZ4OdVVV31V7so3v6cIN4WwaOtGAzWKOrB4r 13 | Oa4ZybhmEMW7rLOnSUvl+r1UyWfh/8rH+ATSYQSynI/TAgMBAAGjggEMMIIBCDAM 14 | BgNVHRMEBTADAQH/MAsGA1UdDwQEAwICpDAdBgNVHSUEFjAUBggrBgEFBQcDAQYI 15 | KwYBBQUHAwIwKAYJYIZIAYb4QgENBBsWGVNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNh 16 | dGUwHQYDVR0OBBYEFDOCM0j6AGn+E4QnDh2Y9rR5Mc1DMIGCBgNVHSMEezB5oWGk 17 | XzBdMQswCQYDVQQGEwJERTEOMAwGA1UECAwFU1RBVEUxDTALBgNVBAcMBENJVFkx 18 | DDAKBgNVBAoMA09SRzEQMA4GA1UECwwHT1JHVU5JVDEPMA0GA1UEAwwGUm9vdENB 19 | ghQDXZ73g0q3KsYhml0RiCuqSMdc3zANBgkqhkiG9w0BAQsFAAOCAQEAbvvh+GyX 20 | KwFC8xaGAAHBsz0yg43LS5W9TNNOospC1qwbgCpSZJ9nWBbF2UWTKUgzjSPUpCjJ 21 | 0kMUvkpFnwFujE8IgJiP0Tha3KE3D14kj91Vfs5jDSyBsexUi8GMTP4caTMbXnU5 22 | +q1iVhigbtOh2gSBKQvTIIdhzhghp9iFX7f68WERRVlSG/xGCSt6DXO5sgUyQb2U 23 | ArHMJZkROIrVeGY6pXp1dWB/j6iguRUTC3GJ0JfRgx5E+pgpFnjItDQ1e2/pxsQr 24 | ikqyFuc2CAHkhlEl0oWz+yWwCQrKkZNLABWyPWtnMecIoCqZQ79EoeQ59JZzQPrg 25 | AQKotV5y5qBInw== 26 | -----END CERTIFICATE----- 27 | -------------------------------------------------------------------------------- /mgradm/cmd/migrate/podman/podman_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package podman 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/spf13/cobra" 11 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 12 | "github.com/uyuni-project/uyuni-tools/shared/testutils/flagstests" 13 | "github.com/uyuni-project/uyuni-tools/shared/types" 14 | ) 15 | 16 | func TestParamsParsing(t *testing.T) { 17 | args := []string{ 18 | "--prepare", 19 | "--user", "sudoer", 20 | "source.fq.dn", 21 | } 22 | 23 | args = append(args, flagstests.MirrorFlagTestArgs...) 24 | args = append(args, flagstests.SCCFlagTestArgs...) 25 | args = append(args, flagstests.PodmanFlagsTestArgs...) 26 | args = append(args, flagstests.ServerFlagsTestArgs()...) 27 | 28 | // Test function asserting that the args are properly parsed 29 | tester := func(_ *types.GlobalFlags, flags *podmanMigrateFlags, 30 | _ *cobra.Command, args []string, 31 | ) error { 32 | testutils.AssertTrue(t, "Prepare not set", flags.Migration.Prepare) 33 | flagstests.AssertMirrorFlag(t, flags.Mirror) 34 | testutils.AssertEquals(t, "Error parsing --user", "sudoer", flags.Migration.User) 35 | testutils.AssertEquals(t, "Wrong FQDN", "source.fq.dn", args[0]) 36 | flagstests.AssertPodmanInstallFlags(t, &flags.Podman) 37 | flagstests.AssertServerFlags(t, &flags.ServerFlags) 38 | return nil 39 | } 40 | 41 | globalFlags := types.GlobalFlags{} 42 | cmd := newCmd(&globalFlags, tester) 43 | 44 | testutils.AssertHasAllFlags(t, cmd, args) 45 | 46 | cmd.SetArgs(args) 47 | if err := cmd.Execute(); err != nil { 48 | t.Errorf("command failed with error: %s", err) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /mgradm/shared/templates/postUpgradeScriptTemplate.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package templates 6 | 7 | import ( 8 | "io" 9 | "text/template" 10 | ) 11 | 12 | const postUpgradeScriptTemplate = ` 13 | sed 's/cobbler\.host.*/cobbler\.host = localhost/' -i /etc/rhn/rhn.conf; 14 | if [ -f /etc/cobbler/settings.d/zz-uyuni.settings ] && \ 15 | grep -q uyuni_authentication_endpoint /etc/cobbler/settings.d/zz-uyuni.settings; then 16 | sed 's/uyuni_authentication_endpoint.*/uyuni_authentication_endpoint: http:\/\/localhost/' \ 17 | -i /etc/cobbler/settings.d/zz-uyuni.settings; 18 | else 19 | echo 'uyuni_authentication_endpoint: "http://localhost"' >> /etc/cobbler/settings.d/zz-uyuni.settings 20 | fi 21 | 22 | if grep -q pam_auth_service /etc/rhn/rhn.conf; then 23 | sed 's/pam_auth_service.*/pam_auth_service = susemanager/' -i /etc/rhn/rhn.conf; 24 | else 25 | echo 'pam_auth_service = susemanager' >> /etc/rhn/rhn.conf 26 | fi 27 | 28 | if test -e /etc/sysconfig/prometheus-postgres_exporter/systemd/60-server.conf; then 29 | sed 's/\/etc\/postgres_exporter\//\/etc\/sysconfig\/prometheus-postgres_exporter\//' \ 30 | -i /etc/sysconfig/prometheus-postgres_exporter/systemd/60-server.conf; 31 | fi 32 | 33 | echo "DONE"` 34 | 35 | // PostUpgradeTemplateData represents information used to create post upgrade. 36 | type PostUpgradeTemplateData struct { 37 | } 38 | 39 | // Render will create script for finalizing PostgreSQL upgrade. 40 | func (data PostUpgradeTemplateData) Render(wr io.Writer) error { 41 | t := template.Must(template.New("script").Parse(postUpgradeScriptTemplate)) 42 | return t.Execute(wr, data) 43 | } 44 | -------------------------------------------------------------------------------- /mgrpxy/cmd/status/status.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package status 6 | 7 | import ( 8 | "errors" 9 | 10 | "github.com/spf13/cobra" 11 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 12 | "github.com/uyuni-project/uyuni-tools/shared/podman" 13 | "github.com/uyuni-project/uyuni-tools/shared/types" 14 | "github.com/uyuni-project/uyuni-tools/shared/utils" 15 | ) 16 | 17 | var systemd podman.Systemd = podman.NewSystemd() 18 | 19 | type statusFlags struct { 20 | } 21 | 22 | func newCmd(globalFlags *types.GlobalFlags, run utils.CommandFunc[statusFlags]) *cobra.Command { 23 | cmd := &cobra.Command{ 24 | Use: "status", 25 | GroupID: "management", 26 | Short: L("Get the proxy status"), 27 | Long: L("Get the proxy status"), 28 | Args: cobra.ExactArgs(0), 29 | RunE: func(cmd *cobra.Command, args []string) error { 30 | var flags statusFlags 31 | return utils.CommandHelper(globalFlags, cmd, args, &flags, nil, run) 32 | }, 33 | } 34 | cmd.SetUsageTemplate(cmd.UsageTemplate()) 35 | 36 | return cmd 37 | } 38 | 39 | // NewCommand to get the status of the server. 40 | func NewCommand(globalFlags *types.GlobalFlags) *cobra.Command { 41 | return newCmd(globalFlags, status) 42 | } 43 | 44 | func status(globalFlags *types.GlobalFlags, flags *statusFlags, cmd *cobra.Command, args []string) error { 45 | if systemd.HasService(podman.ProxyService) { 46 | return podmanStatus(globalFlags, flags, cmd, args) 47 | } 48 | 49 | if utils.IsInstalled("kubectl") && utils.IsInstalled("helm") { 50 | return kubernetesStatus(globalFlags, flags, cmd, args) 51 | } 52 | 53 | return errors.New(L("no installed proxy detected")) 54 | } 55 | -------------------------------------------------------------------------------- /shared/podman/hostinspector_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package podman 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/uyuni-project/uyuni-tools/shared/testutils" 11 | "github.com/uyuni-project/uyuni-tools/shared/utils" 12 | ) 13 | 14 | func TestHostInspectorGenerate(t *testing.T) { 15 | inspector := NewHostInspector() 16 | script, err := inspector.GenerateScript() 17 | if err != nil { 18 | t.Errorf("Unexpected error %s", err) 19 | } 20 | 21 | expected := ` 22 | # inspect.sh, generated by mgradm 23 | echo "scc_username=$(cat /etc/zypp/credentials.d/SCCcredentials 2>/dev/null | grep username | cut -d= -f2 || true)" 24 | echo "scc_password=$(cat /etc/zypp/credentials.d/SCCcredentials 2>/dev/null | grep password | cut -d= -f2 || true)" 25 | echo "has_uyuni_server=$(systemctl list-unit-files uyuni-server.service >/dev/null && echo true || echo false)" 26 | echo "has_salt_minion=$(systemctl list-unit-files venv-salt-minion.service >/dev/null && echo true || echo false)" 27 | exit 0 28 | ` 29 | 30 | testutils.AssertEquals(t, "Wrongly generated script", expected, script) 31 | } 32 | 33 | func TestHostInspectorParse(t *testing.T) { 34 | content := ` 35 | scc_username=myuser 36 | scc_password=mysecret 37 | has_uyuni_server=true 38 | ` 39 | 40 | actual, err := utils.ReadInspectData[HostInspectData]([]byte(content)) 41 | if err != nil { 42 | t.Fatalf("Unexpected error: %s", err) 43 | } 44 | 45 | testutils.AssertEquals(t, "Invalid SCC username", "myuser", actual.SCCUsername) 46 | testutils.AssertEquals(t, "Invalid SCC password", "mysecret", actual.SCCPassword) 47 | testutils.AssertTrue(t, "HasUyuniServer should be true", actual.HasUyuniServer) 48 | } 49 | -------------------------------------------------------------------------------- /mgrctl/cmd/api/login.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package api 6 | 7 | import ( 8 | "errors" 9 | 10 | "github.com/rs/zerolog/log" 11 | "github.com/spf13/cobra" 12 | 13 | "github.com/uyuni-project/uyuni-tools/shared/api" 14 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 15 | "github.com/uyuni-project/uyuni-tools/shared/types" 16 | "github.com/uyuni-project/uyuni-tools/shared/utils" 17 | ) 18 | 19 | func runLogin(_ *types.GlobalFlags, flags *apiFlags, cmd *cobra.Command, _ []string) error { 20 | log.Debug().Msg("Running login command") 21 | 22 | if api.IsAlreadyLoggedIn() && !flags.ForceLogin { 23 | return errors.New(L("Refusing to overwrite existing login. Use --force to ignore this check.")) 24 | } 25 | 26 | utils.AskIfMissing(&flags.Server, cmd.Flag("api-server").Usage, 0, 0, utils.IsWellFormedFQDN) 27 | utils.AskIfMissing(&flags.User, cmd.Flag("api-user").Usage, 0, 0, nil) 28 | utils.AskPasswordIfMissingOnce(&flags.Password, cmd.Flag("api-password").Usage, 0, 0) 29 | 30 | client, err := api.Init(&flags.ConnectionDetails) 31 | if err != nil { 32 | return err 33 | } 34 | if err := client.Login(); err != nil { 35 | return utils.Errorf(err, L("Failed to validate credentials.")) 36 | } 37 | if err := api.StoreLoginCreds(client); err != nil { 38 | return err 39 | } 40 | 41 | log.Info().Msg(L("Login credentials verified.")) 42 | return nil 43 | } 44 | 45 | func runLogout(_ *types.GlobalFlags, _ *apiFlags, _ *cobra.Command, _ []string) error { 46 | log.Debug().Msg("Running logout command") 47 | 48 | if err := api.RemoveLoginCreds(); err != nil { 49 | return err 50 | } 51 | log.Info().Msg(L("Successfully logged out")) 52 | return nil 53 | } 54 | -------------------------------------------------------------------------------- /mgrpxy/cmd/uninstall/uninstall.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package uninstall 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/shared" 10 | "github.com/uyuni-project/uyuni-tools/shared/kubernetes" 11 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | "github.com/uyuni-project/uyuni-tools/shared/utils" 14 | ) 15 | 16 | func newCmd(globalFlags *types.GlobalFlags, run utils.CommandFunc[utils.UninstallFlags]) *cobra.Command { 17 | uninstallCmd := &cobra.Command{ 18 | Use: "uninstall", 19 | GroupID: "deploy", 20 | Short: L("Uninstall a proxy"), 21 | Long: L(`Uninstall a proxy and optionally the corresponding volumes. 22 | By default it will only print what would be done, use --force to actually remove.`) + kubernetes.UninstallHelp(), 23 | Args: cobra.ExactArgs(0), 24 | RunE: func(cmd *cobra.Command, args []string) error { 25 | var flags utils.UninstallFlags 26 | return utils.CommandHelper(globalFlags, cmd, args, &flags, nil, run) 27 | }, 28 | } 29 | utils.AddUninstallFlags(uninstallCmd, true) 30 | 31 | return uninstallCmd 32 | } 33 | 34 | // NewCommand for uninstall proxy. 35 | func NewCommand(globalFlags *types.GlobalFlags) *cobra.Command { 36 | return newCmd(globalFlags, uninstall) 37 | } 38 | 39 | func uninstall( 40 | globalFlags *types.GlobalFlags, 41 | flags *utils.UninstallFlags, 42 | cmd *cobra.Command, 43 | args []string, 44 | ) error { 45 | fn, err := shared.ChoosePodmanOrKubernetes(cmd.Flags(), uninstallForPodman, uninstallForKubernetes) 46 | if err != nil { 47 | return err 48 | } 49 | 50 | return fn(globalFlags, flags, cmd, args) 51 | } 52 | -------------------------------------------------------------------------------- /mgrpxy/cmd/upgrade/podman/podman.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package podman 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/mgrpxy/shared/podman" 10 | "github.com/uyuni-project/uyuni-tools/mgrpxy/shared/utils" 11 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 12 | shared_podman "github.com/uyuni-project/uyuni-tools/shared/podman" 13 | "github.com/uyuni-project/uyuni-tools/shared/types" 14 | shared_utils "github.com/uyuni-project/uyuni-tools/shared/utils" 15 | ) 16 | 17 | func newCmd(globalFlags *types.GlobalFlags, run shared_utils.CommandFunc[podman.PodmanProxyFlags]) *cobra.Command { 18 | podmanCmd := &cobra.Command{ 19 | Use: "podman", 20 | Short: L("Upgrade a proxy on podman"), 21 | Long: L(`Upgrade a proxy on podman 22 | 23 | The upgrade podman command assumes podman is upgraded locally. 24 | 25 | /etc/uyuni/proxy/apache.conf and /etc/uyuni/squid.conf will be used as tuning files 26 | for apache and squid if available and not superseded by the matching command arguments. 27 | 28 | NOTE: for now upgrading on a remote podman is not supported! 29 | `), 30 | Args: cobra.ExactArgs(0), 31 | RunE: func(cmd *cobra.Command, args []string) error { 32 | var flags podman.PodmanProxyFlags 33 | return shared_utils.CommandHelper(globalFlags, cmd, args, &flags, nil, run) 34 | }, 35 | } 36 | 37 | utils.AddSCCFlag(podmanCmd) 38 | utils.AddImageFlags(podmanCmd) 39 | shared_podman.AddPodmanArgFlag(podmanCmd) 40 | 41 | return podmanCmd 42 | } 43 | 44 | // NewCommand install a new proxy on podman from scratch. 45 | func NewCommand(globalFlags *types.GlobalFlags) *cobra.Command { 46 | return newCmd(globalFlags, upgradePodman) 47 | } 48 | -------------------------------------------------------------------------------- /shared/api/types.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package api 6 | 7 | import "net/http" 8 | 9 | const rootPathApiv1 = "/rhn/manager/api" 10 | const apiCredentialsStore = ".uyuni-api.json" 11 | 12 | // APIClient is the API entrypoint structure. 13 | type APIClient struct { 14 | 15 | // URL to the API endpoint of the target host 16 | BaseURL string 17 | 18 | // net/http client 19 | Client HTTPClient 20 | 21 | // Authentication cookie storage 22 | AuthCookie *http.Cookie 23 | 24 | // Connection details 25 | Details *ConnectionDetails 26 | } 27 | 28 | // HTTPClient is a minimal HTTPClient interface primarily for unit testing. 29 | type HTTPClient interface { 30 | Do(req *http.Request) (*http.Response, error) 31 | } 32 | 33 | // ConnectionDetails holds the details for initial API connection. 34 | type ConnectionDetails struct { 35 | 36 | // FQDN of the target host. 37 | Server string 38 | 39 | // User to login under. 40 | User string 41 | 42 | // Password for the user. 43 | Password string 44 | 45 | // Path to CA certificate file used for target host validation. 46 | // Provided certificate is used together with system certificates. 47 | CApath string `mapstructure:"cacert"` 48 | 49 | // Disable certificate validation, unsecure and not recommended. 50 | Insecure bool 51 | 52 | // Indicates if details we loaded from cache 53 | InSession bool 54 | 55 | // PXE cookie 56 | Cookie string 57 | } 58 | 59 | // APIResponse describes the HTTP response where T is the type of the result. 60 | type APIResponse[T interface{}] struct { 61 | Result T 62 | Success bool 63 | Message string 64 | } 65 | 66 | // Authentication storage. 67 | type authStorage struct { 68 | Session string 69 | Server string 70 | CApath string 71 | } 72 | -------------------------------------------------------------------------------- /mgradm/cmd/status/kubernetes.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | //go:build !nok8s 6 | 7 | package status 8 | 9 | import ( 10 | "errors" 11 | 12 | "github.com/rs/zerolog" 13 | "github.com/rs/zerolog/log" 14 | "github.com/spf13/cobra" 15 | adm_utils "github.com/uyuni-project/uyuni-tools/mgradm/shared/utils" 16 | "github.com/uyuni-project/uyuni-tools/shared" 17 | "github.com/uyuni-project/uyuni-tools/shared/kubernetes" 18 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 19 | "github.com/uyuni-project/uyuni-tools/shared/types" 20 | "github.com/uyuni-project/uyuni-tools/shared/utils" 21 | ) 22 | 23 | func kubernetesStatus( 24 | _ *types.GlobalFlags, 25 | _ *statusFlags, 26 | _ *cobra.Command, 27 | _ []string, 28 | ) error { 29 | cnx := shared.NewConnection("kubectl", "", kubernetes.ServerFilter) 30 | namespace, err := cnx.GetNamespace("") 31 | if err != nil { 32 | return utils.Errorf(err, L("failed to find the uyuni deployment namespace")) 33 | } 34 | 35 | // Is the pod running? Do we have all the replicas? 36 | status, err := kubernetes.GetDeploymentStatus(namespace, kubernetes.ServerApp) 37 | if err != nil { 38 | return utils.Errorf(err, L("failed to get deployment status")) 39 | } 40 | if status.Replicas != status.ReadyReplicas { 41 | log.Warn().Msgf(L("Some replicas are not ready: %[1]d / %[2]d"), status.ReadyReplicas, status.Replicas) 42 | } 43 | 44 | if status.AvailableReplicas == 0 { 45 | return errors.New(L("the pod is not running")) 46 | } 47 | 48 | // Are the services running in the container? 49 | if err := adm_utils.ExecCommand(zerolog.InfoLevel, cnx, "spacewalk-service", "status"); err != nil { 50 | return utils.Errorf(err, L("failed to run spacewalk-service status")) 51 | } 52 | return nil 53 | } 54 | -------------------------------------------------------------------------------- /mgradm/cmd/uninstall/uninstall.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SUSE LLC 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package uninstall 6 | 7 | import ( 8 | "github.com/spf13/cobra" 9 | "github.com/uyuni-project/uyuni-tools/shared" 10 | "github.com/uyuni-project/uyuni-tools/shared/kubernetes" 11 | . "github.com/uyuni-project/uyuni-tools/shared/l10n" 12 | "github.com/uyuni-project/uyuni-tools/shared/types" 13 | "github.com/uyuni-project/uyuni-tools/shared/utils" 14 | ) 15 | 16 | func newCmd(globalFlags *types.GlobalFlags, run utils.CommandFunc[utils.UninstallFlags]) *cobra.Command { 17 | uninstallCmd := &cobra.Command{ 18 | Use: "uninstall", 19 | GroupID: "deploy", 20 | Short: L("Uninstall a server"), 21 | Long: L(`Uninstall a server and optionally the corresponding volumes. 22 | By default it will only print what would be done, use --force to actually remove.`) + kubernetes.UninstallHelp(), 23 | Args: cobra.ExactArgs(0), 24 | RunE: func(cmd *cobra.Command, args []string) error { 25 | var flags utils.UninstallFlags 26 | return utils.CommandHelper(globalFlags, cmd, args, &flags, nil, run) 27 | }, 28 | } 29 | utils.AddUninstallFlags(uninstallCmd, utils.KubernetesBuilt) 30 | 31 | return uninstallCmd 32 | } 33 | 34 | // NewCommand uninstall a server and optionally the corresponding volumes. 35 | func NewCommand(globalFlags *types.GlobalFlags) *cobra.Command { 36 | return newCmd(globalFlags, uninstall) 37 | } 38 | 39 | func uninstall( 40 | globalFlags *types.GlobalFlags, 41 | flags *utils.UninstallFlags, 42 | cmd *cobra.Command, 43 | args []string, 44 | ) error { 45 | fn, err := shared.ChoosePodmanOrKubernetes(cmd.Flags(), uninstallForPodman, uninstallForKubernetes) 46 | if err != nil { 47 | return err 48 | } 49 | 50 | return fn(globalFlags, flags, cmd, args) 51 | } 52 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 SUSE LLC 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | # See https://pre-commit.com for more information 6 | # See https://pre-commit.com/hooks.html for more hooks 7 | repos: 8 | - repo: https://github.com/pre-commit/pre-commit-hooks 9 | rev: v5.0.0 10 | hooks: 11 | - id: trailing-whitespace 12 | - id: end-of-file-fixer 13 | - id: check-yaml 14 | - id: check-added-large-files 15 | - repo: https://github.com/golangci/golangci-lint 16 | rev: v1.59.1 17 | hooks: 18 | - id: golangci-lint 19 | fail_fast: true 20 | stages: 21 | - pre-push 22 | 23 | - repo: https://github.com/fsfe/reuse-tool 24 | rev: v4.0.3 25 | hooks: 26 | - id: reuse 27 | 28 | - repo: https://github.com/cbosdo/gettext-go-lint 29 | rev: gettext-go-lint-0.1.1-0 30 | hooks: 31 | - id: lint 32 | args: 33 | - --keyword=L,NL,PL 34 | 35 | - repo: local 36 | hooks: 37 | - id: check-localizable 38 | name: Check localizable strings 39 | entry: ./check_localizable 40 | files: '.*\.go' 41 | language: script 42 | - id: build 43 | name: Build 44 | fail_fast: true 45 | pass_filenames: false 46 | entry: ./pre-commit-build.sh 47 | language: script 48 | stages: 49 | - pre-push 50 | - id: build-all-tags 51 | name: Build with all tags 52 | fail_fast: true 53 | pass_filenames: false 54 | entry: ./pre-commit-build.sh 55 | language: script 56 | args: 57 | - -tags=nok8s,ptf 58 | stages: 59 | - pre-push 60 | - id: copyright-year 61 | name: Copyright year is up to date in changed files 62 | entry: ./update-copyright-year.sh 63 | language: script 64 | require_serial: true 65 | stages: 66 | - pre-push 67 | - pre-commit 68 | --------------------------------------------------------------------------------