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