diff --git a/cmd/helm/install.go b/cmd/helm/install.go index be9b61b75..86ff15efe 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -190,6 +190,7 @@ func (i *installCmd) run() error { fmt.Printf("FINAL NAME: %s\n", i.name) } + res, err := i.client.InstallRelease( i.chartPath, i.namespace, diff --git a/pkg/helm/client.go b/pkg/helm/client.go index 91e666362..d88a40248 100644 --- a/pkg/helm/client.go +++ b/pkg/helm/client.go @@ -20,15 +20,43 @@ import ( "golang.org/x/net/context" "google.golang.org/grpc" + "fmt" "k8s.io/helm/pkg/chartutil" + hapi_chart "k8s.io/helm/pkg/proto/hapi/chart" rls "k8s.io/helm/pkg/proto/hapi/services" + hapi "k8s.io/helm/tillerc/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" + cl"k8s.io/helm/tillerc/client/clientset" + ss"k8s.io/helm/pkg/proto/hapi/release" ) +const ( + defaultAPIPath = "/apis" +) + +type extendedCodec struct { + pretty bool + yaml bool +} + +var ExtendedCodec = &extendedCodec{} + +type DirectCodecFactory struct { + *extendedCodec +} + // Client manages client side of the helm-tiller protocol type Client struct { opts options } +type ExtensionsClient struct { + restClient rest.Interface +} + // NewClient creates a new client. func NewClient(opts ...Option) *Client { var c Client @@ -84,7 +112,8 @@ func (h *Client) InstallRelease(chstr, ns string, opts ...InstallOption) (*rls.I return nil, err } } - return h.install(ctx, req) + return h.install(ctx, req) /* "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/unversioned"*/ } // DeleteRelease uninstalls a named release and returns the response. @@ -250,14 +279,42 @@ 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{} + releaseObj := makeReleaseObject(req) + c, err := getConfig() + config := *c if err != nil { - return nil, err + return resp, err } - defer c.Close() - - rlc := rls.NewReleaseServiceClient(c) - return rlc.InstallRelease(ctx, req) + release := new(hapi.Release) + client, err := cl.NewExtensionsForConfig(&config) + if err != nil { + return resp, err + } + err = client.RESTClient().Post().Namespace(releaseObj.Namespace).Resource("releases").Body(releaseObj).Do().Into(release) + if err != nil { + return resp, err + } + resp.Release = new(ss.Release) + resp.Release.Name = release.Name + resp.Release.Namespace = release.Namespace + resp.Release.Hooks = release.Spec.Hooks + //resp.Release.Config = new(hapi_chart.Chart) + 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(ss.Info) + resp.Release.Info.Status = release.Status.Status + return resp, nil } // Executes tiller.UninstallRelease RPC. @@ -343,3 +400,49 @@ 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 + 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 newKubeClient() (clientset.Interface, 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 clientset.NewForConfig(config) +} + + diff --git a/pkg/helm/helm_test.go b/pkg/helm/helm_test.go index a6289f2c8..81afa3180 100644 --- a/pkg/helm/helm_test.go +++ b/pkg/helm/helm_test.go @@ -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") diff --git a/pkg/proto/hapi/services/tiller.pb.go b/pkg/proto/hapi/services/tiller.pb.go index 5c244e1bc..0c330adb4 100644 --- a/pkg/proto/hapi/services/tiller.pb.go +++ b/pkg/proto/hapi/services/tiller.pb.go @@ -507,7 +507,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 diff --git a/tillerc/api/extensions/helm.yaml b/tillerc/api/extensions/helm.yaml new file mode 100644 index 000000000..5b79b3774 --- /dev/null +++ b/tillerc/api/extensions/helm.yaml @@ -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 diff --git a/tillerc/api/install/install.go b/tillerc/api/install/install.go new file mode 100644 index 000000000..758af426d --- /dev/null +++ b/tillerc/api/install/install.go @@ -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) + } +} diff --git a/tillerc/api/register.go b/tillerc/api/register.go new file mode 100644 index 000000000..0ee39e812 --- /dev/null +++ b/tillerc/api/register.go @@ -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 } diff --git a/tillerc/api/register_v1beta1.go b/tillerc/api/register_v1beta1.go new file mode 100644 index 000000000..331bfe14a --- /dev/null +++ b/tillerc/api/register_v1beta1.go @@ -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 +} diff --git a/tillerc/api/types.go b/tillerc/api/types.go new file mode 100644 index 000000000..b9184b0bd --- /dev/null +++ b/tillerc/api/types.go @@ -0,0 +1,112 @@ +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" +) + +//------------------------------------------------------------------------------------------- +// 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"` +} diff --git a/tillerc/client/clientset/codec.go b/tillerc/client/clientset/codec.go new file mode 100644 index 000000000..a73fb99d9 --- /dev/null +++ b/tillerc/client/clientset/codec.go @@ -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()) +} diff --git a/tillerc/client/clientset/extensions.go b/tillerc/client/clientset/extensions.go new file mode 100644 index 000000000..e3cab37b1 --- /dev/null +++ b/tillerc/client/clientset/extensions.go @@ -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 = ©GroupVersion + } + + 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 +} diff --git a/tillerc/client/clientset/imports.go b/tillerc/client/clientset/imports.go new file mode 100644 index 000000000..98126dcbd --- /dev/null +++ b/tillerc/client/clientset/imports.go @@ -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)) + } +} diff --git a/tillerc/client/clientset/release.go b/tillerc/client/clientset/release.go new file mode 100644 index 000000000..30246bc6f --- /dev/null +++ b/tillerc/client/clientset/release.go @@ -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() +} diff --git a/tillerc/client/clientset/release_expansion.go b/tillerc/client/clientset/release_expansion.go new file mode 100644 index 000000000..ec6f661a3 --- /dev/null +++ b/tillerc/client/clientset/release_expansion.go @@ -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 +} diff --git a/tillerc/client/clientset/release_version.go b/tillerc/client/clientset/release_version.go new file mode 100644 index 000000000..e6ba8b9a4 --- /dev/null +++ b/tillerc/client/clientset/release_version.go @@ -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 +}