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