-
Notifications
You must be signed in to change notification settings - Fork 578
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
✨ Supporting externally managed Control Plane #4438
Conversation
Welcome @prometherion! |
Hi @prometherion. Thanks for your PR. I'm waiting for a kubernetes-sigs member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
58dca4e
to
e36b61e
Compare
/ok-to-test |
41f95ad
to
db16163
Compare
If the proposed approach is ok I can work on proper unit-tests for this. |
369c894
to
64fca56
Compare
64fca56
to
fe32fd4
Compare
fe32fd4
to
a4b2f1e
Compare
/retest |
/milestone v2.4.0 |
Until #4733 merges /hold But this looks good to me, pending any changes required after 4733. |
3bb5d3a
to
6b4fec7
Compare
Signed-off-by: Dario Tranchitella <[email protected]>
Signed-off-by: Dario Tranchitella <[email protected]>
Signed-off-by: Dario Tranchitella <[email protected]>
6b4fec7
to
fc3cb07
Compare
/test pull-cluster-api-provider-aws-e2e |
Thanks, @richardcase, rebased as requested. The failed test seems unrelated to the changes we introduced. |
Thanks @prometherion /unhold |
/test pull-cluster-api-provider-aws-e2e |
/lgtm |
the tests are all passing, and the code looks good. i think this is ready to merge |
@@ -1178,3 +1186,22 @@ func (r *AWSMachineReconciler) ensureInstanceMetadataOptions(ec2svc services.EC2 | |||
|
|||
return ec2svc.ModifyInstanceMetadataOptions(instance.ID, machine.Spec.InstanceMetadataOptions) | |||
} | |||
|
|||
// +kubebuilder:rbac:groups=controlplane.cluster.x-k8s.io,resources=*,verbs=get;list;watch |
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 undecided whether we should have all these in one place.
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.
TBH, this wildcard makes obsolete the following ones:
// +kubebuilder:rbac:groups=controlplane.cluster.x-k8s.io,resources=rosacontrolplanes;rosacontrolplanes/status,verbs=get;list;watch |
// +kubebuilder:rbac:groups=controlplane.cluster.x-k8s.io,resources=awsmanagedcontrolplanes,verbs=get;list;watch |
// +kubebuilder:rbac:groups=controlplane.cluster.x-k8s.io,resources=awsmanagedcontrolplanes;awsmanagedcontrolplanes/status,verbs=get;list;watch |
// +kubebuilder:rbac:groups=controlplane.cluster.x-k8s.io,resources=rosacontrolplanes;rosacontrolplanes/status,verbs=get;list;watch |
...and many other lines.
Although we could optimize the role rules, I think these are more intuitive for developers, since it's pretty straightforward trying to understand the objects controlled by the various controllers.
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 move these to a single place above
@@ -298,5 +298,49 @@ func (r *AWSCluster) validateControlPlaneLBs() field.ErrorList { | |||
} | |||
} | |||
|
|||
if r.Spec.ControlPlaneLoadBalancer.LoadBalancerType == LoadBalancerTypeDisabled { | |||
if r.Spec.ControlPlaneLoadBalancer.Name != 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.
I'm wondering if we need a func Empty() bool
on the load balancer instead of checking each sub field. But lets discuss that separately.
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.
We still would need the check of each subfield, unfortunately. We could slender the webhook file, of course, but from a UX perspective, knowing which field is breaking the validation would be helpful.
/approve |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: richardcase 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 |
@@ -229,7 +230,7 @@ type AWSLoadBalancerSpec struct { | |||
|
|||
// LoadBalancerType sets the type for a load balancer. The default type is classic. |
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.
Could we add a comment on what each value for this does and what the new value is useful for?
@@ -298,5 +298,49 @@ func (r *AWSCluster) validateControlPlaneLBs() field.ErrorList { | |||
} | |||
} | |||
|
|||
if r.Spec.ControlPlaneLoadBalancer.LoadBalancerType == LoadBalancerTypeDisabled { |
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 we validating somewhere that the type
cannot be changed once created? How are we dealing right now if a user creates the type = disabled
and then wants alb
and vice-versa?
if r.Spec.ControlPlaneLoadBalancer.CrossZoneLoadBalancing { | ||
allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "controlPlaneLoadBalancer", "crossZoneLoadBalancing"), r.Spec.ControlPlaneLoadBalancer.CrossZoneLoadBalancing, "cross-zone load balancing cannot be set if the LoadBalancer reconciliation is disabled")) | ||
} | ||
|
||
if len(r.Spec.ControlPlaneLoadBalancer.Subnets) > 0 { | ||
allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "controlPlaneLoadBalancer", "subnets"), r.Spec.ControlPlaneLoadBalancer.Subnets, "subnets cannot be set if the LoadBalancer reconciliation is disabled")) | ||
} | ||
|
||
if r.Spec.ControlPlaneLoadBalancer.HealthCheckProtocol != nil { | ||
allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "controlPlaneLoadBalancer", "healthCheckProtocol"), r.Spec.ControlPlaneLoadBalancer.HealthCheckProtocol, "healthcheck protocol cannot be set if the LoadBalancer reconciliation is disabled")) | ||
} | ||
|
||
if len(r.Spec.ControlPlaneLoadBalancer.AdditionalSecurityGroups) > 0 { | ||
allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "controlPlaneLoadBalancer", "additionalSecurityGroups"), r.Spec.ControlPlaneLoadBalancer.AdditionalSecurityGroups, "additional Security Groups cannot be set if the LoadBalancer reconciliation is disabled")) | ||
} | ||
|
||
if len(r.Spec.ControlPlaneLoadBalancer.AdditionalListeners) > 0 { | ||
allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "controlPlaneLoadBalancer", "additionalListeners"), r.Spec.ControlPlaneLoadBalancer.AdditionalListeners, "cannot set additional listeners if the LoadBalancer reconciliation is disabled")) | ||
} | ||
|
||
if len(r.Spec.ControlPlaneLoadBalancer.IngressRules) > 0 { | ||
allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "controlPlaneLoadBalancer", "ingressRules"), r.Spec.ControlPlaneLoadBalancer.IngressRules, "ingress rules cannot be set if the LoadBalancer reconciliation is disabled")) | ||
} | ||
|
||
if r.Spec.ControlPlaneLoadBalancer.PreserveClientIP { | ||
allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "controlPlaneLoadBalancer", "preserveClientIP"), r.Spec.ControlPlaneLoadBalancer.PreserveClientIP, "cannot preserve client IP if the LoadBalancer reconciliation is disabled")) | ||
} | ||
|
||
if r.Spec.ControlPlaneLoadBalancer.DisableHostsRewrite { | ||
allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "controlPlaneLoadBalancer", "disableHostsRewrite"), r.Spec.ControlPlaneLoadBalancer.DisableHostsRewrite, "cannot disable hosts rewrite if the LoadBalancer reconciliation is disabled")) | ||
} | ||
} | ||
|
||
for _, rule := range r.Spec.ControlPlaneLoadBalancer.IngressRules { | ||
if (rule.CidrBlocks != nil || rule.IPv6CidrBlocks != nil) && (rule.SourceSecurityGroupIDs != nil || rule.SourceSecurityGroupRoles != nil) { | ||
allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "controlPlaneLoadBalancer", "ingressRules"), r.Spec.ControlPlaneLoadBalancer.IngressRules, "CIDR blocks and security group IDs or security group roles cannot be used together")) | ||
} | ||
} |
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.
We should open an issue to track for the next API version to rework this, it seems to me that we're going around the current API structure to disable the control plane management
func (r *AWSClusterReconciler) reconcileLoadBalancer(clusterScope *scope.ClusterScope, awsCluster *infrav1.AWSCluster) (*time.Duration, error) { | ||
retryAfterDuration := 15 * time.Second |
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.
Could we rework this to just return an error
and leave the retryAfterDuration
outside?
func (r *AWSClusterReconciler) checkForExternalControlPlaneLoadBalancer(clusterScope *scope.ClusterScope, awsCluster *infrav1.AWSCluster) *time.Duration { | ||
requeueAfterPeriod := 15 * time.Second | ||
|
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.
Same as above, the retry after should be outside in a caller
cp, err := r.getControlPlane(ctx, log, cluster) | ||
if err != nil { | ||
return ctrl.Result{}, 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.
It seems we're missing that the control plane is an optional reference, and this is going to panic when 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.
Potentially could be solved with #4817.
@@ -1178,3 +1186,22 @@ func (r *AWSMachineReconciler) ensureInstanceMetadataOptions(ec2svc services.EC2 | |||
|
|||
return ec2svc.ModifyInstanceMetadataOptions(instance.ID, machine.Spec.InstanceMetadataOptions) | |||
} | |||
|
|||
// +kubebuilder:rbac:groups=controlplane.cluster.x-k8s.io,resources=*,verbs=get;list;watch |
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 move these to a single place above
@@ -371,6 +377,10 @@ func (m *MachineScope) IsEKSManaged() bool { | |||
return m.InfraCluster.InfraCluster().GetObjectKind().GroupVersionKind().Kind == ekscontrolplanev1.AWSManagedControlPlaneKind | |||
} | |||
|
|||
func (m *MachineScope) IsControlPlaneExternallyManaged() 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.
A bit confusing on why this is needed, the control plane reference can be anything, including a new CRD; why do we need to mark it as externally managed?
What type of PR is this?
/kind feature
What this PR does / why we need it:
Cluster API allows defining externally managed control plane for the given cluster, the current code-base doesn't consider this since it nevertheless performs the following actions:
Which issue(s) this PR fixes:
Fixes #4437
Special notes for your reviewer:
Checklist:
Release note: