mirror of https://github.com/helm/helm
Merge pull request #837 from fibonacci1729/ref/pkg-helm-new
ref(pkg/helm) replace 'pkg/helm' with 'pkg/helmx'pull/839/head
commit
36bf76548b
@ -1,43 +1,128 @@
|
||||
package helm
|
||||
|
||||
import (
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc"
|
||||
"k8s.io/helm/pkg/chartutil"
|
||||
rls "k8s.io/helm/pkg/proto/hapi/services"
|
||||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
// $HELM_HOST envvar
|
||||
HelmHostEnvVar = "HELM_HOST"
|
||||
|
||||
// $HELM_HOME envvar
|
||||
HelmHomeEnvVar = "HELM_HOME"
|
||||
|
||||
"k8s.io/helm/pkg/proto/hapi/services"
|
||||
// Default tiller server host address.
|
||||
DefaultHelmHost = ":44134"
|
||||
|
||||
// Default $HELM_HOME envvar value
|
||||
DefaultHelmHome = "$HOME/.helm"
|
||||
)
|
||||
|
||||
type client struct {
|
||||
cfg *config
|
||||
conn *grpc.ClientConn
|
||||
impl services.ReleaseServiceClient
|
||||
// Helm client manages client side of the helm-tiller protocol
|
||||
type Client struct {
|
||||
opts options
|
||||
}
|
||||
|
||||
func NewClient(opts ...Option) *Client {
|
||||
return new(Client).Init().Option(opts...)
|
||||
}
|
||||
|
||||
// Configure the helm client with the provided options
|
||||
func (h *Client) Option(opts ...Option) *Client {
|
||||
for _, opt := range opts {
|
||||
opt(&h.opts)
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
// Initializes the helm client with default options
|
||||
func (h *Client) Init() *Client {
|
||||
return h.Option(HelmHost(DefaultHelmHost)).
|
||||
Option(HelmHome(os.ExpandEnv(DefaultHelmHome)))
|
||||
}
|
||||
|
||||
// ListReleases lists the current releases.
|
||||
func (h *Client) ListReleases(opts ...ReleaseListOption) (*rls.ListReleasesResponse, error) {
|
||||
c, err := grpc.Dial(h.opts.host, grpc.WithInsecure())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
return h.opts.rpcListReleases(rls.NewReleaseServiceClient(c), opts...)
|
||||
}
|
||||
|
||||
func (c *client) dial() (err error) {
|
||||
c.conn, err = grpc.Dial(c.cfg.ServAddr, c.cfg.DialOpts()...)
|
||||
c.impl = services.NewReleaseServiceClient(c.conn)
|
||||
return
|
||||
// InstallRelease installs a new chart and returns the release response.
|
||||
func (h *Client) InstallRelease(chStr string, opts ...InstallOption) (*rls.InstallReleaseResponse, error) {
|
||||
c, err := grpc.Dial(h.opts.host, grpc.WithInsecure())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
chart, err := chartutil.Load(chStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return h.opts.rpcInstallRelease(chart, rls.NewReleaseServiceClient(c), opts...)
|
||||
}
|
||||
|
||||
func (c *client) install(req *services.InstallReleaseRequest) (res *services.InstallReleaseResponse, err error) {
|
||||
if err = c.dial(); err != nil {
|
||||
return
|
||||
// UninstallRelease uninstalls a named release and returns the response.
|
||||
//
|
||||
// Note: there aren't currently any supported DeleteOptions, but they are
|
||||
// kept in the API signature as a placeholder for future additions.
|
||||
func (h *Client) DeleteRelease(rlsName string, opts ...DeleteOption) (*rls.UninstallReleaseResponse, error) {
|
||||
c, err := grpc.Dial(h.opts.host, grpc.WithInsecure())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
return h.opts.rpcDeleteRelease(rlsName, rls.NewReleaseServiceClient(c), opts...)
|
||||
}
|
||||
|
||||
// UpdateRelease updates a release to a new/different chart.
|
||||
//
|
||||
// Note: there aren't currently any supported UpdateOptions, but they
|
||||
// are kept in the API signature as a placeholder for future additions.
|
||||
func (h *Client) UpdateRelease(rlsName string, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error) {
|
||||
c, err := grpc.Dial(h.opts.host, grpc.WithInsecure())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
return c.impl.InstallRelease(context.TODO(), req, c.cfg.CallOpts()...)
|
||||
return h.opts.rpcUpdateRelease(rlsName, rls.NewReleaseServiceClient(c), opts...)
|
||||
}
|
||||
|
||||
func (c *client) uninstall(req *services.UninstallReleaseRequest) (*services.UninstallReleaseResponse, error) {
|
||||
if err := c.dial(); err != nil {
|
||||
// ReleaseStatus returns the given release's status.
|
||||
//
|
||||
// Note: there aren't currently any supported StatusOptions,
|
||||
// but they are kept in the API signature as a placeholder for future additions.
|
||||
func (h *Client) ReleaseStatus(rlsName string, opts ...StatusOption) (*rls.GetReleaseStatusResponse, error) {
|
||||
c, err := grpc.Dial(h.opts.host, grpc.WithInsecure())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
return c.impl.UninstallRelease(context.TODO(), req, c.cfg.CallOpts()...)
|
||||
return h.opts.rpcGetReleaseStatus(rlsName, rls.NewReleaseServiceClient(c), opts...)
|
||||
}
|
||||
|
||||
func (c *client) Close() error {
|
||||
return c.conn.Close()
|
||||
// ReleaseContent returns the configuration for a given release.
|
||||
//
|
||||
// Note: there aren't currently any supported ContentOptions, but
|
||||
// they are kept in the API signature as a placeholder for future additions.
|
||||
func (h *Client) ReleaseContent(rlsName string, opts ...ContentOption) (*rls.GetReleaseContentResponse, error) {
|
||||
c, err := grpc.Dial(h.opts.host, grpc.WithInsecure())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
return h.opts.rpcGetReleaseContent(rlsName, rls.NewReleaseServiceClient(c), opts...)
|
||||
}
|
||||
|
@ -1,28 +0,0 @@
|
||||
package helm
|
||||
|
||||
import (
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
ServAddr string
|
||||
Insecure bool
|
||||
}
|
||||
|
||||
func (cfg *config) DialOpts() (opts []grpc.DialOption) {
|
||||
if cfg.Insecure {
|
||||
opts = append(opts, grpc.WithInsecure())
|
||||
} else {
|
||||
// TODO: handle transport credentials
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (cfg *config) CallOpts() (opts []grpc.CallOption) {
|
||||
return
|
||||
}
|
||||
|
||||
func (cfg *config) client() *client {
|
||||
return &client{cfg: cfg}
|
||||
}
|
@ -1,132 +0,0 @@
|
||||
package helm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
chartutil "k8s.io/helm/pkg/chart"
|
||||
chartpbs "k8s.io/helm/pkg/proto/hapi/chart"
|
||||
)
|
||||
|
||||
// ChartToProto converts a chart to its Protobuf struct representation.
|
||||
func ChartToProto(ch *chartutil.Chart) (chpb *chartpbs.Chart, err error) {
|
||||
chpb = new(chartpbs.Chart)
|
||||
|
||||
chpb.Metadata, err = MetadataToProto(ch)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
chpb.Templates, err = TemplatesToProto(ch)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
chpb.Values, err = ValuesToProto(ch)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
chs, err := WalkChartFile(ch)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, dep := range chs.deps {
|
||||
chdep, err := ChartToProto(dep.File())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
chpb.Dependencies = append(chpb.Dependencies, chdep)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// MetadataToProto converts Chart.yaml data into protocol buffere Metadata.
|
||||
func MetadataToProto(ch *chartutil.Chart) (*chartpbs.Metadata, error) {
|
||||
if ch == nil {
|
||||
return nil, ErrMissingChart
|
||||
}
|
||||
|
||||
chfi := ch.Chartfile()
|
||||
|
||||
md := &chartpbs.Metadata{
|
||||
Name: chfi.Name,
|
||||
Home: chfi.Home,
|
||||
Version: chfi.Version,
|
||||
Description: chfi.Description,
|
||||
}
|
||||
|
||||
md.Sources = make([]string, len(chfi.Source))
|
||||
copy(md.Sources, chfi.Source)
|
||||
|
||||
md.Keywords = make([]string, len(chfi.Keywords))
|
||||
copy(md.Keywords, chfi.Keywords)
|
||||
|
||||
for _, maintainer := range chfi.Maintainers {
|
||||
md.Maintainers = append(md.Maintainers, &chartpbs.Maintainer{
|
||||
Name: maintainer.Name,
|
||||
Email: maintainer.Email,
|
||||
})
|
||||
}
|
||||
|
||||
return md, nil
|
||||
}
|
||||
|
||||
// TemplatesToProto converts chart templates to their protobuf representation.
|
||||
func TemplatesToProto(ch *chartutil.Chart) (tpls []*chartpbs.Template, err error) {
|
||||
if ch == nil {
|
||||
return nil, ErrMissingChart
|
||||
}
|
||||
|
||||
members, err := ch.LoadTemplates()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var tpl *chartpbs.Template
|
||||
|
||||
for _, member := range members {
|
||||
tpl = &chartpbs.Template{
|
||||
Name: member.Path,
|
||||
Data: make([]byte, len(member.Content)),
|
||||
}
|
||||
|
||||
copy(tpl.Data, member.Content)
|
||||
|
||||
tpls = append(tpls, tpl)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// OverridesToProto converts arbitrary TOML override data to Config data.
|
||||
func OverridesToProto(values []byte) *chartpbs.Config {
|
||||
return &chartpbs.Config{
|
||||
Raw: string(values),
|
||||
}
|
||||
}
|
||||
|
||||
// ValuesToProto converts a chart's values.toml data to protobuf.
|
||||
func ValuesToProto(ch *chartutil.Chart) (*chartpbs.Config, error) {
|
||||
if ch == nil {
|
||||
return nil, ErrMissingChart
|
||||
}
|
||||
|
||||
vals, err := ch.LoadValues()
|
||||
if err != nil {
|
||||
//return nil, ErrMissingValues
|
||||
vals = map[string]interface{}{}
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err = vals.Encode(&buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cfgVals := new(chartpbs.Config)
|
||||
cfgVals.Raw = buf.String()
|
||||
|
||||
return cfgVals, nil
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
package helm
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
chartutil "k8s.io/helm/pkg/chart"
|
||||
)
|
||||
|
||||
func TestInstallReleaseOverrides(t *testing.T) {
|
||||
// FIXME: This can't currently run unless a Tiller server is running, simply
|
||||
// because --dry-run still uses the server. There's already a WIP for a
|
||||
// testing harness, so this can be ported when that is done.
|
||||
t.Skip()
|
||||
|
||||
vals := `name = "mariner"`
|
||||
ch := "./testdata/albatross"
|
||||
ir, err := InstallRelease([]byte(vals), "foo", ch, true)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to release: %s", err)
|
||||
}
|
||||
|
||||
if len(ir.Release.Manifest) == 0 {
|
||||
t.Fatalf("Expected a manifest.")
|
||||
}
|
||||
|
||||
// Parse the result and see if the override worked
|
||||
d := map[string]interface{}{}
|
||||
if err := yaml.Unmarshal([]byte(ir.Release.Manifest), d); err != nil {
|
||||
t.Fatalf("Failed to unmarshal manifest: %s", err)
|
||||
}
|
||||
|
||||
if d["name"] != "mariner" {
|
||||
t.Errorf("Unexpected name %q", d["name"])
|
||||
}
|
||||
|
||||
if d["home"] != "nest" {
|
||||
t.Errorf("Unexpected home %q", d["home"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestOverridesToProto(t *testing.T) {
|
||||
override := []byte(`test = "foo"`)
|
||||
c := OverridesToProto(override)
|
||||
if c.Raw != string(override) {
|
||||
t.Errorf("Expected %q to match %q", c.Raw, override)
|
||||
}
|
||||
}
|
||||
|
||||
func TestChartToProto(t *testing.T) {
|
||||
c, err := chartutil.LoadDir("./testdata/albatross")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to load testdata chart: %s", err)
|
||||
}
|
||||
|
||||
p, err := ChartToProto(c)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to conver chart to proto: %s", err)
|
||||
}
|
||||
|
||||
if p.Metadata.Name != c.Chartfile().Name {
|
||||
t.Errorf("Expected names to match.")
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
package helm
|
||||
|
||||
const (
|
||||
// ErrNotImplemented indicates that this API is not implemented.
|
||||
ErrNotImplemented = Error("helm api not implemented")
|
||||
// ErrInvalidSrvAddr indicates an invalid address to the Tiller server.
|
||||
ErrInvalidSrvAddr = Error("invalid tiller address")
|
||||
// ErrMissingTpls indicates that the templates are missing from a chart.
|
||||
ErrMissingTpls = Error("missing chart templates")
|
||||
// ErrMissingChart indicates that the Chart.yaml data is missing.
|
||||
ErrMissingChart = Error("missing chart metadata")
|
||||
// ErrMissingValues indicates that the config values.yaml data is missing.
|
||||
ErrMissingValues = Error("missing chart values")
|
||||
)
|
||||
|
||||
// Error represents a Helm client error.
|
||||
type Error string
|
||||
|
||||
// Error returns a string representation of this error.
|
||||
func (e Error) Error() string {
|
||||
return string(e)
|
||||
}
|
@ -1,107 +0,0 @@
|
||||
package helm
|
||||
|
||||
import (
|
||||
"golang.org/x/net/context"
|
||||
|
||||
chartutil "k8s.io/helm/pkg/chart"
|
||||
"k8s.io/helm/pkg/proto/hapi/services"
|
||||
)
|
||||
|
||||
// Config defines a gRPC client's configuration.
|
||||
var Config = &config{
|
||||
ServAddr: ":44134",
|
||||
Insecure: true,
|
||||
}
|
||||
|
||||
// ListReleases lists the current releases.
|
||||
func ListReleases(limit int, offset string, sort services.ListSort_SortBy, order services.ListSort_SortOrder, filter string) (*services.ListReleasesResponse, error) {
|
||||
c := Config.client()
|
||||
if err := c.dial(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
req := &services.ListReleasesRequest{
|
||||
Limit: int64(limit),
|
||||
Offset: offset,
|
||||
SortBy: sort,
|
||||
SortOrder: order,
|
||||
Filter: filter,
|
||||
}
|
||||
cli, err := c.impl.ListReleases(context.TODO(), req, c.cfg.CallOpts()...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return cli.Recv()
|
||||
}
|
||||
|
||||
// GetReleaseStatus returns the given release's status.
|
||||
func GetReleaseStatus(name string) (*services.GetReleaseStatusResponse, error) {
|
||||
c := Config.client()
|
||||
if err := c.dial(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
req := &services.GetReleaseStatusRequest{Name: name}
|
||||
return c.impl.GetReleaseStatus(context.TODO(), req, c.cfg.CallOpts()...)
|
||||
}
|
||||
|
||||
// GetReleaseContent returns the configuration for a given release.
|
||||
func GetReleaseContent(name string) (*services.GetReleaseContentResponse, error) {
|
||||
c := Config.client()
|
||||
if err := c.dial(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
req := &services.GetReleaseContentRequest{Name: name}
|
||||
return c.impl.GetReleaseContent(context.TODO(), req, c.cfg.CallOpts()...)
|
||||
}
|
||||
|
||||
// UpdateRelease updates a release to a new/different chart.
|
||||
// TODO: This must take more than just name for an arg.
|
||||
func UpdateRelease(name string) (*services.UpdateReleaseResponse, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
// UninstallRelease uninstalls a named release and returns the response.
|
||||
func UninstallRelease(name string, dryRun bool) (*services.UninstallReleaseResponse, error) {
|
||||
|
||||
if dryRun {
|
||||
// In the dry run case, just see if the release exists.
|
||||
res, err := GetReleaseContent(name)
|
||||
if err != nil {
|
||||
return &services.UninstallReleaseResponse{}, err
|
||||
}
|
||||
return &services.UninstallReleaseResponse{Release: res.Release}, nil
|
||||
}
|
||||
|
||||
u := &services.UninstallReleaseRequest{
|
||||
Name: name,
|
||||
}
|
||||
return Config.client().uninstall(u)
|
||||
}
|
||||
|
||||
// InstallRelease installs a new chart and returns the release response.
|
||||
func InstallRelease(rawVals []byte, name string, chStr string, dryRun bool) (*services.InstallReleaseResponse, error) {
|
||||
chfi, err := chartutil.LoadChart(chStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
chpb, err := ChartToProto(chfi)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vals := OverridesToProto(rawVals)
|
||||
|
||||
return Config.client().install(&services.InstallReleaseRequest{
|
||||
Chart: chpb,
|
||||
Values: vals,
|
||||
DryRun: dryRun,
|
||||
Name: name,
|
||||
})
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package helmx
|
||||
package helm
|
||||
|
||||
import (
|
||||
"fmt"
|
@ -1 +0,0 @@
|
||||
name = "foo"
|
@ -1,4 +0,0 @@
|
||||
name: albatross
|
||||
description: testing chart
|
||||
version: 0.1.0
|
||||
home: "https://k8s.io/helm"
|
@ -1,3 +0,0 @@
|
||||
# Test data. Not a valid Kubernetes manifest
|
||||
name: {{.name}}
|
||||
home: {{.home}}
|
@ -1,2 +0,0 @@
|
||||
name = "albatross"
|
||||
home = "nest"
|
@ -1,115 +0,0 @@
|
||||
package helm
|
||||
|
||||
import (
|
||||
chartutil "k8s.io/helm/pkg/chart"
|
||||
)
|
||||
|
||||
//
|
||||
// TODO - we should probably consolidate
|
||||
// most of the code in this package, that
|
||||
// is specific to charts, into chartutil.
|
||||
//
|
||||
|
||||
// Walk a chart's dependency tree, returning
|
||||
// a pointer to the root chart.
|
||||
//
|
||||
// The following is an example chart dependency
|
||||
// hierarchy and the structure of a chartObj
|
||||
// post traversal. (note some chart files are
|
||||
// omitted for brevity),
|
||||
//
|
||||
// mychart/
|
||||
// charts/
|
||||
// chart_A/
|
||||
// charts/
|
||||
// chart_B/
|
||||
// chart_C/
|
||||
// charts/
|
||||
// chart_F/
|
||||
// chart_D/
|
||||
// charts/
|
||||
// chart_E/
|
||||
// chart_F/
|
||||
//
|
||||
//
|
||||
// chart: mychart (deps = 2)
|
||||
// |
|
||||
// |----> chart_A (deps = 2)
|
||||
// |
|
||||
// |--------> chart_B (deps = 0)
|
||||
// |
|
||||
// |--------> chart_C (deps = 1)
|
||||
// |
|
||||
// |------------> chart_F (deps = 0)
|
||||
// |
|
||||
// |----> chart_D (deps = 2)
|
||||
// |
|
||||
// |--------> chart_E (deps = 0)
|
||||
// |
|
||||
// |--------> chart_F (deps = 0)
|
||||
//
|
||||
//
|
||||
|
||||
// WalkChartFile walks a chart and returns a *chartObj.
|
||||
//
|
||||
// FIXME: Why does an exported function return an unexported struct whose only
|
||||
// exported method is to return the object passed into this method?
|
||||
func WalkChartFile(chfi *chartutil.Chart) (*chartObj, error) {
|
||||
root := &chartObj{file: chfi}
|
||||
err := root.walkChartDeps(chfi)
|
||||
|
||||
return root, err
|
||||
}
|
||||
|
||||
type chartObj struct {
|
||||
file *chartutil.Chart
|
||||
deps []*chartObj
|
||||
}
|
||||
|
||||
// File returns the *chartutil.Chart associated with this *chartObj.
|
||||
func (chd *chartObj) File() *chartutil.Chart {
|
||||
return chd.file
|
||||
}
|
||||
|
||||
func (chs *chartObj) walkChartDeps(chfi *chartutil.Chart) error {
|
||||
if hasDeps(chfi) {
|
||||
names, err := chfi.ChartDepNames()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(names) > 0 {
|
||||
chs.deps = append(chs.deps, resolveChartDeps(names)...)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resolveChartDeps(names []string) (deps []*chartObj) {
|
||||
for _, name := range names {
|
||||
chfi, err := chartutil.LoadDir(name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
chs := &chartObj{file: chfi}
|
||||
err = chs.walkChartDeps(chfi)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
deps = append(deps, chs)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func hasDeps(chfi *chartutil.Chart) bool {
|
||||
names, err := chfi.ChartDepNames()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return chfi.ChartsDir() != "" && len(names) > 0
|
||||
}
|
@ -1,128 +0,0 @@
|
||||
package helmx
|
||||
|
||||
import (
|
||||
"google.golang.org/grpc"
|
||||
"k8s.io/helm/pkg/chartutil"
|
||||
rls "k8s.io/helm/pkg/proto/hapi/services"
|
||||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
// $HELM_HOST envvar
|
||||
HelmHostEnvVar = "HELM_HOST"
|
||||
|
||||
// $HELM_HOME envvar
|
||||
HelmHomeEnvVar = "HELM_HOME"
|
||||
|
||||
// Default tiller server host address.
|
||||
DefaultHelmHost = ":44134"
|
||||
|
||||
// Default $HELM_HOME envvar value
|
||||
DefaultHelmHome = "$HOME/.helm"
|
||||
)
|
||||
|
||||
// Helm client manages client side of the helm-tiller protocol
|
||||
type Client struct {
|
||||
opts options
|
||||
}
|
||||
|
||||
func NewClient(opts ...Option) *Client {
|
||||
return new(Client).Init().Option(opts...)
|
||||
}
|
||||
|
||||
// Configure the helm client with the provided options
|
||||
func (h *Client) Option(opts ...Option) *Client {
|
||||
for _, opt := range opts {
|
||||
opt(&h.opts)
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
// Initializes the helm client with default options
|
||||
func (h *Client) Init() *Client {
|
||||
return h.Option(HelmHost(DefaultHelmHost)).
|
||||
Option(HelmHome(os.ExpandEnv(DefaultHelmHome)))
|
||||
}
|
||||
|
||||
// ListReleases lists the current releases.
|
||||
func (h *Client) ListReleases(opts ...ReleaseListOption) (*rls.ListReleasesResponse, error) {
|
||||
c, err := grpc.Dial(h.opts.host, grpc.WithInsecure())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
return h.opts.rpcListReleases(rls.NewReleaseServiceClient(c), opts...)
|
||||
}
|
||||
|
||||
// InstallRelease installs a new chart and returns the release response.
|
||||
func (h *Client) InstallRelease(chStr string, opts ...InstallOption) (*rls.InstallReleaseResponse, error) {
|
||||
c, err := grpc.Dial(h.opts.host, grpc.WithInsecure())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
chart, err := chartutil.Load(chStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return h.opts.rpcInstallRelease(chart, rls.NewReleaseServiceClient(c), opts...)
|
||||
}
|
||||
|
||||
// UninstallRelease uninstalls a named release and returns the response.
|
||||
//
|
||||
// Note: there aren't currently any supported DeleteOptions, but they are
|
||||
// kept in the API signature as a placeholder for future additions.
|
||||
func (h *Client) DeleteRelease(rlsName string, opts ...DeleteOption) (*rls.UninstallReleaseResponse, error) {
|
||||
c, err := grpc.Dial(h.opts.host, grpc.WithInsecure())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
return h.opts.rpcDeleteRelease(rlsName, rls.NewReleaseServiceClient(c), opts...)
|
||||
}
|
||||
|
||||
// UpdateRelease updates a release to a new/different chart.
|
||||
//
|
||||
// Note: there aren't currently any supported UpdateOptions, but they
|
||||
// are kept in the API signature as a placeholder for future additions.
|
||||
func (h *Client) UpdateRelease(rlsName string, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error) {
|
||||
c, err := grpc.Dial(h.opts.host, grpc.WithInsecure())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
return h.opts.rpcUpdateRelease(rlsName, rls.NewReleaseServiceClient(c), opts...)
|
||||
}
|
||||
|
||||
// ReleaseStatus returns the given release's status.
|
||||
//
|
||||
// Note: there aren't currently any supported StatusOptions,
|
||||
// but they are kept in the API signature as a placeholder for future additions.
|
||||
func (h *Client) ReleaseStatus(rlsName string, opts ...StatusOption) (*rls.GetReleaseStatusResponse, error) {
|
||||
c, err := grpc.Dial(h.opts.host, grpc.WithInsecure())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
return h.opts.rpcGetReleaseStatus(rlsName, rls.NewReleaseServiceClient(c), opts...)
|
||||
}
|
||||
|
||||
// ReleaseContent returns the configuration for a given release.
|
||||
//
|
||||
// Note: there aren't currently any supported ContentOptions, but
|
||||
// they are kept in the API signature as a placeholder for future additions.
|
||||
func (h *Client) ReleaseContent(rlsName string, opts ...ContentOption) (*rls.GetReleaseContentResponse, error) {
|
||||
c, err := grpc.Dial(h.opts.host, grpc.WithInsecure())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
return h.opts.rpcGetReleaseContent(rlsName, rls.NewReleaseServiceClient(c), opts...)
|
||||
}
|
Loading…
Reference in new issue