Skip to content

Commit

Permalink
refactor: make HasDependents record primary resource type and helper
Browse files Browse the repository at this point in the history
  • Loading branch information
metacosm committed Oct 22, 2019
1 parent 5272ef8 commit ca9338d
Show file tree
Hide file tree
Showing 7 changed files with 56 additions and 70 deletions.
13 changes: 4 additions & 9 deletions pkg/controller/capability/capability.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,20 @@ type Capability struct {
*framework.HasDependents
}

func (in *Capability) PrimaryResourceType() runtime.Object {
return &halkyon.Capability{}
}

func (in *Capability) Delete() error {
return nil
}

func (in *Capability) CreateOrUpdate() error {
helper := framework.GetHelperFor(in.PrimaryResourceType())
return in.CreateOrUpdateDependents(helper)
return in.CreateOrUpdateDependents()
}

func (in *Capability) FetchAndCreateNew(name, namespace string) (framework.Resource, error) {
return in.HasDependents.FetchAndInitNewResource(name, namespace, NewCapability())
}

func (in *Capability) ComputeStatus(err error, helper *framework.K8SHelper) (needsUpdate bool) {
statuses, update := in.HasDependents.ComputeStatus(in, err, helper)
func (in *Capability) ComputeStatus(err error) (needsUpdate bool) {
statuses, update := in.HasDependents.ComputeStatus(in, err)
return in.SetSuccessStatus(statuses, "Ready") || update
}

Expand All @@ -59,7 +54,7 @@ func (in *Capability) GetAPIObject() runtime.Object {
}

func NewCapability() *Capability {
dependents := framework.NewHasDependents()
dependents := framework.NewHasDependents(&halkyon.Capability{})
c := &Capability{
Capability: &halkyon.Capability{},
HasDependents: dependents,
Expand Down
3 changes: 1 addition & 2 deletions pkg/controller/component/build_deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package component

import (
component "halkyon.io/api/component/v1beta1"
"halkyon.io/operator/pkg/controller/framework"
"k8s.io/api/apps/v1"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
Expand All @@ -26,7 +25,7 @@ func (res deployment) installBuild() (runtime.Object, error) {
// and we will enrich the deployment resource of the runtime container
// create a "dev" version of the component to be able to check if the dev deployment exists
devDeployment := &appsv1.Deployment{}
_, err = framework.GetHelperFor(c.GetAPIObject()).Fetch(DeploymentNameFor(c, component.DevDeploymentMode), c.Namespace, devDeployment)
_, err = c.Helper().Fetch(DeploymentNameFor(c, component.DevDeploymentMode), c.Namespace, devDeployment)
if err == nil {
devContainer := &devDeployment.Spec.Template.Spec.Containers[0]
runtimeContainer.Env = devContainer.Env
Expand Down
26 changes: 10 additions & 16 deletions pkg/controller/component/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@ type Component struct {
*framework.HasDependents
}

func (in *Component) PrimaryResourceType() runtime.Object {
return &halkyon.Component{}
}

func (in *Component) Delete() error {
if framework.IsTargetClusterRunningOpenShift() {
// Delete the ImageStream created by OpenShift if it exists as the Component doesn't own this resource
Expand All @@ -38,18 +34,16 @@ func (in *Component) Delete() error {
}

// attempt to delete the imagestream if it exists
helper := framework.GetHelperFor(in.PrimaryResourceType())
if e := helper.Client.Delete(context.TODO(), imageStream); e != nil && !errors.IsNotFound(e) {
if e := in.Helper().Client.Delete(context.TODO(), imageStream); e != nil && !errors.IsNotFound(e) {
return e
}
}
return nil
}

func (in *Component) CreateOrUpdate() (err error) {
helper := framework.GetHelperFor(in.PrimaryResourceType())
if halkyon.BuildDeploymentMode == in.Spec.DeploymentMode {
err = in.CreateOrUpdateDependents(helper)
err = in.CreateOrUpdateDependents()
} else {
// Enrich Component with k8s recommend Labels
in.ObjectMeta.Labels = PopulateK8sLabels(in, "Backend")
Expand All @@ -61,7 +55,7 @@ func (in *Component) CreateOrUpdate() (err error) {
// Enrich Env Vars with Default values
populateEnvVar(in)

return in.CreateOrUpdateDependents(helper)
return in.CreateOrUpdateDependents()
}
return err
}
Expand All @@ -70,12 +64,12 @@ func (in *Component) FetchAndCreateNew(name, namespace string) (framework.Resour
return in.HasDependents.FetchAndInitNewResource(name, namespace, NewComponent())
}

func (in *Component) ComputeStatus(err error, helper *framework.K8SHelper) (needsUpdate bool) {
statuses, update := in.HasDependents.ComputeStatus(in, err, helper)
func (in *Component) ComputeStatus(err error) (needsUpdate bool) {
statuses, update := in.HasDependents.ComputeStatus(in, err)
if len(in.Status.Links) > 0 {
for i, link := range in.Status.Links {
if link.Status == halkyon.Started {
p, err := in.FetchUpdatedDependent(&corev1.Pod{}, helper)
p, err := in.FetchUpdatedDependent(&corev1.Pod{})
name := p.(*corev1.Pod).Name
if err != nil || name == link.OriginalPodName {
in.Status.Phase = halkyon.ComponentLinking
Expand All @@ -84,7 +78,7 @@ func (in *Component) ComputeStatus(err error, helper *framework.K8SHelper) (need
} else {
// update link status
l := &hLink.Link{}
err := helper.Client.Get(context.TODO(), types.NamespacedName{
err := in.Helper().Client.Get(context.TODO(), types.NamespacedName{
Namespace: in.Namespace,
Name: link.Name,
}, l)
Expand All @@ -96,10 +90,10 @@ func (in *Component) ComputeStatus(err error, helper *framework.K8SHelper) (need
}

l.Status.Message = fmt.Sprintf("'%s' finished linking", in.Name)
err = helper.Client.Status().Update(context.TODO(), l)
err = in.Helper().Client.Status().Update(context.TODO(), l)
if err != nil {
// todo: fix-me
helper.ReqLogger.Error(err, "couldn't update link status", "link name", l.Name)
in.Helper().ReqLogger.Error(err, "couldn't update link status", "link name", l.Name)
}

link.Status = halkyon.Linked
Expand Down Expand Up @@ -128,7 +122,7 @@ func (in *Component) GetAPIObject() runtime.Object {
}

func NewComponent() *Component {
dependents := framework.NewHasDependents()
dependents := framework.NewHasDependents(&halkyon.Component{})
c := &Component{
Component: &halkyon.Component{},
HasDependents: dependents,
Expand Down
8 changes: 6 additions & 2 deletions pkg/controller/framework/generic.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ func NewGenericReconciler(resource Resource) *GenericReconciler {

type GenericReconciler struct {
resource Resource
helper *K8SHelper
}

func (b *GenericReconciler) watchedSecondaryResourcesTypes() []runtime.Object {
Expand All @@ -35,7 +36,10 @@ func (b *GenericReconciler) watchedSecondaryResourcesTypes() []runtime.Object {
}

func (b *GenericReconciler) Helper() *K8SHelper {
return GetHelperFor(b.resource.PrimaryResourceType())
if b.helper == nil {
b.helper = GetHelperFor(b.resource.PrimaryResourceType())
}
return b.helper
}

func (b *GenericReconciler) logger() logr.Logger {
Expand Down Expand Up @@ -106,7 +110,7 @@ func (b *GenericReconciler) Reconcile(request reconcile.Request) (reconcile.Resu

func (b *GenericReconciler) updateStatusIfNeeded(instance Resource, err error) {
// compute the status and update the resource if the status has changed
if needsStatusUpdate := instance.ComputeStatus(err, b.Helper()); needsStatusUpdate {
if needsStatusUpdate := instance.ComputeStatus(err); needsStatusUpdate {
object := instance.GetAPIObject()
if e := b.Helper().Client.Status().Update(context.Background(), object); e != nil {
b.logger().Error(e, fmt.Sprintf("failed to update status for '%s' %s", instance.GetName(), util.GetObjectName(object)))
Expand Down
54 changes: 28 additions & 26 deletions pkg/controller/framework/hasdependents.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,21 @@ import (
)

type HasDependents struct {
dependents map[string]DependentResource
requeue bool
dependents map[string]DependentResource
requeue bool
helper *K8SHelper
primaryResourceType runtime.Object
}

func (b *HasDependents) PrimaryResourceType() runtime.Object {
return b.primaryResourceType
}

func (b *HasDependents) Helper() *K8SHelper {
if b.helper == nil {
b.helper = GetHelperFor(b.primaryResourceType)
}
return b.helper
}

func (b *HasDependents) SetNeedsRequeue(requeue bool) {
Expand All @@ -21,8 +34,8 @@ func (b *HasDependents) NeedsRequeue() bool {
return b.requeue
}

func NewHasDependents() *HasDependents {
return &HasDependents{dependents: make(map[string]DependentResource, 7)}
func NewHasDependents(primary runtime.Object) *HasDependents {
return &HasDependents{dependents: make(map[string]DependentResource, 15), primaryResourceType: primary}
}

func keyFor(resourceType runtime.Object) (key string) {
Expand All @@ -33,9 +46,9 @@ func keyFor(resourceType runtime.Object) (key string) {
return
}

func (b *HasDependents) CreateOrUpdateDependents(helper *K8SHelper) error {
func (b *HasDependents) CreateOrUpdateDependents() error {
for _, dep := range b.dependents {
if e := dep.CreateOrUpdate(helper); e != nil {
if e := dep.CreateOrUpdate(b.Helper()); e != nil {
return e
}
}
Expand All @@ -46,21 +59,20 @@ func (b *HasDependents) FetchAndInitNewResource(name string, namespace string, t
toInit.SetName(name)
toInit.SetNamespace(namespace)
resourceType := toInit.GetAPIObject()
helper := GetHelperFor(resourceType)
_, err := helper.Fetch(name, namespace, resourceType)
_, err := b.Helper().Fetch(name, namespace, resourceType)
if err != nil {
return toInit, err
}
return toInit, err
}

func (b *HasDependents) FetchUpdatedDependent(dependentType runtime.Object, helper *K8SHelper) (runtime.Object, error) {
func (b *HasDependents) FetchUpdatedDependent(dependentType runtime.Object) (runtime.Object, error) {
key := keyFor(dependentType)
resource, ok := b.dependents[key]
if !ok {
return nil, fmt.Errorf("couldn't find any dependent resource of kind '%s'", util.GetObjectName(dependentType))
}
fetch, err := resource.Fetch(helper)
fetch, err := resource.Fetch(b.Helper())
if err != nil {
return nil, err
}
Expand All @@ -82,21 +94,11 @@ func (b *HasDependents) AddDependentResource(resources ...DependentResource) {
}
}

func (b *HasDependents) WatchedSecondaryResourceTypes() []runtime.Object {
watched := make([]runtime.Object, 0, len(b.dependents))
for _, dep := range b.dependents {
if dep.ShouldWatch() {
watched = append(watched, dep.Prototype())
}
}
return watched
}

func (b *HasDependents) ComputeStatus(current Resource, err error, helper *K8SHelper) (statuses []DependentResourceStatus, needsUpdate bool) {
func (b *HasDependents) ComputeStatus(current Resource, err error) (statuses []DependentResourceStatus, needsUpdate bool) {
if err != nil {
return statuses, current.SetErrorStatus(err)
}
statuses = b.areDependentResourcesReady(helper)
statuses = b.areDependentResourcesReady()
msgs := make([]string, 0, len(statuses))
for _, status := range statuses {
if !status.Ready {
Expand All @@ -105,22 +107,22 @@ func (b *HasDependents) ComputeStatus(current Resource, err error, helper *K8SHe
}
if len(msgs) > 0 {
msg := fmt.Sprintf("Waiting for the following resources: %s", strings.Join(msgs, " / "))
helper.ReqLogger.Info(msg)
b.Helper().ReqLogger.Info(msg)
// set the status but ignore the result since dependents are not ready, we do need to update and requeue in any case
_ = current.SetInitialStatus(msg)
current.SetNeedsRequeue(true)
b.SetNeedsRequeue(true)
return statuses, true
}

return statuses, false
}

func (b *HasDependents) areDependentResourcesReady(helper *K8SHelper) (statuses []DependentResourceStatus) {
func (b *HasDependents) areDependentResourcesReady() (statuses []DependentResourceStatus) {
statuses = make([]DependentResourceStatus, 0, len(b.dependents))
for _, dependent := range b.dependents {
if dependent.ShouldBeCheckedForReadiness() {
objectType := dependent.Prototype()
fetched, err := b.FetchUpdatedDependent(objectType, helper)
fetched, err := b.FetchUpdatedDependent(objectType)
name := util.GetObjectName(objectType)
if err != nil {
statuses = append(statuses, NewFailedDependentResourceStatus(name, err))
Expand Down
4 changes: 1 addition & 3 deletions pkg/controller/framework/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,15 @@ type Resource interface {
v1.Object
runtime.Object
NeedsRequeue() bool
SetNeedsRequeue(requeue bool)
GetStatusAsString() string
ShouldDelete() bool
SetErrorStatus(err error) bool
SetSuccessStatus(statuses []DependentResourceStatus, msg string) bool
SetInitialStatus(msg string) bool
ComputeStatus(err error, helper *K8SHelper) (needsUpdate bool)
ComputeStatus(err error) (needsUpdate bool)
CheckValidity() error
Init() bool
GetAPIObject() runtime.Object
FetchUpdatedDependent(dependentType runtime.Object, helper *K8SHelper) (runtime.Object, error)
FetchAndCreateNew(name, namespace string) (Resource, error)
PrimaryResourceType() runtime.Object
Delete() error
Expand Down
18 changes: 6 additions & 12 deletions pkg/controller/link/link.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ type Link struct {
*framework.HasDependents
}

func (in *Link) PrimaryResourceType() runtime.Object {
return &halkyon.Link{}
}

func (in *Link) Delete() error {
return nil
}
Expand All @@ -43,8 +39,7 @@ func (in *Link) CreateOrUpdate() error {
}

// if the deployment has been updated, we need to update the component's status
helper := framework.GetHelperFor(in.PrimaryResourceType())
fetch, err := in.FetchUpdatedDependent(&v1beta1.Component{}, helper)
fetch, err := in.FetchUpdatedDependent(&v1beta1.Component{})
if err != nil {
return fmt.Errorf("cannot retrieve associated component")
}
Expand All @@ -54,7 +49,7 @@ func (in *Link) CreateOrUpdate() error {
compStatus.SetLinkingStatus(in.Name, v1beta1.Started, compStatus.PodName)
compStatus.PodName = ""
compStatus.Message = fmt.Sprintf("Initiating link %s", in.Name)
err = helper.Client.Status().Update(context.TODO(), c)
err = in.Helper().Client.Status().Update(context.TODO(), c)
if err != nil {
return err
}
Expand All @@ -67,8 +62,8 @@ func (in *Link) FetchAndCreateNew(name, namespace string) (framework.Resource, e
return in.HasDependents.FetchAndInitNewResource(name, namespace, NewLink())
}

func (in *Link) ComputeStatus(err error, helper *framework.K8SHelper) (needsUpdate bool) {
statuses, update := in.HasDependents.ComputeStatus(in, err, helper)
func (in *Link) ComputeStatus(err error) (needsUpdate bool) {
statuses, update := in.HasDependents.ComputeStatus(in, err)
return in.SetSuccessStatus(statuses, "Ready") || update
}

Expand All @@ -81,7 +76,7 @@ func (in *Link) GetAPIObject() runtime.Object {
}

func NewLink() *Link {
dependents := framework.NewHasDependents()
dependents := framework.NewHasDependents(&halkyon.Link{})
l := &Link{
Link: &halkyon.Link{},
HasDependents: dependents,
Expand Down Expand Up @@ -208,9 +203,8 @@ func update(d *appsv1.Deployment) error {

func updateDeploymentWithLink(d *appsv1.Deployment, link *Link) error {
// Update the Deployment of the component
helper := framework.GetHelperFor(&halkyon.Link{})
if err := update(d); err != nil {
helper.ReqLogger.Info("Failed to update deployment.")
link.Helper().ReqLogger.Info("Failed to update deployment.")
return err
}

Expand Down

0 comments on commit ca9338d

Please sign in to comment.