Support for azure acr helm repositories (#1526)
Adds a basic support for Helm repositories hosted on Azure Container Registry (not OCI but classic ones). Add a new field to RepositorySpec to state that is externally managed and runs the `az-cli` command instead of the helm one to manage the repository.
This commit is contained in:
		
							parent
							
								
									563fce4adf
								
							
						
					
					
						commit
						8f8669778c
					
				|  | @ -2418,7 +2418,7 @@ func (helm *mockHelmExec) SetExtraArgs(args ...string) { | |||
| func (helm *mockHelmExec) SetHelmBinary(bin string) { | ||||
| 	return | ||||
| } | ||||
| func (helm *mockHelmExec) AddRepo(name, repository, cafile, certfile, keyfile, username, password string) error { | ||||
| func (helm *mockHelmExec) AddRepo(name, repository, cafile, certfile, keyfile, username, password string, managed string) error { | ||||
| 	helm.repos = append(helm.repos, mockRepo{Name: name}) | ||||
| 	return nil | ||||
| } | ||||
|  |  | |||
|  | @ -41,7 +41,7 @@ func (helm *noCallHelmExec) SetHelmBinary(bin string) { | |||
| 	helm.doPanic() | ||||
| 	return | ||||
| } | ||||
| func (helm *noCallHelmExec) AddRepo(name, repository, cafile, certfile, keyfile, username, password string) error { | ||||
| func (helm *noCallHelmExec) AddRepo(name, repository, cafile, certfile, keyfile, username, password string, managed string) error { | ||||
| 	helm.doPanic() | ||||
| 	return nil | ||||
| } | ||||
|  |  | |||
|  | @ -82,8 +82,8 @@ func (helm *Helm) SetExtraArgs(args ...string) { | |||
| func (helm *Helm) SetHelmBinary(bin string) { | ||||
| 	return | ||||
| } | ||||
| func (helm *Helm) AddRepo(name, repository, cafile, certfile, keyfile, username, password string) error { | ||||
| 	helm.Repo = []string{name, repository, cafile, certfile, keyfile, username, password} | ||||
| func (helm *Helm) AddRepo(name, repository, cafile, certfile, keyfile, username, password string, managed string) error { | ||||
| 	helm.Repo = []string{name, repository, cafile, certfile, keyfile, username, password, managed} | ||||
| 	return nil | ||||
| } | ||||
| func (helm *Helm) UpdateRepo() error { | ||||
|  |  | |||
|  | @ -105,12 +105,19 @@ func (helm *execer) SetHelmBinary(bin string) { | |||
| 	helm.helmBinary = bin | ||||
| } | ||||
| 
 | ||||
| func (helm *execer) AddRepo(name, repository, cafile, certfile, keyfile, username, password string) error { | ||||
| func (helm *execer) AddRepo(name, repository, cafile, certfile, keyfile, username, password string, managed string) error { | ||||
| 	var args []string | ||||
| 	var out []byte | ||||
| 	var err error | ||||
| 	if name == "" && repository != "" { | ||||
| 		helm.logger.Infof("empty field name\n") | ||||
| 		return fmt.Errorf("empty field name") | ||||
| 	} | ||||
| 	switch managed { | ||||
| 	case "acr": | ||||
| 		helm.logger.Infof("Adding repo %v (acr)", name) | ||||
| 		out, err = helm.azcli(name) | ||||
| 	case "": | ||||
| 		args = append(args, "repo", "add", name, repository) | ||||
| 
 | ||||
| 		// See https://github.com/helm/helm/pull/8777
 | ||||
|  | @ -132,7 +139,12 @@ func (helm *execer) AddRepo(name, repository, cafile, certfile, keyfile, usernam | |||
| 			args = append(args, "--username", username, "--password", password) | ||||
| 		} | ||||
| 		helm.logger.Infof("Adding repo %v %v", name, repository) | ||||
| 	out, err := helm.exec(args, map[string]string{}) | ||||
| 		out, err = helm.exec(args, map[string]string{}) | ||||
| 	default: | ||||
| 		helm.logger.Errorf("ERROR: unknown type '%v' for repository %v", managed, name) | ||||
| 		out = nil | ||||
| 		err = nil | ||||
| 	} | ||||
| 	helm.info(out) | ||||
| 	return err | ||||
| } | ||||
|  | @ -370,6 +382,15 @@ func (helm *execer) exec(args []string, env map[string]string) ([]byte, error) { | |||
| 	return bytes, err | ||||
| } | ||||
| 
 | ||||
| func (helm *execer) azcli(name string) ([]byte, error) { | ||||
| 	cmdargs := append(strings.Split("acr helm repo add --name", " "), name) | ||||
| 	cmd := fmt.Sprintf("exec: az %s", strings.Join(cmdargs, " ")) | ||||
| 	helm.logger.Debug(cmd) | ||||
| 	bytes, err := helm.runner.Execute("az", cmdargs, map[string]string{}) | ||||
| 	helm.logger.Debugf("%s: %s", cmd, bytes) | ||||
| 	return bytes, err | ||||
| } | ||||
| 
 | ||||
| func (helm *execer) info(out []byte) { | ||||
| 	if len(out) > 0 { | ||||
| 		helm.logger.Infof("%s", out) | ||||
|  |  | |||
|  | @ -82,7 +82,7 @@ func Test_AddRepo_Helm_3_3_2(t *testing.T) { | |||
| 		kubeContext: "dev", | ||||
| 		runner:      &mockRunner{}, | ||||
| 	} | ||||
| 	helm.AddRepo("myRepo", "https://repo.example.com/", "", "cert.pem", "key.pem", "", "") | ||||
| 	helm.AddRepo("myRepo", "https://repo.example.com/", "", "cert.pem", "key.pem", "", "", "") | ||||
| 	expected := `Adding repo myRepo https://repo.example.com/
 | ||||
| exec: helm --kube-context dev repo add myRepo https://repo.example.com/ --force-update --cert-file cert.pem --key-file key.pem
 | ||||
| exec: helm --kube-context dev repo add myRepo https://repo.example.com/ --force-update --cert-file cert.pem --key-file key.pem: 
 | ||||
|  | @ -96,7 +96,7 @@ func Test_AddRepo(t *testing.T) { | |||
| 	var buffer bytes.Buffer | ||||
| 	logger := NewLogger(&buffer, "debug") | ||||
| 	helm := MockExecer(logger, "dev") | ||||
| 	helm.AddRepo("myRepo", "https://repo.example.com/", "", "cert.pem", "key.pem", "", "") | ||||
| 	helm.AddRepo("myRepo", "https://repo.example.com/", "", "cert.pem", "key.pem", "", "", "") | ||||
| 	expected := `Adding repo myRepo https://repo.example.com/
 | ||||
| exec: helm --kube-context dev repo add myRepo https://repo.example.com/ --cert-file cert.pem --key-file key.pem
 | ||||
| exec: helm --kube-context dev repo add myRepo https://repo.example.com/ --cert-file cert.pem --key-file key.pem: 
 | ||||
|  | @ -106,7 +106,7 @@ exec: helm --kube-context dev repo add myRepo https://repo.example.com/ --cert-f | |||
| 	} | ||||
| 
 | ||||
| 	buffer.Reset() | ||||
| 	helm.AddRepo("myRepo", "https://repo.example.com/", "ca.crt", "", "", "", "") | ||||
| 	helm.AddRepo("myRepo", "https://repo.example.com/", "ca.crt", "", "", "", "", "") | ||||
| 	expected = `Adding repo myRepo https://repo.example.com/
 | ||||
| exec: helm --kube-context dev repo add myRepo https://repo.example.com/ --ca-file ca.crt
 | ||||
| exec: helm --kube-context dev repo add myRepo https://repo.example.com/ --ca-file ca.crt: 
 | ||||
|  | @ -116,7 +116,7 @@ exec: helm --kube-context dev repo add myRepo https://repo.example.com/ --ca-fil | |||
| 	} | ||||
| 
 | ||||
| 	buffer.Reset() | ||||
| 	helm.AddRepo("myRepo", "https://repo.example.com/", "", "", "", "", "") | ||||
| 	helm.AddRepo("myRepo", "https://repo.example.com/", "", "", "", "", "", "") | ||||
| 	expected = `Adding repo myRepo https://repo.example.com/
 | ||||
| exec: helm --kube-context dev repo add myRepo https://repo.example.com/
 | ||||
| exec: helm --kube-context dev repo add myRepo https://repo.example.com/: 
 | ||||
|  | @ -126,7 +126,25 @@ exec: helm --kube-context dev repo add myRepo https://repo.example.com/: | |||
| 	} | ||||
| 
 | ||||
| 	buffer.Reset() | ||||
| 	helm.AddRepo("myRepo", "https://repo.example.com/", "", "", "", "example_user", "example_password") | ||||
| 	helm.AddRepo("acrRepo", "", "", "", "", "", "", "acr") | ||||
| 	expected = `Adding repo acrRepo (acr) | ||||
| exec: az acr helm repo add --name acrRepo | ||||
| exec: az acr helm repo add --name acrRepo:  | ||||
| ` | ||||
| 	if buffer.String() != expected { | ||||
| 		t.Errorf("helmexec.AddRepo()\nactual = %v\nexpect = %v", buffer.String(), expected) | ||||
| 	} | ||||
| 
 | ||||
| 	buffer.Reset() | ||||
| 	helm.AddRepo("otherRepo", "", "", "", "", "", "", "unknown") | ||||
| 	expected = `ERROR: unknown type 'unknown' for repository otherRepo | ||||
| ` | ||||
| 	if buffer.String() != expected { | ||||
| 		t.Errorf("helmexec.AddRepo()\nactual = %v\nexpect = %v", buffer.String(), expected) | ||||
| 	} | ||||
| 
 | ||||
| 	buffer.Reset() | ||||
| 	helm.AddRepo("myRepo", "https://repo.example.com/", "", "", "", "example_user", "example_password", "") | ||||
| 	expected = `Adding repo myRepo https://repo.example.com/
 | ||||
| exec: helm --kube-context dev repo add myRepo https://repo.example.com/ --username example_user --password example_password
 | ||||
| exec: helm --kube-context dev repo add myRepo https://repo.example.com/ --username example_user --password example_password: 
 | ||||
|  | @ -136,7 +154,7 @@ exec: helm --kube-context dev repo add myRepo https://repo.example.com/ --userna | |||
| 	} | ||||
| 
 | ||||
| 	buffer.Reset() | ||||
| 	helm.AddRepo("", "https://repo.example.com/", "", "", "", "", "") | ||||
| 	helm.AddRepo("", "https://repo.example.com/", "", "", "", "", "", "") | ||||
| 	expected = `empty field name | ||||
| 
 | ||||
| ` | ||||
|  | @ -482,7 +500,7 @@ func Test_LogLevels(t *testing.T) { | |||
| 		buffer.Reset() | ||||
| 		logger := NewLogger(&buffer, logLevel) | ||||
| 		helm := MockExecer(logger, "") | ||||
| 		helm.AddRepo("myRepo", "https://repo.example.com/", "", "", "", "example_user", "example_password") | ||||
| 		helm.AddRepo("myRepo", "https://repo.example.com/", "", "", "", "example_user", "example_password", "") | ||||
| 		if buffer.String() != expected { | ||||
| 			t.Errorf("helmexec.AddRepo()\nactual = %v\nexpect = %v", buffer.String(), expected) | ||||
| 		} | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ type Interface interface { | |||
| 	SetExtraArgs(args ...string) | ||||
| 	SetHelmBinary(bin string) | ||||
| 
 | ||||
| 	AddRepo(name, repository, cafile, certfile, keyfile, username, password string) error | ||||
| 	AddRepo(name, repository, cafile, certfile, keyfile, username, password string, managed string) error | ||||
| 	UpdateRepo() error | ||||
| 	BuildDeps(name, chart string) error | ||||
| 	UpdateDeps(chart string) error | ||||
|  |  | |||
|  | @ -157,6 +157,7 @@ type RepositorySpec struct { | |||
| 	KeyFile  string `yaml:"keyFile,omitempty"` | ||||
| 	Username string `yaml:"username,omitempty"` | ||||
| 	Password string `yaml:"password,omitempty"` | ||||
| 	Managed  string `yaml:"managed,omitempty"` | ||||
| } | ||||
| 
 | ||||
| // ReleaseSpec defines the structure of a helm release
 | ||||
|  | @ -313,7 +314,7 @@ func (st *HelmState) ApplyOverrides(spec *ReleaseSpec) { | |||
| } | ||||
| 
 | ||||
| type RepoUpdater interface { | ||||
| 	AddRepo(name, repository, cafile, certfile, keyfile, username, password string) error | ||||
| 	AddRepo(name, repository, cafile, certfile, keyfile, username, password string, managed string) error | ||||
| 	UpdateRepo() error | ||||
| } | ||||
| 
 | ||||
|  | @ -355,7 +356,7 @@ func (st *HelmState) SyncRepos(helm RepoUpdater, shouldSkip map[string]bool) ([] | |||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		if err := helm.AddRepo(repo.Name, repo.URL, repo.CaFile, repo.CertFile, repo.KeyFile, repo.Username, repo.Password); err != nil { | ||||
| 		if err := helm.AddRepo(repo.Name, repo.URL, repo.CaFile, repo.CertFile, repo.KeyFile, repo.Username, repo.Password, repo.Managed); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
|  |  | |||
|  | @ -857,7 +857,18 @@ func TestHelmState_SyncRepos(t *testing.T) { | |||
| 				}, | ||||
| 			}, | ||||
| 			helm: &exectest.Helm{}, | ||||
| 			want: []string{"name", "http://example.com/", "", "", "", "", ""}, | ||||
| 			want: []string{"name", "http://example.com/", "", "", "", "", "", ""}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "ACR hosted repository", | ||||
| 			repos: []RepositorySpec{ | ||||
| 				{ | ||||
| 					Name:    "name", | ||||
| 					Managed: "acr", | ||||
| 				}, | ||||
| 			}, | ||||
| 			helm: &exectest.Helm{}, | ||||
| 			want: []string{"name", "", "", "", "", "", "", "acr"}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "repository with cert and key", | ||||
|  | @ -872,7 +883,7 @@ func TestHelmState_SyncRepos(t *testing.T) { | |||
| 				}, | ||||
| 			}, | ||||
| 			helm: &exectest.Helm{}, | ||||
| 			want: []string{"name", "http://example.com/", "", "certfile", "keyfile", "", ""}, | ||||
| 			want: []string{"name", "http://example.com/", "", "certfile", "keyfile", "", "", ""}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "repository with ca file", | ||||
|  | @ -886,7 +897,7 @@ func TestHelmState_SyncRepos(t *testing.T) { | |||
| 				}, | ||||
| 			}, | ||||
| 			helm: &exectest.Helm{}, | ||||
| 			want: []string{"name", "http://example.com/", "cafile", "", "", "", ""}, | ||||
| 			want: []string{"name", "http://example.com/", "cafile", "", "", "", "", ""}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "repository with username and password", | ||||
|  | @ -901,7 +912,7 @@ func TestHelmState_SyncRepos(t *testing.T) { | |||
| 				}, | ||||
| 			}, | ||||
| 			helm: &exectest.Helm{}, | ||||
| 			want: []string{"name", "http://example.com/", "", "", "", "example_user", "example_password"}, | ||||
| 			want: []string{"name", "http://example.com/", "", "", "", "example_user", "example_password", ""}, | ||||
| 		}, | ||||
| 	} | ||||
| 	for i := range tests { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue