Skip to content

Commit db13cf1

Browse files
committed
WIP - move ports out of instance
1 parent a873934 commit db13cf1

18 files changed

+846
-107
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.PortsStatus = nil
448+
449+
return nil
450+
}

api/v1alpha5/zz_generated.conversion.go

Lines changed: 1 addition & 5 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.PortsStatus = nil
670+
671+
return nil
672+
}

api/v1alpha6/zz_generated.conversion.go

Lines changed: 1 addition & 5 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: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ const (
2222
// InstanceReadyCondition reports on current status of the OpenStack instance. Ready indicates the instance is in a Running state.
2323
InstanceReadyCondition clusterv1.ConditionType = "InstanceReady"
2424

25+
// PortsReadyCondition reports on the current status of the ports. Ready indicates that all ports have been created
26+
// successfully and ready to be attached to the instance.
27+
PortsReadyCondition clusterv1.ConditionType = "PortsReady"
28+
2529
// WaitingForClusterInfrastructureReason used when machine is waiting for cluster infrastructure to be ready before proceeding.
2630
WaitingForClusterInfrastructureReason = "WaitingForClusterInfrastructure"
2731
// WaitingForBootstrapDataReason used when machine is waiting for bootstrap data to be ready before proceeding.
@@ -42,6 +46,8 @@ const (
4246
InstanceDeleteFailedReason = "InstanceDeleteFailed"
4347
// OpenstackErrorReason used when there is an error communicating with OpenStack.
4448
OpenStackErrorReason = "OpenStackError"
49+
// PortsCreateFailedReason used when creating the ports failed.
50+
PortsCreateFailedReason = "PortsCreateFailed"
4551
)
4652

4753
const (

api/v1alpha7/openstackmachine_types.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@ type OpenStackMachineStatus struct {
113113

114114
FailureReason *errors.MachineStatusError `json:"failureReason,omitempty"`
115115

116+
// PortsStatus is the status of the ports associated with the machine.
117+
// +optional
118+
PortsStatus []PortStatus `json:"portsStatus,omitempty"`
119+
116120
// FailureMessage will be set in the event that there is a terminal problem
117121
// reconciling the Machine and will contain a more verbose string suitable
118122
// for logging and human consumption.

api/v1alpha7/types.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,12 @@ type PortOpts struct {
128128
ValueSpecs []ValueSpec `json:"valueSpecs,omitempty"`
129129
}
130130

131+
type PortStatus struct {
132+
// ID is the unique identifier of the port.
133+
// +optional
134+
ID string `json:"id,omitempty"`
135+
}
136+
131137
type BindingProfile struct {
132138
// OVSHWOffload enables or disables the OVS hardware offload feature.
133139
OVSHWOffload bool `json:"ovsHWOffload,omitempty"`

api/v1alpha7/zz_generated.deepcopy.go

Lines changed: 20 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: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1603,6 +1603,16 @@ spec:
16031603
description: InstanceState is the state of the OpenStack instance
16041604
for this machine.
16051605
type: string
1606+
portsStatus:
1607+
description: PortsStatus is the status of the ports associated with
1608+
the machine.
1609+
items:
1610+
properties:
1611+
id:
1612+
description: ID is the unique identifier of the port.
1613+
type: string
1614+
type: object
1615+
type: array
16061616
ready:
16071617
description: Ready is true when the provider resource is ready.
16081618
type: boolean

controllers/openstackcluster_controller.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ func reconcileBastion(scope scope.Scope, cluster *clusterv1.Cluster, openStackCl
349349
}
350350
}
351351

352-
instanceStatus, err = computeService.CreateInstance(openStackCluster, openStackCluster, instanceSpec, cluster.Name)
352+
instanceStatus, err = computeService.CreateInstance(openStackCluster, openStackCluster, instanceSpec, cluster.Name, []string{})
353353
if err != nil {
354354
return fmt.Errorf("failed to reconcile bastion: %w", err)
355355
}

controllers/openstackmachine_controller.go

Lines changed: 77 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -328,9 +328,24 @@ func (r *OpenStackMachineReconciler) reconcileNormal(ctx context.Context, scope
328328
return ctrl.Result{}, err
329329
}
330330

331-
instanceStatus, err := r.getOrCreate(scope.Logger(), cluster, openStackCluster, machine, openStackMachine, computeService, userData)
331+
managedSecurityGroups := getManagedSecurityGroups(openStackCluster, machine, openStackMachine)
332+
instanceTags := getInstanceTags(openStackMachine, openStackCluster)
333+
portsStatus, err := r.getOrCreatePorts(scope.Logger(), clusterName, openStackCluster, openStackMachine.Spec.Ports, openStackMachine.Spec.Trunk, managedSecurityGroups, instanceTags, openStackMachine.Name, openStackMachine, networkingService)
332334
if err != nil {
333-
// Conditions set in getOrCreate
335+
// Conditions set in getOrCreatePorts
336+
return ctrl.Result{}, err
337+
}
338+
// TODO(emilien) do we want to deal with Ports Status like we do for the nova instance? Might be expensive...
339+
// In the meantime, we consider that ports are ready if they are created.
340+
conditions.MarkTrue(openStackMachine, infrav1.PortsReadyCondition)
341+
portIDs := make([]string, len(*portsStatus))
342+
for i, portStatus := range *portsStatus {
343+
portIDs[i] = portStatus.ID
344+
}
345+
346+
instanceStatus, err := r.getOrCreateInstance(scope.Logger(), cluster, openStackCluster, machine, openStackMachine, computeService, userData, portIDs)
347+
if err != nil {
348+
// Conditions set in getOrCreateInstance
334349
return ctrl.Result{}, err
335350
}
336351

@@ -430,7 +445,33 @@ func (r *OpenStackMachineReconciler) reconcileNormal(ctx context.Context, scope
430445
return ctrl.Result{}, nil
431446
}
432447

433-
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) {
448+
func (r *OpenStackMachineReconciler) getOrCreatePorts(logger logr.Logger, clusterName string, openStackCluster *infrav1.OpenStackCluster, machinePorts []infrav1.PortOpts, trunkEnabled bool, securityGroups []infrav1.SecurityGroupFilter, instanceTags []string, instanceName string, openStackMachine *infrav1.OpenStackMachine, networkingService *networking.Service) (*[]infrav1.PortStatus, error) {
449+
// TODO(emilien) implement portsStatus where we check if the machine has ports created and part of the OpenStackMachine.Status
450+
// Check `GetInstanceStatusByName` as it's done for instances. For each port found in Status, we might want get the port name and verify there is no duplicate.
451+
// If Status is empty, we create the ports and add them to the Status.
452+
// If Status is not empty, we try to adopt the existing ports by checking if the ports are still there and if not, we create them and add them to the Status.
453+
454+
// For now, we create the ports.
455+
var portsStatus *[]infrav1.PortStatus
456+
var err error
457+
458+
if openStackMachine.Status.PortsStatus == nil {
459+
logger.Info("Creating ports for OpenStackMachine", "name", openStackMachine.Name)
460+
portsStatus, err = networkingService.CreatePorts(openStackMachine, clusterName, openStackCluster, machinePorts, trunkEnabled, securityGroups, instanceTags, instanceName)
461+
if err != nil {
462+
// Add Conditions
463+
conditions.MarkFalse(openStackMachine, infrav1.PortsReadyCondition, infrav1.PortsCreateFailedReason, clusterv1.ConditionSeverityError, err.Error())
464+
return nil, fmt.Errorf("create ports: %w", err)
465+
}
466+
}
467+
468+
// TODO(emilien) maybe we want to set PortsStatus in OpenStackMachineStatus here instead of in port.go?
469+
// Major difference of doing it in port.go is that we can add ports one by one into the status instead of all at once in the controller.
470+
471+
return portsStatus, nil
472+
}
473+
474+
func (r *OpenStackMachineReconciler) getOrCreateInstance(logger logr.Logger, cluster *clusterv1.Cluster, openStackCluster *infrav1.OpenStackCluster, machine *clusterv1.Machine, openStackMachine *infrav1.OpenStackMachine, computeService *compute.Service, userData string, portIDs []string) (*compute.InstanceStatus, error) {
434475
instanceStatus, err := computeService.GetInstanceStatusByName(openStackMachine, openStackMachine.Name)
435476
if err != nil {
436477
logger.Info("Unable to get OpenStack instance", "name", openStackMachine.Name)
@@ -441,7 +482,7 @@ func (r *OpenStackMachineReconciler) getOrCreate(logger logr.Logger, cluster *cl
441482
if instanceStatus == nil {
442483
instanceSpec := machineToInstanceSpec(openStackCluster, machine, openStackMachine, userData)
443484
logger.Info("Machine does not exist, creating Machine", "name", openStackMachine.Name)
444-
instanceStatus, err = computeService.CreateInstance(openStackMachine, openStackCluster, instanceSpec, cluster.Name)
485+
instanceStatus, err = computeService.CreateInstance(openStackMachine, openStackCluster, instanceSpec, cluster.Name, portIDs)
445486
if err != nil {
446487
conditions.MarkFalse(openStackMachine, infrav1.InstanceReadyCondition, infrav1.InstanceCreateFailedReason, clusterv1.ConditionSeverityError, err.Error())
447488
return nil, fmt.Errorf("create OpenStack instance: %w", err)
@@ -472,6 +513,19 @@ func machineToInstanceSpec(openStackCluster *infrav1.OpenStackCluster, machine *
472513
instanceSpec.FailureDomain = *machine.Spec.FailureDomain
473514
}
474515

516+
instanceSpec.Tags = getInstanceTags(openStackMachine, openStackCluster)
517+
518+
instanceSpec.SecurityGroups = getManagedSecurityGroups(openStackCluster, machine, openStackMachine)
519+
520+
instanceSpec.Ports = openStackMachine.Spec.Ports
521+
522+
return &instanceSpec
523+
}
524+
525+
// getInstanceTags returns the tags that should be applied to the instance.
526+
// The tags are a combination of the tags specified on the OpenStackMachine and
527+
// the ones specified on the OpenStackCluster.
528+
func getInstanceTags(openStackMachine *infrav1.OpenStackMachine, openStackCluster *infrav1.OpenStackCluster) []string {
475529
machineTags := []string{}
476530

477531
// Append machine specific tags
@@ -494,31 +548,31 @@ func machineToInstanceSpec(openStackCluster *infrav1.OpenStackCluster, machine *
494548
}
495549
machineTags = deduplicate(machineTags)
496550

497-
instanceSpec.Tags = machineTags
551+
return machineTags
552+
}
498553

499-
instanceSpec.SecurityGroups = openStackMachine.Spec.SecurityGroups
500-
if openStackCluster.Spec.ManagedSecurityGroups {
501-
var managedSecurityGroup string
502-
if util.IsControlPlaneMachine(machine) {
503-
if openStackCluster.Status.ControlPlaneSecurityGroup != nil {
504-
managedSecurityGroup = openStackCluster.Status.ControlPlaneSecurityGroup.ID
505-
}
506-
} else {
507-
if openStackCluster.Status.WorkerSecurityGroup != nil {
508-
managedSecurityGroup = openStackCluster.Status.WorkerSecurityGroup.ID
509-
}
554+
// getManagedSecurityGroups returns a combination of OpenStackMachine.Spec.SecurityGroups
555+
// and the security group managed by the OpenStackCluster whether it's a control plane or a worker machine.
556+
func getManagedSecurityGroups(openStackCluster *infrav1.OpenStackCluster, machine *clusterv1.Machine, openStackMachine *infrav1.OpenStackMachine) []infrav1.SecurityGroupFilter {
557+
machineSpecSecurityGroups := openStackMachine.Spec.SecurityGroups
558+
var managedSecurityGroup string
559+
if util.IsControlPlaneMachine(machine) {
560+
if openStackCluster.Status.ControlPlaneSecurityGroup != nil {
561+
managedSecurityGroup = openStackCluster.Status.ControlPlaneSecurityGroup.ID
510562
}
511-
512-
if managedSecurityGroup != "" {
513-
instanceSpec.SecurityGroups = append(instanceSpec.SecurityGroups, infrav1.SecurityGroupFilter{
514-
ID: managedSecurityGroup,
515-
})
563+
} else {
564+
if openStackCluster.Status.WorkerSecurityGroup != nil {
565+
managedSecurityGroup = openStackCluster.Status.WorkerSecurityGroup.ID
516566
}
517567
}
518568

519-
instanceSpec.Ports = openStackMachine.Spec.Ports
569+
if managedSecurityGroup != "" {
570+
machineSpecSecurityGroups = append(machineSpecSecurityGroups, infrav1.SecurityGroupFilter{
571+
ID: managedSecurityGroup,
572+
})
573+
}
520574

521-
return &instanceSpec
575+
return machineSpecSecurityGroups
522576
}
523577

524578
func (r *OpenStackMachineReconciler) reconcileLoadBalancerMember(scope scope.Scope, openStackCluster *infrav1.OpenStackCluster, openStackMachine *infrav1.OpenStackMachine, instanceNS *compute.InstanceNetworkStatus, clusterName string) error {

controllers/suite_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ var _ = Describe("When calling getOrCreate", func() {
151151
openStackMachine := &infrav1.OpenStackMachine{}
152152

153153
mockScopeFactory.ComputeClient.EXPECT().ListServers(gomock.Any()).Return(nil, errors.New("Test error when listing servers"))
154-
instanceStatus, err := reconsiler.getOrCreate(logger, cluster, openStackCluster, machine, openStackMachine, computeService, "")
154+
instanceStatus, err := reconsiler.getOrCreateInstance(logger, cluster, openStackCluster, machine, openStackMachine, computeService, "", []string{})
155155
Expect(err).To(HaveOccurred())
156156
Expect(instanceStatus).To(BeNil())
157157
conditions := openStackMachine.GetConditions()

pkg/clients/networking.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ import (
3636
"sigs.k8s.io/cluster-api-provider-openstack/pkg/metrics"
3737
)
3838

39+
// PortExt is the base gophercloud Port with extensions used by PortStatus.
40+
type PortExt struct {
41+
ports.Port
42+
}
43+
3944
type NetworkClient interface {
4045
ListFloatingIP(opts floatingips.ListOptsBuilder) ([]floatingips.FloatingIP, error)
4146
CreateFloatingIP(opts floatingips.CreateOptsBuilder) (*floatingips.FloatingIP, error)

0 commit comments

Comments
 (0)