- 
                Notifications
    You must be signed in to change notification settings 
- Fork 303
introduce load balancer API for capv #538
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
Conversation
| [APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: yastij The full list of commands accepted by this bot can be found here. 
Needs approval from an approver in each of these files:
 Approvers can indicate their approval by writing  | 
8910a60    to
    7dbaea2      
    Compare
  
    450b125    to
    85f60e9      
    Compare
  
    | /retest | 
| Hi @yastij, I started my review yesterday, but didn't have time to complete it. One thing I noticed was that the types are in  Example 1 ├── api
│   └── v1alpha2
│       ├── cloud
│       └── load-balancer
│           └── vmc
│               └── awsor Example 2 ├── api
│   ├── load-balancer
│   │   └── v1alpha1
│   │       └── vmc
│   │           └── aws
│   └── vsphere
│       └── v1alpha2
│           └── cloudNow obviously the second pattern would require not insignificant refactoring since it changes the location of the existing vSphere types, but, the second pattern does adhere to the Kubebuilder recommended guidelines for multi-group projects. Thoughts? | 
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.
Hi @yastij,
I love this PR! Thank you so, so, SO much for this work. I am truly sorry I reviewed this in the morning when I'm at my more attentive :)
/hold
        
          
                api/v1alpha2/cloud/types.go
              
                Outdated
          
        
      | // LoadBalancerConfig describes the supported Load balancer providers | ||
| type LoadBalancerConfig struct { | ||
| // AwsProvider specifies the information needed to run VMC on AWS | ||
| AwsProvider *AwsProviderSpec `json:"awsProvider,omitempty"` | 
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.
Hi @yastij,
Any field that is omitempty should also have a godoc of // +optional according to the OpenAPI guidelines.
        
          
                api/v1alpha2/cloud/types.go
              
                Outdated
          
        
      | // VpcID is the id of the VPC used to create loadBalancers | ||
| VpcID string `json:"vpcID"` | ||
|  | ||
| // Subnets is the list of subnets where | 
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.
Hi @yastij,
The godoc for Subnets is incomplete. Also, maybe rename the field to SubnetIDs or SubnetARNs?
| // LoadBalancerFinalizer allows to clean up the load balancer | ||
| // associated with VSphereCluster before removing it from the | ||
| // API server. | ||
| LoadBalancerFinalizer = "loadbalancer.infrastructure.cluster.x-k8s.io" | 
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.
Hi @yastij,
There could technically be multiple load balancers, right? Should the LB finalizer be specific to the type of LB used?
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, the finalizer is added to the cluster object. The cluster object only supports one provider.
        
          
                api/v1alpha2/vspherecluster_types.go
              
                Outdated
          
        
      |  | ||
| // LoadBalancerConfiguration holds a provider-specific configuration to provision | ||
| // a Load balancer as a control plane endpoint | ||
| LoadBalancerConfiguration *cloud.LoadBalancerConfig `json:"loadBalancerConfiguration,omitempty"` | 
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.
Hi @yastij,
Any field that is omitempty should also have a godoc of // +optional according to the OpenAPI guidelines. The reason the CloudProviderConfiguration doesn't is because it's not a pointer, and thus is never technically empty.
| @@ -0,0 +1,142 @@ | |||
| package 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.
Hi @yastij,
I'm wondering if the load balancer controller shouldn't be in a new sub-directory:
├── controllers
    └── load-balancerI'm just thinking of things to make it easier to move the work in this PR to a separate module or repository at a later date. If we're already importing the LB types/controller from inside this repo, it makes it easier to move it later since we'll just rewrite imports.
| } | ||
|  | ||
| func (svc *Service) reconcileLoadBalancer(clusterName string, subnets []string) (*string, *string, error) { | ||
| var loadBalancerArn *string | 
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.
Hi @yastij,
Please simplify as:
var (
	loadBalancerArn *string
	loadBalancerDNS *string
	describeLoadBalancersInput = &elbv2.DescribeLoadBalancersInput{
		Names: []*string{aws.String(generateELBName(clusterName))},
	}
)| } | ||
|  | ||
| func (svc *Service) reconcileListeners(loadBalancerArn *string, targetGroupArn *string) (*int64, error) { | ||
| var listenerPort *int64 | 
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.
Hi @yastij,
Please simplify as:
var (
	listenerPort *int64
	describeListnerInput = &elbv2.DescribeListenersInput{
		LoadBalancerArn: loadBalancerArn,
	}
)| } | ||
|  | ||
| func (svc *Service) deleteTargetGroup(clusterName string) error { | ||
| describeTargetGroupInput := &elbv2.DescribeTargetGroupsInput{} | 
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.
Hi @yastij,
Please simplify as:
describeTargetGroupInput := &elbv2.DescribeTargetGroupsInput{
	Names: []*string{aws.String(clusterName+"-controlPlane")},
}Also, please note that I recommended above to extract the building of this name into a distinct function.
|  | ||
| func (svc *Service) reconcileTargetGroup(clusterName string, vpcID string, controlPlaneIPs []string) (*string, error) { | ||
| describeTargetGroupInput := &elbv2.DescribeTargetGroupsInput{} | ||
| describeTargetGroupInput.Names = append(describeTargetGroupInput.Names, aws.String(clusterName+"-controlPlane")) | 
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.
Hi @yastij,
I've seen aws.String(clusterName+"-controlPlane") at least twice. Due to the fact that this is required to find a resource, let's extract this into a function:
// GetTargetGroupNameForCluster returns the name of a target group for the provided cluster.
func GetTargetGroupNameForCluster(clusterName string) *string {
	return aws.String(clusterName+"-controlPlane")
}| return err | ||
| } | ||
|  | ||
| if err := svc.deleteTargetGroup(clusterName); 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.
Hi @yastij,
This could be simplified as:
return svc.deleteTargetGroup(clusterName)Or please feel free to leave as-is if you think we may include additional logic beneath this call one day.
c0e10a0    to
    90a023e      
    Compare
  
    9b7c7a3    to
    cbb90be      
    Compare
  
    | /retest | 
d2f8fb6    to
    d8a9817      
    Compare
  
            
          
                api/v1alpha2/loadbalancer/types.go
              
                Outdated
          
        
      |  | ||
| const ( | ||
| // AwsProvider is the name of the aws provider | ||
| AwsProvider = "aws" | 
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 the provider name should be explicit to the LB implementation, not the cloud provider, so this should be "ELB", thoughts?
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.
actually this should be removed. As the current PR uses Kind to store/retrieve the provider
        
          
                api/v1alpha2/loadbalancer/types.go
              
                Outdated
          
        
      | // +kubebuilder:subresource:status | ||
|  | ||
| // AWSLoadBalancer is the schema for the AWS Load balancer API | ||
| type AWSLoadBalancer 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.
Shouldn't the API types be generic and the implementations be provider specific?
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. Think of this as a KubeadmBootstrap provider. There will be a diff controller / API model for each implementation of the LB.
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 issue is that there's no common API for loadbalancers, as each provider needs its own information. I don't want us to endup implementing annotations on-top to satisfy each provider's specifics.
Another way could be store the information on-disk/cm implement something Service (e.g. MachineService or MachineLoadbalancer) which would select machines based on a the selector and add them to the load balancing pool. A drawback is that a management cluster is restricted to provision against one Loadbalancing provider. Thoughts @akutz @andrewsykim ?
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 it's that complicated. Just like each Cluster resource today has a ConfigRef to an Infrastructure provider's Cluster, so to will there be a ConfigRef from a Cluster to a load balancer config, in this case, AWSLoadBalancerConfig.
There's some questions around how to get the IP information from the machines, but that's something we can work out.
The benefit of this decoupled model is that it enables the introduction of a load balancer provider of any kind.
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, plus this wouldn't change much the implementation itself. thoughts @andrewsykim ?
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 my thoughts around this was that we introduce a generic LoadBalancer type with a ProviderRef field similar to what @akutz mentioned re: Cluster with a ConfigRef. That way, for each implementation you only have to implement a new ProviderRef and not the entire LoadBalancer API again. Maybe we already agree on this but it's not clear to me yet.
6f6718f    to
    794c59c      
    Compare
  
    | /retest | 
Signed-off-by: Yassine TIJANI <[email protected]>
Signed-off-by: Yassine TIJANI <[email protected]>
Signed-off-by: Yassine TIJANI <[email protected]>
Signed-off-by: Yassine TIJANI <[email protected]>
| // APIEndpoint represents the endpoint to communicate with the load | ||
| // balancer. | ||
| // +optional | ||
| APIEndpoint APIEndpoint `json:"apiEndpoint,omitempty"` | 
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.
Not doing a full review on this right now (unless you'd like), but one thing I wanted to mention was the API endpoint needs to be in spec, not status. If you have a provider that generates an endpoint (e.g. a DNS name) and the endpoint is not something you can determine by querying, we would lose the data if we store it in status and we're trying to move the resource from one management cluster to another.
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.
@ncdc - I'll rebase and ping you for an API review
| @yastij: PR needs rebase. 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. | 
| @yastij: The following tests failed, say  
 Full PR test history. Your PR dashboard. Please help us cut down on flakes by linking to an open issue when you hit one in your PR. 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. I understand the commands that are listed here. | 
| /close | 
| @akutz: Closed this PR. In 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. | 
* Make sure ubuntu gets proper version of cloud-init * Add Goss test * Use packer-goss provisioner to execute Goss tests * Add packer docs * Add link to packer documentation in README file. * Add link to packer-goss * Add Ansible as prerequisite for packer
What this PR does / why we need it: This PR introduces a load balancing API to implement in-tree load balacing providers. This PR ships AWS as a first provider
Which issue(s) this PR fixes : Fixes #468
Special notes for your reviewer:
what is missing
loadbalancerRefkustomization and anAWSLoadBalancerresource/assign @akutz
/cc @andrewsykim
Please confirm that if this PR changes any image versions, then that's the sole change this PR makes.
Release note: