@@ -126,9 +126,12 @@ func (s *Service) GetPortForExternalNetwork(instanceID string, externalNetworkID
126
126
127
127
// ensurePortTagsAndTrunk ensures that the provided port has the tags and trunk defined in portSpec.
128
128
func (s * Service ) ensurePortTagsAndTrunk (port * ports.Port , eventObject runtime.Object , portSpec * infrav1.ResolvedPortSpec ) error {
129
- if len (portSpec .Tags ) > 0 {
130
- if err := s .replaceAllAttributesTags (eventObject , portResource , port .ID , portSpec .Tags ); err != nil {
131
- record .Warnf (eventObject , "FailedReplaceTags" , "Failed to replace port tags %s: %v" , portSpec .Name , err )
129
+ wantedTags := uniqueSortedTags (portSpec .Tags )
130
+ actualTags := uniqueSortedTags (port .Tags )
131
+ // Only replace tags if there is a difference
132
+ if ! slices .Equal (wantedTags , actualTags ) && len (wantedTags ) > 0 {
133
+ if err := s .replaceAllAttributesTags (eventObject , portResource , port .ID , wantedTags ); err != nil {
134
+ record .Warnf (eventObject , "FailedReplaceTags" , "Failed to replace port tags %s: %v" , port .Name , err )
132
135
return err
133
136
}
134
137
}
@@ -138,21 +141,30 @@ func (s *Service) ensurePortTagsAndTrunk(port *ports.Port, eventObject runtime.O
138
141
record .Warnf (eventObject , "FailedCreateTrunk" , "Failed to create trunk for port %s: %v" , port .Name , err )
139
142
return err
140
143
}
141
- if err = s .replaceAllAttributesTags (eventObject , trunkResource , trunk .ID , portSpec .Tags ); err != nil {
142
- record .Warnf (eventObject , "FailedReplaceTags" , "Failed to replace trunk tags %s: %v" , port .Name , err )
143
- return err
144
+
145
+ if ! slices .Equal (wantedTags , trunk .Tags ) {
146
+ if err = s .replaceAllAttributesTags (eventObject , trunkResource , trunk .ID , wantedTags ); err != nil {
147
+ record .Warnf (eventObject , "FailedReplaceTags" , "Failed to replace trunk tags %s: %v" , port .Name , err )
148
+ return err
149
+ }
144
150
}
145
151
}
146
152
return nil
147
153
}
148
154
149
155
// EnsurePort ensure that a port defined with portSpec Name and NetworkID exists,
150
- // and that the port has suitable tags and trunk.
151
- func (s * Service ) EnsurePort (eventObject runtime.Object , portSpec * infrav1.ResolvedPortSpec ) (* ports.Port , error ) {
152
- existingPorts , err := s .client .ListPort (ports.ListOpts {
156
+ // and that the port has suitable tags and trunk. If the PortStatus is already known,
157
+ // use the ID when filtering for existing ports.
158
+ func (s * Service ) EnsurePort (eventObject runtime.Object , portSpec * infrav1.ResolvedPortSpec , portStatus infrav1.PortStatus ) (* ports.Port , error ) {
159
+ opts := ports.ListOpts {
153
160
Name : portSpec .Name ,
154
161
NetworkID : portSpec .NetworkID ,
155
- })
162
+ }
163
+ if portStatus .ID != "" {
164
+ opts .ID = portStatus .ID
165
+ }
166
+
167
+ existingPorts , err := s .client .ListPort (opts )
156
168
if err != nil {
157
169
return nil , fmt .Errorf ("searching for existing port for server: %v" , err )
158
170
}
@@ -359,16 +371,27 @@ func getPortName(baseName string, portSpec *infrav1.PortOpts, netIndex int) stri
359
371
// EnsurePorts ensures that every one of desiredPorts is created and has
360
372
// expected trunk and tags.
361
373
func (s * Service ) EnsurePorts (eventObject runtime.Object , desiredPorts []infrav1.ResolvedPortSpec , resources * infrav1alpha1.ServerResources ) error {
362
- for _ , portSpec := range desiredPorts {
374
+ for i := range desiredPorts {
375
+ // If we already created the port, make use of the status
376
+ portStatus := infrav1.PortStatus {}
377
+ if i < len (resources .Ports ) {
378
+ portStatus = resources .Ports [i ]
379
+ }
363
380
// Events are recorded in EnsurePort
364
- port , err := s .EnsurePort (eventObject , & portSpec )
381
+ port , err := s .EnsurePort (eventObject , & desiredPorts [ i ], portStatus )
365
382
if err != nil {
366
383
return err
367
384
}
368
385
369
- resources .Ports = append (resources .Ports , infrav1.PortStatus {
370
- ID : port .ID ,
371
- })
386
+ // If we already have the status, replace it,
387
+ // otherwise append it.
388
+ if i < len (resources .Ports ) {
389
+ resources .Ports [i ] = portStatus
390
+ } else {
391
+ resources .Ports = append (resources .Ports , infrav1.PortStatus {
392
+ ID : port .ID ,
393
+ })
394
+ }
372
395
}
373
396
374
397
return nil
@@ -628,3 +651,19 @@ func (s *Service) AdoptPortsServer(scope *scope.WithLogger, desiredPorts []infra
628
651
629
652
return nil
630
653
}
654
+
655
+ // uniqueSortedTags returns a new, sorted slice where any duplicates have been removed.
656
+ func uniqueSortedTags (tags []string ) []string {
657
+ // remove duplicate values from tags
658
+ tagsMap := make (map [string ]string )
659
+ for _ , t := range tags {
660
+ tagsMap [t ] = t
661
+ }
662
+
663
+ uniqueTags := []string {}
664
+ for k := range tagsMap {
665
+ uniqueTags = append (uniqueTags , k )
666
+ }
667
+ slices .Sort (uniqueTags )
668
+ return uniqueTags
669
+ }
0 commit comments