github.com/wangchanggan/helm@v0.0.0-20211020154240-11b1b7d5406d/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 "path/filepath" 24 "strings" 25 "syscall" 26 "time" 27 28 "golang.org/x/crypto/ssh/terminal" 29 30 "github.com/gofrs/flock" 31 "github.com/spf13/cobra" 32 33 "k8s.io/helm/pkg/getter" 34 "k8s.io/helm/pkg/helm/helmpath" 35 "k8s.io/helm/pkg/repo" 36 ) 37 38 type repoAddCmd struct { 39 name string 40 url string 41 username string 42 password string 43 home helmpath.Home 44 noupdate bool 45 46 certFile string 47 keyFile string 48 caFile string 49 50 out io.Writer 51 } 52 53 func newRepoAddCmd(out io.Writer) *cobra.Command { 54 add := &repoAddCmd{out: out} 55 56 cmd := &cobra.Command{ 57 Use: "add [flags] [NAME] [URL]", 58 Short: "Add a chart repository", 59 RunE: func(cmd *cobra.Command, args []string) error { 60 if err := checkArgsLength(len(args), "name for the chart repository", "the url of the chart repository"); err != nil { 61 return err 62 } 63 64 add.name = args[0] 65 add.url = args[1] 66 add.home = settings.Home 67 68 return add.run() 69 }, 70 } 71 72 f := cmd.Flags() 73 f.StringVar(&add.username, "username", "", "Chart repository username") 74 f.StringVar(&add.password, "password", "", "Chart repository password") 75 f.BoolVar(&add.noupdate, "no-update", false, "Raise error if repo is already registered") 76 f.StringVar(&add.certFile, "cert-file", "", "Identify HTTPS client using this SSL certificate file") 77 f.StringVar(&add.keyFile, "key-file", "", "Identify HTTPS client using this SSL key file") 78 f.StringVar(&add.caFile, "ca-file", "", "Verify certificates of HTTPS-enabled servers using this CA bundle") 79 80 return cmd 81 } 82 83 func (a *repoAddCmd) run() error { 84 if a.username != "" && a.password == "" { 85 fmt.Fprint(a.out, "Password:") 86 password, err := readPassword() 87 fmt.Fprintln(a.out) 88 if err != nil { 89 return err 90 } 91 a.password = password 92 } 93 94 if err := addRepository(a.name, a.url, a.username, a.password, a.home, a.certFile, a.keyFile, a.caFile, a.noupdate); err != nil { 95 return err 96 } 97 fmt.Fprintf(a.out, "%q has been added to your repositories\n", a.name) 98 return nil 99 } 100 101 func readPassword() (string, error) { 102 password, err := terminal.ReadPassword(int(syscall.Stdin)) 103 if err != nil { 104 return "", err 105 } 106 return string(password), nil 107 } 108 109 func addRepository(name, url, username, password string, home helmpath.Home, certFile, keyFile, caFile string, noUpdate bool) error { 110 f, err := repo.LoadRepositoriesFile(home.RepositoryFile()) 111 if err != nil { 112 return err 113 } 114 115 if noUpdate && f.Has(name) { 116 return fmt.Errorf("repository name (%s) already exists, please specify a different name", name) 117 } 118 119 cif := home.CacheIndex(name) 120 c := repo.Entry{ 121 Name: name, 122 Cache: cif, 123 URL: url, 124 Username: username, 125 Password: password, 126 CertFile: certFile, 127 KeyFile: keyFile, 128 CAFile: caFile, 129 } 130 131 r, err := repo.NewChartRepository(&c, getter.All(settings)) 132 if err != nil { 133 return err 134 } 135 136 if err := r.DownloadIndexFile(home.Cache()); err != nil { 137 return fmt.Errorf("Looks like %q is not a valid chart repository or cannot be reached: %s", url, err.Error()) 138 } 139 140 repoFile := home.RepositoryFile() 141 142 // Acquire a file lock for process synchronization 143 fileLock := flock.New(strings.Replace(repoFile, filepath.Ext(repoFile), ".lock", 1)) 144 lockCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second) 145 defer cancel() 146 locked, err := fileLock.TryLockContext(lockCtx, time.Second) 147 if err == nil && locked { 148 defer fileLock.Unlock() 149 } 150 if err != nil { 151 return err 152 } 153 154 // Re-read the repositories file before updating it as its content may have been changed 155 // by a concurrent execution after the first read and before being locked 156 f, err = repo.LoadRepositoriesFile(repoFile) 157 if err != nil { 158 return err 159 } 160 161 f.Update(&c) 162 163 return f.WriteFile(repoFile, 0644) 164 }