-
Notifications
You must be signed in to change notification settings - Fork 391
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
✨ Partition reconciliation #2469
✨ Partition reconciliation #2469
Conversation
/hold this PR is based on #2432 and will be rebased once it has merged |
dc435b3
to
731507d
Compare
731507d
to
1b84a53
Compare
1b84a53
to
a91c0b3
Compare
/retest |
2d4ab7b
to
ba989f8
Compare
7fc8039
to
33a632d
Compare
/unhold |
@@ -224,6 +254,32 @@ func (c *controller) enqueueAllAPIExportEndpointSlices(shard interface{}) { | |||
} | |||
} | |||
|
|||
// enqueuePartition maps a Partition to APIExportEndpointSlices for enqueuing. | |||
func (c *controller) enqueuePartition(obj interface{}) { | |||
key, err := kcpcache.DeletionHandlingMetaClusterNamespaceKeyFunc(obj) |
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.
why not to use an obj
to get slices?
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.
As per the previous comment. This is only used for enqueuing.
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.
yes, it seems we could make use of the object to find what we need
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.
are partition names unique across workspace?
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 don't think so, does it mean we always have to find a local partition for the given slice?
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.
would it make sense to list endpoints for the given cluster
and check which ones reference a particular name instead?
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.
does it mean we always have to find a local partition for the given slice?
yes that is the intended design, partition and APIExportEndpointSlices being in the same workspace. There can however be multiple of them in different workspaces for covering different regions for instance.
Otherwise we would need to make them global and at this point in time I don't see the need for it.
would it make sense to list endpoints for the given cluster and check which ones reference a particular name instead?
there is max one endpoint per shard, the Partition resource allows to specify shards for which endpoints get added to the APIExportEndpointSlice.
getPartition: func(clusterName logicalcluster.Name, name string) (*topologyv1alpha1.Partition, error) { | ||
return partitionClusterInformer.Lister().Cluster(clusterName).Get(name) | ||
}, | ||
getAPIExportEndpointSlicesByPartition: func(key string) ([]interface{}, 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.
why not to change the signature of this method to return strong types?
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.
also the signature could accept partition name
not a key
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.
This would mean looping one more time, although I expect the loop to be small. This is however only used for enqueuing and not exposed to the reconcile (there is a separate struct).
}, | ||
) | ||
|
||
if err := apiExportEndpointSliceClusterInformer.Informer().AddIndexers(cache.Indexers{ |
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.
use indexers.AddIfNotPresentOrDie
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.
Yes I will do that
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
listShards: func() ([]*corev1alpha1.Shard, error) { | ||
return shardClusterInformer.Lister().List(labels.Everything()) | ||
listShards: func(selector labels.Selector) ([]*corev1alpha1.Shard, error) { | ||
return shardClusterInformer.Lister().List(selector) | ||
}, | ||
getAPIExportEndpointSlice: func(clusterName logicalcluster.Name, name string) (*apisv1alpha1.APIExportEndpointSlice, error) { | ||
return apiExportEndpointSliceClusterInformer.Lister().Cluster(clusterName).Get(name) | ||
}, | ||
getAPIExport: func(path logicalcluster.Path, name string) (*apisv1alpha1.APIExport, error) { | ||
return indexers.ByPathAndName[*apisv1alpha1.APIExport](apisv1alpha1.Resource("apiexports"), apiExportClusterInformer.Informer().GetIndexer(), path, name) |
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.
did we make it local ? (doesn't use the global lister)
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 is the other way around, only looking at the cache server. This was discussed and done in the previous PR (APIExportEndpointSlice reconciliation)
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.
should we change the name of the variable ?
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.
my strategy so far has been to use local and global prefix when both are used and not to have any prefix otherwise. I thought it was the consensus. It seems it is not the case (anymore?). I will add the global prefix to shardClusterInformer and apiExportClusterInformer.
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
} | ||
|
||
logger := logging.WithObject(logging.WithReconciler(klog.Background(), ControllerName), obj.(*topologyv1alpha1.Partition)) | ||
logging.WithQueueKey(logger, key).V(2).Info("queuing APIExportEndpointSlices because Partition changed") |
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.
too verbose, make it V(4)
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 is not consistent across the other controllers, sometimes V(2) is used, not more often V(4). I can use V(4) here if you want
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
@@ -64,35 +68,103 @@ func (r *endpointsReconciler) reconcile(ctx context.Context, apiExportEndpointSl | |||
} | |||
apiExport, err := r.getAPIExport(apiExportPath, apiExportEndpointSlice.Spec.APIExport.Name) | |||
if err != nil { | |||
reason := apisv1alpha1.InternalErrorReason |
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.
is this an internal error so that the conditions stay stable?
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.
how will we know the 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.
It is an internal error not to leak any information to the user(discussed in the previous PR).
The error details are available in the logs for a privileged user.
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.
an error could be used for troubleshooting
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.
hence in the logs
) | ||
conditions.MarkFalse( | ||
apiExportEndpointSlice, | ||
apisv1alpha1.APIExportEndpointSliceURLsReady, |
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.
so a single transient error can flip this condition false
, should we do better?
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.
If it is an error, which is recoverable the condition is indeed set to false because the reconciliation was not successful but it is queued again. If it is transient it flips back to true when the condition has gone.
The alternative is to set it as "unknown"
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.
set to unknown
pkg/reconciler/apis/apiexportendpointslice/apiexportendpointslice_reconcile.go
Outdated
Show resolved
Hide resolved
pkg/reconciler/apis/apiexportendpointslice/apiexportendpointslice_reconcile.go
Show resolved
Hide resolved
pkg/reconciler/apis/apiexportendpointslice/apiexportendpointslice_reconcile.go
Outdated
Show resolved
Hide resolved
apisv1alpha1.APIExportEndpointSliceURLsReady, | ||
apisv1alpha1.ErrorGeneratingURLsReason, | ||
conditionsv1alpha1.ConditionSeverityError, | ||
"error listing shards", |
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.
how will we known the err?
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.
logs for privileged users.
|
||
if err = r.updateEndpoints(ctx, apiExportEndpointSlice, apiExport); err != nil { | ||
if err = r.updateEndpoints(ctx, apiExportEndpointSlice, apiExport, shards); err != nil { |
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.
or pass the selector :)
6090da8
to
5b6195a
Compare
apisv1alpha1.PartitionValid, | ||
apisv1alpha1.InternalErrorReason, | ||
conditionsv1alpha1.ConditionSeverityError, | ||
err.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.
didn't you want to hide errors?
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.
No. I wanted to avoid leaking information and it does not. APIExportEndpointSlice and Partitions are cluster scoped resources in the same workspace.
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 am confused how does it differ from /~https://github.com/kcp-dev/kcp/pull/2469/files#diff-a028d37be8294707fd6fdcb63d85f41486832f61eb70c14605fc5fc712958f48R94 ?
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.
An APIExport from a different workspace may be referenced in the APIExportEndpointSlice. It is not the case for a Partition (only considering the same workspace). By creating an APIExportEndpointSlice (or an APIBinding) a user may get additional information on the APIExport and other workspaces if the error was returned. This scenario does not happen for Partition.
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 was thinking that an invalid request - a one that would use an incorrect APIExport would be rejected by /~https://github.com/kcp-dev/kcp/pull/2560/files#r1064359708
apisv1alpha1.PartitionValid, | ||
apisv1alpha1.PartitionInvalidReferenceReason, | ||
conditionsv1alpha1.ConditionSeverityError, | ||
err.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.
didn't you want to hide errors?
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.
see above
// Partition reference is invalid. | ||
PartitionInvalidReferenceReason = "PartitionInvalidReference" | ||
// PartitionNotFoundReason is a reason for the PartitionValid condition that the referenced Partition is not found. | ||
PartitionNotFoundReason = "PartitionNotFound" |
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.
this is not used, is it? (not a blocker to merge)
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.
true. I will remove it
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
apisv1alpha1.PartitionValid, | ||
apisv1alpha1.PartitionInvalidReferenceReason, | ||
conditionsv1alpha1.ConditionSeverityError, | ||
err.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.
I don't like exposing this error. Rule of thumb: we must not give a hint about existence of a workspace ever. Here, this is not that clear. (follow-up is fine)
/lgtm |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: sttts The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
/retest |
2 similar comments
/retest |
/retest |
5b6195a
to
e341969
Compare
@sttts rebased and repushed. Checks are now successful but lgtm label has been removed. |
…rtition Signed-off-by: Frederic Giloux <fgiloux@redhat.com>
e341969
to
d224162
Compare
/lgtm |
Summary
This PR implements a reconciliation mechanism so that the endpoints listed in the status of an APIExportEndpointSlice match the filtering provided by the specified partition.
Design document
Related issue(s)
Follows #2432
Fixes #2333