Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add 'addOwnerRef' flag to the spec. #87

Merged
merged 4 commits into from
Feb 20, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 19 additions & 8 deletions pkg/apis/app/v1beta1/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@ import (

// Mutate - mutate expected
func (a *Application) Mutate(rsrc interface{}, labels map[string]string, status interface{}, expected, dependent, observed *resource.ObjectBag) (*resource.ObjectBag, error) {
return observed, nil
exp := resource.ObjectBag{}
for _, o := range observed.Items() {
o.Lifecycle = resource.LifecycleManaged
exp.Add(o)
}
return &exp, nil
}

// Finalize - execute finalizers
Expand Down Expand Up @@ -140,14 +145,20 @@ func (a *Application) Components() []component.Component {
}

// OwnerRef returns owner ref object with the component's resource as owner
func (a *Application) OwnerRef() []metav1.OwnerReference {
return []metav1.OwnerReference{
*metav1.NewControllerRef(a, schema.GroupVersionKind{
Group: SchemeGroupVersion.Group,
Version: SchemeGroupVersion.Version,
Kind: "Application",
}),
func (a *Application) OwnerRef() *metav1.OwnerReference {
if !a.Spec.Adopt {
return nil
}

isController := false
gvk := schema.GroupVersionKind{
Group: SchemeGroupVersion.Group,
Version: SchemeGroupVersion.Version,
Kind: "Application",
}
ref := metav1.NewControllerRef(a, gvk)
ref.Controller = &isController
return ref
}

// NewRsrc - return a new resource object
Expand Down
3 changes: 3 additions & 0 deletions pkg/apis/app/v1beta1/application_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ type ApplicationSpec struct {
// More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors
Selector *metav1.LabelSelector `json:"selector,omitempty"`

// Adopt objects - flag to indicate if we need to add OwnerRefs to matching objects
Adopt bool `json:"adopt,omitempty"`

// Info contains human readable key,value pairs for the Application.
Info []InfoItem `json:"info,omitempty"`

Expand Down
7 changes: 3 additions & 4 deletions pkg/component/component_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,9 @@ var FilerObject = Filer{

var _ = Describe("Resource", func() {
var c = component.Component{
Handle: nil,
Name: "base",
CR: &FilerObject,
OwnerRef: nil,
Handle: nil,
Name: "base",
CR: &FilerObject,
}

BeforeEach(func() {
Expand Down
2 changes: 1 addition & 1 deletion pkg/component/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ type Component struct {
Handle
Name string
CR metav1.Object
OwnerRef []metav1.OwnerReference
OwnerRef *metav1.OwnerReference
barney-s marked this conversation as resolved.
Show resolved Hide resolved
}

// KVMap is a map[string]string
Expand Down
34 changes: 32 additions & 2 deletions pkg/genericreconciler/genericreconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
urt "k8s.io/apimachinery/pkg/util/runtime"
Expand Down Expand Up @@ -96,6 +97,7 @@ func specDiffers(o1, o2 metav1.Object) bool {
e = reflect.Indirect(reflect.ValueOf(o1)).FieldByName("Data")
o = reflect.Indirect(reflect.ValueOf(o2)).FieldByName("Data")
}

if e.IsValid() && o.IsValid() {
if reflect.DeepEqual(e.Interface(), o.Interface()) {
return false
Expand All @@ -104,6 +106,33 @@ func specDiffers(o1, o2 metav1.Object) bool {
return true
}

func isReferringSameObject(a, b metav1.OwnerReference) bool {
aGV, err := schema.ParseGroupVersion(a.APIVersion)
if err != nil {
return false
}
bGV, err := schema.ParseGroupVersion(b.APIVersion)
if err != nil {
return false
}
return aGV == bGV && a.Kind == b.Kind && a.Name == b.Name
barney-s marked this conversation as resolved.
Show resolved Hide resolved
}

func injectOwnerRefs(o metav1.Object, ref *metav1.OwnerReference) bool {
if ref == nil {
return false
}
objRefs := o.GetOwnerReferences()
for _, r := range objRefs {
if isReferringSameObject(*ref, r) {
barney-s marked this conversation as resolved.
Show resolved Hide resolved
return false
}
}
objRefs = append(objRefs, *ref)
o.SetOwnerReferences(objRefs)
return true
}

// ReconcileCR is a generic function that reconciles expected and observed resources
func (gr *Reconciler) ReconcileCR(namespacedname types.NamespacedName, handle cr.Handle) error {
var status interface{}
Expand Down Expand Up @@ -239,7 +268,6 @@ func (gr *Reconciler) ReconcileComponent(crname string, c component.Component, s
aggregated.Add(expected.Items()...)
log.Printf("%s Expected Resources:\n", cname)
for _, e := range expected.Items() {
e.Obj.SetOwnerReferences(c.OwnerRef)
log.Printf("%s exp: %s/%s/%s\n", cname, e.Obj.GetNamespace(), reflect.TypeOf(e.Obj).String(), e.Obj.GetName())
}
log.Printf("%s Observed Resources:\n", cname)
Expand All @@ -262,7 +290,8 @@ func (gr *Reconciler) ReconcileComponent(crname string, c component.Component, s
}
// rsrc is seen in both expected and observed, update it if needed
e.Obj.SetResourceVersion(o.Obj.GetResourceVersion())
if e.Lifecycle == resource.LifecycleManaged && specDiffers(e.Obj, o.Obj) && c.Differs(e.Obj, o.Obj) {
e.Obj.SetOwnerReferences(o.Obj.GetOwnerReferences())
if e.Lifecycle == resource.LifecycleManaged && (specDiffers(e.Obj, o.Obj) && c.Differs(e.Obj, o.Obj) || injectOwnerRefs(e.Obj, c.OwnerRef)) {
if err := gr.Update(context.TODO(), e.Obj.(runtime.Object).DeepCopyObject()); err != nil {
errs = handleErrorArr("update", eRsrcInfo, err, errs)
} else {
Expand All @@ -278,6 +307,7 @@ func (gr *Reconciler) ReconcileComponent(crname string, c component.Component, s
// rsrc is in expected but not in observed - create
if !seen {
if e.Lifecycle == resource.LifecycleManaged {
injectOwnerRefs(e.Obj, c.OwnerRef)
if err := gr.Create(context.TODO(), e.Obj.(runtime.Object)); err != nil {
errs = handleErrorArr("Create", cname, err, errs)
} else {
Expand Down