Skip to content

Commit

Permalink
Merge pull request #2261 from kubernetes-sigs/issue_2260
Browse files Browse the repository at this point in the history
🐛 Better checks before creating Floating IPs
  • Loading branch information
k8s-ci-robot authored Nov 22, 2024
2 parents 7518781 + 5429b4b commit dc71d68
Show file tree
Hide file tree
Showing 8 changed files with 62 additions and 4 deletions.
2 changes: 2 additions & 0 deletions api/v1beta1/openstackcluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ const (
)

// OpenStackClusterSpec defines the desired state of OpenStackCluster.
// +kubebuilder:validation:XValidation:rule="has(self.disableExternalNetwork) && self.disableExternalNetwork ? !has(self.bastion) || !has(self.bastion.floatingIP) : true",message="bastion floating IP cannot be set when disableExternalNetwork is true"
// +kubebuilder:validation:XValidation:rule="has(self.disableExternalNetwork) && self.disableExternalNetwork ? has(self.disableAPIServerFloatingIP) && self.disableAPIServerFloatingIP : true",message="disableAPIServerFloatingIP cannot be false when disableExternalNetwork is true"
type OpenStackClusterSpec struct {
// ManagedSubnets describe OpenStack Subnets to be created. Cluster actuator will create a network,
// subnets with the defined CIDR, and a router connected to these subnets. Currently only one IPv4
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 7 additions & 3 deletions controllers/openstackcluster_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,11 @@ func (r *OpenStackClusterReconciler) reconcileBastion(ctx context.Context, scope
return nil, err
}

return bastionAddFloatingIP(openStackCluster, clusterResourceName, port, networkingService)
if !ptr.Deref(openStackCluster.Spec.DisableExternalNetwork, false) {
return bastionAddFloatingIP(openStackCluster, clusterResourceName, port, networkingService)
}

return nil, nil
}

func bastionAddFloatingIP(openStackCluster *infrav1.OpenStackCluster, clusterResourceName string, port *ports.Port, networkingService *networking.Service) (*reconcile.Result, error) {
Expand Down Expand Up @@ -798,9 +802,9 @@ func reconcileControlPlaneEndpoint(scope *scope.WithLogger, networkingService *n
case openStackCluster.Spec.ControlPlaneEndpoint != nil && openStackCluster.Spec.ControlPlaneEndpoint.IsValid():
host = openStackCluster.Spec.ControlPlaneEndpoint.Host

// API server load balancer is disabled, but floating IP is not. Create
// API server load balancer is disabled, but external netowork and floating IP are not. Create
// a floating IP to be attached directly to a control plane host.
case !ptr.Deref(openStackCluster.Spec.DisableAPIServerFloatingIP, false):
case !ptr.Deref(openStackCluster.Spec.DisableAPIServerFloatingIP, false) && !ptr.Deref(openStackCluster.Spec.DisableExternalNetwork, false):
fp, err := networkingService.GetOrCreateFloatingIP(openStackCluster, openStackCluster, clusterResourceName, openStackCluster.Spec.APIServerFloatingIP)
if err != nil {
handleUpdateOSCError(openStackCluster, fmt.Errorf("floating IP cannot be got or created: %w", err), false)
Expand Down
2 changes: 1 addition & 1 deletion controllers/openstackmachine_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -628,7 +628,7 @@ func (r *OpenStackMachineReconciler) reconcileAPIServerLoadBalancer(scope *scope
conditions.MarkFalse(openStackMachine, infrav1.APIServerIngressReadyCondition, infrav1.LoadBalancerMemberErrorReason, clusterv1.ConditionSeverityError, "Reconciling load balancer member failed: %v", err)
return fmt.Errorf("reconcile load balancer member: %w", err)
}
} else if !ptr.Deref(openStackCluster.Spec.DisableAPIServerFloatingIP, false) {
} else if !ptr.Deref(openStackCluster.Spec.DisableAPIServerFloatingIP, false) && !ptr.Deref(openStackCluster.Spec.DisableExternalNetwork, false) {
var floatingIPAddress *string
switch {
case openStackCluster.Spec.ControlPlaneEndpoint != nil && openStackCluster.Spec.ControlPlaneEndpoint.IsValid():
Expand Down
4 changes: 4 additions & 0 deletions docs/book/src/clusteropenstack/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,8 @@ associated to the first controller node and the other controller nodes have no f
to any other controller node. So we recommend to only set one controller node when floating IP is needed,
or please consider using load balancer instead, see [issue #1265](https://github.com/kubernetes-sigs/cluster-api-provider-openstack/issues/1265) for further information.

Note: `spec.disableExternalNetwork` must be unset or set to `false` to allow the API server to have a floating IP.

### Disabling the API server floating IP

It is possible to provision a cluster without a floating IP for the API server by setting
Expand Down Expand Up @@ -717,6 +719,8 @@ spec:
floatingIP: <Floating IP address>
```

Note: A floating IP can only be added if `OpenStackCluster.Spec.DisableExternalNetwork` is not set or set to `false`.

If `managedSecurityGroups` is set to a non-nil value (e.g. `{}`), security group rule opening 22/tcp is added to security groups for bastion, controller, and worker nodes respectively. Otherwise, you have to add `securityGroups` to the `bastion` in `OpenStackCluster` spec and `OpenStackMachineTemplate` spec template respectively.

### Making changes to the bastion host
Expand Down
5 changes: 5 additions & 0 deletions pkg/cloud/services/networking/floatingip.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ func (s *Service) GetOrCreateFloatingIP(eventObject runtime.Object, openStackClu
var err error
var fpCreateOpts floatingips.CreateOpts

// This is a safeguard, we shouldn't reach it and if we do, it's something to fix in the caller of the function.
if openStackCluster.Status.ExternalNetwork == nil {
return nil, fmt.Errorf("external network not found")
}

if ptr.Deref(ip, "") != "" {
fp, err = s.GetFloatingIP(*ip)
if err != nil {
Expand Down
23 changes: 23 additions & 0 deletions test/e2e/suites/apivalidations/openstackcluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,29 @@ var _ = Describe("OpenStackCluster API validations", func() {
Expect(createObj(cluster)).NotTo(Succeed(), "OpenStackCluster creation should not succeed")
})

It("should not allow a bastion floating IP with DisableExternalNetwork set to true", func() {
cluster.Spec.Bastion = &infrav1.Bastion{
Enabled: ptr.To(true),
Spec: &infrav1.OpenStackMachineSpec{
Flavor: ptr.To("flavor-name"),
Image: infrav1.ImageParam{
Filter: &infrav1.ImageFilter{
Name: ptr.To("fake-image"),
},
},
},
FloatingIP: ptr.To("10.0.0.0"),
}
cluster.Spec.DisableExternalNetwork = ptr.To(true)
Expect(createObj(cluster)).ToNot(Succeed(), "OpenStackCluster creation should not succeed")
})

It("should not allow DisableAPIServerFloatingIP to be false with DisableExternalNetwork set to true", func() {
cluster.Spec.DisableAPIServerFloatingIP = ptr.To(false)
cluster.Spec.DisableExternalNetwork = ptr.To(true)
Expect(createObj(cluster)).ToNot(Succeed(), "OpenStackCluster creation should not succeed")
})

// We must use unstructured to set values which can't be marshalled by the Go type
unstructuredClusterWithAPIPort := func(apiServerPort any) *unstructured.Unstructured {
obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(cluster)
Expand Down

0 comments on commit dc71d68

Please sign in to comment.