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  }