github.com/stefanmcshane/helm@v0.0.0-20221213002717-88a4a2c6e77d/pkg/action/pull.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 action 18 19 import ( 20 "fmt" 21 "io/ioutil" 22 "os" 23 "path/filepath" 24 "strings" 25 26 "github.com/pkg/errors" 27 28 "github.com/stefanmcshane/helm/pkg/chartutil" 29 "github.com/stefanmcshane/helm/pkg/cli" 30 "github.com/stefanmcshane/helm/pkg/downloader" 31 "github.com/stefanmcshane/helm/pkg/getter" 32 "github.com/stefanmcshane/helm/pkg/registry" 33 "github.com/stefanmcshane/helm/pkg/repo" 34 ) 35 36 // Pull is the action for checking a given release's information. 37 // 38 // It provides the implementation of 'helm pull'. 39 type Pull struct { 40 ChartPathOptions 41 42 Settings *cli.EnvSettings // TODO: refactor this out of pkg/action 43 44 Devel bool 45 Untar bool 46 VerifyLater bool 47 UntarDir string 48 DestDir string 49 cfg *Configuration 50 } 51 52 type PullOpt func(*Pull) 53 54 func WithConfig(cfg *Configuration) PullOpt { 55 return func(p *Pull) { 56 p.cfg = cfg 57 } 58 } 59 60 // NewPull creates a new Pull object. 61 func NewPull() *Pull { 62 return NewPullWithOpts() 63 } 64 65 // NewPullWithOpts creates a new pull, with configuration options. 66 func NewPullWithOpts(opts ...PullOpt) *Pull { 67 p := &Pull{} 68 for _, fn := range opts { 69 fn(p) 70 } 71 72 return p 73 } 74 75 // Run executes 'helm pull' against the given release. 76 func (p *Pull) Run(chartRef string) (string, error) { 77 var out strings.Builder 78 79 c := downloader.ChartDownloader{ 80 Out: &out, 81 Keyring: p.Keyring, 82 Verify: downloader.VerifyNever, 83 Getters: getter.All(p.Settings), 84 Options: []getter.Option{ 85 getter.WithBasicAuth(p.Username, p.Password), 86 getter.WithPassCredentialsAll(p.PassCredentialsAll), 87 getter.WithTLSClientConfig(p.CertFile, p.KeyFile, p.CaFile), 88 getter.WithInsecureSkipVerifyTLS(p.InsecureSkipTLSverify), 89 }, 90 RegistryClient: p.cfg.RegistryClient, 91 RepositoryConfig: p.Settings.RepositoryConfig, 92 RepositoryCache: p.Settings.RepositoryCache, 93 } 94 95 if registry.IsOCI(chartRef) { 96 c.Options = append(c.Options, 97 getter.WithRegistryClient(p.cfg.RegistryClient)) 98 } 99 100 if p.Verify { 101 c.Verify = downloader.VerifyAlways 102 } else if p.VerifyLater { 103 c.Verify = downloader.VerifyLater 104 } 105 106 // If untar is set, we fetch to a tempdir, then untar and copy after 107 // verification. 108 dest := p.DestDir 109 if p.Untar { 110 var err error 111 dest, err = ioutil.TempDir("", "helm-") 112 if err != nil { 113 return out.String(), errors.Wrap(err, "failed to untar") 114 } 115 defer os.RemoveAll(dest) 116 } 117 118 if p.RepoURL != "" { 119 chartURL, err := repo.FindChartInAuthAndTLSAndPassRepoURL(p.RepoURL, p.Username, p.Password, chartRef, p.Version, p.CertFile, p.KeyFile, p.CaFile, p.InsecureSkipTLSverify, p.PassCredentialsAll, getter.All(p.Settings)) 120 if err != nil { 121 return out.String(), err 122 } 123 chartRef = chartURL 124 } 125 126 saved, v, err := c.DownloadTo(chartRef, p.Version, dest) 127 if err != nil { 128 return out.String(), err 129 } 130 131 if p.Verify { 132 for name := range v.SignedBy.Identities { 133 fmt.Fprintf(&out, "Signed by: %v\n", name) 134 } 135 fmt.Fprintf(&out, "Using Key With Fingerprint: %X\n", v.SignedBy.PrimaryKey.Fingerprint) 136 fmt.Fprintf(&out, "Chart Hash Verified: %s\n", v.FileHash) 137 } 138 139 // After verification, untar the chart into the requested directory. 140 if p.Untar { 141 ud := p.UntarDir 142 if !filepath.IsAbs(ud) { 143 ud = filepath.Join(p.DestDir, ud) 144 } 145 // Let udCheck to check conflict file/dir without replacing ud when untarDir is the current directory(.). 146 udCheck := ud 147 if udCheck == "." { 148 _, udCheck = filepath.Split(chartRef) 149 } else { 150 _, chartName := filepath.Split(chartRef) 151 udCheck = filepath.Join(udCheck, chartName) 152 } 153 154 if _, err := os.Stat(udCheck); err != nil { 155 if err := os.MkdirAll(udCheck, 0755); err != nil { 156 return out.String(), errors.Wrap(err, "failed to untar (mkdir)") 157 } 158 159 } else { 160 return out.String(), errors.Errorf("failed to untar: a file or directory with the name %s already exists", udCheck) 161 } 162 163 return out.String(), chartutil.ExpandFile(ud, saved) 164 } 165 return out.String(), nil 166 }