CONSOLE 2919: create OAuth clients on spoke clusters - rebased#602
Conversation
- Still need feature gate and oauth work for multicluster to be fully implmented - Add managed cluster controller that watches ACM ManagedCluster resources and builds a config file that can be consumed by the console backend - Update console deployment sync with new volumes and volume mounts for managed cluster config and CA bundles. - Add managed cluster and API server CA bundle ConfigMaps to subresources - Update informer event filter utils - Add github.com/open-cluster-management/api dependency
Creates oauth clients on spoke clusters using the new managed cluster controller via a dynamic client. CONSOLE 2919: clean up oauth client impl on spoke clusters Add informers for CRD changes via dyanmic informer
|
/retest |
2 similar comments
|
/retest |
|
/retest |
| apiVersion: v1 | ||
| kind: ConfigMap | ||
| metadata: | ||
| namespace: openshift-config-managed |
There was a problem hiding this comment.
Since this is a config specific to the console, I think this should be created in the openshift-console namespace.
| namespace: openshift-config-managed | |
| namespace: openshift-console |
There was a problem hiding this comment.
yes, we should put it int console's namespace
TheRealJon
left a comment
There was a problem hiding this comment.
This looks good! I think after addressing the few comments I left, we can probably merge this. There is still more follow-on work to do that we can address in future PRs:
- Update console deployment with Volumes and VolumeMounts for the managed cluster default ingress cert bundles.
- Add
Oauth.ClientID,Oauth.ClientSecret, andOauth.CAFileproperties for each managed cluster config in the mainmanaged-clustersConfigMap. - Make the managed cluster controller idempotent. This will include changes to my original logic because I didn't consider this. When a managed cluster is detached, we need to make sure all related resources that were created by our controller get deleted. We also need to make sure we clean up when no MangedClusters are found or the ManagedCluster API is not found on the cluster (ACM isn't installed).
| return nil, "" | ||
| } | ||
|
|
||
| func (c *ManagedClusterController) removeManagedClusters(ctx context.Context) error { |
There was a problem hiding this comment.
We will need to add logic here to remove any ManagedClusterAction, ManageClusterView, and ConfigMap resources that were created by this controller when the operator is in a "Removed" state.
There was a problem hiding this comment.
would be good to have an object in the controller struct which would contain list of created resources, to keep track of them.
On removeManagedClusters we would just flush the list.
Or just label all those resources with api.ManagedClusterLabel and then just list them and delete them
| URL: clientConfig.URL, | ||
| CAFile: fmt.Sprintf("%s/%s/%s", api.ManagedClusterAPIServerCAMountDir, configmapsub.APIServerCAConfigMapName(clusterName), api.ManagedClusterAPIServerCAKey), | ||
| }, | ||
| }) |
There was a problem hiding this comment.
Follow-on: We will need to add oauth info for each managed cluster to the main managed-cluster configmap:
| }) | |
| Oauth: { | |
| ClientID: // Managed cluster oauth client name, | |
| ClientSecret: // Managed cluster oauth client secret, | |
| CAFile: // Path to ca bundle file (determined by the VolumeMount that's created in the Deployment) | |
| }, | |
| }) |
| if !status || statusErr != nil { | ||
| namespace, namespaceErr := managedclusterviewsub.GetNamespace(managedClusterOAuthView) | ||
| if namespaceErr != nil || namespace == "" { | ||
| managedClusterListErrors = append(managedClusterListErrors, fmt.Sprintf("Unable to create oauth client for cluster %v: managed cluster view status unknown", namespace)) |
There was a problem hiding this comment.
namespace is likely to be an empty string here, but we are using it in a formatted string.
There was a problem hiding this comment.
| managedClusterListErrors = append(managedClusterListErrors, fmt.Sprintf("Unable to create oauth client for cluster %v: managed cluster view status unknown", namespace)) | |
| managedClusterListErrors = append(managedClusterListErrors, fmt.Sprintf("Unable to create oauth client for cluster %s: managed cluster view status unknown", namespace)) |
There was a problem hiding this comment.
We should log the namespaceErr here
| managedClusterListErrors := []string{} | ||
| for _, managedClusterOAuthView := range managedClusterOAuthClientViews { | ||
| status, statusErr := managedclusterviewsub.GetStatus(managedClusterOAuthView) | ||
| if !status || statusErr != nil { |
There was a problem hiding this comment.
If I'm reading correctly, we create an MCA for any MCV where we don't know a status, but we do know a namespace? Seems like there could be a race condition here where the status hasn't had time to propagate to the MCV and we try to create an MCA.
There was a problem hiding this comment.
does the status of the contain any meaning full info? Dont see anything particularly helpful in the Unstructured struct & funcs
| } | ||
|
|
||
| func (c *ManagedClusterController) SyncManagedClusterViewIngressCert(ctx context.Context, operatorConfig *operatorv1.Console) ([]*unstructured.Unstructured, error, string) { | ||
| managedClusters, listErr := c.listManagedClusters(ctx) |
There was a problem hiding this comment.
We list managed clusters at least 3 times per sync loop. We could probably just do this once at the beginning of the sync loop.
There was a problem hiding this comment.
The same for:
gvr := managedclusterviewsub.GetGVR()
We'll also need to consider this when we add the feature flag. Going from true to false state will mean that we need to clean up. |
jhadvig
left a comment
There was a problem hiding this comment.
Hey @florkbr @TheRealJon thanks for the PR with your commits. The work looks really good!
Added couple of comments.
| apiVersion: v1 | ||
| kind: ConfigMap | ||
| metadata: | ||
| namespace: openshift-config-managed |
There was a problem hiding this comment.
yes, we should put it int console's namespace
|
|
||
| // Get a list of ManagedCluster resources, degraded if error is returned | ||
| managedClusterClientConfigs, managedClusterClientConfigValidationErr, managedClusterClientConfigValidationErrReason := c.ValidateManagedClusterClientConfigs(ctx, operatorConfig, controllerContext.Recorder()) | ||
| statusHandler.AddConditions(status.HandleProgressingOrDegraded("ManagedClusterValidation", managedClusterClientConfigValidationErrReason, managedClusterClientConfigValidationErr)) |
There was a problem hiding this comment.
Here and below as well I would suggest to reduce the amount of the condition types prefixes.
| statusHandler.AddConditions(status.HandleProgressingOrDegraded("ManagedClusterValidation", managedClusterClientConfigValidationErrReason, managedClusterClientConfigValidationErr)) | |
| statusHandler.AddConditions(status.HandleProgressingOrDegraded("ManagedClusterSync", managedClusterClientConfigValidationErrReason, managedClusterClientConfigValidationErr)) |
The issue here is that each type prefix will register conditions that we need to maintain. For example calling status.HandleProgressingOrDegraded("ManagedClusterValidation" ...) will register these two conditions:
- ManagedClusterValidationProgressing
- ManagedClusterValidationDegraded
For that reason we should reduce those prefixes to only those that would make sense for debugging issues and rather make clear error reasons.
| } | ||
|
|
||
| // Return slice of clusterv1.ClientConfigs that have been validated or error and reaons if unable to list ManagedClusters | ||
| func (c *ManagedClusterController) ValidateManagedClusterClientConfigs(ctx context.Context, operatorConfig *operatorv1.Console, recorder events.Recorder) (map[string]*clusterv1.ClientConfig, error, string) { |
There was a problem hiding this comment.
nit: error should go as last return value
| func (c *ManagedClusterController) ValidateManagedClusterClientConfigs(ctx context.Context, operatorConfig *operatorv1.Console, recorder events.Recorder) (map[string]*clusterv1.ClientConfig, error, string) { | |
| func (c *ManagedClusterController) ValidateManagedClusterClientConfigs(ctx context.Context, operatorConfig *operatorv1.Console, recorder events.Recorder) (map[string]*clusterv1.ClientConfig, string, error) { |
| return statusHandler.FlushAndReturn(configSyncErr) | ||
| } | ||
|
|
||
| // Return slice of clusterv1.ClientConfigs that have been validated or error and reaons if unable to list ManagedClusters |
There was a problem hiding this comment.
| // Return slice of clusterv1.ClientConfigs that have been validated or error and reaons if unable to list ManagedClusters | |
| // Return slice of clusterv1.ClientConfigs that have been validated or error and its reason, if unable to list ManagedClusters |
| return validatedClientConfigs, nil, "" | ||
| } | ||
|
|
||
| // Using ManagedCluster.spec.ManagedClusterClientConfigs, sync ConfigMaps containing the API server CA bundle for each managed cluster |
There was a problem hiding this comment.
Great to see all those godocs 👍
| OAuthServingCert(useDefaultCAFile). | ||
| APIServerURL(getApiUrl(infrastructureConfig)). | ||
| InactivityTimeout(inactivityTimeoutSeconds). | ||
| ManagedClusterConfigFile(fmt.Sprintf("%v/%v", api.ManagedClusterConfigMountDir, api.ManagedClusterConfigKey)). |
There was a problem hiding this comment.
| ManagedClusterConfigFile(fmt.Sprintf("%v/%v", api.ManagedClusterConfigMountDir, api.ManagedClusterConfigKey)). | |
| ManagedClusterConfigFile(fmt.Sprintf("%s/%s", api.ManagedClusterConfigMountDir, api.ManagedClusterConfigKey)). |
There was a problem hiding this comment.
Is this file always present on the cluster ? What does it contain if the cluster is not part of the ACM ?
There was a problem hiding this comment.
Wondring if we should not pass canMountManagedClusterConfig to the DefaultConfigMap() method and based on that bool either pass the fmt.Sprintf("%s/%s", api.ManagedClusterConfigMountDir, api.ManagedClusterConfigKey) or not?
| // Degraded if managed cluster config map is present but doesn't have the correct data key | ||
| _, ok := managedClusterConfigMap.Data[api.ManagedClusterConfigKey] | ||
| if !ok { | ||
| return false, "MissingManagedClusterConfig", fmt.Errorf("%v ConfigMap is missing %v data key", api.ManagedClusterConfigMapName, api.ManagedClusterConfigKey) |
There was a problem hiding this comment.
| return false, "MissingManagedClusterConfig", fmt.Errorf("%v ConfigMap is missing %v data key", api.ManagedClusterConfigMapName, api.ManagedClusterConfigKey) | |
| return false, "MissingManagedClusterConfig", fmt.Errorf("%s ConfigMap is missing %s data key", api.ManagedClusterConfigMapName, api.ManagedClusterConfigKey) |
| // Create managed cluster views for oauth clients | ||
| managedClusterViewOAuthClients, managedClusterViewOAuthClientErr, managedClusterViewOAuthClientErrReason := c.SyncManagedClusterViewOAuthClient(ctx, operatorConfig) | ||
| statusHandler.AddConditions(status.HandleProgressingOrDegraded("ManagedClusterViewOAuthClientSync", managedClusterViewOAuthClientErrReason, managedClusterViewOAuthClientErr)) | ||
|
|
There was a problem hiding this comment.
Why arent we erroring out on error here and below ?
if managedClusterViewOAuthClientErr != nil {
return statusHandler.FlushAndReturn(managedClusterViewOAuthClientErr)
}|
/retest |
2 similar comments
|
/retest |
|
/retest |
|
Tagging the PR to merge to feature branch. Would be good to address pending comments. |
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: florkbr, jhadvig The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
|
/test e2e-aws-operator |
|
/retest-required Please review the full test history for this PR and help us cut down flakes. |
|
/test e2e-aws-operator |
/test e2e-aws-operator |
|
/retest-required Please review the full test history for this PR and help us cut down flakes. |
|
/retest-required Please review the full test history for this PR and help us cut down flakes. |
3 similar comments
|
/retest-required Please review the full test history for this PR and help us cut down flakes. |
|
/retest-required Please review the full test history for this PR and help us cut down flakes. |
|
/retest-required Please review the full test history for this PR and help us cut down flakes. |
Addresses @jhadvig comments on openshift#602.
Creates oauth clients on spoke clusters using the new managed cluster
controller via a dynamic client.