RepoReady condition

This commit is contained in:
GLYASAI 2021-04-15 19:36:45 +08:00
parent cf871ea270
commit 3333acd0db
17 changed files with 219 additions and 110 deletions

View File

@ -2,6 +2,10 @@ package main
import "C"
import (
"context"
"os"
"time"
rainbondv1alpha1 "github.com/goodrain/rainbond/pkg/apis/rainbond/v1alpha1"
"github.com/goodrain/rainbond/pkg/generated/clientset/versioned"
k8sutil "github.com/goodrain/rainbond/util/k8s"
@ -9,8 +13,6 @@ import (
"github.com/sirupsen/logrus"
k8sErrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"os"
"time"
)
func init() {
@ -36,19 +38,25 @@ func main() {
},
Spec: rainbondv1alpha1.HelmAppSpec{
PreStatus: "",
AppName: "",
AppName: "rainbond-operator",
Version: "v1.0.0",
Revision: Int32(0),
Values: "",
AppStore: &rainbondv1alpha1.HelmAppStore{
Version: "1111111",
Name: "rainbond",
URL: "https://openchart.goodrain.com/goodrain/rainbond",
},
},
}
if _, err := clientset.RainbondV1alpha1().HelmApps("rbd-system").Create(helmApp); err != nil {
if _, err := clientset.RainbondV1alpha1().HelmApps("rbd-system").Create(context.Background(),
helmApp, metav1.CreateOptions{}); err != nil {
if !k8sErrors.IsAlreadyExists(err) {
logrus.Fatal(err)
}
}
ctrl := helmapp.NewController(stopCh, restcfg, 5*time.Second)
ctrl := helmapp.NewController(stopCh, restcfg, 5*time.Second, "/tmp/helm/repo/repositories.yaml", "/tmp/helm/cache")
if err = ctrl.Start(); err != nil {
logrus.Fatalf("start controller: %v", err)
}

View File

@ -26,6 +26,12 @@ func (in *HelmAppStatus) GetCondition(t HelmAppConditionType) (int, *HelmAppCond
return -1, nil
}
// IsConditionTrue checks if the condition is ready or not based on the given condition type.
func (in *HelmAppStatus) IsConditionTrue(t HelmAppConditionType) bool {
idx, condition := in.GetCondition(t)
return idx != -1 && condition.Status == corev1.ConditionTrue
}
// SetCondition setups the given HelmApp condition.
func (in *HelmAppStatus) SetCondition(c HelmAppCondition) {
pos, cp := in.GetCondition(c.Type)
@ -40,3 +46,44 @@ func (in *HelmAppStatus) SetCondition(c HelmAppCondition) {
in.Conditions = append(in.Conditions, c)
}
}
// UpdateCondition updates existing HelmApp condition or creates a new
// one. Sets LastTransitionTime to now if the status has changed.
// Returns true if HelmApp condition has changed or has been added.
func (in *HelmAppStatus) UpdateCondition(condition *HelmAppCondition) bool {
condition.LastTransitionTime = metav1.Now()
// Try to find this HelmApp condition.
conditionIndex, oldCondition := in.GetCondition(condition.Type)
if oldCondition == nil {
// We are adding new HelmApp condition.
in.Conditions = append(in.Conditions, *condition)
return true
}
// We are updating an existing condition, so we need to check if it has changed.
if condition.Status == oldCondition.Status {
condition.LastTransitionTime = oldCondition.LastTransitionTime
}
isEqual := condition.Status == oldCondition.Status &&
condition.Reason == oldCondition.Reason &&
condition.Message == oldCondition.Message &&
condition.LastTransitionTime.Equal(&oldCondition.LastTransitionTime)
in.Conditions[conditionIndex] = *condition
// Return true if one of the fields have changed.
return !isEqual
}
func (in *HelmAppStatus) UpdateConditionStatus(conditionType HelmAppConditionType, conditionStatus corev1.ConditionStatus) {
_, condition := in.GetCondition(conditionType)
if condition != nil {
condition.Status = conditionStatus
in.UpdateCondition(condition)
return
}
condition = NewHelmAppCondition(conditionType, conditionStatus, "", "")
in.UpdateCondition(condition)
}

View File

@ -62,8 +62,10 @@ type HelmAppConditionType string
// These are valid conditions of helm app.
const (
// HelmAppDetected indicates whether the helm app has been detected.
HelmAppDetected HelmAppConditionType = "Detected"
// HelmAppRepoReady indicates whether the helm repository is ready.
HelmAppRepoReady HelmAppConditionType = "RepoReady"
// HelmAppChartReady indicates whether the chart is ready.
HelmAppChartReady HelmAppConditionType = "ChartReady"
// HelmAppDetected indicates whether the helm app has been installed.
HelmAppInstalled HelmAppConditionType = "Installed"
)
@ -109,6 +111,10 @@ type HelmAppSpec struct {
// The values.yaml of the helm app, encoded by base64.
Values string `json:"values"`
// The helm app store.
// TODO: validation. not null
AppStore *HelmAppStore `json:"appStore"`
}
// HelmAppStore represents a helm repo.

View File

@ -109,6 +109,11 @@ func (in *HelmAppSpec) DeepCopyInto(out *HelmAppSpec) {
*out = new(int32)
**out = **in
}
if in.AppStore != nil {
in, out := &in.AppStore, &out.AppStore
*out = new(HelmAppStore)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmAppSpec.

View File

@ -61,7 +61,7 @@ func NewForConfig(c *rest.Config) (*Clientset, error) {
configShallowCopy := *c
if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 {
if configShallowCopy.Burst <= 0 {
return nil, fmt.Errorf("Burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0")
return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0")
}
configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst)
}

View File

@ -31,7 +31,7 @@ import (
var scheme = runtime.NewScheme()
var codecs = serializer.NewCodecFactory(scheme)
var parameterCodec = runtime.NewParameterCodec(scheme)
var localSchemeBuilder = runtime.SchemeBuilder{
rainbondv1alpha1.AddToScheme,
}

View File

@ -21,6 +21,8 @@
package fake
import (
"context"
v1alpha1 "github.com/goodrain/rainbond/pkg/apis/rainbond/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
labels "k8s.io/apimachinery/pkg/labels"
@ -41,7 +43,7 @@ var helmappsResource = schema.GroupVersionResource{Group: "rainbond.goodrain.io"
var helmappsKind = schema.GroupVersionKind{Group: "rainbond.goodrain.io", Version: "v1alpha1", Kind: "HelmApp"}
// Get takes name of the helmApp, and returns the corresponding helmApp object, and an error if there is any.
func (c *FakeHelmApps) Get(name string, options v1.GetOptions) (result *v1alpha1.HelmApp, err error) {
func (c *FakeHelmApps) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.HelmApp, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetAction(helmappsResource, c.ns, name), &v1alpha1.HelmApp{})
@ -52,7 +54,7 @@ func (c *FakeHelmApps) Get(name string, options v1.GetOptions) (result *v1alpha1
}
// List takes label and field selectors, and returns the list of HelmApps that match those selectors.
func (c *FakeHelmApps) List(opts v1.ListOptions) (result *v1alpha1.HelmAppList, err error) {
func (c *FakeHelmApps) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.HelmAppList, err error) {
obj, err := c.Fake.
Invokes(testing.NewListAction(helmappsResource, helmappsKind, c.ns, opts), &v1alpha1.HelmAppList{})
@ -74,14 +76,14 @@ func (c *FakeHelmApps) List(opts v1.ListOptions) (result *v1alpha1.HelmAppList,
}
// Watch returns a watch.Interface that watches the requested helmApps.
func (c *FakeHelmApps) Watch(opts v1.ListOptions) (watch.Interface, error) {
func (c *FakeHelmApps) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(testing.NewWatchAction(helmappsResource, c.ns, opts))
}
// Create takes the representation of a helmApp and creates it. Returns the server's representation of the helmApp, and an error, if there is any.
func (c *FakeHelmApps) Create(helmApp *v1alpha1.HelmApp) (result *v1alpha1.HelmApp, err error) {
func (c *FakeHelmApps) Create(ctx context.Context, helmApp *v1alpha1.HelmApp, opts v1.CreateOptions) (result *v1alpha1.HelmApp, err error) {
obj, err := c.Fake.
Invokes(testing.NewCreateAction(helmappsResource, c.ns, helmApp), &v1alpha1.HelmApp{})
@ -92,7 +94,7 @@ func (c *FakeHelmApps) Create(helmApp *v1alpha1.HelmApp) (result *v1alpha1.HelmA
}
// Update takes the representation of a helmApp and updates it. Returns the server's representation of the helmApp, and an error, if there is any.
func (c *FakeHelmApps) Update(helmApp *v1alpha1.HelmApp) (result *v1alpha1.HelmApp, err error) {
func (c *FakeHelmApps) Update(ctx context.Context, helmApp *v1alpha1.HelmApp, opts v1.UpdateOptions) (result *v1alpha1.HelmApp, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateAction(helmappsResource, c.ns, helmApp), &v1alpha1.HelmApp{})
@ -104,7 +106,7 @@ func (c *FakeHelmApps) Update(helmApp *v1alpha1.HelmApp) (result *v1alpha1.HelmA
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *FakeHelmApps) UpdateStatus(helmApp *v1alpha1.HelmApp) (*v1alpha1.HelmApp, error) {
func (c *FakeHelmApps) UpdateStatus(ctx context.Context, helmApp *v1alpha1.HelmApp, opts v1.UpdateOptions) (*v1alpha1.HelmApp, error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateSubresourceAction(helmappsResource, "status", c.ns, helmApp), &v1alpha1.HelmApp{})
@ -115,7 +117,7 @@ func (c *FakeHelmApps) UpdateStatus(helmApp *v1alpha1.HelmApp) (*v1alpha1.HelmAp
}
// Delete takes name of the helmApp and deletes it. Returns an error if one occurs.
func (c *FakeHelmApps) Delete(name string, options *v1.DeleteOptions) error {
func (c *FakeHelmApps) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
_, err := c.Fake.
Invokes(testing.NewDeleteAction(helmappsResource, c.ns, name), &v1alpha1.HelmApp{})
@ -123,15 +125,15 @@ func (c *FakeHelmApps) Delete(name string, options *v1.DeleteOptions) error {
}
// DeleteCollection deletes a collection of objects.
func (c *FakeHelmApps) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
action := testing.NewDeleteCollectionAction(helmappsResource, c.ns, listOptions)
func (c *FakeHelmApps) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
action := testing.NewDeleteCollectionAction(helmappsResource, c.ns, listOpts)
_, err := c.Fake.Invokes(action, &v1alpha1.HelmAppList{})
return err
}
// Patch applies the patch and returns the patched helmApp.
func (c *FakeHelmApps) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.HelmApp, err error) {
func (c *FakeHelmApps) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.HelmApp, err error) {
obj, err := c.Fake.
Invokes(testing.NewPatchSubresourceAction(helmappsResource, c.ns, name, pt, data, subresources...), &v1alpha1.HelmApp{})

View File

@ -21,6 +21,7 @@
package v1alpha1
import (
"context"
"time"
v1alpha1 "github.com/goodrain/rainbond/pkg/apis/rainbond/v1alpha1"
@ -39,15 +40,15 @@ type HelmAppsGetter interface {
// HelmAppInterface has methods to work with HelmApp resources.
type HelmAppInterface interface {
Create(*v1alpha1.HelmApp) (*v1alpha1.HelmApp, error)
Update(*v1alpha1.HelmApp) (*v1alpha1.HelmApp, error)
UpdateStatus(*v1alpha1.HelmApp) (*v1alpha1.HelmApp, error)
Delete(name string, options *v1.DeleteOptions) error
DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
Get(name string, options v1.GetOptions) (*v1alpha1.HelmApp, error)
List(opts v1.ListOptions) (*v1alpha1.HelmAppList, error)
Watch(opts v1.ListOptions) (watch.Interface, error)
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.HelmApp, err error)
Create(ctx context.Context, helmApp *v1alpha1.HelmApp, opts v1.CreateOptions) (*v1alpha1.HelmApp, error)
Update(ctx context.Context, helmApp *v1alpha1.HelmApp, opts v1.UpdateOptions) (*v1alpha1.HelmApp, error)
UpdateStatus(ctx context.Context, helmApp *v1alpha1.HelmApp, opts v1.UpdateOptions) (*v1alpha1.HelmApp, error)
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.HelmApp, error)
List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.HelmAppList, error)
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.HelmApp, err error)
HelmAppExpansion
}
@ -66,20 +67,20 @@ func newHelmApps(c *RainbondV1alpha1Client, namespace string) *helmApps {
}
// Get takes name of the helmApp, and returns the corresponding helmApp object, and an error if there is any.
func (c *helmApps) Get(name string, options v1.GetOptions) (result *v1alpha1.HelmApp, err error) {
func (c *helmApps) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.HelmApp, err error) {
result = &v1alpha1.HelmApp{}
err = c.client.Get().
Namespace(c.ns).
Resource("helmapps").
Name(name).
VersionedParams(&options, scheme.ParameterCodec).
Do().
Do(ctx).
Into(result)
return
}
// List takes label and field selectors, and returns the list of HelmApps that match those selectors.
func (c *helmApps) List(opts v1.ListOptions) (result *v1alpha1.HelmAppList, err error) {
func (c *helmApps) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.HelmAppList, err error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
@ -90,13 +91,13 @@ func (c *helmApps) List(opts v1.ListOptions) (result *v1alpha1.HelmAppList, err
Resource("helmapps").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Do().
Do(ctx).
Into(result)
return
}
// Watch returns a watch.Interface that watches the requested helmApps.
func (c *helmApps) Watch(opts v1.ListOptions) (watch.Interface, error) {
func (c *helmApps) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
@ -107,87 +108,90 @@ func (c *helmApps) Watch(opts v1.ListOptions) (watch.Interface, error) {
Resource("helmapps").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Watch()
Watch(ctx)
}
// Create takes the representation of a helmApp and creates it. Returns the server's representation of the helmApp, and an error, if there is any.
func (c *helmApps) Create(helmApp *v1alpha1.HelmApp) (result *v1alpha1.HelmApp, err error) {
func (c *helmApps) Create(ctx context.Context, helmApp *v1alpha1.HelmApp, opts v1.CreateOptions) (result *v1alpha1.HelmApp, err error) {
result = &v1alpha1.HelmApp{}
err = c.client.Post().
Namespace(c.ns).
Resource("helmapps").
VersionedParams(&opts, scheme.ParameterCodec).
Body(helmApp).
Do().
Do(ctx).
Into(result)
return
}
// Update takes the representation of a helmApp and updates it. Returns the server's representation of the helmApp, and an error, if there is any.
func (c *helmApps) Update(helmApp *v1alpha1.HelmApp) (result *v1alpha1.HelmApp, err error) {
func (c *helmApps) Update(ctx context.Context, helmApp *v1alpha1.HelmApp, opts v1.UpdateOptions) (result *v1alpha1.HelmApp, err error) {
result = &v1alpha1.HelmApp{}
err = c.client.Put().
Namespace(c.ns).
Resource("helmapps").
Name(helmApp.Name).
VersionedParams(&opts, scheme.ParameterCodec).
Body(helmApp).
Do().
Do(ctx).
Into(result)
return
}
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *helmApps) UpdateStatus(helmApp *v1alpha1.HelmApp) (result *v1alpha1.HelmApp, err error) {
func (c *helmApps) UpdateStatus(ctx context.Context, helmApp *v1alpha1.HelmApp, opts v1.UpdateOptions) (result *v1alpha1.HelmApp, err error) {
result = &v1alpha1.HelmApp{}
err = c.client.Put().
Namespace(c.ns).
Resource("helmapps").
Name(helmApp.Name).
SubResource("status").
VersionedParams(&opts, scheme.ParameterCodec).
Body(helmApp).
Do().
Do(ctx).
Into(result)
return
}
// Delete takes name of the helmApp and deletes it. Returns an error if one occurs.
func (c *helmApps) Delete(name string, options *v1.DeleteOptions) error {
func (c *helmApps) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
return c.client.Delete().
Namespace(c.ns).
Resource("helmapps").
Name(name).
Body(options).
Do().
Body(&opts).
Do(ctx).
Error()
}
// DeleteCollection deletes a collection of objects.
func (c *helmApps) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
func (c *helmApps) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
var timeout time.Duration
if listOptions.TimeoutSeconds != nil {
timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second
if listOpts.TimeoutSeconds != nil {
timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
}
return c.client.Delete().
Namespace(c.ns).
Resource("helmapps").
VersionedParams(&listOptions, scheme.ParameterCodec).
VersionedParams(&listOpts, scheme.ParameterCodec).
Timeout(timeout).
Body(options).
Do().
Body(&opts).
Do(ctx).
Error()
}
// Patch applies the patch and returns the patched helmApp.
func (c *helmApps) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.HelmApp, err error) {
func (c *helmApps) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.HelmApp, err error) {
result = &v1alpha1.HelmApp{}
err = c.client.Patch(pt).
Namespace(c.ns).
Resource("helmapps").
SubResource(subresources...).
Name(name).
SubResource(subresources...).
VersionedParams(&opts, scheme.ParameterCodec).
Body(data).
Do().
Do(ctx).
Into(result)
return
}

View File

@ -21,6 +21,7 @@
package v1alpha1
import (
"context"
time "time"
rainbondv1alpha1 "github.com/goodrain/rainbond/pkg/apis/rainbond/v1alpha1"
@ -63,13 +64,13 @@ func NewFilteredHelmAppInformer(client versioned.Interface, namespace string, re
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.RainbondV1alpha1().HelmApps(namespace).List(options)
return client.RainbondV1alpha1().HelmApps(namespace).List(context.TODO(), options)
},
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.RainbondV1alpha1().HelmApps(namespace).Watch(options)
return client.RainbondV1alpha1().HelmApps(namespace).Watch(context.TODO(), options)
},
},
&rainbondv1alpha1.HelmApp{},

View File

@ -28,8 +28,10 @@ import (
)
// HelmAppLister helps list HelmApps.
// All objects returned here must be treated as read-only.
type HelmAppLister interface {
// List lists all HelmApps in the indexer.
// Objects returned here must be treated as read-only.
List(selector labels.Selector) (ret []*v1alpha1.HelmApp, err error)
// HelmApps returns an object that can list and get HelmApps.
HelmApps(namespace string) HelmAppNamespaceLister
@ -60,10 +62,13 @@ func (s *helmAppLister) HelmApps(namespace string) HelmAppNamespaceLister {
}
// HelmAppNamespaceLister helps list and get HelmApps.
// All objects returned here must be treated as read-only.
type HelmAppNamespaceLister interface {
// List lists all HelmApps in the indexer for a given namespace.
// Objects returned here must be treated as read-only.
List(selector labels.Selector) (ret []*v1alpha1.HelmApp, err error)
// Get retrieves the HelmApp from the indexer for a given namespace and name.
// Objects returned here must be treated as read-only.
Get(name string) (*v1alpha1.HelmApp, error)
HelmAppNamespaceListerExpansion
}

View File

@ -8,8 +8,6 @@ import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"

View File

@ -16,12 +16,13 @@ type Controller struct {
controlLoop *ControlLoop
}
func NewController(stopCh chan struct{}, restcfg *rest.Config, resyncPeriod time.Duration) *Controller {
func NewController(stopCh chan struct{}, restcfg *rest.Config, resyncPeriod time.Duration,
repoFile, repoCache string) *Controller {
queue := workqueue.New()
clientset := versioned.NewForConfigOrDie(restcfg)
storer := NewStorer(clientset, resyncPeriod, queue)
controlLoop := NewControlLoop(storer, queue)
controlLoop := NewControlLoop(clientset, storer, queue, repoFile, repoCache)
return &Controller{
storer: storer,

View File

@ -1,6 +1,10 @@
package helmapp
import (
"context"
"github.com/goodrain/rainbond/pkg/generated/clientset/versioned"
"github.com/goodrain/rainbond/worker/controllers/helmapp/helm"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"strings"
"github.com/goodrain/rainbond/pkg/apis/rainbond/v1alpha1"
@ -10,17 +14,26 @@ import (
)
type ControlLoop struct {
clientset versioned.Interface
storer Storer
workqueue workqueue.Interface
repo *helm.Repo
}
// NewControlLoop -
func NewControlLoop(storer Storer,
func NewControlLoop(clientset versioned.Interface,
storer Storer,
workqueue workqueue.Interface,
repoFile string,
repoCache string,
) *ControlLoop {
repo := helm.NewRepo(repoFile, repoCache)
return &ControlLoop{
clientset: clientset,
storer: storer,
workqueue: workqueue,
repo: repo,
}
}
@ -61,8 +74,20 @@ func (c *ControlLoop) Reconcile(helmApp *v1alpha1.HelmApp) error {
status := NewStatus(helmApp.Status)
detector := NewDetector(status)
detector.Detect()
detector := NewDetector(helmApp, status, c.repo)
err := detector.Detect()
if err != nil {
// TODO: create event
return err
}
helmApp.Status = status.HelmAppStatus
// TODO: context
if _, err := c.clientset.RainbondV1alpha1().HelmApps(helmApp.Namespace).
UpdateStatus(context.Background(), helmApp, metav1.UpdateOptions{}); err != nil {
// TODO: create event
return err
}
return nil
}

View File

@ -1,12 +1,22 @@
package helmapp
import (
"github.com/goodrain/rainbond/pkg/apis/rainbond/v1alpha1"
"github.com/goodrain/rainbond/worker/controllers/helmapp/helm"
corev1 "k8s.io/api/core/v1"
)
type Detector struct {
helmApp *v1alpha1.HelmApp
status *Status
repo *helm.Repo
}
func NewDetector(status *Status) *Detector {
func NewDetector(helmApp *v1alpha1.HelmApp, status *Status, repo *helm.Repo) *Detector {
return &Detector{
helmApp: helmApp,
status: status,
repo: repo,
}
}
@ -16,6 +26,15 @@ func (d *Detector) Detect() error {
}
// add repo
if !d.status.IsConditionTrue(v1alpha1.HelmAppRepoReady) {
appStore := d.helmApp.Spec.AppStore
if err := d.repo.Add(appStore.Name, appStore.URL, "", ""); err != nil {
d.status.SetCondition(*v1alpha1.NewHelmAppCondition(
v1alpha1.HelmAppRepoReady, corev1.ConditionFalse, "RepoFailed", err.Error()))
return err
}
d.status.UpdateConditionStatus(v1alpha1.HelmAppRepoReady, corev1.ConditionTrue)
}
return nil
}

View File

@ -27,33 +27,24 @@ var deprecatedRepos = map[string]string{
// Repo -
type Repo struct {
name string
url string
username string
password string
forceUpdate bool
repoFile string
repoCache string
forceUpdate bool
insecureSkipTLSverify bool
}
func NewRepo(name, url, username, password, repoFile, repoCache string) *Repo {
// NewRepo creates a new repo.
func NewRepo(repoFile, repoCache string) *Repo {
return &Repo{
name: name,
url: url,
username: username,
password: password,
forceUpdate: true,
repoFile: repoFile,
repoCache: repoCache,
}
}
func (o *Repo) Add() error {
func (o *Repo) Add(name, url, username, password string) error {
var buf bytes.Buffer
err := o.add(&buf)
err := o.add(&buf, name, url, username, password)
if err != nil {
return err
}
@ -64,11 +55,11 @@ func (o *Repo) Add() error {
return nil
}
func (o *Repo) add(out io.Writer) error {
func (o *Repo) add(out io.Writer, name, url, username, password string) error {
// Block deprecated repos
for oldURL, newURL := range deprecatedRepos {
if strings.Contains(o.url, oldURL) {
return fmt.Errorf("repo %q is no longer available; try %q instead", o.url, newURL)
if strings.Contains(url, oldURL) {
return fmt.Errorf("repo %q is no longer available; try %q instead", url, newURL)
}
}
@ -101,27 +92,27 @@ func (o *Repo) add(out io.Writer) error {
}
c := repo.Entry{
Name: o.name,
URL: o.url,
Username: o.username,
Password: o.password,
Name: name,
URL: url,
Username: username,
Password: password,
InsecureSkipTLSverify: o.insecureSkipTLSverify,
}
// If the repo exists do one of two things:
// 1. If the configuration for the name is the same continue without error
// 2. When the config is different require --force-update
if !o.forceUpdate && f.Has(o.name) {
existing := f.Get(o.name)
if !o.forceUpdate && f.Has(name) {
existing := f.Get(name)
if c != *existing {
// The input coming in for the name is different from what is already
// configured. Return an error.
return errors.Errorf("repository name (%s) already exists, please specify a different name", o.name)
return errors.Errorf("repository name (%s) already exists, please specify a different name", name)
}
// The add is idempotent so do nothing
fmt.Fprintf(out, "%q already exists with the same configuration, skipping\n", o.name)
fmt.Fprintf(out, "%q already exists with the same configuration, skipping\n", name)
return nil
}
@ -137,7 +128,7 @@ func (o *Repo) add(out io.Writer) error {
r.CachePath = o.repoCache
}
if _, err := r.DownloadIndexFile(); err != nil {
return errors.Wrapf(err, "looks like %q is not a valid chart repository or cannot be reached", o.url)
return errors.Wrapf(err, "looks like %q is not a valid chart repository or cannot be reached", url)
}
f.Update(&c)
@ -145,6 +136,6 @@ func (o *Repo) add(out io.Writer) error {
if err := f.WriteFile(o.repoFile, 0644); err != nil {
return err
}
fmt.Fprintf(out, "%q has been added to your repositories\n", o.name)
fmt.Fprintf(out, "%q has been added to your repositories\n", name)
return nil
}

View File

@ -7,11 +7,9 @@ import (
)
func TestRepoAdd(t *testing.T) {
repo := NewRepo(util.NewUUID(),
"https://openchart.goodrain.com/goodrain/rainbond",
"", "",
repo := NewRepo(
"/tmp/helm/repo/repositories.yaml",
"/tmp/helm/cache")
err := repo.Add()
err := repo.Add(util.NewUUID(), "https://openchart.goodrain.com/goodrain/rainbond", "", "")
assert.Nil(t, err)
}

View File

@ -11,16 +11,7 @@ type Status struct {
// NewStatus creates a new helm app status.
func NewStatus(status v1alpha1.HelmAppStatus) *Status {
idx, _ := status.GetCondition(v1alpha1.HelmAppDetected)
if idx == -1 {
status.SetCondition(*v1alpha1.NewHelmAppCondition(
v1alpha1.HelmAppDetected,
corev1.ConditionFalse,
"",
"",
))
}
idx, _ = status.GetCondition(v1alpha1.HelmAppInstalled)
idx, _ := status.GetCondition(v1alpha1.HelmAppInstalled)
if idx == -1 {
status.SetCondition(*v1alpha1.NewHelmAppCondition(
v1alpha1.HelmAppInstalled,
@ -35,6 +26,14 @@ func NewStatus(status v1alpha1.HelmAppStatus) *Status {
}
func (s *Status) isDetected() bool {
idx, condition := s.GetCondition(v1alpha1.HelmAppDetected)
return idx != -1 && condition.Status == corev1.ConditionTrue
types := []v1alpha1.HelmAppConditionType{
v1alpha1.HelmAppRepoReady,
v1alpha1.HelmAppChartReady,
}
for _, t := range types {
if !s.IsConditionTrue(t) {
return false
}
}
return true
}