-
Notifications
You must be signed in to change notification settings - Fork 2
Conversation
Allow for compilation using Go 1.12 and later.
There was a problem hiding this 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
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"}
@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. |
api/v1alpha1/imagemap_types.go
Outdated
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"` |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
controllers/imagemap_controller.go
Outdated
r.Log.V(1).Info("mappings", "map", r.Map.Dump()) | ||
} | ||
|
||
if statusUpdated { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
adopted
controllers/imagemap_controller.go
Outdated
} | ||
|
||
// copy the image map in case we need to mutate it | ||
imageMap = *imageMap.DeepCopy() |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
Outdated
} | ||
|
||
func maybeUpdateCondition(conds *[]mapperv1alpha1.Condition, cond mapperv1alpha1.Condition) bool { | ||
if len(*conds) != 1 || (*conds)[0] != cond { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
controllers/imagemap_controller.go
Outdated
@@ -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, |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this 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
No description provided.