Skip to content

Commit 7cbcf4e

Browse files
committed
Reconcile SecurityGroups <-> Instances separately
Originally, we were adding the SecurityGroups to the instanceSpec. Now, the openstackmachine controller will first create the instances without security groups. Then we have a loop that will reconcile the desired security groups that we want to apply in the cluster[1] with the ones that are added to the instance's ports. [1] for now, we have 2 sets of rules: the one that can be added to `OpenStackMachine.Spec.SecurityGroups` and the one managed by `OpenStackCluster.Spec.ManagedSecurityGroups`.
1 parent 70494b6 commit 7cbcf4e

12 files changed

+281
-106
lines changed

api/v1alpha5/conversion.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,3 +437,14 @@ func Convert_v1alpha5_OpenStackClusterStatus_To_v1alpha7_OpenStackClusterStatus(
437437
func Convert_v1alpha7_OpenStackMachineSpec_To_v1alpha5_OpenStackMachineSpec(in *infrav1.OpenStackMachineSpec, out *OpenStackMachineSpec, s conversion.Scope) error {
438438
return autoConvert_v1alpha7_OpenStackMachineSpec_To_v1alpha5_OpenStackMachineSpec(in, out, s)
439439
}
440+
441+
func Convert_v1alpha7_OpenStackMachineStatus_To_v1alpha5_OpenStackMachineStatus(in *infrav1.OpenStackMachineStatus, out *OpenStackMachineStatus, s conversion.Scope) error {
442+
err := autoConvert_v1alpha7_OpenStackMachineStatus_To_v1alpha5_OpenStackMachineStatus(in, out, s)
443+
if err != nil {
444+
return err
445+
}
446+
447+
in.SecurityGroups = nil
448+
449+
return nil
450+
}

api/v1alpha5/zz_generated.conversion.go

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

api/v1alpha6/conversion.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,3 +659,14 @@ func Convert_v1alpha6_OpenStackClusterStatus_To_v1alpha7_OpenStackClusterStatus(
659659
func Convert_v1alpha7_OpenStackMachineSpec_To_v1alpha6_OpenStackMachineSpec(in *infrav1.OpenStackMachineSpec, out *OpenStackMachineSpec, s apiconversion.Scope) error {
660660
return autoConvert_v1alpha7_OpenStackMachineSpec_To_v1alpha6_OpenStackMachineSpec(in, out, s)
661661
}
662+
663+
func Convert_v1alpha7_OpenStackMachineStatus_To_v1alpha6_OpenStackMachineStatus(in *infrav1.OpenStackMachineStatus, out *OpenStackMachineStatus, s apiconversion.Scope) error {
664+
err := autoConvert_v1alpha7_OpenStackMachineStatus_To_v1alpha6_OpenStackMachineStatus(in, out, s)
665+
if err != nil {
666+
return err
667+
}
668+
669+
in.SecurityGroups = nil
670+
671+
return nil
672+
}

api/v1alpha6/zz_generated.conversion.go

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

api/v1alpha7/conditions_consts.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ const (
4242
InstanceDeleteFailedReason = "InstanceDeleteFailed"
4343
// OpenstackErrorReason used when there is an error communicating with OpenStack.
4444
OpenStackErrorReason = "OpenStackError"
45+
// SecurityGroupAppliedFailedCondition used when the security group could not be applied.
46+
SecurityGroupApplyFailedReason = "SecurityGroupAppliedFailed"
4547
)
4648

4749
const (

api/v1alpha7/openstackmachine_types.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,11 @@ type OpenStackMachineStatus struct {
111111
// +optional
112112
InstanceState *InstanceState `json:"instanceState,omitempty"`
113113

114+
// SecurityGroups is the list of security groups that were applied to the ports
115+
// attached to the instance.
116+
// +optional
117+
SecurityGroups []SecurityGroup `json:"securityGroups,omitempty"`
118+
114119
FailureReason *errors.MachineStatusError `json:"failureReason,omitempty"`
115120

116121
// FailureMessage will be set in the event that there is a terminal problem

api/v1alpha7/zz_generated.deepcopy.go

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

config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachines.yaml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1606,6 +1606,61 @@ spec:
16061606
ready:
16071607
description: Ready is true when the provider resource is ready.
16081608
type: boolean
1609+
securityGroups:
1610+
description: SecurityGroups is the list of security groups that were
1611+
applied to the ports attached to the instance.
1612+
items:
1613+
description: SecurityGroup represents the basic information of the
1614+
associated OpenStack Neutron Security Group.
1615+
properties:
1616+
id:
1617+
type: string
1618+
name:
1619+
type: string
1620+
rules:
1621+
items:
1622+
description: SecurityGroupRule represent the basic information
1623+
of the associated OpenStack Security Group Role.
1624+
properties:
1625+
description:
1626+
type: string
1627+
direction:
1628+
type: string
1629+
etherType:
1630+
type: string
1631+
name:
1632+
type: string
1633+
portRangeMax:
1634+
type: integer
1635+
portRangeMin:
1636+
type: integer
1637+
protocol:
1638+
type: string
1639+
remoteGroupID:
1640+
type: string
1641+
remoteIPPrefix:
1642+
type: string
1643+
securityGroupID:
1644+
type: string
1645+
required:
1646+
- description
1647+
- direction
1648+
- etherType
1649+
- name
1650+
- portRangeMax
1651+
- portRangeMin
1652+
- protocol
1653+
- remoteGroupID
1654+
- remoteIPPrefix
1655+
- securityGroupID
1656+
type: object
1657+
type: array
1658+
required:
1659+
- id
1660+
- name
1661+
- rules
1662+
type: object
1663+
type: array
16091664
type: object
16101665
type: object
16111666
served: true

controllers/openstackmachine_controller.go

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,12 @@ func (r *OpenStackMachineReconciler) reconcileNormal(ctx context.Context, scope
334334
return ctrl.Result{}, err
335335
}
336336

337+
err = r.reconcileSecurityGroupsToInstance(scope.Logger(), openStackCluster, machine, openStackMachine, instanceStatus, computeService, networkingService)
338+
if err != nil {
339+
conditions.MarkFalse(openStackMachine, infrav1.InstanceReadyCondition, infrav1.SecurityGroupApplyFailedReason, clusterv1.ConditionSeverityError, "Applying security groups failed: %v", err)
340+
return ctrl.Result{}, fmt.Errorf("add security groups to instance: %w", err)
341+
}
342+
337343
// TODO(sbueringer) From CAPA: TODO(ncdc): move this validation logic into a validating webhook (for us: create validation logic in webhook)
338344

339345
openStackMachine.Spec.ProviderID = pointer.String(fmt.Sprintf("openstack:///%s", instanceStatus.ID()))
@@ -430,6 +436,56 @@ func (r *OpenStackMachineReconciler) reconcileNormal(ctx context.Context, scope
430436
return ctrl.Result{}, nil
431437
}
432438

439+
func (r *OpenStackMachineReconciler) reconcileSecurityGroupsToInstance(logger logr.Logger, openStackCluster *infrav1.OpenStackCluster, machine *clusterv1.Machine, openStackMachine *infrav1.OpenStackMachine, instanceStatus *compute.InstanceStatus, computeService *compute.Service, networkingService *networking.Service) error {
440+
logger.Info("Reconciling security groups to instance")
441+
442+
desiredSecurityGroups := []*infrav1.SecurityGroup{}
443+
444+
// These security groups are currently not managed by CAPO and provided by the user
445+
// Later we'll have an API to manage them.
446+
for _, sg := range openStackMachine.Spec.SecurityGroups {
447+
if sg.ID == "" {
448+
// lookup security group by name
449+
securityGroup, err := networkingService.GetSecurityGroupByName(sg.Name)
450+
if err != nil {
451+
return fmt.Errorf("get security group %q: %w", sg.Name, err)
452+
}
453+
sg.ID = securityGroup.ID
454+
}
455+
desiredSecurityGroups = append(desiredSecurityGroups, &infrav1.SecurityGroup{
456+
ID: sg.ID,
457+
})
458+
}
459+
460+
if openStackCluster.Spec.ManagedSecurityGroups {
461+
if util.IsControlPlaneMachine(machine) && openStackCluster.Status.ControlPlaneSecurityGroup != nil {
462+
desiredSecurityGroups = append(desiredSecurityGroups, openStackCluster.Status.ControlPlaneSecurityGroup)
463+
} else if openStackCluster.Status.WorkerSecurityGroup != nil {
464+
desiredSecurityGroups = append(desiredSecurityGroups, openStackCluster.Status.WorkerSecurityGroup)
465+
}
466+
}
467+
468+
if len(desiredSecurityGroups) > 0 {
469+
instanceID := instanceStatus.ID()
470+
desiredSecurityGroupsIDs := make([]string, len(desiredSecurityGroups))
471+
for i, sg := range desiredSecurityGroups {
472+
desiredSecurityGroupsIDs[i] = sg.ID
473+
}
474+
// Security Groups are attached to ports, not instances so we need to get the ports first
475+
attachedInterfaces, err := computeService.GetAttachedInterfaces(instanceID)
476+
if err != nil {
477+
return fmt.Errorf("get attached interfaces for instance %q: %w", instanceStatus.Name(), err)
478+
}
479+
err = networkingService.ReconcileSecurityGroupsToInstanceAttachedInterfaces(logger, openStackMachine, attachedInterfaces, desiredSecurityGroupsIDs)
480+
if err != nil {
481+
return fmt.Errorf("reconcile security groups %q to instance %q: %w", desiredSecurityGroupsIDs, instanceStatus.Name(), err)
482+
}
483+
}
484+
485+
logger.Info("Reconciled security groups to instance successfully")
486+
return nil
487+
}
488+
433489
func (r *OpenStackMachineReconciler) getOrCreate(logger logr.Logger, cluster *clusterv1.Cluster, openStackCluster *infrav1.OpenStackCluster, machine *clusterv1.Machine, openStackMachine *infrav1.OpenStackMachine, computeService *compute.Service, userData string) (*compute.InstanceStatus, error) {
434490
instanceStatus, err := computeService.GetInstanceStatusByName(openStackMachine, openStackMachine.Name)
435491
if err != nil {
@@ -496,20 +552,6 @@ func machineToInstanceSpec(openStackCluster *infrav1.OpenStackCluster, machine *
496552

497553
instanceSpec.Tags = machineTags
498554

499-
instanceSpec.SecurityGroups = openStackMachine.Spec.SecurityGroups
500-
if openStackCluster.Spec.ManagedSecurityGroups {
501-
var managedSecurityGroup string
502-
if util.IsControlPlaneMachine(machine) && openStackCluster.Status.ControlPlaneSecurityGroup != nil {
503-
managedSecurityGroup = openStackCluster.Status.ControlPlaneSecurityGroup.ID
504-
} else if openStackCluster.Status.WorkerSecurityGroup != nil {
505-
managedSecurityGroup = openStackCluster.Status.WorkerSecurityGroup.ID
506-
}
507-
508-
instanceSpec.SecurityGroups = append(instanceSpec.SecurityGroups, infrav1.SecurityGroupFilter{
509-
ID: managedSecurityGroup,
510-
})
511-
}
512-
513555
instanceSpec.Ports = openStackMachine.Spec.Ports
514556

515557
return &instanceSpec

0 commit comments

Comments
 (0)