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

Controller #2

Merged
merged 4 commits into from
Nov 20, 2019
Merged

Controller #2

merged 4 commits into from
Nov 20, 2019

Conversation

glyn
Copy link
Contributor

@glyn glyn commented Oct 9, 2019

No description provided.

Allow for compilation using Go 1.12 and later.
@glyn glyn self-assigned this Oct 9, 2019
@glyn glyn requested a review from scothis October 9, 2019 15:43
Copy link

@scothis scothis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ll need to take a deeper look at the unimap in the morning, but here’s my high level feedback

Dockerfile Outdated Show resolved Hide resolved
Dockerfile Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
api/v1alpha1/groupversion_info.go Outdated Show resolved Hide resolved
api/v1alpha1/imagemap_types.go Outdated Show resolved Hide resolved
config/default/kustomization.yaml Outdated Show resolved Hide resolved
headache.json Outdated Show resolved Hide resolved
pkg/unimap/composite.go Show resolved Hide resolved
pkg/unimap/composite.go Show resolved Hide resolved
controllers/imagemap_controller.go Outdated Show resolved Hide resolved
This was the result of running:

mkdir hack
cp <license header> hack/boilerplate.go.txt
kubebuilder init --domain imagerelocation.pivotal.io

where `kubebuilder version` returns:

Version: version.Version{KubeBuilderVersion:"2.0.0",
KubernetesVendor:"1.14.1",
GitCommit:"b31cc5d96dbc91749eb49c2cf600bd951a46d4bd",
BuildDate:"2019-08-22T23:39:53Z", GoOs:"unknown", GoArch:"unknown"}
This was the result of running:

kubebuilder create api --group mapper --version v1alpha1 --kind ImageMap

where `kubebuilder version` returns:

Version: version.Version{KubeBuilderVersion:"2.0.0",
KubernetesVendor:"1.14.1",
GitCommit:"b31cc5d96dbc91749eb49c2cf600bd951a46d4bd",
BuildDate:"2019-08-22T23:39:53Z", GoOs:"unknown", GoArch:"unknown"}
api/v1alpha1/imagemap_types.go Outdated Show resolved Hide resolved
go.mod Outdated Show resolved Hide resolved
go.mod Outdated Show resolved Hide resolved
controllers/imagemap_controller.go Outdated Show resolved Hide resolved
controllers/imagemap_controller.go Outdated Show resolved Hide resolved
controllers/imagemap_controller.go Outdated Show resolved Hide resolved
controllers/imagemap_controller.go Outdated Show resolved Hide resolved
controllers/imagemap_controller.go Outdated Show resolved Hide resolved
controllers/imagemap_controller.go Outdated Show resolved Hide resolved
controllers/imagemap_controller.go Outdated Show resolved Hide resolved
@glyn glyn requested a review from scothis November 14, 2019 04:45
@glyn
Copy link
Contributor Author

glyn commented Nov 14, 2019

@scothis I addressed your comments in a fresh commit, so PTAL. Please squash just this commit and the previous one and leave the rest unsquashed, or simply approve and leave it to me to merge.

Status corev1.ConditionStatus `json:"status" description:"status of the condition, one of True, False, Unknown"`

// ObservationTime records when the condition was observed
ObservedGeneration int64 `json:"observedGeneration,omitempty" description:"the ImageMap generation when the condition was observed"`
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ObservedGeneration should be on the Status, not the condition. The generation is not a good indication of when something happened as the condition can and does change without a spec change. ObservedGeneration is only an indicator of whether or not the status is for the current spec. Also the doc is out of sync.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll move ObservedGeneration out of the condition and replace it with ObservationTime as I think it's useful to know the actual time that the condition was observed. Will sort out doc too.

r.Log.V(1).Info("mappings", "map", r.Map.Dump())
}

if statusUpdated {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's far more robust to diff the new status with the existing status and then call update if there is a meaningful difference. This eliminates bugs and the complexity of manual tracking.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

adopted

}

// copy the image map in case we need to mutate it
imageMap = *imageMap.DeepCopy()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typically you'd still hold a reference to the current value for later comparision

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's functionally equivalent to my current code, but I'll adopt the suggestion as it may make the code more maintainable.

controllers/imagemap_controller.go Show resolved Hide resolved
}

func maybeUpdateCondition(conds *[]mapperv1alpha1.Condition, cond mapperv1alpha1.Condition) bool {
if len(*conds) != 1 || (*conds)[0] != cond {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updating one condition should not remove every other conditions that may exist. It would be better to remove the existing condition from the array and then insert the new condition.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@glyn glyn requested a review from scothis November 18, 2019 17:27
@@ -55,12 +56,16 @@ func (r *ImageMapReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
return resp, err
}

func (r *ImageMapReconciler) doReconcile(req ctrl.Request) (ctrl.Result, error) {
func (r *ImageMapReconciler) reconcile(req ctrl.Request,
get func(context.Context, client.ObjectKey, runtime.Object) error,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now there are two ways to interact with the Client: the receiver and the arguments. It would be better to only have one way to interact with the client.

Copy link
Contributor Author

@glyn glyn Nov 20, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mode of interaction with client.Client is as usual (receiver and arguments). What this code does is inject functional shims between reconcile and client.Client so that test shims can be provided in the unit test. I've used this pattern successfully elsewhere.

An approach I think you may be suggesting in another comment, which avoids the shims, is to mock an interface instead. This has the advantage that reconcile interacts with client receiver and arguments and so the unit test can be in a test package and can drive Reconcile instead. A downside is that there is more boilerplate in the unit test. See glyn#1 which shows the diff between this PR and that other approach.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the direction of glyn#1 much better. Left a few comments there for further improvements.

})

JustBeforeEach(func() {
result, err = reconciler.reconcile(req, get, update, status)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The canonical way to test controller-runtime reconcilers is to use envtest standup a test api-server.

That may be overkill for simple controllers, in that case, it be easier to create a fake/stub/mock client and create a reconciler with that client before calling the reconcile method?

Copy link
Contributor Author

@glyn glyn Nov 20, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think an integration test may be warranted in due course: raised #8.

I think a unit test is desirable too, especially to test some error paths which would be tricky to drive in an integration test.

See the earlier comment about the mocking the client interface.

Based on the spike in vmware-archive/image-relocation#37.

Deleted controllers/suite_test.go until we are ready to add an integration test.
@glyn glyn requested a review from scothis November 20, 2019 15:03
Copy link

@scothis scothis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's not let perfect be the enemy of good. Let's get this merged and iterate

@glyn glyn merged commit 2754620 into vmware-archive:master Nov 20, 2019
@glyn glyn deleted the controller branch November 20, 2019 15:05
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants