feat: add AdditionalVPCs field to HostedZoneSpec#99
feat: add AdditionalVPCs field to HostedZoneSpec#99ecordell wants to merge 1 commit intoaws-controllers-k8s:mainfrom
Conversation
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: ecordell The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
Hi @ecordell. Thanks for your PR. I'm waiting for a aws-controllers-k8s 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. DetailsInstructions 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. |
| { | ||
| primaryVPCID := "" | ||
| if ko.Spec.VPC != nil && ko.Spec.VPC.VPCID != nil { | ||
| primaryVPCID = *ko.Spec.VPC.VPCID | ||
| } | ||
| var additionalVPCs []*svcapitypes.VPC | ||
| for _, v := range resp.VPCs { | ||
| if v.VPCId == nil || *v.VPCId == primaryVPCID { | ||
| continue | ||
| } | ||
| region := string(v.VPCRegion) | ||
| additionalVPCs = append(additionalVPCs, &svcapitypes.VPC{ | ||
| VPCID: v.VPCId, | ||
| VPCRegion: ®ion, | ||
| }) | ||
| } | ||
| ko.Spec.AdditionalVPCs = additionalVPCs |
There was a problem hiding this comment.
should we support cases where the user would want to disassociate the primaryVPC as well?
There was a problem hiding this comment.
If the original vpc specified by spec.vpc isn't special and can be disassociated I agree it doesn't make sense for the ACK controller to prevent users from disassociating that VPC. But we'd need to be careful in how that is implemented. As-is the logic for create and delete could become stuck in a broken state if we allow spec.vpc to be disassociated by un-setting the field.
- If
spec.vpcis unset after creating the resource and later the ACK needs to recreate the hosted zone after it as been deleted in AWS the ACK controller will attempt to create hosted zone without an initial VPC and fail if an initial VPC is required. - When the ACK controller is deleting the hosted zone it first attempts to disassociate all VPCs defined in
spec.additionalVPCs. Ifspec.vpchas been unset the controller will attempt to disassociate all VPCs from the hosted zone before deletion which based on the DisassociateVPCFromHostedZone API docs will result in a validation failure.
Additionally, we might want to change the name of spec.additionalVPCs if we allow user to disassociate the VPC defined by spec.vpc. If that disassociation is expressed by un-setting spec.vpc having spec.additionalVPCs by itself could be confusing.
There was a problem hiding this comment.
This is good feedback, thanks
What do we think about this:
- Enforce an invariant that
spec.vpcmust be non-nil iflen(spec.additionalVPCs) > 0 - When syncing VPC associations, treat
spec.vpc + []spec.additionalVPCsas one set to reconcile; first associating new VPCs and then disassociating any not in the desired set. - (side affect of the first two) Changing
spec.vpcwill associate the new vpc before disassociating the old vpc and is effectively mutable, but can't be empty.
I think it may also make sense to enforce spec.vpc is non-nil for private hosted zones?
There was a problem hiding this comment.
Unless I'm missing it, I don't see a good way to enforce what I want - I don't see where I can easily set custom cel rules in the generator.
So some options:
- I could update the generator to allow passing custom cel validation (not against this but would be a longer lead time than I'd like)
- Do what I listed above, but nothing stops you from cleaning out the
spec.vpc. That will remove the association but means you can havespec.vpc = nil, additionalVPCs = [a,b]which is a little weird. But, there will be an error condition if you try and disassociate the final VPC. - Leave the current behavior - only changes to additionalVPCs will disassociate VPCs. You can clear out
spec.vpcif you want but it won't disassociate that VPC.
LMK which sounds best and I will address it.
There was a problem hiding this comment.
I've opened aws-controllers-k8s/code-generator#677 as well
There was a problem hiding this comment.
For the sake of review I've updated this PR to generate with my fork ^
It will fail the codegen check until that PR is merged. Or, if we don't like that direction, I can work on a different option.
There was a problem hiding this comment.
Managing the set of associated VPCs across two fields seems like it could be a bit awkward from a usability standpoint. Naively, if I had the below manifest and wanted to disassociate the VPC associated with spec.vpc I'd be a bit surprised that I have to "pop" a VPC out of spec.additionalVPCs to make it work.
apiVersion: route53.services.k8s.aws/v1alpha1
kind: HostedZone
metadata:
name: test-zone
spec:
name: test-zone
vpc:
vpcID: vpc-1
vpcRegion: us-west-2
additionalVPCs:
- vpcID: vpc-2
vpcRegion: us-west-2
- vpcID: vpc-3
vpcRegion: us-west-2
What do you think about adding a spec.vpcs field instead of spec.additionalVPCs that this mutually exclusive with spec.vpc? That way users would have the ability to only interact with a single field when managing one or more associated VPCs.
# managing multiple VPCs
apiVersion: route53.services.k8s.aws/v1alpha1
kind: HostedZone
metadata:
name: test-zone
spec:
name: test-zone
vpcs:
- vpcID: vpc-1
vpcRegion: us-west-2
- vpcID: vpc-2
vpcRegion: us-west-2
- vpcID: vpc-3
vpcRegion: us-west-2
-----
# managing a single VPC can use either spec.vpcs or spec.vpc
apiVersion: route53.services.k8s.aws/v1alpha1
kind: HostedZone
metadata:
name: test-zone
spec:
name: test-zone
vpcs:
- vpcID: vpc-1
vpcRegion: us-west-2
or
apiVersion: route53.services.k8s.aws/v1alpha1
kind: HostedZone
metadata:
name: test-zone
spec:
name: test-zone
vpc:
vpcID: vpc-1
vpcRegion: us-west-2
There was a problem hiding this comment.
I like spec.vpcs as a mutually exclusive alternative to spec.vpc - I shied away from this because CreateHostedZone does have a first-class vpc field that mirrors the current ACK API and is required for private hosted zones. So if they're mutually exclusive, we'd need some rule like "spec.vpcs[0] is used as the vpc for the initial CreateHostedZone."
I don't have a strong opinion about which is more or less awkward, neither seems perfect to me (better would be if this was implemented in the AWS HostedZone API directly 😄). I'll defer to whatever you prefer.
There's also the alternative I mentioned in another comment - a new top-level HostedZoneAssociatedVPC type.
There was a problem hiding this comment.
There's also the alternative I mentioned in another comment - a new top-level HostedZoneAssociatedVPC type.
Hmm how would disassociating the VPC defined in the HostedZone's spec.vpc work with this approach? I think we'd need to ensure that we don't allow user's to naively unset spec.vpc since that could result in the controller entering a state where the HostedZone can't be re-created after an accidental deletion.
|
/test all |
228d3b6 to
fed7184
Compare
|
/test all |
fed7184 to
0732d39
Compare
|
/test all |
|
@ecordell: Cannot trigger testing until a trusted user reviews the PR and leaves an DetailsIn response to this:
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. |
|
/ok-to-test |
0732d39 to
2f4d39a
Compare
|
@ecordell: The following tests failed, say
Full PR test history. Your PR dashboard. DetailsInstructions 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. I understand the commands that are listed here. |
| custom_method_name: customUpdateRecordSet | ||
| HostedZone: | ||
| custom_cel_rules: | ||
| - rule: "!has(self.hostedZoneConfig) || !self.hostedZoneConfig.privateZone || has(self.vpc)" |
There was a problem hiding this comment.
p: This case is probably fairly stable, but normally we delegate validation of the resource to the AWS API itself as its the source of truth for the service's validation rules. Performing the validation within the ACK controller runs the risk of our validation becoming out of sync with what the AWS service itself actually allows.
There was a problem hiding this comment.
I think the thing that's weird about this case is that each AssociateVPCWithHostedZone is a separate API call and the additionalVPCs don't have a direct representation in CreateHostedZone.
One alternative would be to make a brand new ACK type, like HostedZoneAssociatedVPC that just has spec.vpc and spec.hostedZone?
| // Fetch current VPC associations from AWS. | ||
| resp, err := client.GetHostedZone(ctx, &svcsdk.GetHostedZoneInput{Id: hostedZoneID}) | ||
| if rm.metrics != nil { | ||
| rm.metrics.RecordAPICall("READ_ONE", "GetHostedZone", err) | ||
| } | ||
| if err != nil { | ||
| return err | ||
| } |
There was a problem hiding this comment.
why do we want to fetch all VPCs again? wouldn't we populate latest from sdkFind?
There was a problem hiding this comment.
This was to work around the AWS api not actually having a top-level VPC field (and to address the earlier comment that spec.VPC should be mutable).
latest is a DeepCopy of desired but with values from the AWS API filled in. The upstream api doesn't distinguish a "primary" associated VPC - the associated VPCs are a flat list. So when we get the response we don't know what we should fill in for spec.VPC. There's not enough information between latest and desired to figure out a diff in spec.VPC
An alternative to a second API call here is to store the full associated VPC list as a status field as well, which we can then assume is accurate and diff with the desired state. But that is basically the design in #102 if you prefer it.
| // HostedZoneSpec defines the desired state of HostedZone. | ||
| // | ||
| // A complex type that contains general information about the hosted zone. | ||
| // +kubebuilder:validation:XValidation:rule="!has(self.hostedZoneConfig) || !self.hostedZoneConfig.privateZone || has(self.vpc)",message="spec.vpc is required for private hosted zones" |
There was a problem hiding this comment.
can we validate spec.AdditionalVPCs is also empty if the hostedZone is public?
|
@michaelhtm @knottnt I appreciate the reviews on this. After reflecting I think that the API in #102 provides a better UX and addresses all of the concerns raised here (and as a bonus, doesn't require the cel validation support in code-generator). Closing this in favor of the other, PTAL? |
I'd like to be able to associate additional VPCs with a hosted zone - the current APIs force you to manually make the association after.
I've tested in an AWS environment, but I'm not familiar with how testing works for this repo generally. Is there a process to follow?