-
Notifications
You must be signed in to change notification settings - Fork 529
Federated Status Implementation for federated types #247
Conversation
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: shashidharatd 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 |
@shashidharatd Am I missing something, or is the entirety of status being collected? I wasn't aware that chatty fields like |
ClusterStatuses []FederatedIngressClusterStatus `json:"clusterStatuses,omitempty"` | ||
} | ||
|
||
// FederatedDeploymentClusterStatus is the observed status for a named cluster |
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.
s/FederatedDeploymentClusterStatus/FederatedIngressClusterStatus
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.
oops, fixed. Thanks!
@@ -303,7 +303,6 @@ var ( | |||
Scope: "Namespaced", | |||
Validation: &v1beta1.CustomResourceValidation{ | |||
OpenAPIV3Schema: &v1beta1.JSONSchemaProps{ | |||
Type: "object", |
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 this change will not needed if the PR #250 got merged before this PR.
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.
Agree. if it lands before. i will remove it.
@@ -31,4 +31,5 @@ type Interface interface { | |||
GetPlacement() metav1.APIResource | |||
GetOverride() *metav1.APIResource | |||
GetOverridePath() []string | |||
GetCollectStatus() bool |
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.
Can you move this commit ahead of 3f94daf
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.
its already in the same order as you asked (if you look in git). github may have messed up the order of commits).
@@ -89,6 +89,35 @@ type FederatedTypeConfig struct { | |||
Status FederatedTypeConfigStatus `json:"status,omitempty"` | |||
} | |||
|
|||
// FederatedResource is a generic resource representing any federated type |
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.
What is the target of this resource type? Does the intend is want to handle arbitrary resource 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.
yes, as the comment suggest FederatedResource type generically represent any arbitrary federated type.
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 see, then what is the relationship between this and #60 ? Why put this commit in this PR? With this generic resource type, do we still need other resource types? Like FederatedDeployment
, FederatedIngress
etc?
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 sync controller is already capable of handling propogation of arbitrary types. here is the e2e test case which does that, https://github.com/kubernetes-sigs/federation-v2/blob/master/test/e2e/crud.go#L89 and there is no need to define an API for that. #60 is some additional feature to automatically create template, override & placement CRDs for a federated type.
The type FederatedResource
which i defined in this PR represents a generic federated type which is used by the controller to Marshall/Unmarshall Json. We still need specific federated types defined like FederatedDeployment
, FederatedIngress
etc.. because they help validating user inputs and offer type safety.
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.
Thanks @shashidharatd , clear now. But still have more question, I think we do not have placement
policy for generic resources, what is the plan for this?
@marun, the entire status is being collected. the purpose here was to be a generic solution. I agree that fields like conditions are not useful. overtime these fields will be obsoleted from kubernetes types itself as inferred from kubernetes/kubernetes#50798, and we may need not do any special handling. currently too many of the kubernetes controller may have moved from updating this field. Alternatively, Should we drop conditions in status if found in status? wdyt? |
af0c37d
to
37e10e0
Compare
test/common/crudtester.go
Outdated
statusFound := false | ||
for _, resourceClusterStatus := range resource.Status.ClusterStatuses { | ||
if resourceClusterStatus.ClusterName == clusterName { | ||
statusFound = true |
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.
break
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.
updated.
@@ -89,6 +89,35 @@ type FederatedTypeConfig struct { | |||
Status FederatedTypeConfigStatus `json:"status,omitempty"` | |||
} | |||
|
|||
// FederatedResource is a generic resource representing any federated type | |||
// +k8s:deepcopy-gen=false | |||
type FederatedResource struct { |
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'm not sure I understand the need for this generic FederatedResource
API type. I don't see it being persisted; it looks like it's just used to capture the status into this generic object and then just copied into the specified Federated<Type>
resource for persistence. Why not work directly with the status for each individual Federated<Type>
resource that you've added in this PR? Am I missing something?
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.
Agree with your argument. Updated accordingly. PTAL. Thanks!
37e10e0
to
87ab586
Compare
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.
LGTM
I'm reviewing this. |
87ab586
to
b91d99c
Compare
cool, waiting for your inputs. Thanks ! |
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 this PR makes sense if the target use case is user visibility into member cluster state of federated resources. If the goal is to provide status for consumption by other controllers, though, I have concerns with having the sync controller collect status.
If the scheduling controllers are rewritten to consume status written by the sync controller they effectively have a dependency on push propagation. What about pull propagation? Similarly, if the dns record controllers were rewritten to consume status written by the sync controller, what is a user wanted to deploy without propagation of any kind (a use case that has been previously discussed)?
If status were collected via a controller other than sync, though, it could complicate version tracking since propagated versions need to be maintained in response to status updates. That could suggest storing status separately from templates (i.e. in status-specific resources).
cc: @pmorie
pkg/controller/sync/controller.go
Outdated
newTemplate.Object["metadata"] = oldTemplate.Object["metadata"] | ||
newTemplate.Object["spec"] = oldTemplate.Object["spec"] | ||
|
||
newTemplate, err := s.templateClient.Resources(newTemplate.GetNamespace()).Update(newTemplate) |
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 action required) Interesting, I didn't realize until now that the dynamic client doesn't have separate Update
and UpdateStatus
methods.
@@ -89,6 +92,19 @@ type FederatedTypeConfig struct { | |||
Status FederatedTypeConfigStatus `json:"status,omitempty"` | |||
} | |||
|
|||
// FederatedResourceStatus defines status of generic federated type | |||
// +k8s:deepcopy-gen=false | |||
type FederatedResourceStatus struct { |
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 does this non-api type belong in this file, or in the api path at all?
status, ok, err := unstructured.NestedMap(clusterObj.Object, "status") | ||
if err != nil || !ok { | ||
wrappedErr := fmt.Errorf("Failed to get status of cluster resource object %s %q for cluster %q: %v", targetKind, key, clusterName, err) | ||
runtime.HandleError(wrappedErr) |
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 is status still collected for the cluster if it can't be retrieved successfully?
pkg/controller/sync/controller.go
Outdated
return federatedResourceStatus.ClusterStatuses[i].ClusterName < federatedResourceStatus.ClusterStatuses[j].ClusterName | ||
}) | ||
newTemplate := &unstructured.Unstructured{make(map[string]interface{})} | ||
newTemplate.Object["status"] = federatedResourceStatus |
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 is it desirable to return a template wrapper instead of just the status slice?
pkg/controller/sync/controller.go
Outdated
if err != nil { | ||
glog.Errorf("Error updating federated type status: %v", err) | ||
} | ||
return newTemplate, 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.
Why is it safe to return newTemplate
if an error occurred?
pkg/controller/sync/controller.go
Outdated
wrappedErr := fmt.Errorf("Failed to get status of cluster resource object %s %q for cluster %q: %v", targetKind, key, clusterName, err) | ||
runtime.HandleError(wrappedErr) | ||
} | ||
resourceClusterStatus := fedv1a1.ResourceClusterStatus{ClusterName: clusterName, Status: 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.
Why is it desirable to collect status in this arbitrary type instead of a map?
pkg/controller/sync/controller.go
Outdated
@@ -167,6 +171,7 @@ func newFederationSyncController(typeConfig typeconfig.Interface, kubeConfig *re | |||
templateClient: templateClient, | |||
pendingVersionUpdates: sets.String{}, | |||
fedNamespace: fedNamespace, | |||
collectStatus: typeConfig.GetCollectStatus(), |
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 is it desirable to have this is a first-class field vs just calling the method on the typeconfig?
pkg/controller/sync/controller.go
Outdated
@@ -638,7 +643,18 @@ func (s *FederationSyncController) syncToClusters(selectedClusters, unselectedCl | |||
updatedClusterVersions, operationErrors := s.updater.Update(operations) | |||
|
|||
defer func() { | |||
err = updatePropagatedVersion(s.typeConfig, s.fedClient, updatedClusterVersions, template, override, | |||
if s.collectStatus { |
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.
Status and propagated version will not be written if there are no operations (as per [1]). I'm assuming this is an oversight, since status could change even if no changes need to be propagated. Consider adding a test that validates this corner case.
pkg/controller/sync/controller.go
Outdated
@@ -638,7 +643,18 @@ func (s *FederationSyncController) syncToClusters(selectedClusters, unselectedCl | |||
updatedClusterVersions, operationErrors := s.updater.Update(operations) | |||
|
|||
defer func() { | |||
err = updatePropagatedVersion(s.typeConfig, s.fedClient, updatedClusterVersions, template, override, | |||
if s.collectStatus { | |||
newTemplate, err = s.UpdateFederatedStatus(template, newTemplate) |
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.
Consider using a more descriptive name than newTemplate
(e.g. updatedTemplate
or statusUpdatedTemplate
).
b91d99c
to
fe97176
Compare
Closing this in favour of #291 |
This pr implements a generic federated status for federated types by extending the sync controller. The federated status is a list of resource status in member cluster, as outlined in the first alternative in issue #246
Later the controllers depending upon the status in member clusters can make use of this without monitoring the resource in individual clusters.
/cc @onyiny-ang @pmorie @marun @kubernetes-sigs/federation-wg