github.com/latiif/helm@v2.15.0+incompatible/cmd/helm/repo_add.go (about) 1 /* 2 Copyright The Helm Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package main 18 19 import ( 20 "context" 21 "fmt" 22 "io" 23 "syscall" 24 "time" 25 26 "golang.org/x/crypto/ssh/terminal" 27 28 "github.com/gofrs/flock" 29 "github.com/spf13/cobra" 30 31 "k8s.io/helm/pkg/getter" 32 "k8s.io/helm/pkg/helm/helmpath" 33 "k8s.io/helm/pkg/repo" 34 ) 35 36 type repoAddCmd struct { 37 name string 38 url string 39 username string 40 password string 41 home helmpath.Home 42 noupdate bool 43 44 certFile string 45 keyFile string 46 caFile string 47 48 out io.Writer 49 } 50 51 func newRepoAddCmd(out io.Writer) *cobra.Command { 52 add := &repoAddCmd{out: out} 53 54 cmd := &cobra.Command{ 55 Use: "add [flags] [NAME] [URL]", 56 Short: "Add a chart repository", 57 RunE: func(cmd *cobra.Command, args []string) error { 58 if err := checkArgsLength(len(args), "name for the chart repository", "the url of the chart repository"); err != nil { 59 return err 60 } 61 62 add.name = args[0] 63 add.url = args[1] 64 add.home = settings.Home 65 66 return add.run() 67 }, 68 } 69 70 f := cmd.Flags() 71 f.StringVar(&add.username, "username", "", "Chart repository username") 72 f.StringVar(&add.password, "password", "", "Chart repository password") 73 f.BoolVar(&add.noupdate, "no-update", false, "Raise error if repo is already registered") 74 f.StringVar(&add.certFile, "cert-file", "", "Identify HTTPS client using this SSL certificate file") 75 f.StringVar(&add.keyFile, "key-file", "", "Identify HTTPS client using this SSL key file") 76 f.StringVar(&add.caFile, "ca-file", "", "Verify certificates of HTTPS-enabled servers using this CA bundle") 77 78 return cmd 79 } 80 81 func (a *repoAddCmd) run() error { 82 if a.username != "" && a.password == "" { 83 fmt.Fprint(a.out, "Password:") 84 password, err := readPassword() 85 fmt.Fprintln(a.out) 86 if err != nil { 87 return err 88 } 89 a.password = password 90 } 91 92 if err := addRepository(a.name, a.url, a.username, a.password, a.home, a.certFile, a.keyFile, a.caFile, a.noupdate); err != nil { 93 return err 94 } 95 fmt.Fprintf(a.out, "%q has been added to your repositories\n", a.name) 96 return nil 97 } 98 99 func readPassword() (string, error) { 100 password, err := terminal.ReadPassword(int(syscall.Stdin)) 101 if err != nil { 102 return "", err 103 } 104 return string(password), nil 105 } 106 107 func addRepository(name, url, username, password string, home helmpath.Home, certFile, keyFile, caFile string, noUpdate bool) error { 108 f, err := repo.LoadRepositoriesFile(home.RepositoryFile()) 109 if err != nil { 110 return err 111 } 112 113 if noUpdate && f.Has(name) { 114 return fmt.Errorf("repository name (%s) already exists, please specify a different name", name) 115 } 116 117 cif := home.CacheIndex(name) 118 c := repo.Entry{ 119 Name: name, 120 Cache: cif, 121 URL: url, 122 Username: username, 123 Password: password, 124 CertFile: certFile, 125 KeyFile: keyFile, 126 CAFile: caFile, 127 } 128 129 r, err := repo.NewChartRepository(&c, getter.All(settings)) 130 if err != nil { 131 return err 132 } 133 134 if err := r.DownloadIndexFile(home.Cache()); err != nil { 135 return fmt.Errorf("Looks like %q is not a valid chart repository or cannot be reached: %s", url, err.Error()) 136 } 137 138 // Lock the repository file for concurrent goroutines or processes synchronization 139 fileLock := flock.New(home.RepositoryFile()) 140 lockCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second) 141 defer cancel() 142 locked, err := fileLock.TryLockContext(lockCtx, time.Second) 143 if err == nil && locked { 144 defer fileLock.Unlock() 145 } 146 if err != nil { 147 return err 148 } 149 150 // Re-read the repositories file before updating it as its content may have been changed 151 // by a concurrent execution after the first read and before being locked 152 f, err = repo.LoadRepositoriesFile(home.RepositoryFile()) 153 if err != nil { 154 return err 155 } 156 157 f.Update(&c) 158 159 return f.WriteFile(home.RepositoryFile(), 0644) 160 }