Skip to content
This repository has been archived by the owner on Nov 1, 2022. It is now read-only.

Commit

Permalink
Support both new and old custom resources
Browse files Browse the repository at this point in the history
Instead of requiring people to cut across from the old version of the
helm operator to the new, support both in fluxd.

This means you can not only have different versions of the custom
resources, you can keep running the old operator, while you transition
to the new.

To keep the `kind` part of Resource IDs unambiguous, I have renamed
the new custom resource to `HelmRelease` (it was already in the API
`flux.weave.works/v1beta`). This is the same as the kind bitnami's
helm operator uses, but the `apiVersion` is different (so Kubernetes
won't confuse them), and it's unlikely you'd be running both
operators.
  • Loading branch information
squaremo committed Nov 5, 2018
1 parent 6f521f1 commit a2a0387
Show file tree
Hide file tree
Showing 27 changed files with 653 additions and 605 deletions.
2 changes: 1 addition & 1 deletion cluster/kubernetes/resource/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ func unmarshalKind(base baseObject, bytes []byte) (resource.Resource, error) {
var list List
unmarshalList(base, &raw, &list)
return &list, nil
case "FluxHelmRelease":
case "FluxHelmRelease", "HelmRelease":
var fhr = FluxHelmRelease{baseObject: base}
if err := yaml.Unmarshal(bytes, &fhr); err != nil {
return nil, err
Expand Down
64 changes: 56 additions & 8 deletions cluster/kubernetes/resourcekinds.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
kresource "github.com/weaveworks/flux/cluster/kubernetes/resource"
"github.com/weaveworks/flux/image"
fhr_v1beta1 "github.com/weaveworks/flux/integrations/apis/flux.weave.works/v1beta1"
fhr_v1alpha2 "github.com/weaveworks/flux/integrations/apis/helm.integrations.flux.weave.works/v1alpha2"
"github.com/weaveworks/flux/resource"
)

Expand Down Expand Up @@ -370,16 +371,15 @@ func makeCronJobPodController(cronJob *apibatch.CronJob) podController {
type fluxHelmReleaseKind struct{}

func (fhr *fluxHelmReleaseKind) getPodController(c *Cluster, namespace, name string) (podController, error) {
fluxHelmRelease, err := c.client.FluxV1beta1().FluxHelmReleases(namespace).Get(name, meta_v1.GetOptions{})
fluxHelmRelease, err := c.client.HelmV1alpha2().FluxHelmReleases(namespace).Get(name, meta_v1.GetOptions{})
if err != nil {
return podController{}, err
}

return makeFluxHelmReleasePodController(fluxHelmRelease), nil
}

func (fhr *fluxHelmReleaseKind) getPodControllers(c *Cluster, namespace string) ([]podController, error) {
fluxHelmReleases, err := c.client.FluxV1beta1().FluxHelmReleases(namespace).List(meta_v1.ListOptions{})
fluxHelmReleases, err := c.client.HelmV1alpha2().FluxHelmReleases(namespace).List(meta_v1.ListOptions{})
if err != nil {
return nil, err
}
Expand All @@ -392,8 +392,8 @@ func (fhr *fluxHelmReleaseKind) getPodControllers(c *Cluster, namespace string)
return podControllers, nil
}

func makeFluxHelmReleasePodController(fluxHelmRelease *fhr_v1beta1.FluxHelmRelease) podController {
containers := createK8sFHRContainers(fluxHelmRelease.Spec)
func makeFluxHelmReleasePodController(fluxHelmRelease *fhr_v1alpha2.FluxHelmRelease) podController {
containers := createK8sFHRContainers(fluxHelmRelease.Spec.Values)

podTemplate := apiv1.PodTemplateSpec{
ObjectMeta: fluxHelmRelease.ObjectMeta,
Expand All @@ -404,7 +404,7 @@ func makeFluxHelmReleasePodController(fluxHelmRelease *fhr_v1beta1.FluxHelmRelea
}

return podController{
apiVersion: "flux.weave.works/v1beta1",
apiVersion: "helm.integrations.flux.weave.works/v1alpha2",
kind: "FluxHelmRelease",
name: fluxHelmRelease.ObjectMeta.Name,
status: fluxHelmRelease.Status.ReleaseStatus,
Expand All @@ -416,9 +416,9 @@ func makeFluxHelmReleasePodController(fluxHelmRelease *fhr_v1beta1.FluxHelmRelea
// createK8sContainers creates a list of k8s containers by
// interpreting the FluxHelmRelease resource. The interpretation is
// analogous to that in cluster/kubernetes/resource/fluxhelmrelease.go
func createK8sFHRContainers(spec fhr_v1beta1.FluxHelmReleaseSpec) []apiv1.Container {
func createK8sFHRContainers(values map[string]interface{}) []apiv1.Container {
var containers []apiv1.Container
_ = kresource.FindFluxHelmReleaseContainers(spec.Values, func(name string, image image.Ref, _ kresource.ImageSetter) error {
_ = kresource.FindFluxHelmReleaseContainers(values, func(name string, image image.Ref, _ kresource.ImageSetter) error {
containers = append(containers, apiv1.Container{
Name: name,
Image: image.String(),
Expand All @@ -427,3 +427,51 @@ func createK8sFHRContainers(spec fhr_v1beta1.FluxHelmReleaseSpec) []apiv1.Contai
})
return containers
}

/////////////////////////////////////////////////////////////////////////////
// flux.weave.works/v1beta1 HelmRelease

type helmReleaseKind struct{}

func (hr *helmReleaseKind) getPodController(c *Cluster, namespace, name string) (podController, error) {
helmRelease, err := c.client.FluxV1beta1().HelmReleases(namespace).Get(name, meta_v1.GetOptions{})
if err != nil {
return podController{}, err
}
return makeHelmReleasePodController(helmRelease), nil
}

func (hr *helmReleaseKind) getPodControllers(c *Cluster, namespace string) ([]podController, error) {
helmReleases, err := c.client.FluxV1beta1().HelmReleases(namespace).List(meta_v1.ListOptions{})
if err != nil {
return nil, err
}

var podControllers []podController
for _, f := range helmReleases.Items {
podControllers = append(podControllers, makeHelmReleasePodController(&f))
}

return podControllers, nil
}

func makeHelmReleasePodController(helmRelease *fhr_v1beta1.HelmRelease) podController {
containers := createK8sFHRContainers(helmRelease.Spec.Values)

podTemplate := apiv1.PodTemplateSpec{
ObjectMeta: helmRelease.ObjectMeta,
Spec: apiv1.PodSpec{
Containers: containers,
ImagePullSecrets: []apiv1.LocalObjectReference{},
},
}

return podController{
apiVersion: "flux.weave.works/v1beta1",
kind: "HelmRelease",
name: helmRelease.ObjectMeta.Name,
status: helmRelease.Status.ReleaseStatus,
podTemplate: podTemplate,
k8sObject: helmRelease,
}
}
10 changes: 5 additions & 5 deletions cmd/helm-operator/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func init() {
tillerTLSCACert = fs.String("tiller-tls-ca-cert-path", "", "path to CA certificate file used to validate the Tiller server; required if tiller-tls-verify is enabled")
tillerTLSHostname = fs.String("tiller-tls-hostname", "", "server name used to verify the hostname on the returned certificates from the server")

chartsSyncInterval = fs.Duration("charts-sync-interval", 3*time.Minute, "period on which to reconcile the Helm releases with FluxHelmRelease resources")
chartsSyncInterval = fs.Duration("charts-sync-interval", 3*time.Minute, "period on which to reconcile the Helm releases with HelmRelease resources")
logReleaseDiffs = fs.Bool("log-release-diffs", false, "log the diff when a chart release diverges; potentially insecure")
updateDependencies = fs.Bool("update-chart-deps", true, "Update chart dependencies before installing/upgrading a release")

Expand Down Expand Up @@ -171,11 +171,11 @@ func main() {
})

// The status updater, to keep track the release status for each
// FluxHelmRelease. It runs as a separate loop for now.
// HelmRelease. It runs as a separate loop for now.
statusUpdater := status.New(ifClient, kubeClient, helmClient)
go statusUpdater.Loop(shutdown, log.With(logger, "component", "annotator"))

// release instance is needed during the sync of Charts changes and during the sync of FluxHelmRelease changes
// release instance is needed during the sync of Charts changes and during the sync of HelmRelease changes
rel := release.New(log.With(logger, "component", "release"), helmClient)
// CHARTS CHANGES SYNC ------------------------------------------------------------------
chartSync := chartsync.New(log.With(logger, "component", "chartsync"),
Expand All @@ -189,8 +189,8 @@ func main() {
// SharedInformerFactory sets up informer, that maps resource type to a cache shared informer.
// operator attaches event handler to the informer and syncs the informer cache
ifInformerFactory := ifinformers.NewSharedInformerFactory(ifClient, 30*time.Second)
// Reference to shared index informers for the FluxHelmRelease
fhrInformer := ifInformerFactory.Flux().V1beta1().FluxHelmReleases()
// Reference to shared index informers for the HelmRelease
fhrInformer := ifInformerFactory.Flux().V1beta1().HelmReleases()

opr := operator.New(log.With(logger, "component", "operator"), *logReleaseDiffs, kubeClient, fhrInformer, chartSync)
// Starts handling k8s events related to the given resource kind
Expand Down
10 changes: 5 additions & 5 deletions deploy-helm/flux-helm-release-crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: fluxhelmreleases.flux.weave.works
name: helmreleases.flux.weave.works
spec:
group: flux.weave.works
names:
kind: FluxHelmRelease
listKind: FluxHelmReleaseList
plural: fluxhelmreleases
kind: HelmRelease
listKind: HelmReleaseList
plural: helmreleases
shortNames:
- fhr
- hr
scope: Namespaced
version: v1beta1
versions:
Expand Down
4 changes: 2 additions & 2 deletions integrations/apis/flux.weave.works/v1beta1/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ func init() {
// Adds the list of known types to api.Scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&FluxHelmRelease{},
&FluxHelmReleaseList{},
&HelmRelease{},
&HelmReleaseList{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
Expand Down
46 changes: 23 additions & 23 deletions integrations/apis/flux.weave.works/v1beta1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,19 @@ import (
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// FluxHelmRelease represents custom resource associated with a Helm Chart
type FluxHelmRelease struct {
type HelmRelease struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata"`

Spec FluxHelmReleaseSpec `json:"spec"`
Status FluxHelmReleaseStatus `json:"status"`
Spec HelmReleaseSpec `json:"spec"`
Status HelmReleaseStatus `json:"status"`
}

// ResourceID returns an ID made from the identifying parts of the
// resource, as a convenience for Flux, which uses them
// everywhere.
func (fhr FluxHelmRelease) ResourceID() flux.ResourceID {
return flux.MakeResourceID(fhr.Namespace, "FluxHelmRelease", fhr.Name)
func (fhr HelmRelease) ResourceID() flux.ResourceID {
return flux.MakeResourceID(fhr.Namespace, "HelmRelease", fhr.Name)
}

type ChartSource struct {
Expand Down Expand Up @@ -64,15 +64,15 @@ type RepoChartSource struct {

// FluxHelmReleaseSpec is the spec for a FluxHelmRelease resource
// FluxHelmReleaseSpec
type FluxHelmReleaseSpec struct {
type HelmReleaseSpec struct {
ChartSource `json:"chart"`
ReleaseName string `json:"releaseName,omitempty"`

ValueFileSecrets []v1.LocalObjectReference `json:"valueFileSecrets,omitempty"`
FluxHelmValues `json:",inline"`
HelmValues `json:",inline"`
}

type FluxHelmReleaseStatus struct {
type HelmReleaseStatus struct {
// ReleaseName is the name as either supplied or generated.
// +optional
ReleaseName string `json:"releaseName"`
Expand All @@ -86,12 +86,12 @@ type FluxHelmReleaseStatus struct {
// +optional
// +patchMergeKey=type
// +patchStrategy=merge
Conditions []FluxHelmReleaseCondition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
Conditions []HelmReleaseCondition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
}

type FluxHelmReleaseCondition struct {
Type FluxHelmReleaseConditionType `json:"type"`
Status v1.ConditionStatus `json:"status"`
type HelmReleaseCondition struct {
Type HelmReleaseConditionType `json:"type"`
Status v1.ConditionStatus `json:"status"`
// +optional
LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"`
// +optional
Expand All @@ -100,25 +100,25 @@ type FluxHelmReleaseCondition struct {
Message string `json:"message,omitempty"`
}

type FluxHelmReleaseConditionType string
type HelmReleaseConditionType string

const (
// ChartFetched means the chart to which the FluxHelmRelease
// refers has been fetched successfully
FluxHelmReleaseChartFetched FluxHelmReleaseConditionType = "ChartFetched"
// ChartFetched means the chart to which the HelmRelease refers
// has been fetched successfully
HelmReleaseChartFetched HelmReleaseConditionType = "ChartFetched"
// Released means the chart release, as specified in this
// FluxHelmRelease, has been processed by Helm.
FluxHelmReleaseReleased FluxHelmReleaseConditionType = "Released"
// HelmRelease, has been processed by Helm.
HelmReleaseReleased HelmReleaseConditionType = "Released"
)

// FluxHelmValues embeds chartutil.Values so we can implement deepcopy on map[string]interface{}
// +k8s:deepcopy-gen=false
type FluxHelmValues struct {
type HelmValues struct {
chartutil.Values `json:"values,omitempty"`
}

// DeepCopyInto implements deepcopy-gen method for use in generated code
func (in *FluxHelmValues) DeepCopyInto(out *FluxHelmValues) {
func (in *HelmValues) DeepCopyInto(out *HelmValues) {
if in == nil {
return
}
Expand All @@ -137,10 +137,10 @@ func (in *FluxHelmValues) DeepCopyInto(out *FluxHelmValues) {

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// FluxHelmReleaseList is a list of FluxHelmRelease resources
type FluxHelmReleaseList struct {
// HelmReleaseList is a list of FluxHelmRelease resources
type HelmReleaseList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata"`

Items []FluxHelmRelease `json:"items"`
Items []HelmRelease `json:"items"`
}
34 changes: 17 additions & 17 deletions integrations/apis/flux.weave.works/v1beta1/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,45 +6,45 @@ import (
"github.com/stretchr/testify/assert"
)

func TestFluxHelmValues(t *testing.T) {
func TestHelmValues(t *testing.T) {
testCases := []struct {
original *FluxHelmValues
transformer func(v *FluxHelmValues) *FluxHelmValues
expectedCopy *FluxHelmValues
expectedOriginal *FluxHelmValues
original *HelmValues
transformer func(v *HelmValues) *HelmValues
expectedCopy *HelmValues
expectedOriginal *HelmValues
}{
// reassignment
{
original: nil,
transformer: func(v *FluxHelmValues) *FluxHelmValues {
return &FluxHelmValues{}
transformer: func(v *HelmValues) *HelmValues {
return &HelmValues{}
},
expectedCopy: &FluxHelmValues{},
expectedCopy: &HelmValues{},
expectedOriginal: nil,
},
// mutation
{
original: &FluxHelmValues{Values: map[string]interface{}{}},
transformer: func(v *FluxHelmValues) *FluxHelmValues {
original: &HelmValues{Values: map[string]interface{}{}},
transformer: func(v *HelmValues) *HelmValues {
v.Values["foo"] = "bar"
return v
},
expectedCopy: &FluxHelmValues{Values: map[string]interface{}{"foo": "bar"}},
expectedOriginal: &FluxHelmValues{Values: map[string]interface{}{}},
expectedCopy: &HelmValues{Values: map[string]interface{}{"foo": "bar"}},
expectedOriginal: &HelmValues{Values: map[string]interface{}{}},
},
{
original: &FluxHelmValues{Values: map[string]interface{}{"foo": map[string]interface{}{"bar": "baz"}}},
transformer: func(v *FluxHelmValues) *FluxHelmValues {
original: &HelmValues{Values: map[string]interface{}{"foo": map[string]interface{}{"bar": "baz"}}},
transformer: func(v *HelmValues) *HelmValues {
v.Values["foo"] = map[string]interface{}{"bar": "oof"}
return v
},
expectedCopy: &FluxHelmValues{Values: map[string]interface{}{"foo": map[string]interface{}{"bar": "oof"}}},
expectedOriginal: &FluxHelmValues{Values: map[string]interface{}{"foo": map[string]interface{}{"bar": "baz"}}},
expectedCopy: &HelmValues{Values: map[string]interface{}{"foo": map[string]interface{}{"bar": "oof"}}},
expectedOriginal: &HelmValues{Values: map[string]interface{}{"foo": map[string]interface{}{"bar": "baz"}}},
},
}

for i, tc := range testCases {
output := &FluxHelmValues{}
output := &HelmValues{}
tc.original.DeepCopyInto(output)
assert.Exactly(t, tc.expectedCopy, tc.transformer(output), "copy was not mutated. test case: %d", i)
assert.Exactly(t, tc.expectedOriginal, tc.original, "original was mutated. test case: %d", i)
Expand Down
Loading

0 comments on commit a2a0387

Please sign in to comment.