Use TillerC api instead of gRPC Tiller.

pull/1909/head
sauman 9 years ago
parent 8d75b0c0c0
commit d1165ef92d

@ -0,0 +1,15 @@
metadata:
name: release.helm.sh
apiVersion: extensions/v1beta1
kind: ThirdPartyResource
description: "A specification of Helm release"
versions:
- name: v1beta1
---
metadata:
name: release-version.helm.sh
apiVersion: extensions/v1beta1
kind: ThirdPartyResource
description: "A specification of Helm release version"
versions:
- name: v1beta1

@ -0,0 +1,24 @@
package install
import (
aci "k8s.io/helm/tillerc/api"
"k8s.io/kubernetes/pkg/apimachinery/announced"
"k8s.io/kubernetes/pkg/util/sets"
)
func init() {
if err := announced.NewGroupMetaFactory(
&announced.GroupMetaFactoryArgs{
GroupName: aci.GroupName,
VersionPreferenceOrder: []string{aci.V1beta1SchemeGroupVersion.Version},
ImportPrefix: "github.com/appscode/tillerc/api",
RootScopedKinds: sets.NewString("ThirdPartyResource"),
AddInternalObjectsToScheme: aci.AddToScheme,
},
announced.VersionToSchemeFunc{
aci.V1beta1SchemeGroupVersion.Version: aci.V1betaAddToScheme,
},
).Announce().RegisterAndEnable(); err != nil {
panic(err)
}
}

@ -0,0 +1,49 @@
package kube
import (
"k8s.io/kubernetes/pkg/api"
schema "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/runtime"
)
// GroupName is the group name use in this package
const GroupName = "helm.sh"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}
// Kind takes an unqualified kind and returns back a Group qualified GroupKind
func Kind(kind string) schema.GroupKind {
return SchemeGroupVersion.WithKind(kind).GroupKind()
}
// Resource takes an unqualified resource and returns back a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
var (
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
AddToScheme = SchemeBuilder.AddToScheme
)
// Adds the list of known types to api.Scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&Release{},
&ReleaseList{},
&ReleaseVersion{},
&ReleaseVersionList{},
&api.ListOptions{},
&api.DeleteOptions{},
)
return nil
}
func (obj *Release) GetObjectKind() schema.ObjectKind { return &obj.TypeMeta }
func (obj *ReleaseList) GetObjectKind() schema.ObjectKind { return &obj.TypeMeta }
func (obj *ReleaseVersion) GetObjectKind() schema.ObjectKind { return &obj.TypeMeta }
func (obj *ReleaseVersionList) GetObjectKind() schema.ObjectKind { return &obj.TypeMeta }

@ -0,0 +1,32 @@
package kube
import (
schema "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/runtime"
versionedwatch "k8s.io/kubernetes/pkg/watch/versioned"
)
// SchemeGroupVersion is group version used to register these objects
var V1beta1SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1beta1"}
var (
V1beta1SchemeBuilder = runtime.NewSchemeBuilder(v1addKnownTypes)
V1betaAddToScheme = V1beta1SchemeBuilder.AddToScheme
)
// Adds the list of known types to api.Scheme.
func v1addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(V1beta1SchemeGroupVersion,
&Release{},
&ReleaseList{},
&ReleaseVersion{},
&ReleaseVersionList{},
&v1.ListOptions{},
&v1.DeleteOptions{},
)
versionedwatch.AddToGroupVersion(scheme, V1beta1SchemeGroupVersion)
return nil
}

@ -0,0 +1,139 @@
package kube
import (
hapi_chart "k8s.io/helm/pkg/proto/hapi/chart"
hapi_release "k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
google_protobuf1 "github.com/golang/protobuf/ptypes/any"
)
//-------------------------------------------------------------------------------------------
// Chart represents a chart that is installed in a Release.
// The ChartSource represents the location and type of a chart to install.
// This is modelled like Volume in Pods, which allows specifying a chart
// inline (like today) or pulling a chart object from a (potentially private) chart registry similar to pulling a Docker image.
// +optional
type ChartSource struct {
// Inline charts are what is done today with Helm cli. Release request
// contains the chart definition in the release spec, sent by Helm cli.
Inline *hapi_chart.Chart `json:"inline,omitempty"`
}
//------------------------------------------------------------
// Release describes a deployment of a chart, together with the chart
// and the variables used to deploy that chart.
type Release struct {
unversioned.TypeMeta `json:",inline,omitempty"`
api.ObjectMeta `json:"metadata,omitempty"`
Spec ReleaseSpec `json:"spec,omitempty"`
Status ReleaseStatus `json:"status,omitempty"`
}
type ReleaseSpec struct {
// The ChartSource represents the location and type of a chart to install.
// This is modelled like Volume in Pods, which allows specifying a chart
// inline (like today) or pulling a chart object from a (potentially private)
// chart registry similar to pulling a Docker image.
Chart ChartSource `protobuf:"bytes,1,opt,name=chart" json:"chart,omitempty"`
//// Values is a string containing (unparsed) YAML values.
//Values *Config `protobuf:"bytes,2,opt,name=values" json:"values,omitempty"`
// Config is the set of extra Values added to the chart.
// These values override the default values inside of the chart.
Config *hapi_chart.Config `protobuf:"bytes,4,opt,name=config" json:"config,omitempty"`
// DisableHooks causes the server to skip running any hooks for the install.
DisableHooks bool `protobuf:"varint,5,opt,name=disable_hooks,json=disableHooks" json:"disable_hooks,omitempty"`
// Manifest is the string representation of the rendered template.
Manifest string `protobuf:"bytes,5,opt,name=manifest" json:"manifest,omitempty"`
// Hooks are all of the hooks declared for this release.
Hooks []*hapi_release.Hook `protobuf:"bytes,6,rep,name=hooks" json:"hooks,omitempty"`
// Version is an int32 which represents the version of the release.
Version int32 `protobuf:"varint,7,opt,name=version" json:"version,omitempty"`
// Performs pods restart for resources if applicable
Recreate bool `protobuf:"varint,6,opt,name=recreate" json:"recreate,omitempty"`
// timeout specifies the max amount of time any kubernetes client command can run.
Timeout int64 `protobuf:"varint,7,opt,name=timeout" json:"timeout,omitempty"`
Purge bool `protobuf:"varint,3,opt,name=purge" json:"purge,omitempty"`
// dry_run, if true, will run through the release logic, but neither create
DryRun bool `protobuf:"varint,4,opt,name=dry_run,json=dryRun" json:"dry_run,omitempty"`
}
/*type ReleaseStatus struct {
// Info contains information about the release.
//Info *Info `protobuf:"bytes,2,opt,name=info" json:"info,omitempty"`
Status *hapi_release.Status `protobuf:"bytes,1,opt,name=status" json:"status,omitempty"`
FirstDeployed unversioned.Time `protobuf:"bytes,2,opt,name=first_deployed,json=firstDeployed" json:"first_deployed,omitempty"`
LastDeployed unversioned.Time `protobuf:"bytes,3,opt,name=last_deployed,json=lastDeployed" json:"last_deployed,omitempty"`
// Deleted tracks when this object was deleted.
Deleted unversioned.Time `protobuf:"bytes,4,opt,name=deleted" json:"deleted,omitempty"`
}*/
type ReleaseList struct {
unversioned.TypeMeta `json:",inline"`
unversioned.ListMeta `json:"metadata,omitempty"`
Items []Release `json:"items,omitempty"`
}
// ---------------------------------------------------------------------------------------------------------------------
// ReleaseVersion captures the state of a individual release and are immutable.
// ReleaseVersion replaces the version wise configmaps used by Tiller 2.0
type ReleaseVersion struct {
unversioned.TypeMeta `json:",inline,omitempty"`
api.ObjectMeta `json:"metadata,omitempty"`
Spec ReleaseVersionSpec `json:"spec,omitempty"`
Status ReleaseVersionStatus `json:"status,omitempty"`
}
type ReleaseVersionSpec struct {
ReleaseSpec ReleaseSpec `json:"inline,omitempty"`
}
/*type ReleaseVersionStatus struct {
Status *hapi_release.Status `protobuf:"bytes,1,opt,name=status" json:"status,omitempty"`
Deployed unversioned.Time `protobuf:"bytes,2,opt,name=deployed" json:"deployed,omitempty"`
}*/
type ReleaseVersionList struct {
unversioned.TypeMeta `json:",inline"`
unversioned.ListMeta `json:"metadata,omitempty"`
Items []ReleaseVersion `json:"items,omitempty"`
}
type ReleaseStatus struct {
//LastDeploymentStatus *hapi_release.Status `json:"last_deployment_status,omitempty"`
Code hapi_release.Status_Code `protobuf:"varint,1,opt,name=code,enum=hapi.release.Status_Code" json:"code,omitempty"`
Details *google_protobuf1.Any `protobuf:"bytes,2,opt,name=details" json:"details,omitempty"`
// Cluster resources as kubectl would print them.
//Resources string `protobuf:"bytes,3,opt,name=resources" json:"resources,omitempty"`
// Contains the rendered templates/NOTES.txt if available
Notes string `protobuf:"bytes,4,opt,name=notes" json:"notes,omitempty"`
LastDeployedVersion int32 `json:"last_deployed_version,omitempty"`
LastDeployed unversioned.Time `json:"last_deployed,omitempty"`
FirstDeployed unversioned.Time `json:"first_deployed,omitempty"`
}
type ReleaseVersionStatus struct {
//Status *hapi_release.Status `protobuf:"bytes,1,opt,name=status" json:"status,omitempty"`
// Version is an int32 which represents the version of the release.
Code hapi_release.Status_Code `protobuf:"varint,1,opt,name=code,enum=hapi.release.Status_Code" json:"code,omitempty"`
Details *google_protobuf1.Any `protobuf:"bytes,2,opt,name=details" json:"details,omitempty"`
// Cluster resources as kubectl would print them.
//Resources string `protobuf:"bytes,3,opt,name=resources" json:"resources,omitempty"`
// Contains the rendered templates/NOTES.txt if available
Notes string `protobuf:"bytes,4,opt,name=notes" json:"notes,omitempty"`
Version int32 `protobuf:"varint,7,opt,name=version" json:"version,omitempty"`
Deployed unversioned.Time `protobuf:"bytes,2,opt,name=deployed,json=firstDeployed" json:"deployed,omitempty"`
}

@ -0,0 +1,163 @@
package client
import (
"encoding/json"
"io"
"net/url"
"reflect"
"strings"
aci "k8s.io/helm/tillerc/api"
"github.com/ghodss/yaml"
//"github.com/golang/glog"
"k8s.io/kubernetes/pkg/api"
schema "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/runtime"
kubejson "k8s.io/kubernetes/pkg/runtime/serializer/json"
)
// TODO(@sadlil): Find a better way to replace ExtendedCodec to encode and decode objects.
// Follow the guide to replace it with api.Codec and api.ParameterCodecs.
var ExtendedCodec = &extendedCodec{}
// DirectCodecFactory provides methods for retrieving "DirectCodec"s, which do not do conversion.
type DirectCodecFactory struct {
*extendedCodec
}
// EncoderForVersion returns an encoder that does not do conversion. gv is ignored.
func (f DirectCodecFactory) EncoderForVersion(serializer runtime.Encoder, _ runtime.GroupVersioner) runtime.Encoder {
return serializer
}
// DecoderToVersion returns an decoder that does not do conversion. gv is ignored.
func (f DirectCodecFactory) DecoderToVersion(serializer runtime.Decoder, _ runtime.GroupVersioner) runtime.Decoder {
return serializer
}
// SupportedMediaTypes returns the RFC2046 media types that this factory has serializers for.
func (f DirectCodecFactory) SupportedMediaTypes() []runtime.SerializerInfo {
return []runtime.SerializerInfo{
{
MediaType: "application/json",
EncodesAsText: true,
Serializer: &extendedCodec{},
PrettySerializer: &extendedCodec{pretty: true},
StreamSerializer: &runtime.StreamSerializerInfo{
Framer: kubejson.Framer,
EncodesAsText: true,
Serializer: &extendedCodec{},
},
},
{
MediaType: "application/yaml",
EncodesAsText: true,
Serializer: &extendedCodec{yaml: true},
PrettySerializer: &extendedCodec{yaml: true},
},
}
}
type extendedCodec struct {
pretty bool
yaml bool
}
func (e *extendedCodec) Decode(data []byte, gvk *schema.GroupVersionKind, obj runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) {
if e.yaml {
altered, err := yaml.YAMLToJSON(data)
if err != nil {
return nil, nil, err
}
data = altered
}
if obj == nil {
metadata := &schema.TypeMeta{}
err := json.Unmarshal(data, metadata)
if err != nil {
return obj, gvk, err
}
//glog.V(7).Infoln("Detected metadata type for nil object, got", metadata.APIVersion, metadata.Kind)
obj, err = setDefaultType(metadata)
if err != nil {
// glog.Errorln("faild to create type", err)
}
}
err := json.Unmarshal(data, obj)
if err != nil {
return obj, gvk, err
}
return obj, gvk, nil
}
func (e *extendedCodec) Encode(obj runtime.Object, w io.Writer) error {
setDefaultVersionKind(obj)
if e.yaml {
json, err := json.Marshal(obj)
if err != nil {
return err
}
data, err := yaml.JSONToYAML(json)
if err != nil {
return err
}
_, err = w.Write(data)
}
if e.pretty {
data, err := json.MarshalIndent(obj, "", " ")
if err != nil {
return err
}
_, err = w.Write(data)
return err
}
return json.NewEncoder(w).Encode(obj)
}
// DecodeParameters converts the provided url.Values into an object of type From with the kind of into, and then
// converts that object to into (if necessary). Returns an error if the operation cannot be completed.
func (*extendedCodec) DecodeParameters(parameters url.Values, from schema.GroupVersion, into runtime.Object) error {
if len(parameters) == 0 {
return nil
}
_, okDelete := into.(*api.DeleteOptions)
if _, okList := into.(*api.ListOptions); okList || okDelete {
from = schema.GroupVersion{Version: "v1"}
}
return runtime.NewParameterCodec(api.Scheme).DecodeParameters(parameters, from, into)
}
// EncodeParameters converts the provided object into the to version, then converts that object to url.Values.
// Returns an error if conversion is not possible.
func (c *extendedCodec) EncodeParameters(obj runtime.Object, to schema.GroupVersion) (url.Values, error) {
result := url.Values{}
if obj == nil {
return result, nil
}
_, okDelete := obj.(*api.DeleteOptions)
if _, okList := obj.(*api.ListOptions); okList || okDelete {
to = schema.GroupVersion{Version: "v1"}
}
return runtime.NewParameterCodec(api.Scheme).EncodeParameters(obj, to)
}
func setDefaultVersionKind(obj runtime.Object) {
// Check the values can are In type Extended Ingress
defaultGVK := schema.GroupVersionKind{
Group: aci.V1beta1SchemeGroupVersion.Group,
Version: aci.V1beta1SchemeGroupVersion.Version,
}
fullyQualifiedKind := reflect.ValueOf(obj).Type().String()
lastIndexOfDot := strings.LastIndex(fullyQualifiedKind, ".")
if lastIndexOfDot > 0 {
defaultGVK.Kind = fullyQualifiedKind[lastIndexOfDot+1:]
}
obj.GetObjectKind().SetGroupVersionKind(defaultGVK)
}
func setDefaultType(metadata *schema.TypeMeta) (runtime.Object, error) {
return api.Scheme.New(metadata.GroupVersionKind())
}

@ -0,0 +1,104 @@
package client
import (
"errors"
schema "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apimachinery/registered"
rest "k8s.io/kubernetes/pkg/client/restclient"
)
const (
defaultAPIPath = "/apis"
)
type ExtensionInterface interface {
RESTClient() rest.Interface
ReleaseNamespacer
ReleaseVersionNamespacer
}
// AppsCodeExtensionsClient is used to interact with experimental Kubernetes features.
// Features of Extensions group are not supported and may be changed or removed in
// incompatible ways at any time.
type ExtensionsClient struct {
restClient rest.Interface
}
func (a *ExtensionsClient) Release(namespace string) ReleaseInterface {
return newRelease(a, namespace)
}
func (a *ExtensionsClient) ReleaseVersion(namespace string) ReleaseVersionInterface {
return newReleaseVersion(a, namespace)
}
// NewAppsCodeExtensions creates a new AppsCodeExtensionsClient for the given config. This client
// provides access to experimental Kubernetes features.
// Features of Extensions group are not supported and may be changed or removed in
// incompatible ways at any time.
func NewExtensionsForConfig(c *rest.Config) (*ExtensionsClient, error) {
config := *c
if err := setExtensionsDefaults(&config); err != nil {
return nil, err
}
client, err := rest.RESTClientFor(&config)
if err != nil {
return nil, err
}
return &ExtensionsClient{client}, nil
}
// NewAppsCodeExtensionsOrDie creates a new AppsCodeExtensionsClient for the given config and
// panics if there is an error in the config.
// Features of Extensions group are not supported and may be changed or removed in
// incompatible ways at any time.
func NewExtensionsForConfigOrDie(c *rest.Config) *ExtensionsClient {
client, err := NewExtensionsForConfig(c)
if err != nil {
panic(err)
}
return client
}
// New creates a new ExtensionsV1beta1Client for the given RESTClient.
func NewNewExtensions(c rest.Interface) *ExtensionsClient {
return &ExtensionsClient{c}
}
func setExtensionsDefaults(config *rest.Config) error {
gv, err := schema.ParseGroupVersion("helm.sh/v1beta1")
if err != nil {
return err
}
// if helm.sh/v1beta1 is not enabled, return an error
if !registered.IsEnabledVersion(gv) {
return errors.New("helm.sh/v1beta1 is not enabled")
}
config.APIPath = defaultAPIPath
if config.UserAgent == "" {
config.UserAgent = rest.DefaultKubernetesUserAgent()
}
if config.GroupVersion == nil || config.GroupVersion.Group != "helm.sh" {
g, err := registered.Group("helm.sh")
if err != nil {
return err
}
copyGroupVersion := g.GroupVersion
config.GroupVersion = &copyGroupVersion
}
config.NegotiatedSerializer = DirectCodecFactory{extendedCodec: ExtendedCodec}
return nil
}
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *ExtensionsClient) RESTClient() rest.Interface {
if c == nil {
return nil
}
return c.restClient
}

@ -0,0 +1,26 @@
package client
// These imports are the API groups the client will support.
import (
"fmt"
_ "k8s.io/helm/tillerc/api/install"
_ "k8s.io/kubernetes/pkg/api/install"
"k8s.io/kubernetes/pkg/apimachinery/registered"
_ "k8s.io/kubernetes/pkg/apis/apps/install"
_ "k8s.io/kubernetes/pkg/apis/authentication/install"
_ "k8s.io/kubernetes/pkg/apis/authorization/install"
_ "k8s.io/kubernetes/pkg/apis/autoscaling/install"
_ "k8s.io/kubernetes/pkg/apis/batch/install"
_ "k8s.io/kubernetes/pkg/apis/certificates/install"
_ "k8s.io/kubernetes/pkg/apis/extensions/install"
_ "k8s.io/kubernetes/pkg/apis/policy/install"
_ "k8s.io/kubernetes/pkg/apis/rbac/install"
_ "k8s.io/kubernetes/pkg/apis/storage/install"
)
func init() {
if missingVersions := registered.ValidateEnvRequestedVersions(); len(missingVersions) != 0 {
panic(fmt.Sprintf("KUBE_API_VERSIONS contains versions that are not installed: %q.", missingVersions))
}
}

@ -0,0 +1,137 @@
package client
import (
aci "k8s.io/helm/tillerc/api"
"k8s.io/kubernetes/pkg/api"
rest "k8s.io/kubernetes/pkg/client/restclient"
"k8s.io/kubernetes/pkg/watch"
)
type ReleaseNamespacer interface {
Release(namespace string) ReleaseInterface
}
// ReleaseInterface has methods to work with Release resources.
type ReleaseInterface interface {
Create(*aci.Release) (*aci.Release, error)
Update(*aci.Release) (*aci.Release, error)
UpdateStatus(*aci.Release) (*aci.Release, error)
Delete(name string, options *api.DeleteOptions) error
DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error
Get(name string) (*aci.Release, error)
List(opts api.ListOptions) (*aci.ReleaseList, error)
Watch(opts api.ListOptions) (watch.Interface, error)
ReleaseExpansion
}
// releases implements ReleaseInterface
type releases struct {
client rest.Interface
ns string
}
func newRelease(c *ExtensionsClient, namespace string) *releases {
return &releases{c.restClient, namespace}
}
// newReleases returns a Releases
func newReleases(c *ExtensionsClient, namespace string) *releases {
return &releases{
client: c.RESTClient(),
ns: namespace,
}
}
// Create takes the representation of a release and creates it. Returns the server's representation of the release, and an error, if there is any.
func (c *releases) Create(release *aci.Release) (result *aci.Release, err error) {
result = &aci.Release{}
err = c.client.Post().
Namespace(c.ns).
Resource("releases").
Body(release).
Do().
Into(result)
return
}
// Update takes the representation of a release and updates it. Returns the server's representation of the release, and an error, if there is any.
func (c *releases) Update(release *aci.Release) (result *aci.Release, err error) {
result = &aci.Release{}
err = c.client.Put().
Namespace(c.ns).
Resource("releases").
Name(release.Name).
Body(release).
Do().
Into(result)
return
}
func (c *releases) UpdateStatus(release *aci.Release) (result *aci.Release, err error) {
result = &aci.Release{}
err = c.client.Put().
Namespace(c.ns).
Resource("releases").
Name(release.Name).
SubResource("status").
Body(release).
Do().
Into(result)
return
}
// Delete takes name of the release and deletes it. Returns an error if one occurs.
func (c *releases) Delete(name string, options *api.DeleteOptions) error {
return c.client.Delete().
Namespace(c.ns).
Resource("releases").
Name(name).
Body(options).
Do().
Error()
}
// DeleteCollection deletes a collection of objects.
func (c *releases) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error {
return c.client.Delete().
Namespace(c.ns).
Resource("releases").
VersionedParams(&listOptions, api.ParameterCodec).
Body(options).
Do().
Error()
}
// Get takes name of the release, and returns the corresponding release object, and an error if there is any.
func (c *releases) Get(name string) (result *aci.Release, err error) {
result = &aci.Release{}
err = c.client.Get().
Namespace(c.ns).
Resource("releases").
Name(name).
Do().
Into(result)
return
}
// List takes label and field selectors, and returns the list of Releases that match those selectors.
func (c *releases) List(opts api.ListOptions) (result *aci.ReleaseList, err error) {
result = &aci.ReleaseList{}
err = c.client.Get().
Namespace(c.ns).
Resource("releases").
VersionedParams(&opts, api.ParameterCodec).
Do().
Into(result)
return
}
// Watch returns a watch.Interface that watches the requested releases.
func (c *releases) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.client.Get().
Prefix("watch").
Namespace(c.ns).
Resource("releases").
VersionedParams(&opts, api.ParameterCodec).
Watch()
}

@ -0,0 +1,22 @@
package client
import aci "k8s.io/helm/tillerc/api"
// The ReleaseExpansion interface allows manually adding extra methods to the ReleaseInterface.
type ReleaseExpansion interface {
Dryrun(*aci.Release) (*aci.Release, error)
}
// Dryrun applied the provided ReleaseDryrun to the named release in the current namespace.
func (c *releases) Dryrun(release *aci.Release) (result *aci.Release, err error) {
result = &aci.Release{}
err = c.client.Put().
Namespace(c.ns).
Resource("releases").
Name(release.Name).
SubResource("dryrun").
Body(release).
Do().
Into(result)
return
}

@ -0,0 +1,123 @@
package client
import (
aci "k8s.io/helm/tillerc/api"
"k8s.io/kubernetes/pkg/api"
rest "k8s.io/kubernetes/pkg/client/restclient"
"k8s.io/kubernetes/pkg/watch"
)
type ReleaseVersionNamespacer interface {
ReleaseVersion(namespace string) ReleaseVersionInterface
}
// ReleaseVersionInterface has methods to work with ReleaseVersion resources.
type ReleaseVersionInterface interface {
Create(*aci.ReleaseVersion) (*aci.ReleaseVersion, error)
Update(*aci.ReleaseVersion) (*aci.ReleaseVersion, error)
Delete(name string, options *api.DeleteOptions) error
DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error
Get(name string) (*aci.ReleaseVersion, error)
List(opts api.ListOptions) (*aci.ReleaseVersionList, error)
Watch(opts api.ListOptions) (watch.Interface, error)
}
// release-versions implements ReleaseVersionInterface
type releaseVersions struct {
client rest.Interface
ns string
}
func newReleaseVersion(c *ExtensionsClient, namespace string) *releaseVersions {
return &releaseVersions{c.restClient, namespace}
}
// newReleaseVersions returns a ReleaseVersions
func newReleaseVersions(c *ExtensionsClient, namespace string) *releaseVersions {
return &releaseVersions{
client: c.RESTClient(),
ns: namespace,
}
}
// Create takes the representation of a release and creates it. Returns the server's representation of the release, and an error, if there is any.
func (c *releaseVersions) Create(version *aci.ReleaseVersion) (result *aci.ReleaseVersion, err error) {
result = &aci.ReleaseVersion{}
err = c.client.Post().
Namespace(c.ns).
Resource("releaseVersions").
Body(version).
Do().
Into(result)
return
}
// Delete takes name of the release and deletes it. Returns an error if one occurs.
func (c *releaseVersions) Delete(name string, options *api.DeleteOptions) error {
return c.client.Delete().
Namespace(c.ns).
Resource("releaseVersions").
Name(name).
Body(options).
Do().
Error()
}
// DeleteCollection deletes a collection of objects.
func (c *releaseVersions) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error {
return c.client.Delete().
Namespace(c.ns).
Resource("releaseVersions").
VersionedParams(&listOptions, api.ParameterCodec).
Body(options).
Do().
Error()
}
// Get takes name of the release, and returns the corresponding release object, and an error if there is any.
func (c *releaseVersions) Get(name string) (result *aci.ReleaseVersion, err error) {
result = &aci.ReleaseVersion{}
err = c.client.Get().
Namespace(c.ns).
Resource("releaseVersions").
Name(name).
Do().
Into(result)
return
}
// List takes label and field selectors, and returns the list of ReleaseVersions that match those selectors.
func (c *releaseVersions) List(opts api.ListOptions) (result *aci.ReleaseVersionList, err error) {
result = &aci.ReleaseVersionList{}
err = c.client.Get().
Namespace(c.ns).
Resource("releaseVersions").
VersionedParams(&opts, api.ParameterCodec).
Do().
Into(result)
return
}
// Watch returns a watch.Interface that watches the requested release-versions.
func (c *releaseVersions) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.client.Get().
Prefix("watch").
Namespace(c.ns).
Resource("releaseVersions").
VersionedParams(&opts, api.ParameterCodec).
Watch()
}
//updates release-version
func (c *releaseVersions) Update(version *aci.ReleaseVersion) (result *aci.ReleaseVersion, err error) {
result = &aci.ReleaseVersion{}
err = c.client.Put().
Namespace(c.ns).
Resource("releaseVersions").
Name(version.Name).
Body(version).
Do().
Into(result)
return
}

@ -40,6 +40,7 @@ type deleteCmd struct {
disableHooks bool
purge bool
timeout int64
namespace string
out io.Writer
client helm.Interface
@ -75,6 +76,7 @@ func newDeleteCmd(c helm.Interface, out io.Writer) *cobra.Command {
}
f := cmd.Flags()
f.StringVar(&del.namespace, "namespace", "default", "namespace to uninstall the release")
f.BoolVar(&del.dryRun, "dry-run", false, "simulate a delete")
f.BoolVar(&del.disableHooks, "no-hooks", false, "prevent hooks from running during deletion")
f.BoolVar(&del.purge, "purge", false, "remove the release from the store and make its name free for later use")
@ -90,7 +92,7 @@ func (d *deleteCmd) run() error {
helm.DeletePurge(d.purge),
helm.DeleteTimeout(d.timeout),
}
res, err := d.client.DeleteRelease(d.name, opts...)
res, err := d.client.DeleteRelease(d.name, d.namespace, opts...)
if res != nil && res.Info != "" {
fmt.Fprintln(d.out, res.Info)
}

@ -198,7 +198,6 @@ func (i *installCmd) run() error {
// Print the final name so the user knows what the final name of the release is.
fmt.Printf("FINAL NAME: %s\n", i.name)
}
res, err := i.client.InstallRelease(
i.chartPath,
i.namespace,
@ -213,19 +212,23 @@ func (i *installCmd) run() error {
return prettyError(err)
}
rel := res.GetRelease()
/* rel := res.GetRelease()
if rel == nil {
return nil
}*/
rel := res.Release
if rel == nil {
return nil
}
i.printRelease(rel)
// If this is a dry run, we can't display status.
if i.dryRun {
return nil
}
// Print the status like status command does
status, err := i.client.ReleaseStatus(rel.Name)
status, err := i.client.ReleaseStatus(rel.Name, rel.Namespace, helm.StatusReleaseVersion(1))
if err != nil {
return prettyError(err)
}

@ -36,6 +36,7 @@ second is a revision (version) number. To see revision numbers, run
type rollbackCmd struct {
name string
namespace string
revision int32
dryRun bool
recreate bool
@ -77,6 +78,7 @@ func newRollbackCmd(c helm.Interface, out io.Writer) *cobra.Command {
f := cmd.Flags()
f.BoolVar(&rollback.dryRun, "dry-run", false, "simulate a rollback")
f.StringVar(&rollback.namespace, "namespace", "default", "namespace of the release")
f.BoolVar(&rollback.recreate, "recreate-pods", false, "performs pods restart for the resource if applicable")
f.BoolVar(&rollback.disableHooks, "no-hooks", false, "prevent hooks from running during rollback")
f.Int64Var(&rollback.timeout, "timeout", 300, "time in seconds to wait for any individual kubernetes operation (like Jobs for hooks)")
@ -88,6 +90,7 @@ func newRollbackCmd(c helm.Interface, out io.Writer) *cobra.Command {
func (r *rollbackCmd) run() error {
_, err := r.client.RollbackRelease(
r.name,
r.namespace,
helm.RollbackDryRun(r.dryRun),
helm.RollbackRecreate(r.recreate),
helm.RollbackDisableHooks(r.disableHooks),

@ -41,6 +41,7 @@ The status consists of:
type statusCmd struct {
release string
namespace string
out io.Writer
client helm.Interface
version int32
@ -70,12 +71,13 @@ func newStatusCmd(client helm.Interface, out io.Writer) *cobra.Command {
}
cmd.PersistentFlags().Int32Var(&status.version, "revision", 0, "if set, display the status of the named release with revision")
cmd.PersistentFlags().StringVar(&status.namespace, "namespace", "default", "namespace of the release")
return cmd
}
func (s *statusCmd) run() error {
res, err := s.client.ReleaseStatus(s.release, helm.StatusReleaseVersion(s.version))
res, err := s.client.ReleaseStatus(s.release, s.namespace, helm.StatusReleaseVersion(s.version))
if err != nil {
return prettyError(err)
}

@ -163,6 +163,7 @@ func (u *upgradeCmd) run() error {
resp, err := u.client.UpdateRelease(
u.release,
chartPath,
u.namespace,
helm.UpdateValueOverrides(rawVals),
helm.UpgradeDryRun(u.dryRun),
helm.UpgradeRecreate(u.recreate),
@ -181,7 +182,7 @@ func (u *upgradeCmd) run() error {
fmt.Fprintf(u.out, "Release %q has been upgraded. Happy Helming!\n", u.release)
// Print the status like status command does
status, err := u.client.ReleaseStatus(u.release)
status, err := u.client.ReleaseStatus(u.release, u.namespace)
if err != nil {
return prettyError(err)
}

@ -17,19 +17,45 @@ limitations under the License.
package helm // import "k8s.io/helm/pkg/helm"
import (
"bytes"
"errors"
"fmt"
"github.com/golang/protobuf/ptypes"
"github.com/technosophos/moniker"
"golang.org/x/net/context"
"google.golang.org/grpc"
"gopkg.in/square/go-jose.v1/json"
"k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/proto/hapi/chart"
"k8s.io/helm/pkg/kube"
hapi_chart "k8s.io/helm/pkg/proto/hapi/chart"
rs "k8s.io/helm/pkg/proto/hapi/release"
rls "k8s.io/helm/pkg/proto/hapi/services"
hapi "k8s.io/helm/api"
cs "k8s.io/helm/client/clientset"
"k8s.io/kubernetes/pkg/api"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/client/restclient"
rest "k8s.io/kubernetes/pkg/client/restclient"
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
"log"
"math/rand"
"strconv"
"time"
)
// Client manages client side of the helm-tiller protocol
func init() {
rand.Seed(time.Now().UnixNano())
}
type Client struct {
opts options
}
type ExtensionsClient struct {
restClient rest.Interface
}
// NewClient creates a new client.
func NewClient(opts ...Option) *Client {
var c Client
@ -72,7 +98,7 @@ func (h *Client) InstallRelease(chstr, ns string, opts ...InstallOption) (*rls.I
}
// InstallReleaseFromChart installs a new chart and returns the release response.
func (h *Client) InstallReleaseFromChart(chart *chart.Chart, ns string, opts ...InstallOption) (*rls.InstallReleaseResponse, error) {
func (h *Client) InstallReleaseFromChart(chart *hapi_chart.Chart, ns string, opts ...InstallOption) (*rls.InstallReleaseResponse, error) {
// apply the install options
for _, opt := range opts {
opt(&h.opts)
@ -94,7 +120,7 @@ func (h *Client) InstallReleaseFromChart(chart *chart.Chart, ns string, opts ...
}
// DeleteRelease uninstalls a named release and returns the response.
func (h *Client) DeleteRelease(rlsName string, opts ...DeleteOption) (*rls.UninstallReleaseResponse, error) {
func (h *Client) DeleteRelease(rlsName string, namespace string, opts ...DeleteOption) (*rls.UninstallReleaseResponse, error) {
// apply the uninstall options
for _, opt := range opts {
opt(&h.opts)
@ -119,22 +145,23 @@ func (h *Client) DeleteRelease(rlsName string, opts ...DeleteOption) (*rls.Unins
return nil, err
}
}
return h.delete(ctx, req)
return h.delete(ctx, namespace, req)
}
// UpdateRelease loads a chart from chstr and updates a release to a new/different chart
func (h *Client) UpdateRelease(rlsName string, chstr string, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error) {
// UpdateRelease updates a release to a new/different chart
func (h *Client) UpdateRelease(rlsName string, chstr string, namespace string, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error) {
// load the chart to update
chart, err := chartutil.Load(chstr)
if err != nil {
return nil, err
}
return h.UpdateReleaseFromChart(rlsName, chart, opts...)
return h.UpdateReleaseFromChart(rlsName, chart, namespace, opts...)
}
// UpdateReleaseFromChart updates a release to a new/different chart
func (h *Client) UpdateReleaseFromChart(rlsName string, chart *chart.Chart, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error) {
func (h *Client) UpdateReleaseFromChart(rlsName string, chart *hapi_chart.Chart,namespace string, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error) {
// apply the update options
for _, opt := range opts {
@ -148,13 +175,12 @@ func (h *Client) UpdateReleaseFromChart(rlsName string, chart *chart.Chart, opts
req.Recreate = h.opts.recreate
req.ResetValues = h.opts.resetValues
ctx := NewContext()
if h.opts.before != nil {
if err := h.opts.before(ctx, req); err != nil {
return nil, err
}
}
return h.update(ctx, req)
return h.update(ctx, namespace, req)
}
// GetVersion returns the server version
@ -174,7 +200,7 @@ func (h *Client) GetVersion(opts ...VersionOption) (*rls.GetVersionResponse, err
}
// RollbackRelease rolls back a release to the previous version
func (h *Client) RollbackRelease(rlsName string, opts ...RollbackOption) (*rls.RollbackReleaseResponse, error) {
func (h *Client) RollbackRelease(rlsName string, namespace string, opts ...RollbackOption) (*rls.RollbackReleaseResponse, error) {
for _, opt := range opts {
opt(&h.opts)
}
@ -189,24 +215,24 @@ func (h *Client) RollbackRelease(rlsName string, opts ...RollbackOption) (*rls.R
return nil, err
}
}
return h.rollback(ctx, req)
return h.rollback(ctx, namespace, req)
}
// ReleaseStatus returns the given release's status.
func (h *Client) ReleaseStatus(rlsName string, opts ...StatusOption) (*rls.GetReleaseStatusResponse, error) {
func (h *Client) ReleaseStatus(rlsName string, namespace string, opts ...StatusOption) (*rls.GetReleaseStatusResponse, error) {
for _, opt := range opts {
opt(&h.opts)
}
req := &h.opts.statusReq
req.Name = rlsName
req.Version = h.opts.statusReq.Version
ctx := NewContext()
if h.opts.before != nil {
if err := h.opts.before(ctx, req); err != nil {
return nil, err
}
}
return h.status(ctx, req)
return h.status(ctx, namespace, req)
}
// ReleaseContent returns the configuration for a given release.
@ -217,7 +243,6 @@ func (h *Client) ReleaseContent(rlsName string, opts ...ContentOption) (*rls.Get
req := &h.opts.contentReq
req.Name = rlsName
ctx := NewContext()
if h.opts.before != nil {
if err := h.opts.before(ctx, req); err != nil {
return nil, err
@ -263,62 +288,252 @@ func (h *Client) list(ctx context.Context, req *rls.ListReleasesRequest) (*rls.L
// Executes tiller.InstallRelease RPC.
func (h *Client) install(ctx context.Context, req *rls.InstallReleaseRequest) (*rls.InstallReleaseResponse, error) {
c, err := grpc.Dial(h.opts.host, grpc.WithInsecure())
/* c, err := grpc.Dial(h.opts.host, grpc.WithInsecure())
if err != nil {
return nil, err
}
defer c.Close()
rlc := rls.NewReleaseServiceClient(c)
return rlc.InstallRelease(ctx, req)*/
resp := &rls.InstallReleaseResponse{}
maxTries := 5
releaseNameMaxLen := 53
name := req.Name
client, err := getRESTClient()
if err != nil {
return nil, err
return resp, err
}
// make uniq name
if len(name) == 0 {
for i := 0; i < maxTries; i++ {
namer := moniker.New()
name = namer.NameSep("-")
if len(name) > releaseNameMaxLen {
name = name[:releaseNameMaxLen]
}
rv := name + "-v1"
err = client.RESTClient().Get().Namespace(req.Namespace).Resource("releaseversion").Name(rv).Do().Error()
if err == nil {
fmt.Println("info: Name %q is taken. Searching again.", name)
} else {
break
}
}
}
defer c.Close()
rlc := rls.NewReleaseServiceClient(c)
return rlc.InstallRelease(ctx, req)
req.Name = name
releaseObj := makeReleaseObject(req)
releaseObj.Spec.Version = 1
release := new(hapi.Release)
err = client.RESTClient().Post().Namespace(req.Namespace).Resource("releases").Body(releaseObj).Do().Into(release)
if err != nil {
return resp, err
}
resp.Release = new(rs.Release)
resp.Release.Name = release.Name
resp.Release.Namespace = release.Namespace
resp.Release.Hooks = release.Spec.Hooks
resp.Release.Config = release.Spec.Config
resp.Release.Chart = new(hapi_chart.Chart)
resp.Release.Chart = release.Spec.Chart.Inline
resp.Release.Manifest = release.Spec.Manifest
resp.Release.Info = new(rs.Info)
resp.Release.Info.Status = new(rs.Status)
resp.Release.Info.Status.Notes = release.Status.Notes
resp.Release.Info.Status.Code = release.Status.Code
resp.Release.Info.Status.Details = release.Status.Details
firstDeployed, err := ptypes.TimestampProto(release.Status.FirstDeployed.Time)
if err != nil {
return resp, err
}
resp.Release.Info.FirstDeployed = firstDeployed
lastDeployed, err := ptypes.TimestampProto(release.Status.LastDeployed.Time)
if err != nil {
return resp, err
}
resp.Release.Info.FirstDeployed = lastDeployed
return resp, nil
}
// Executes tiller.UninstallRelease RPC.
func (h *Client) delete(ctx context.Context, req *rls.UninstallReleaseRequest) (*rls.UninstallReleaseResponse, error) {
c, err := grpc.Dial(h.opts.host, grpc.WithInsecure())
func (h *Client) delete(ctx context.Context, namespace string, req *rls.UninstallReleaseRequest) (*rls.UninstallReleaseResponse, error) {
/* c, err := grpc.Dial(h.opts.host, grpc.WithInsecure())
if err != nil {
return nil, err
}
defer c.Close()
rlc := rls.NewReleaseServiceClient(c)
return rlc.UninstallRelease(ctx, req)*/
resp := &rls.UninstallReleaseResponse{}
client, err := getRESTClient()
// TODO handle response
//release := new(hapi.Release)
err = client.RESTClient().Delete().Namespace(namespace).Resource("releases").Name(req.Name).Do().Error()
if err != nil {
return nil, err
return resp, err
}
defer c.Close()
rlc := rls.NewReleaseServiceClient(c)
return rlc.UninstallRelease(ctx, req)
return resp, nil
}
// Executes tiller.UpdateRelease RPC.
func (h *Client) update(ctx context.Context, req *rls.UpdateReleaseRequest) (*rls.UpdateReleaseResponse, error) {
c, err := grpc.Dial(h.opts.host, grpc.WithInsecure())
func (h *Client) update(ctx context.Context, namespace string, req *rls.UpdateReleaseRequest) (*rls.UpdateReleaseResponse, error) {
/* c, err := grpc.Dial(h.opts.host, grpc.WithInsecure())
if err != nil {
return nil, err
}
defer c.Close()
rlc := rls.NewReleaseServiceClient(c)
return rlc.UpdateRelease(ctx, req)*/
resp := &rls.UpdateReleaseResponse{}
client, err := getRESTClient()
// get the release
release := new(hapi.Release)
err = client.RESTClient().Get().Namespace(namespace).Resource("releases").Name(req.Name).Do().Into(release)
if err != nil {
return nil, err
}
defer c.Close()
rlc := rls.NewReleaseServiceClient(c)
return rlc.UpdateRelease(ctx, req)
return resp, err
}
release.Spec.Config = req.Values
release.Spec.DryRun = req.DryRun
release.Spec.DisableHooks = req.DisableHooks
release.Spec.Recreate = req.Recreate
release.Spec.Timeout = req.Timeout
release.Spec.Chart.Inline = req.Chart
release.Spec.Version = release.Spec.Version + 1
// update the release
updatedRelease := new(hapi.Release)
err = client.RESTClient().Put().Namespace(namespace).Resource("releases").Name(release.Name).Body(release).Do().Into(updatedRelease)
if err != nil {
return resp, err
}
resp.Release = new(rs.Release)
resp.Release.Name = updatedRelease.Name
resp.Release.Chart = updatedRelease.Spec.Chart.Inline
resp.Release.Config = updatedRelease.Spec.Config
resp.Release.Manifest = updatedRelease.Spec.Manifest
resp.Release.Hooks = updatedRelease.Spec.Hooks
resp.Release.Version = updatedRelease.Spec.Version
resp.Release.Info = new(rs.Info)
resp.Release.Info.Status = new(rs.Status)
resp.Release.Info.Status.Code = updatedRelease.Status.Code
resp.Release.Info.Status.Details = updatedRelease.Status.Details
resp.Release.Info.Status.Notes = updatedRelease.Status.Notes
return resp, nil
}
// Executes tiller.RollbackRelease RPC.
func (h *Client) rollback(ctx context.Context, req *rls.RollbackReleaseRequest) (*rls.RollbackReleaseResponse, error) {
c, err := grpc.Dial(h.opts.host, grpc.WithInsecure())
func (h *Client) rollback(ctx context.Context, namespace string, req *rls.RollbackReleaseRequest) (*rls.RollbackReleaseResponse, error) {
/* c, err := grpc.Dial(h.opts.host, grpc.WithInsecure())
if err != nil {
return nil, err
}
defer c.Close()
rlc := rls.NewReleaseServiceClient(c)
return rlc.RollbackRelease(ctx, req)*/
resp := &rls.RollbackReleaseResponse{}
config, err := getConfig()
if err != nil {
return nil, err
return resp, err
}
defer c.Close()
rlc := rls.NewReleaseServiceClient(c)
return rlc.RollbackRelease(ctx, req)
extClient, err := getRESTClient()
client, err := clientset.NewForConfig(config)
err = extClient.RESTClient().Get().Namespace(namespace).Resource("releases").Name(req.Name).Do().Error()
if err != nil {
return resp, errors.New("Release not found")
}
event, err := makeEventForRollBack(req)
event.ObjectMeta.Namespace = namespace
event.InvolvedObject.Namespace = namespace
event.InvolvedObject.Name = (req.Name + "-v" + strconv.Itoa(int(req.Version)))
event.ObjectMeta.Name = event.InvolvedObject.Name + "-" + RandStringRunes(5)
if err != nil {
return resp, err
}
err = extClient.RESTClient().Get().Namespace(namespace).Resource("releaseversions").Name(event.InvolvedObject.Name).Do().Error()
if err != nil {
return resp, errors.New("Release Version not found")
}
_, err = client.Core().Events(namespace).Create(event)
if err != nil {
return resp, err
}
return resp, nil
}
// Executes tiller.GetReleaseStatus RPC.
func (h *Client) status(ctx context.Context, req *rls.GetReleaseStatusRequest) (*rls.GetReleaseStatusResponse, error) {
c, err := grpc.Dial(h.opts.host, grpc.WithInsecure())
func (h *Client) status(ctx context.Context, namespace string, req *rls.GetReleaseStatusRequest) (*rls.GetReleaseStatusResponse, error) {
/*
c, err := grpc.Dial(h.opts.host, grpc.WithInsecure())
if err != nil {
return nil, err
}
defer c.Close()
rlc := rls.NewReleaseServiceClient(c)
return rlc.GetReleaseStatus(ctx, req)
*/
resp := &rls.GetReleaseStatusResponse{}
client, err := getRESTClient()
if err != nil {
return nil, err
return resp, err
}
defer c.Close()
release := new(hapi.Release)
resp.Info = new(rs.Info)
resp.Info.Status = new(rs.Status)
if req.Version == 0 {
err = client.RESTClient().Get().Namespace(namespace).Resource("releases").Name(req.Name).Do().Into(release)
if err != nil {
e := client.RESTClient().Get().Namespace(namespace).Resource("releaseversions").Name(req.Name + "-v1").Do().Error()
if e != nil {
return resp, err
} else {
resp.Namespace = namespace
resp.Info.Status.Code = rs.Status_DELETED
return resp, nil
}
}
req.Version = release.Spec.Version
}
duration := time.Duration(2) * time.Second
releaseVersion := new(hapi.ReleaseVersion)
name := req.Name + "-v" + strconv.Itoa(int(req.Version))
for i := 0; i <= 20; i++ {
err = client.RESTClient().Get().Namespace(namespace).Resource("releaseversions").Name(name).Do().Into(releaseVersion)
if err != nil {
time.Sleep(duration)
continue
} else {
break
}
}
if err != nil {
return resp, err
}
err = client.RESTClient().Get().Namespace(namespace).Resource("releases").Name(req.Name).Do().Into(release)
if err != nil {
return resp, err
}
resp.Name = release.Name
resp.Namespace = release.Namespace
rlc := rls.NewReleaseServiceClient(c)
return rlc.GetReleaseStatus(ctx, req)
resp.Info.Status.Code = release.Status.Code
resp.Info.Status.Notes = release.Status.Notes
resp.Info.Status.Details = release.Status.Details
resp.Info.Status.Resources = GetLatestResourceStatus(release.Namespace, release.Spec.Manifest)
f, err := ptypes.TimestampProto(release.Status.FirstDeployed.Time)
if err != nil {
return resp, err
}
resp.Info.FirstDeployed = f
l, err := ptypes.TimestampProto(release.Status.LastDeployed.Time)
if err != nil {
return resp, err
}
resp.Info.LastDeployed = l
return resp, nil
}
// Executes tiller.GetReleaseContent RPC.
@ -356,3 +571,104 @@ func (h *Client) history(ctx context.Context, req *rls.GetHistoryRequest) (*rls.
rlc := rls.NewReleaseServiceClient(c)
return rlc.GetHistory(ctx, req)
}
func makeReleaseObject(req *rls.InstallReleaseRequest) *hapi.Release {
release := &hapi.Release{}
release.TypeMeta.Kind = "Release"
release.TypeMeta.APIVersion = "helm.sh/v1beta1"
release.ObjectMeta.Name = req.Name
release.ObjectMeta.Namespace = req.Namespace
release.Spec = makeObjectSpec(req)
return release
}
func makeObjectSpec(req *rls.InstallReleaseRequest) hapi.ReleaseSpec {
spec := hapi.ReleaseSpec{}
spec.DryRun = req.DryRun
spec.DisableHooks = req.DisableHooks
// spec.Reuse = req.ReuseName TODO To enable reuse in installation
spec.Config = req.Values
spec.Chart.Inline = new(hapi_chart.Chart)
spec.Chart.Inline.Files = req.Chart.Files
spec.Chart.Inline.Metadata = req.Chart.Metadata
spec.Chart.Inline.Templates = req.Chart.Templates
spec.Chart.Inline.Values = req.Chart.Values
return spec
}
func getConfig() (*restclient.Config, error) {
rules := clientcmd.NewDefaultClientConfigLoadingRules()
rules.DefaultClientConfig = &clientcmd.DefaultClientConfig
overrides := &clientcmd.ConfigOverrides{ClusterDefaults: clientcmd.ClusterDefaults}
config, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(rules, overrides).ClientConfig()
if err != nil {
return nil, fmt.Errorf("Could not get kubernetes config: %s", err)
}
return config, nil
}
func getRESTClient() (*cs.ExtensionsClient, error) {
c, err := getConfig()
config := *c
if err != nil {
return nil, err
}
client, err := cs.NewExtensionsForConfig(&config)
if err != nil {
return nil, err
}
return client, nil
}
type RollbackReq struct {
// dry_run, if true, will run through the release logic but no create
DryRun bool `protobuf:"varint,2,opt,name=dry_run,json=dryRun" json:"dry_run,omitempty"`
// DisableHooks causes the server to skip running any hooks for the rollback
DisableHooks bool `protobuf:"varint,3,opt,name=disable_hooks,json=disableHooks" json:"disable_hooks,omitempty"`
// Performs pods restart for resources if applicable
Recreate bool `protobuf:"varint,5,opt,name=recreate" json:"recreate,omitempty"`
// timeout specifies the max amount of time any kubernetes client command can run.
Timeout int64 `protobuf:"varint,6,opt,name=timeout" json:"timeout,omitempty"`
}
func makeEventForRollBack(req *rls.RollbackReleaseRequest) (*api.Event, error) {
r := RollbackReq{
DryRun: req.DryRun,
Recreate: req.Recreate,
DisableHooks: req.DisableHooks,
Timeout: req.Timeout,
}
message, err := json.Marshal(r)
if err != nil {
return &api.Event{}, err
}
event := &api.Event{
InvolvedObject: api.ObjectReference{
Kind: "release",
},
Reason: "releaseRollback",
Message: string(message),
Type: api.EventTypeNormal,
Count: 1,
}
return event, nil
}
var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
func RandStringRunes(n int) string {
b := make([]rune, n)
for i := range b {
b[i] = letterRunes[rand.Intn(len(letterRunes))]
}
return string(b)
}
func GetLatestResourceStatus(namespace, manifest string) string {
KubeClient := kube.New(nil)
resource, err := KubeClient.Get(namespace, bytes.NewBufferString(manifest))
if err != nil {
log.Println(err)
return ""
}
return resource
}

@ -93,7 +93,7 @@ func TestInstallRelease_VerifyOptions(t *testing.T) {
var disableHooks = true
var releaseName = "test"
var namespace = "default"
var reuseName = true
var reuseName = false
var dryRun = true
var chartName = "alpine"
var overrides = []byte("key1=value1,key2=value2")

@ -26,11 +26,11 @@ type Interface interface {
ListReleases(opts ...ReleaseListOption) (*rls.ListReleasesResponse, error)
InstallRelease(chStr, namespace string, opts ...InstallOption) (*rls.InstallReleaseResponse, error)
InstallReleaseFromChart(chart *chart.Chart, namespace string, opts ...InstallOption) (*rls.InstallReleaseResponse, error)
DeleteRelease(rlsName string, opts ...DeleteOption) (*rls.UninstallReleaseResponse, error)
ReleaseStatus(rlsName string, opts ...StatusOption) (*rls.GetReleaseStatusResponse, error)
UpdateRelease(rlsName, chStr string, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error)
UpdateReleaseFromChart(rlsName string, chart *chart.Chart, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error)
RollbackRelease(rlsName string, opts ...RollbackOption) (*rls.RollbackReleaseResponse, error)
UpdateReleaseFromChart(rlsName string, chart *chart.Chart,namespace string, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error)
DeleteRelease(rlsName string, namespace string, opts ...DeleteOption) (*rls.UninstallReleaseResponse, error)
ReleaseStatus(rlsName string, namespace string, opts ...StatusOption) (*rls.GetReleaseStatusResponse, error)
UpdateRelease(rlsName, chStr string, namespace string, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error)
RollbackRelease(rlsName string, namespace string, opts ...RollbackOption) (*rls.RollbackReleaseResponse, error)
ReleaseContent(rlsName string, opts ...ContentOption) (*rls.GetReleaseContentResponse, error)
ReleaseHistory(rlsName string, opts ...HistoryOption) (*rls.GetHistoryResponse, error)
GetVersion(opts ...VersionOption) (*rls.GetVersionResponse, error)

@ -120,12 +120,13 @@ func (c *Client) Get(namespace string, reader io.Reader) (string, error) {
// Since we don't know what order the objects come in, let's group them by the types, so
// that when we print them, they come looking good (headers apply to subgroups, etc.)
objs := make(map[string][]runtime.Object)
infos, err := c.Build(namespace, reader)
if err != nil {
return "", err
}
err = perform(c, namespace, infos, func(info *resource.Info) error {
log.Printf("Doing get for: '%s'", info.Name)
//log.Printf("Doing get for: '%s'", info.Name)
obj, err := resource.NewHelper(info.Client, info.Mapping).Get(info.Namespace, info.Name, info.Export)
if err != nil {
return err

@ -518,7 +518,7 @@ var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion3
const _ = grpc.SupportPackageIsVersion4
// Client API for ReleaseService service

Loading…
Cancel
Save