ref(pkg/helm): package helm refactor

includes:
 - (#826) removal old pkg/helm
pull/837/head
fibonacci1729 8 years ago
parent 1b59967d2f
commit 91c3521b18

@ -1,43 +0,0 @@
package helm
import (
"golang.org/x/net/context"
"google.golang.org/grpc"
"k8s.io/helm/pkg/proto/hapi/services"
)
type client struct {
cfg *config
conn *grpc.ClientConn
impl services.ReleaseServiceClient
}
func (c *client) dial() (err error) {
c.conn, err = grpc.Dial(c.cfg.ServAddr, c.cfg.DialOpts()...)
c.impl = services.NewReleaseServiceClient(c.conn)
return
}
func (c *client) install(req *services.InstallReleaseRequest) (res *services.InstallReleaseResponse, err error) {
if err = c.dial(); err != nil {
return
}
defer c.Close()
return c.impl.InstallRelease(context.TODO(), req, c.cfg.CallOpts()...)
}
func (c *client) uninstall(req *services.UninstallReleaseRequest) (*services.UninstallReleaseResponse, error) {
if err := c.dial(); err != nil {
return nil, err
}
defer c.Close()
return c.impl.UninstallRelease(context.TODO(), req, c.cfg.CallOpts()...)
}
func (c *client) Close() error {
return c.conn.Close()
}

@ -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 +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
}
Loading…
Cancel
Save