github.com/strongmonkey/helm@v2.7.2+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)
   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.Force = h.opts.force
   163  	req.ResetValues = h.opts.resetValues
   164  	req.ReuseValues = h.opts.reuseValues
   165  	ctx := NewContext()
   166  
   167  	if h.opts.before != nil {
   168  		if err := h.opts.before(ctx, req); err != nil {
   169  			return nil, err
   170  		}
   171  	}
   172  	err := chartutil.ProcessRequirementsEnabled(req.Chart, req.Values)
   173  	if err != nil {
   174  		return nil, err
   175  	}
   176  	err = chartutil.ProcessRequirementsImportValues(req.Chart)
   177  	if err != nil {
   178  		return nil, err
   179  	}
   180  
   181  	return h.update(ctx, req)
   182  }
   183  
   184  // GetVersion returns the server version.
   185  func (h *Client) GetVersion(opts ...VersionOption) (*rls.GetVersionResponse, error) {
   186  	for _, opt := range opts {
   187  		opt(&h.opts)
   188  	}
   189  	req := &rls.GetVersionRequest{}
   190  	ctx := NewContext()
   191  
   192  	if h.opts.before != nil {
   193  		if err := h.opts.before(ctx, req); err != nil {
   194  			return nil, err
   195  		}
   196  	}
   197  	return h.version(ctx, req)
   198  }
   199  
   200  // RollbackRelease rolls back a release to the previous version.
   201  func (h *Client) RollbackRelease(rlsName string, opts ...RollbackOption) (*rls.RollbackReleaseResponse, error) {
   202  	for _, opt := range opts {
   203  		opt(&h.opts)
   204  	}
   205  	req := &h.opts.rollbackReq
   206  	req.Recreate = h.opts.recreate
   207  	req.Force = h.opts.force
   208  	req.DisableHooks = h.opts.disableHooks
   209  	req.DryRun = h.opts.dryRun
   210  	req.Name = rlsName
   211  	ctx := NewContext()
   212  
   213  	if h.opts.before != nil {
   214  		if err := h.opts.before(ctx, req); err != nil {
   215  			return nil, err
   216  		}
   217  	}
   218  	return h.rollback(ctx, req)
   219  }
   220  
   221  // ReleaseStatus returns the given release's status.
   222  func (h *Client) ReleaseStatus(rlsName string, opts ...StatusOption) (*rls.GetReleaseStatusResponse, error) {
   223  	for _, opt := range opts {
   224  		opt(&h.opts)
   225  	}
   226  	req := &h.opts.statusReq
   227  	req.Name = rlsName
   228  	ctx := NewContext()
   229  
   230  	if h.opts.before != nil {
   231  		if err := h.opts.before(ctx, req); err != nil {
   232  			return nil, err
   233  		}
   234  	}
   235  	return h.status(ctx, req)
   236  }
   237  
   238  // ReleaseContent returns the configuration for a given release.
   239  func (h *Client) ReleaseContent(rlsName string, opts ...ContentOption) (*rls.GetReleaseContentResponse, error) {
   240  	for _, opt := range opts {
   241  		opt(&h.opts)
   242  	}
   243  	req := &h.opts.contentReq
   244  	req.Name = rlsName
   245  	ctx := NewContext()
   246  
   247  	if h.opts.before != nil {
   248  		if err := h.opts.before(ctx, req); err != nil {
   249  			return nil, err
   250  		}
   251  	}
   252  	return h.content(ctx, req)
   253  }
   254  
   255  // ReleaseHistory returns a release's revision history.
   256  func (h *Client) ReleaseHistory(rlsName string, opts ...HistoryOption) (*rls.GetHistoryResponse, error) {
   257  	for _, opt := range opts {
   258  		opt(&h.opts)
   259  	}
   260  
   261  	req := &h.opts.histReq
   262  	req.Name = rlsName
   263  	ctx := NewContext()
   264  
   265  	if h.opts.before != nil {
   266  		if err := h.opts.before(ctx, req); err != nil {
   267  			return nil, err
   268  		}
   269  	}
   270  	return h.history(ctx, req)
   271  }
   272  
   273  // RunReleaseTest executes a pre-defined test on a release.
   274  func (h *Client) RunReleaseTest(rlsName string, opts ...ReleaseTestOption) (<-chan *rls.TestReleaseResponse, <-chan error) {
   275  	for _, opt := range opts {
   276  		opt(&h.opts)
   277  	}
   278  
   279  	req := &h.opts.testReq
   280  	req.Name = rlsName
   281  	ctx := NewContext()
   282  
   283  	return h.test(ctx, req)
   284  }
   285  
   286  // connect returns a gRPC connection to Tiller or error. The gRPC dial options
   287  // are constructed here.
   288  func (h *Client) connect(ctx context.Context) (conn *grpc.ClientConn, err error) {
   289  	opts := []grpc.DialOption{
   290  		grpc.WithTimeout(5 * time.Second),
   291  		grpc.WithBlock(),
   292  	}
   293  	switch {
   294  	case h.opts.useTLS:
   295  		opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(h.opts.tlsConfig)))
   296  	default:
   297  		opts = append(opts, grpc.WithInsecure())
   298  	}
   299  	if conn, err = grpc.Dial(h.opts.host, opts...); err != nil {
   300  		return nil, err
   301  	}
   302  	return conn, nil
   303  }
   304  
   305  // Executes tiller.ListReleases RPC.
   306  func (h *Client) list(ctx context.Context, req *rls.ListReleasesRequest) (*rls.ListReleasesResponse, error) {
   307  	c, err := h.connect(ctx)
   308  	if err != nil {
   309  		return nil, err
   310  	}
   311  	defer c.Close()
   312  
   313  	rlc := rls.NewReleaseServiceClient(c)
   314  	s, err := rlc.ListReleases(ctx, req)
   315  	if err != nil {
   316  		return nil, err
   317  	}
   318  
   319  	return s.Recv()
   320  }
   321  
   322  // Executes tiller.InstallRelease RPC.
   323  func (h *Client) install(ctx context.Context, req *rls.InstallReleaseRequest) (*rls.InstallReleaseResponse, error) {
   324  	c, err := h.connect(ctx)
   325  	if err != nil {
   326  		return nil, err
   327  	}
   328  	defer c.Close()
   329  
   330  	rlc := rls.NewReleaseServiceClient(c)
   331  	return rlc.InstallRelease(ctx, req)
   332  }
   333  
   334  // Executes tiller.UninstallRelease RPC.
   335  func (h *Client) delete(ctx context.Context, req *rls.UninstallReleaseRequest) (*rls.UninstallReleaseResponse, error) {
   336  	c, err := h.connect(ctx)
   337  	if err != nil {
   338  		return nil, err
   339  	}
   340  	defer c.Close()
   341  
   342  	rlc := rls.NewReleaseServiceClient(c)
   343  	return rlc.UninstallRelease(ctx, req)
   344  }
   345  
   346  // Executes tiller.UpdateRelease RPC.
   347  func (h *Client) update(ctx context.Context, req *rls.UpdateReleaseRequest) (*rls.UpdateReleaseResponse, error) {
   348  	c, err := h.connect(ctx)
   349  	if err != nil {
   350  		return nil, err
   351  	}
   352  	defer c.Close()
   353  
   354  	rlc := rls.NewReleaseServiceClient(c)
   355  	return rlc.UpdateRelease(ctx, req)
   356  }
   357  
   358  // Executes tiller.RollbackRelease RPC.
   359  func (h *Client) rollback(ctx context.Context, req *rls.RollbackReleaseRequest) (*rls.RollbackReleaseResponse, error) {
   360  	c, err := h.connect(ctx)
   361  	if err != nil {
   362  		return nil, err
   363  	}
   364  	defer c.Close()
   365  
   366  	rlc := rls.NewReleaseServiceClient(c)
   367  	return rlc.RollbackRelease(ctx, req)
   368  }
   369  
   370  // Executes tiller.GetReleaseStatus RPC.
   371  func (h *Client) status(ctx context.Context, req *rls.GetReleaseStatusRequest) (*rls.GetReleaseStatusResponse, error) {
   372  	c, err := h.connect(ctx)
   373  	if err != nil {
   374  		return nil, err
   375  	}
   376  	defer c.Close()
   377  
   378  	rlc := rls.NewReleaseServiceClient(c)
   379  	return rlc.GetReleaseStatus(ctx, req)
   380  }
   381  
   382  // Executes tiller.GetReleaseContent RPC.
   383  func (h *Client) content(ctx context.Context, req *rls.GetReleaseContentRequest) (*rls.GetReleaseContentResponse, error) {
   384  	c, err := h.connect(ctx)
   385  	if err != nil {
   386  		return nil, err
   387  	}
   388  	defer c.Close()
   389  
   390  	rlc := rls.NewReleaseServiceClient(c)
   391  	return rlc.GetReleaseContent(ctx, req)
   392  }
   393  
   394  // Executes tiller.GetVersion RPC.
   395  func (h *Client) version(ctx context.Context, req *rls.GetVersionRequest) (*rls.GetVersionResponse, error) {
   396  	c, err := h.connect(ctx)
   397  	if err != nil {
   398  		return nil, err
   399  	}
   400  	defer c.Close()
   401  
   402  	rlc := rls.NewReleaseServiceClient(c)
   403  	return rlc.GetVersion(ctx, req)
   404  }
   405  
   406  // Executes tiller.GetHistory RPC.
   407  func (h *Client) history(ctx context.Context, req *rls.GetHistoryRequest) (*rls.GetHistoryResponse, error) {
   408  	c, err := h.connect(ctx)
   409  	if err != nil {
   410  		return nil, err
   411  	}
   412  	defer c.Close()
   413  
   414  	rlc := rls.NewReleaseServiceClient(c)
   415  	return rlc.GetHistory(ctx, req)
   416  }
   417  
   418  // Executes tiller.TestRelease RPC.
   419  func (h *Client) test(ctx context.Context, req *rls.TestReleaseRequest) (<-chan *rls.TestReleaseResponse, <-chan error) {
   420  	errc := make(chan error, 1)
   421  	c, err := h.connect(ctx)
   422  	if err != nil {
   423  		errc <- err
   424  		return nil, errc
   425  	}
   426  
   427  	ch := make(chan *rls.TestReleaseResponse, 1)
   428  	go func() {
   429  		defer close(errc)
   430  		defer close(ch)
   431  		defer c.Close()
   432  
   433  		rlc := rls.NewReleaseServiceClient(c)
   434  		s, err := rlc.RunReleaseTest(ctx, req)
   435  		if err != nil {
   436  			errc <- err
   437  			return
   438  		}
   439  
   440  		for {
   441  			msg, err := s.Recv()
   442  			if err == io.EOF {
   443  				return
   444  			}
   445  			if err != nil {
   446  				errc <- err
   447  				return
   448  			}
   449  			ch <- msg
   450  		}
   451  	}()
   452  
   453  	return ch, errc
   454  }