Skip to content

Commit 13486b4

Browse files
sbueringerpierreprinetti
authored andcommitted
Adds Managed APIServer Loadbalancer (kubernetes-sigs#401)
* Adds Managed APIServer Loadbalancer This commit adds the optional feature manage APIServer Loadbalancer. If the feature is enabled a LoadBalancer for the control plane node(s) is created. The cluster actuator creates the LoadBalancers and all corresponding objects. The machine actuator creates and removes LoadBalancer members for control plane nodes. * add check for lb member * fix panic
1 parent 2fef9c7 commit 13486b4

File tree

34 files changed

+4131
-78
lines changed

34 files changed

+4131
-78
lines changed

Gopkg.lock

Lines changed: 13 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crds/openstackproviderconfig_v1alpha1_openstackclusterproviderspec.yaml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,23 @@ spec:
1414
validation:
1515
openAPIV3Schema:
1616
properties:
17+
apiServerLoadBalancerAdditionalPorts:
18+
description: APIServerLoadBalancerAdditionalPorts adds additional ports
19+
to the APIServerLoadBalancer
20+
items:
21+
format: int64
22+
type: integer
23+
type: array
24+
apiServerLoadBalancerFloatingIP:
25+
description: APIServerLoadBalancerFloatingIP is the floatingIP which will
26+
be associated to the APIServer loadbalancer. The floatingIP will be created
27+
if it not already exists.
28+
type: string
29+
apiServerLoadBalancerPort:
30+
description: APIServerLoadBalancerPort is the port on which the listener
31+
on the APIServer loadbalancer will be created
32+
format: int64
33+
type: integer
1734
apiVersion:
1835
description: 'APIVersion defines the versioned schema of this representation
1936
of an object. Servers should convert recognized schemas to the latest
@@ -87,6 +104,10 @@ spec:
87104
ipVersion:
88105
format: int64
89106
type: integer
107+
ipv6AddressMode:
108+
type: string
109+
ipv6RaMode:
110+
type: string
90111
limit:
91112
format: int64
92113
type: integer
@@ -140,6 +161,11 @@ spec:
140161
object represents. Servers may infer this from the endpoint the client
141162
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds'
142163
type: string
164+
managedAPIServerLoadBalancer:
165+
description: 'ManagedAPIServerLoadBalancer defines whether a LoadBalancer
166+
for the APIServer should be created. If set to true the following properties
167+
are mandatory: APIServerLoadBalancerFloatingIP, APIServerLoadBalancerPort'
168+
type: boolean
143169
managedSecurityGroups:
144170
description: ManagedSecurityGroups defines that kubernetes manages the OpenStack
145171
security groups for now, that means that we'll create two security groups,
@@ -177,6 +203,7 @@ spec:
177203
required:
178204
- cloudsSecret
179205
- cloudName
206+
- managedAPIServerLoadBalancer
180207
- managedSecurityGroups
181208
version: v1alpha1
182209
status:

config/crds/openstackproviderconfig_v1alpha1_openstackclusterproviderstatus.yaml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,24 @@ spec:
129129
description: Network contains all information about the created OpenStack
130130
Network. It includes Subnets and Router.
131131
properties:
132+
apiServerLoadBalancer:
133+
description: Be careful when using APIServerLoadBalancer, because this
134+
field is optional and therefore not set in all cases
135+
properties:
136+
id:
137+
type: string
138+
internalIP:
139+
type: string
140+
ip:
141+
type: string
142+
name:
143+
type: string
144+
required:
145+
- name
146+
- id
147+
- ip
148+
- internalIP
149+
type: object
132150
id:
133151
type: string
134152
name:

pkg/apis/openstackproviderconfig/v1alpha1/types.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,23 @@ type OpenstackClusterProviderSpec struct {
203203
// to get public internet to the VMs.
204204
ExternalNetworkID string `json:"externalNetworkId,omitempty"`
205205

206+
// ManagedAPIServerLoadBalancer defines whether a LoadBalancer for the
207+
// APIServer should be created. If set to true the following properties are
208+
// mandatory: APIServerLoadBalancerFloatingIP, APIServerLoadBalancerPort
209+
ManagedAPIServerLoadBalancer bool `json:"managedAPIServerLoadBalancer"`
210+
211+
// APIServerLoadBalancerFloatingIP is the floatingIP which will be associated
212+
// to the APIServer loadbalancer. The floatingIP will be created if it not
213+
// already exists.
214+
APIServerLoadBalancerFloatingIP string `json:"apiServerLoadBalancerFloatingIP,omitempty"`
215+
216+
// APIServerLoadBalancerPort is the port on which the listener on the APIServer
217+
// loadbalancer will be created
218+
APIServerLoadBalancerPort int `json:"apiServerLoadBalancerPort,omitempty"`
219+
220+
// APIServerLoadBalancerAdditionalPorts adds additional ports to the APIServerLoadBalancer
221+
APIServerLoadBalancerAdditionalPorts []int `json:"apiServerLoadBalancerAdditionalPorts,omitempty"`
222+
206223
// ManagedSecurityGroups defines that kubernetes manages the OpenStack security groups
207224
// for now, that means that we'll create two security groups, one allowing SSH
208225
// and API access from everywhere, and another one that allows all traffic to/from
@@ -282,6 +299,10 @@ type Network struct {
282299

283300
Subnet *Subnet `json:"subnet,omitempty"`
284301
Router *Router `json:"router,omitempty"`
302+
303+
// Be careful when using APIServerLoadBalancer, because this field is optional and therefore not
304+
// set in all cases
305+
APIServerLoadBalancer *LoadBalancer `json:"apiServerLoadBalancer,omitempty"`
285306
}
286307

287308
// Subnet represents basic information about the associated OpenStack Neutron Subnet
@@ -298,6 +319,14 @@ type Router struct {
298319
ID string `json:"id"`
299320
}
300321

322+
// LoadBalancer represents basic information about the associated OpenStack LoadBalancer
323+
type LoadBalancer struct {
324+
Name string `json:"name"`
325+
ID string `json:"id"`
326+
IP string `json:"ip"`
327+
InternalIP string `json:"internalIP"`
328+
}
329+
301330
// +genclient
302331
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
303332

pkg/apis/openstackproviderconfig/v1alpha1/zz_generated.deepcopy.go

Lines changed: 26 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/cloud/openstack/cluster/actuator.go

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ func (a *Actuator) Reconcile(cluster *clusterv1.Cluster) error {
8181

8282
defer func() {
8383
if err := a.storeCluster(cluster, clusterCopy, clusterProviderSpec, clusterProviderStatus); err != nil {
84-
klog.Errorf("failed to store cluster %q in namespace %q: %v", cluster.Name, cluster.Namespace, err)
84+
klog.Errorf("Failed to store cluster %q in namespace %q: %v", cluster.Name, cluster.Namespace, err)
8585
}
8686
}()
8787

@@ -107,6 +107,12 @@ func (a *Actuator) Reconcile(cluster *clusterv1.Cluster) error {
107107
if err != nil {
108108
return errors.Errorf("failed to reconcile router: %v", err)
109109
}
110+
if clusterProviderSpec.ManagedAPIServerLoadBalancer {
111+
err = networkingService.ReconcileLoadBalancer(clusterName, clusterProviderSpec, clusterProviderStatus)
112+
if err != nil {
113+
return errors.Errorf("failed to reconcile load balancer: %v", err)
114+
}
115+
}
110116
}
111117

112118
err = networkingService.ReconcileSecurityGroups(clusterName, *clusterProviderSpec, clusterProviderStatus)
@@ -138,6 +144,7 @@ func (a *Actuator) Reconcile(cluster *clusterv1.Cluster) error {
138144
return errors.Wrapf(err, "failed to get kubeconfig secret for cluster %q", cluster.Name)
139145
}
140146

147+
klog.Infof("Reconciled Cluster %s/%s successfully", cluster.Namespace, cluster.Name)
141148
return nil
142149
}
143150

@@ -180,9 +187,9 @@ func (a *Actuator) Delete(cluster *clusterv1.Cluster) error {
180187
return nil
181188
}
182189

183-
func (a *Actuator) storeCluster(cluster *clusterv1.Cluster, clusterCopy *clusterv1.Cluster, spec *providerv1.OpenstackClusterProviderSpec, status *providerv1.OpenstackClusterProviderStatus) error {
190+
func (a *Actuator) storeCluster(cluster *clusterv1.Cluster, clusterCopy *clusterv1.Cluster, clusterProviderSpec *providerv1.OpenstackClusterProviderSpec, clusterProviderStatus *providerv1.OpenstackClusterProviderStatus) error {
184191

185-
rawSpec, rawStatus, err := providerv1.EncodeClusterSpecAndStatus(cluster, spec, status)
192+
rawSpec, rawStatus, err := providerv1.EncodeClusterSpecAndStatus(cluster, clusterProviderSpec, clusterProviderStatus)
186193
if err != nil {
187194
return err
188195
}
@@ -212,6 +219,28 @@ func (a *Actuator) storeCluster(cluster *clusterv1.Cluster, clusterCopy *cluster
212219
cluster.ResourceVersion = result.ResourceVersion
213220
}
214221

222+
// set to APIServerLoadBalancer IP & Port for now. With generated kubeadm
223+
// this can be changed to clusterConfiguration.controlPlaneEndpoint for the
224+
// non-LoadBalancer case. For now it doesn't matter because the Status is not
225+
// used yet.
226+
apiServerHost := clusterProviderSpec.APIServerLoadBalancerFloatingIP
227+
apiServerPort := clusterProviderSpec.APIServerLoadBalancerPort
228+
if clusterProviderSpec.ManagedAPIServerLoadBalancer {
229+
if clusterProviderStatus.Network != nil && clusterProviderStatus.Network.APIServerLoadBalancer != nil &&
230+
apiServerHost != clusterProviderStatus.Network.APIServerLoadBalancer.IP {
231+
return fmt.Errorf("APIServerLoadBalancer has IP %s instead of IP %s", clusterProviderStatus.Network.APIServerLoadBalancer.IP, apiServerHost)
232+
}
233+
}
234+
// Check if API endpoints is not set or has changed.
235+
if len(cluster.Status.APIEndpoints) == 0 || cluster.Status.APIEndpoints[0].Host != apiServerHost {
236+
cluster.Status.APIEndpoints = []clusterv1.APIEndpoint{
237+
{
238+
Host: apiServerHost,
239+
Port: apiServerPort,
240+
},
241+
}
242+
}
243+
215244
cluster.Status.ProviderStatus = rawStatus
216245
if !reflect.DeepEqual(cluster.Status, clusterCopy.Status) {
217246
klog.Infof("Updating cluster status %s", cluster.Name)

0 commit comments

Comments
 (0)