github.com/umeshredd/helm@v3.0.0-alpha.1+incompatible/pkg/registry/client.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 registry // import "helm.sh/helm/pkg/registry" 18 19 import ( 20 "context" 21 "fmt" 22 "io" 23 24 orascontent "github.com/deislabs/oras/pkg/content" 25 orascontext "github.com/deislabs/oras/pkg/context" 26 "github.com/deislabs/oras/pkg/oras" 27 "github.com/gosuri/uitable" 28 "github.com/sirupsen/logrus" 29 30 "helm.sh/helm/pkg/chart" 31 ) 32 33 const ( 34 CredentialsFileBasename = "config.json" 35 ) 36 37 type ( 38 // ClientOptions is used to construct a new client 39 ClientOptions struct { 40 Debug bool 41 Out io.Writer 42 Authorizer Authorizer 43 Resolver Resolver 44 CacheRootDir string 45 } 46 47 // Client works with OCI-compliant registries and local Helm chart cache 48 Client struct { 49 debug bool 50 out io.Writer 51 authorizer Authorizer 52 resolver Resolver 53 cache *filesystemCache // TODO: something more robust 54 } 55 ) 56 57 // NewClient returns a new registry client with config 58 func NewClient(options *ClientOptions) *Client { 59 return &Client{ 60 debug: options.Debug, 61 out: options.Out, 62 resolver: options.Resolver, 63 authorizer: options.Authorizer, 64 cache: &filesystemCache{ 65 out: options.Out, 66 rootDir: options.CacheRootDir, 67 store: orascontent.NewMemoryStore(), 68 }, 69 } 70 } 71 72 // Login logs into a registry 73 func (c *Client) Login(hostname string, username string, password string) error { 74 err := c.authorizer.Login(c.newContext(), hostname, username, password) 75 if err != nil { 76 return err 77 } 78 fmt.Fprint(c.out, "Login succeeded\n") 79 return nil 80 } 81 82 // Logout logs out of a registry 83 func (c *Client) Logout(hostname string) error { 84 err := c.authorizer.Logout(c.newContext(), hostname) 85 if err != nil { 86 return err 87 } 88 fmt.Fprint(c.out, "Logout succeeded\n") 89 return nil 90 } 91 92 // PushChart uploads a chart to a registry 93 func (c *Client) PushChart(ref *Reference) error { 94 c.setDefaultTag(ref) 95 fmt.Fprintf(c.out, "The push refers to repository [%s]\n", ref.Repo) 96 layers, err := c.cache.LoadReference(ref) 97 if err != nil { 98 return err 99 } 100 _, err = oras.Push(c.newContext(), c.resolver, ref.String(), c.cache.store, layers) 101 if err != nil { 102 return err 103 } 104 var totalSize int64 105 for _, layer := range layers { 106 totalSize += layer.Size 107 } 108 fmt.Fprintf(c.out, 109 "%s: pushed to remote (%d layers, %s total)\n", ref.Tag, len(layers), byteCountBinary(totalSize)) 110 return nil 111 } 112 113 // PullChart downloads a chart from a registry 114 func (c *Client) PullChart(ref *Reference) error { 115 c.setDefaultTag(ref) 116 fmt.Fprintf(c.out, "%s: Pulling from %s\n", ref.Tag, ref.Repo) 117 _, layers, err := oras.Pull(c.newContext(), c.resolver, ref.String(), c.cache.store, oras.WithAllowedMediaTypes(KnownMediaTypes())) 118 if err != nil { 119 return err 120 } 121 exists, err := c.cache.StoreReference(ref, layers) 122 if err != nil { 123 return err 124 } 125 if !exists { 126 fmt.Fprintf(c.out, "Status: Downloaded newer chart for %s:%s\n", ref.Repo, ref.Tag) 127 } else { 128 fmt.Fprintf(c.out, "Status: Chart is up to date for %s:%s\n", ref.Repo, ref.Tag) 129 } 130 return nil 131 } 132 133 // SaveChart stores a copy of chart in local cache 134 func (c *Client) SaveChart(ch *chart.Chart, ref *Reference) error { 135 c.setDefaultTag(ref) 136 layers, err := c.cache.ChartToLayers(ch) 137 if err != nil { 138 return err 139 } 140 _, err = c.cache.StoreReference(ref, layers) 141 if err != nil { 142 return err 143 } 144 fmt.Fprintf(c.out, "%s: saved\n", ref.Tag) 145 return nil 146 } 147 148 // LoadChart retrieves a chart object by reference 149 func (c *Client) LoadChart(ref *Reference) (*chart.Chart, error) { 150 c.setDefaultTag(ref) 151 layers, err := c.cache.LoadReference(ref) 152 if err != nil { 153 return nil, err 154 } 155 ch, err := c.cache.LayersToChart(layers) 156 return ch, err 157 } 158 159 // RemoveChart deletes a locally saved chart 160 func (c *Client) RemoveChart(ref *Reference) error { 161 c.setDefaultTag(ref) 162 err := c.cache.DeleteReference(ref) 163 if err != nil { 164 return err 165 } 166 fmt.Fprintf(c.out, "%s: removed\n", ref.Tag) 167 return err 168 } 169 170 // PrintChartTable prints a list of locally stored charts 171 func (c *Client) PrintChartTable() error { 172 table := uitable.New() 173 table.MaxColWidth = 60 174 table.AddRow("REF", "NAME", "VERSION", "DIGEST", "SIZE", "CREATED") 175 rows, err := c.cache.TableRows() 176 if err != nil { 177 return err 178 } 179 for _, row := range rows { 180 table.AddRow(row...) 181 } 182 fmt.Fprintln(c.out, table.String()) 183 return nil 184 } 185 186 func (c *Client) setDefaultTag(ref *Reference) { 187 if ref.Tag == "" { 188 ref.Tag = HelmChartDefaultTag 189 fmt.Fprintf(c.out, "Using default tag: %s\n", HelmChartDefaultTag) 190 } 191 } 192 193 // disable verbose logging coming from ORAS unless debug is enabled 194 func (c *Client) newContext() context.Context { 195 if !c.debug { 196 return orascontext.Background() 197 } 198 ctx := orascontext.WithLoggerFromWriter(context.Background(), c.out) 199 orascontext.GetLogger(ctx).Logger.SetLevel(logrus.DebugLevel) 200 return ctx 201 }