mirror of
https://github.com/argoproj/argo-cd.git
synced 2026-02-20 01:28:45 +01:00
fix: use registry for helm registry .. commands (#23142)
Signed-off-by: Blake Pettersson <blake.pettersson@gmail.com> Co-authored-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
@@ -22,12 +23,13 @@ import (
|
||||
|
||||
// A thin wrapper around the "helm" command, adding logging and error translation.
|
||||
type Cmd struct {
|
||||
helmHome string
|
||||
WorkDir string
|
||||
IsLocal bool
|
||||
IsHelmOci bool
|
||||
proxy string
|
||||
noProxy string
|
||||
helmHome string
|
||||
WorkDir string
|
||||
IsLocal bool
|
||||
IsHelmOci bool
|
||||
proxy string
|
||||
noProxy string
|
||||
runWithRedactor func(cmd *exec.Cmd, redactor func(text string) string) (string, error)
|
||||
}
|
||||
|
||||
func NewCmd(workDir string, version string, proxy string, noProxy string) (*Cmd, error) {
|
||||
@@ -40,11 +42,15 @@ func NewCmd(workDir string, version string, proxy string, noProxy string) (*Cmd,
|
||||
}
|
||||
|
||||
func NewCmdWithVersion(workDir string, isHelmOci bool, proxy string, noProxy string) (*Cmd, error) {
|
||||
return newCmdWithVersion(workDir, isHelmOci, proxy, noProxy, executil.RunWithRedactor)
|
||||
}
|
||||
|
||||
func newCmdWithVersion(workDir string, isHelmOci bool, proxy string, noProxy string, runWithRedactor func(cmd *exec.Cmd, redactor func(text string) string) (string, error)) (*Cmd, error) {
|
||||
tmpDir, err := os.MkdirTemp("", "helm")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create temporary directory for helm: %w", err)
|
||||
}
|
||||
return &Cmd{WorkDir: workDir, helmHome: tmpDir, IsHelmOci: isHelmOci, proxy: proxy, noProxy: noProxy}, err
|
||||
return &Cmd{WorkDir: workDir, helmHome: tmpDir, IsHelmOci: isHelmOci, proxy: proxy, noProxy: noProxy, runWithRedactor: runWithRedactor}, err
|
||||
}
|
||||
|
||||
var redactor = func(text string) string {
|
||||
@@ -63,13 +69,9 @@ func (c Cmd) run(ctx context.Context, args ...string) (string, string, error) {
|
||||
fmt.Sprintf("HELM_CONFIG_HOME=%s/config", c.helmHome))
|
||||
}
|
||||
|
||||
if c.IsHelmOci {
|
||||
cmd.Env = append(cmd.Env, "HELM_EXPERIMENTAL_OCI=1")
|
||||
}
|
||||
|
||||
cmd.Env = proxy.UpsertEnv(cmd, c.proxy, c.noProxy)
|
||||
|
||||
out, err := executil.RunWithRedactor(cmd, redactor)
|
||||
out, err := c.runWithRedactor(cmd, redactor)
|
||||
fullCommand := executil.GetCommandArgsToLog(cmd)
|
||||
if err != nil {
|
||||
return out, fullCommand, fmt.Errorf("failed to get command args to log: %w", err)
|
||||
@@ -79,7 +81,11 @@ func (c Cmd) run(ctx context.Context, args ...string) (string, string, error) {
|
||||
|
||||
func (c *Cmd) RegistryLogin(repo string, creds Creds) (string, error) {
|
||||
args := []string{"registry", "login"}
|
||||
args = append(args, repo)
|
||||
registry, err := c.getHelmRegistry(repo)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to parse registry URL: %w", err)
|
||||
}
|
||||
args = append(args, registry)
|
||||
|
||||
if creds.GetUsername() != "" {
|
||||
args = append(args, "--username", creds.GetUsername())
|
||||
@@ -127,7 +133,11 @@ func (c *Cmd) RegistryLogin(repo string, creds Creds) (string, error) {
|
||||
|
||||
func (c *Cmd) RegistryLogout(repo string, _ Creds) (string, error) {
|
||||
args := []string{"registry", "logout"}
|
||||
args = append(args, repo)
|
||||
registry, err := c.getHelmRegistry(repo)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to parse registry URL: %w", err)
|
||||
}
|
||||
args = append(args, registry)
|
||||
out, _, err := c.run(context.Background(), args...)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to logout from registry: %w", err)
|
||||
@@ -473,3 +483,18 @@ func (c *Cmd) Freestyle(args ...string) (string, error) {
|
||||
func (c *Cmd) Close() {
|
||||
_ = os.RemoveAll(c.helmHome)
|
||||
}
|
||||
|
||||
// getHelmRegistry extracts the registry host from a Helm repository URL. This is because it is required for the
|
||||
// `helm registry login` command to use the registry host rather than the full URL.
|
||||
func (c *Cmd) getHelmRegistry(repo string) (string, error) {
|
||||
if !strings.Contains(repo, "//") {
|
||||
repo = "//" + repo
|
||||
}
|
||||
|
||||
uri, err := url.Parse(repo)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return uri.Host, nil
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package helm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -48,3 +51,126 @@ func TestNewCmd_withProxy(t *testing.T) {
|
||||
assert.Equal(t, "https://proxy:8888", cmd.proxy)
|
||||
assert.Equal(t, ".argoproj.io", cmd.noProxy)
|
||||
}
|
||||
|
||||
func TestRegistryLogin(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
repo string
|
||||
creds *HelmCreds
|
||||
execErr error
|
||||
expectedErr error
|
||||
expectedOut string
|
||||
}{
|
||||
{
|
||||
name: "username and password",
|
||||
repo: "my.registry.com/repo",
|
||||
creds: &HelmCreds{Username: "user", Password: "pass"},
|
||||
expectedOut: "helm registry login my.registry.com --username user --password pass",
|
||||
},
|
||||
{
|
||||
name: "username and password with just the hostname",
|
||||
repo: "my.registry.com",
|
||||
creds: &HelmCreds{Username: "user", Password: "pass"},
|
||||
expectedOut: "helm registry login my.registry.com --username user --password pass",
|
||||
},
|
||||
{
|
||||
name: "ca file path",
|
||||
repo: "my.registry.com/repo",
|
||||
creds: &HelmCreds{CAPath: "/path/to/ca"},
|
||||
expectedOut: "helm registry login my.registry.com --ca-file /path/to/ca",
|
||||
},
|
||||
{
|
||||
name: "insecure skip verify",
|
||||
repo: "my.registry.com/repo",
|
||||
creds: &HelmCreds{InsecureSkipVerify: true},
|
||||
expectedOut: "helm registry login my.registry.com --insecure",
|
||||
},
|
||||
{
|
||||
name: "helm failure",
|
||||
repo: "my.registry.com/repo",
|
||||
creds: &HelmCreds{},
|
||||
execErr: errors.New("exit status 1"),
|
||||
expectedErr: errors.New("failed to login to registry: failed to get command args to log: exit status 1"),
|
||||
},
|
||||
{
|
||||
name: "invalid repo",
|
||||
repo: ":///bad-url",
|
||||
expectedErr: errors.New("failed to parse registry URL: parse \":///bad-url\": missing protocol scheme"),
|
||||
},
|
||||
{
|
||||
name: "username & password",
|
||||
repo: "my.registry.com/repo",
|
||||
creds: &HelmCreds{Username: "user", Password: "pass"},
|
||||
expectedOut: "helm registry login my.registry.com --username user --password pass",
|
||||
},
|
||||
{
|
||||
name: "combined flags",
|
||||
repo: "my.registry.com:5000/repo",
|
||||
creds: &HelmCreds{
|
||||
Username: "u",
|
||||
Password: "p",
|
||||
CAPath: "/ca",
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
expectedOut: "helm registry login my.registry.com:5000 --username u --password p --ca-file /ca --insecure",
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
c, err := newCmdWithVersion(".", false, "", "", func(cmd *exec.Cmd, _ func(_ string) string) (string, error) {
|
||||
if tc.execErr != nil {
|
||||
return "", tc.execErr
|
||||
}
|
||||
return strings.Join(cmd.Args, " "), nil
|
||||
})
|
||||
require.NoError(t, err)
|
||||
out, err := c.RegistryLogin(tc.repo, tc.creds)
|
||||
assert.Equal(t, tc.expectedOut, out)
|
||||
if tc.expectedErr != nil {
|
||||
require.EqualError(t, err, tc.expectedErr.Error())
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegistryLogout(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
repo string
|
||||
execErr error
|
||||
expectedErr error
|
||||
expectedOut string
|
||||
}{
|
||||
{
|
||||
name: "valid repo",
|
||||
repo: "my.registry.com/repo",
|
||||
expectedOut: "helm registry logout my.registry.com",
|
||||
expectedErr: nil,
|
||||
},
|
||||
{
|
||||
name: "invalid repo",
|
||||
repo: ":///bad-url",
|
||||
expectedErr: errors.New("failed to parse registry URL: parse \":///bad-url\": missing protocol scheme"),
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
c, err := newCmdWithVersion(".", false, "", "", func(cmd *exec.Cmd, _ func(_ string) string) (string, error) {
|
||||
if tc.execErr != nil {
|
||||
return "", tc.execErr
|
||||
}
|
||||
return strings.Join(cmd.Args, " "), nil
|
||||
})
|
||||
require.NoError(t, err)
|
||||
out, err := c.RegistryLogout(tc.repo, nil)
|
||||
assert.Equal(t, tc.expectedOut, out)
|
||||
if tc.expectedErr != nil {
|
||||
require.EqualError(t, err, tc.expectedErr.Error())
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user