@@ -126,9 +126,12 @@ func (s *Service) GetPortForExternalNetwork(instanceID string, externalNetworkID
126126
127127// ensurePortTagsAndTrunk ensures that the provided port has the tags and trunk defined in portSpec.
128128func (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 )
132135 return err
133136 }
134137 }
@@ -138,21 +141,30 @@ func (s *Service) ensurePortTagsAndTrunk(port *ports.Port, eventObject runtime.O
138141 record .Warnf (eventObject , "FailedCreateTrunk" , "Failed to create trunk for port %s: %v" , port .Name , err )
139142 return err
140143 }
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+ }
144150 }
145151 }
146152 return nil
147153}
148154
149155// 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 {
153160 Name : portSpec .Name ,
154161 NetworkID : portSpec .NetworkID ,
155- })
162+ }
163+ if portStatus .ID != "" {
164+ opts .ID = portStatus .ID
165+ }
166+
167+ existingPorts , err := s .client .ListPort (opts )
156168 if err != nil {
157169 return nil , fmt .Errorf ("searching for existing port for server: %v" , err )
158170 }
@@ -359,16 +371,27 @@ func getPortName(baseName string, portSpec *infrav1.PortOpts, netIndex int) stri
359371// EnsurePorts ensures that every one of desiredPorts is created and has
360372// expected trunk and tags.
361373func (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+ }
363380 // Events are recorded in EnsurePort
364- port , err := s .EnsurePort (eventObject , & portSpec )
381+ port , err := s .EnsurePort (eventObject , & desiredPorts [ i ], portStatus )
365382 if err != nil {
366383 return err
367384 }
368385
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+ }
372395 }
373396
374397 return nil
@@ -628,3 +651,19 @@ func (s *Service) AdoptPortsServer(scope *scope.WithLogger, desiredPorts []infra
628651
629652 return nil
630653}
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