github.com/lrills/helm@v2.8.1+incompatible/pkg/helm/client.go (about)

     1  /*
     2  Copyright 2016 The Kubernetes Authors All rights reserved.
     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 helm // import "k8s.io/helm/pkg/helm"
    18  
    19  import (
    20  	"io"
    21  	"time"
    22  
    23  	"golang.org/x/net/context"
    24  	"google.golang.org/grpc"
    25  	"google.golang.org/grpc/credentials"
    26  	"google.golang.org/grpc/keepalive"
    27  
    28  	"k8s.io/helm/pkg/chartutil"
    29  	"k8s.io/helm/pkg/proto/hapi/chart"
    30  	rls "k8s.io/helm/pkg/proto/hapi/services"
    31  )
    32  
    33  // Client manages client side of the Helm-Tiller protocol.
    34  type Client struct {
    35  	opts options
    36  }
    37  
    38  // NewClient creates a new client.
    39  func NewClient(opts ...Option) *Client {
    40  	var c Client
    41  	return c.Option(opts...)
    42  }
    43  
    44  // Option configures the Helm client with the provided options.
    45  func (h *Client) Option(opts ...Option) *Client {
    46  	for _, opt := range opts {
    47  		opt(&h.opts)
    48  	}
    49  	return h
    50  }
    51  
    52  // ListReleases lists the current releases.
    53  func (h *Client) ListReleases(opts ...ReleaseListOption) (*rls.ListReleasesResponse, error) {
    54  	reqOpts := h.opts
    55  	for _, opt := range opts {
    56  		opt(&reqOpts)
    57  	}
    58  	req := &reqOpts.listReq
    59  	ctx := NewContext()
    60  
    61  	if reqOpts.before != nil {
    62  		if err := reqOpts.before(ctx, req); err != nil {
    63  			return nil, err
    64  		}
    65  	}
    66  	return h.list(ctx, req)
    67  }
    68  
    69  // InstallRelease loads a chart from chstr, installs it, and returns the release response.
    70  func (h *Client) InstallRelease(chstr, ns string, opts ...InstallOption) (*rls.InstallReleaseResponse, error) {
    71  	// load the chart to install
    72  	chart, err := chartutil.Load(chstr)
    73  	if err != nil {
    74  		return nil, err
    75  	}
    76  
    77  	return h.InstallReleaseFromChart(chart, ns, opts...)
    78  }
    79  
    80  // InstallReleaseFromChart installs a new chart and returns the release response.
    81  func (h *Client) InstallReleaseFromChart(chart *chart.Chart, ns string, opts ...InstallOption) (*rls.InstallReleaseResponse, error) {
    82  	// apply the install options
    83  	reqOpts := h.opts
    84  	for _, opt := range opts {
    85  		opt(&reqOpts)
    86  	}
    87  	req := &reqOpts.instReq
    88  	req.Chart = chart
    89  	req.Namespace = ns
    90  	req.DryRun = reqOpts.dryRun
    91  	req.DisableHooks = reqOpts.disableHooks
    92  	req.ReuseName = reqOpts.reuseName
    93  	ctx := NewContext()
    94  
    95  	if reqOpts.before != nil {
    96  		if err := reqOpts.before(ctx, req); err != nil {
    97  			return nil, err
    98  		}
    99  	}
   100  	err := chartutil.ProcessRequirementsEnabled(req.Chart, req.Values)
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  	err = chartutil.ProcessRequirementsImportValues(req.Chart)
   105  	if err != nil {
   106  		return nil, err
   107  	}
   108  
   109  	return h.install(ctx, req)
   110  }
   111  
   112  // DeleteRelease uninstalls a named release and returns the response.
   113  func (h *Client) DeleteRelease(rlsName string, opts ...DeleteOption) (*rls.UninstallReleaseResponse, error) {
   114  	// apply the uninstall options
   115  	reqOpts := h.opts
   116  	for _, opt := range opts {
   117  		opt(&reqOpts)
   118  	}
   119  
   120  	if reqOpts.dryRun {
   121  		// In the dry run case, just see if the release exists
   122  		r, err := h.ReleaseContent(rlsName)
   123  		if err != nil {
   124  			return &rls.UninstallReleaseResponse{}, err
   125  		}
   126  		return &rls.UninstallReleaseResponse{Release: r.Release}, nil
   127  	}
   128  
   129  	req := &reqOpts.uninstallReq
   130  	req.Name = rlsName
   131  	req.DisableHooks = reqOpts.disableHooks
   132  	ctx := NewContext()
   133  
   134  	if reqOpts.before != nil {
   135  		if err := reqOpts.before(ctx, req); err != nil {
   136  			return nil, err
   137  		}
   138  	}
   139  	return h.delete(ctx, req)
   140  }
   141  
   142  // UpdateRelease loads a chart from chstr and updates a release to a new/different chart.
   143  func (h *Client) UpdateRelease(rlsName string, chstr string, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error) {
   144  	// load the chart to update
   145  	chart, err := chartutil.Load(chstr)
   146  	if err != nil {
   147  		return nil, err
   148  	}
   149  
   150  	return h.UpdateReleaseFromChart(rlsName, chart, opts...)
   151  }
   152  
   153  // UpdateReleaseFromChart updates a release to a new/different chart.
   154  func (h *Client) UpdateReleaseFromChart(rlsName string, chart *chart.Chart, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error) {
   155  	// apply the update options
   156  	reqOpts := h.opts
   157  	for _, opt := range opts {
   158  		opt(&reqOpts)
   159  	}
   160  	req := &reqOpts.updateReq
   161  	req.Chart = chart
   162  	req.DryRun = reqOpts.dryRun
   163  	req.Name = rlsName
   164  	req.DisableHooks = reqOpts.disableHooks
   165  	req.Recreate = reqOpts.recreate
   166  	req.Force = reqOpts.force
   167  	req.ResetValues = reqOpts.resetValues
   168  	req.ReuseValues = reqOpts.reuseValues
   169  	ctx := NewContext()
   170  
   171  	if reqOpts.before != nil {
   172  		if err := reqOpts.before(ctx, req); err != nil {
   173  			return nil, err
   174  		}
   175  	}
   176  	err := chartutil.ProcessRequirementsEnabled(req.Chart, req.Values)
   177  	if err != nil {
   178  		return nil, err
   179  	}
   180  	err = chartutil.ProcessRequirementsImportValues(req.Chart)
   181  	if err != nil {
   182  		return nil, err
   183  	}
   184  
   185  	return h.update(ctx, req)
   186  }
   187  
   188  // GetVersion returns the server version.
   189  func (h *Client) GetVersion(opts ...VersionOption) (*rls.GetVersionResponse, error) {
   190  	reqOpts := h.opts
   191  	for _, opt := range opts {
   192  		opt(&reqOpts)
   193  	}
   194  	req := &rls.GetVersionRequest{}
   195  	ctx := NewContext()
   196  
   197  	if reqOpts.before != nil {
   198  		if err := reqOpts.before(ctx, req); err != nil {
   199  			return nil, err
   200  		}
   201  	}
   202  	return h.version(ctx, req)
   203  }
   204  
   205  // RollbackRelease rolls back a release to the previous version.
   206  func (h *Client) RollbackRelease(rlsName string, opts ...RollbackOption) (*rls.RollbackReleaseResponse, error) {
   207  	reqOpts := h.opts
   208  	for _, opt := range opts {
   209  		opt(&reqOpts)
   210  	}
   211  	req := &reqOpts.rollbackReq
   212  	req.Recreate = reqOpts.recreate
   213  	req.Force = reqOpts.force
   214  	req.DisableHooks = reqOpts.disableHooks
   215  	req.DryRun = reqOpts.dryRun
   216  	req.Name = rlsName
   217  	ctx := NewContext()
   218  
   219  	if reqOpts.before != nil {
   220  		if err := reqOpts.before(ctx, req); err != nil {
   221  			return nil, err
   222  		}
   223  	}
   224  	return h.rollback(ctx, req)
   225  }
   226  
   227  // ReleaseStatus returns the given release's status.
   228  func (h *Client) ReleaseStatus(rlsName string, opts ...StatusOption) (*rls.GetReleaseStatusResponse, error) {
   229  	reqOpts := h.opts
   230  	for _, opt := range opts {
   231  		opt(&reqOpts)
   232  	}
   233  	req := &reqOpts.statusReq
   234  	req.Name = rlsName
   235  	ctx := NewContext()
   236  
   237  	if reqOpts.before != nil {
   238  		if err := reqOpts.before(ctx, req); err != nil {
   239  			return nil, err
   240  		}
   241  	}
   242  	return h.status(ctx, req)
   243  }
   244  
   245  // ReleaseContent returns the configuration for a given release.
   246  func (h *Client) ReleaseContent(rlsName string, opts ...ContentOption) (*rls.GetReleaseContentResponse, error) {
   247  	reqOpts := h.opts
   248  	for _, opt := range opts {
   249  		opt(&reqOpts)
   250  	}
   251  	req := &reqOpts.contentReq
   252  	req.Name = rlsName
   253  	ctx := NewContext()
   254  
   255  	if reqOpts.before != nil {
   256  		if err := reqOpts.before(ctx, req); err != nil {
   257  			return nil, err
   258  		}
   259  	}
   260  	return h.content(ctx, req)
   261  }
   262  
   263  // ReleaseHistory returns a release's revision history.
   264  func (h *Client) ReleaseHistory(rlsName string, opts ...HistoryOption) (*rls.GetHistoryResponse, error) {
   265  	reqOpts := h.opts
   266  	for _, opt := range opts {
   267  		opt(&reqOpts)
   268  	}
   269  
   270  	req := &reqOpts.histReq
   271  	req.Name = rlsName
   272  	ctx := NewContext()
   273  
   274  	if reqOpts.before != nil {
   275  		if err := reqOpts.before(ctx, req); err != nil {
   276  			return nil, err
   277  		}
   278  	}
   279  	return h.history(ctx, req)
   280  }
   281  
   282  // RunReleaseTest executes a pre-defined test on a release.
   283  func (h *Client) RunReleaseTest(rlsName string, opts ...ReleaseTestOption) (<-chan *rls.TestReleaseResponse, <-chan error) {
   284  	reqOpts := h.opts
   285  	for _, opt := range opts {
   286  		opt(&reqOpts)
   287  	}
   288  
   289  	req := &reqOpts.testReq
   290  	req.Name = rlsName
   291  	ctx := NewContext()
   292  
   293  	return h.test(ctx, req)
   294  }
   295  
   296  // PingTiller pings the Tiller pod and ensure's that it is up and runnning
   297  func (h *Client) PingTiller() error {
   298  	ctx := NewContext()
   299  	return h.ping(ctx)
   300  }
   301  
   302  // connect returns a gRPC connection to Tiller or error. The gRPC dial options
   303  // are constructed here.
   304  func (h *Client) connect(ctx context.Context) (conn *grpc.ClientConn, err error) {
   305  	opts := []grpc.DialOption{
   306  		grpc.WithTimeout(5 * time.Second),
   307  		grpc.WithBlock(),
   308  		grpc.WithKeepaliveParams(keepalive.ClientParameters{
   309  			// Send keepalive every 30 seconds to prevent the connection from
   310  			// getting closed by upstreams
   311  			Time: time.Duration(30) * time.Second,
   312  		}),
   313  	}
   314  	switch {
   315  	case h.opts.useTLS:
   316  		opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(h.opts.tlsConfig)))
   317  	default:
   318  		opts = append(opts, grpc.WithInsecure())
   319  	}
   320  	if conn, err = grpc.Dial(h.opts.host, opts...); err != nil {
   321  		return nil, err
   322  	}
   323  	return conn, nil
   324  }
   325  
   326  // Executes tiller.ListReleases RPC.
   327  func (h *Client) list(ctx context.Context, req *rls.ListReleasesRequest) (*rls.ListReleasesResponse, error) {
   328  	c, err := h.connect(ctx)
   329  	if err != nil {
   330  		return nil, err
   331  	}
   332  	defer c.Close()
   333  
   334  	rlc := rls.NewReleaseServiceClient(c)
   335  	s, err := rlc.ListReleases(ctx, req)
   336  	if err != nil {
   337  		return nil, err
   338  	}
   339  
   340  	return s.Recv()
   341  }
   342  
   343  // Executes tiller.InstallRelease RPC.
   344  func (h *Client) install(ctx context.Context, req *rls.InstallReleaseRequest) (*rls.InstallReleaseResponse, error) {
   345  	c, err := h.connect(ctx)
   346  	if err != nil {
   347  		return nil, err
   348  	}
   349  	defer c.Close()
   350  
   351  	rlc := rls.NewReleaseServiceClient(c)
   352  	return rlc.InstallRelease(ctx, req)
   353  }
   354  
   355  // Executes tiller.UninstallRelease RPC.
   356  func (h *Client) delete(ctx context.Context, req *rls.UninstallReleaseRequest) (*rls.UninstallReleaseResponse, error) {
   357  	c, err := h.connect(ctx)
   358  	if err != nil {
   359  		return nil, err
   360  	}
   361  	defer c.Close()
   362  
   363  	rlc := rls.NewReleaseServiceClient(c)
   364  	return rlc.UninstallRelease(ctx, req)
   365  }
   366  
   367  // Executes tiller.UpdateRelease RPC.
   368  func (h *Client) update(ctx context.Context, req *rls.UpdateReleaseRequest) (*rls.UpdateReleaseResponse, error) {
   369  	c, err := h.connect(ctx)
   370  	if err != nil {
   371  		return nil, err
   372  	}
   373  	defer c.Close()
   374  
   375  	rlc := rls.NewReleaseServiceClient(c)
   376  	return rlc.UpdateRelease(ctx, req)
   377  }
   378  
   379  // Executes tiller.RollbackRelease RPC.
   380  func (h *Client) rollback(ctx context.Context, req *rls.RollbackReleaseRequest) (*rls.RollbackReleaseResponse, error) {
   381  	c, err := h.connect(ctx)
   382  	if err != nil {
   383  		return nil, err
   384  	}
   385  	defer c.Close()
   386  
   387  	rlc := rls.NewReleaseServiceClient(c)
   388  	return rlc.RollbackRelease(ctx, req)
   389  }
   390  
   391  // Executes tiller.GetReleaseStatus RPC.
   392  func (h *Client) status(ctx context.Context, req *rls.GetReleaseStatusRequest) (*rls.GetReleaseStatusResponse, error) {
   393  	c, err := h.connect(ctx)
   394  	if err != nil {
   395  		return nil, err
   396  	}
   397  	defer c.Close()
   398  
   399  	rlc := rls.NewReleaseServiceClient(c)
   400  	return rlc.GetReleaseStatus(ctx, req)
   401  }
   402  
   403  // Executes tiller.GetReleaseContent RPC.
   404  func (h *Client) content(ctx context.Context, req *rls.GetReleaseContentRequest) (*rls.GetReleaseContentResponse, error) {
   405  	c, err := h.connect(ctx)
   406  	if err != nil {
   407  		return nil, err
   408  	}
   409  	defer c.Close()
   410  
   411  	rlc := rls.NewReleaseServiceClient(c)
   412  	return rlc.GetReleaseContent(ctx, req)
   413  }
   414  
   415  // Executes tiller.GetVersion RPC.
   416  func (h *Client) version(ctx context.Context, req *rls.GetVersionRequest) (*rls.GetVersionResponse, error) {
   417  	c, err := h.connect(ctx)
   418  	if err != nil {
   419  		return nil, err
   420  	}
   421  	defer c.Close()
   422  
   423  	rlc := rls.NewReleaseServiceClient(c)
   424  	return rlc.GetVersion(ctx, req)
   425  }
   426  
   427  // Executes tiller.GetHistory RPC.
   428  func (h *Client) history(ctx context.Context, req *rls.GetHistoryRequest) (*rls.GetHistoryResponse, error) {
   429  	c, err := h.connect(ctx)
   430  	if err != nil {
   431  		return nil, err
   432  	}
   433  	defer c.Close()
   434  
   435  	rlc := rls.NewReleaseServiceClient(c)
   436  	return rlc.GetHistory(ctx, req)
   437  }
   438  
   439  // Executes tiller.TestRelease RPC.
   440  func (h *Client) test(ctx context.Context, req *rls.TestReleaseRequest) (<-chan *rls.TestReleaseResponse, <-chan error) {
   441  	errc := make(chan error, 1)
   442  	c, err := h.connect(ctx)
   443  	if err != nil {
   444  		errc <- err
   445  		return nil, errc
   446  	}
   447  
   448  	ch := make(chan *rls.TestReleaseResponse, 1)
   449  	go func() {
   450  		defer close(errc)
   451  		defer close(ch)
   452  		defer c.Close()
   453  
   454  		rlc := rls.NewReleaseServiceClient(c)
   455  		s, err := rlc.RunReleaseTest(ctx, req)
   456  		if err != nil {
   457  			errc <- err
   458  			return
   459  		}
   460  
   461  		for {
   462  			msg, err := s.Recv()
   463  			if err == io.EOF {
   464  				return
   465  			}
   466  			if err != nil {
   467  				errc <- err
   468  				return
   469  			}
   470  			ch <- msg
   471  		}
   472  	}()
   473  
   474  	return ch, errc
   475  }
   476  
   477  // Executes tiller.Ping RPC.
   478  func (h *Client) ping(ctx context.Context) error {
   479  	c, err := h.connect(ctx)
   480  	if err != nil {
   481  		return err
   482  	}
   483  	defer c.Close()
   484  
   485  	rlc := rls.NewReleaseServiceClient(c)
   486  	return rlc.PingTiller(ctx)
   487  }