@@ -38,6 +38,51 @@ type portSpace struct {
3838 dynamicPortSpace * idm.Idm
3939}
4040
41+ type allocatedPorts map [api.PortConfig ]map [uint32 ]* api.PortConfig
42+
43+ func (ps allocatedPorts ) addState (p * api.PortConfig ) {
44+ portKey := getPortConfigKey (p )
45+ if _ , ok := ps [portKey ]; ! ok {
46+ ps [portKey ] = make (map [uint32 ]* api.PortConfig )
47+ }
48+ ps [portKey ][p.PublishedPort ] = p
49+ }
50+
51+ func (ps allocatedPorts ) delState (p * api.PortConfig ) * api.PortConfig {
52+ portKey := getPortConfigKey (p )
53+
54+ portStateMap , ok := ps [portKey ]
55+
56+ // If name, port, protocol values don't match then we
57+ // are not allocated.
58+ if ! ok {
59+ return nil
60+ }
61+
62+ if p .PublishedPort != 0 {
63+ // If SwarmPort was user defined but the port state
64+ // SwarmPort doesn't match we are not allocated.
65+ v := portStateMap [p .PublishedPort ]
66+
67+ // Delete state from allocatedPorts
68+ delete (portStateMap , p .PublishedPort )
69+
70+ return v
71+ }
72+
73+ // If PublishedPort == 0 and we don't have non-zero port
74+ // then we are not allocated
75+ for publishedPort , v := range portStateMap {
76+ if publishedPort != 0 {
77+ // Delete state from allocatedPorts
78+ delete (portStateMap , publishedPort )
79+ return v
80+ }
81+ }
82+
83+ return nil
84+ }
85+
4186func newPortAllocator () (* portAllocator , error ) {
4287 portSpaces := make (map [api.PortConfig_Protocol ]* portSpace )
4388 for _ , protocol := range []api.PortConfig_Protocol {api .ProtocolTCP , api .ProtocolUDP } {
@@ -91,40 +136,53 @@ func reconcilePortConfigs(s *api.Service) []*api.PortConfig {
91136 return s .Spec .Endpoint .Ports
92137 }
93138
94- allocatedPorts := make ( map [api. PortConfig ] * api. PortConfig )
139+ portStates := allocatedPorts {}
95140 for _ , portState := range s .Endpoint .Ports {
96- if portState .PublishMode ! = api .PublishModeIngress {
97- continue
141+ if portState .PublishMode = = api .PublishModeIngress {
142+ portStates . addState ( portState )
98143 }
99-
100- allocatedPorts [getPortConfigKey (portState )] = portState
101144 }
102145
103146 var portConfigs []* api.PortConfig
147+
148+ // Process the portConfig with portConfig.PublishMode != api.PublishModeIngress
149+ // and PublishedPort != 0 (high priority)
104150 for _ , portConfig := range s .Spec .Endpoint .Ports {
105- // If the PublishMode is not Ingress simply pick up
106- // the port config.
107151 if portConfig .PublishMode != api .PublishModeIngress {
152+ // If the PublishMode is not Ingress simply pick up the port config.
108153 portConfigs = append (portConfigs , portConfig )
109- continue
110- }
154+ } else if portConfig . PublishedPort != 0 {
155+ // Otherwise we only process PublishedPort != 0 in this round
111156
112- portState , ok := allocatedPorts [getPortConfigKey (portConfig )]
113-
114- // If the portConfig is exactly the same as portState
115- // except if SwarmPort is not user-define then prefer
116- // portState to ensure sticky allocation of the same
117- // port that was allocated before.
118- if ok && portConfig .Name == portState .Name &&
119- portConfig .TargetPort == portState .TargetPort &&
120- portConfig .Protocol == portState .Protocol &&
121- portConfig .PublishedPort == 0 {
122- portConfigs = append (portConfigs , portState )
123- continue
157+ // Remove record from portState
158+ portStates .delState (portConfig )
159+
160+ // For PublishedPort != 0 prefer the portConfig
161+ portConfigs = append (portConfigs , portConfig )
124162 }
163+ }
125164
126- // For all other cases prefer the portConfig
127- portConfigs = append (portConfigs , portConfig )
165+ // Iterate portConfigs with PublishedPort == 0 (low priority)
166+ for _ , portConfig := range s .Spec .Endpoint .Ports {
167+ // Ignore ports which are not PublishModeIngress (already processed)
168+ // And we only process PublishedPort == 0 in this round
169+ // So the following:
170+ // `portConfig.PublishMode == api.PublishModeIngress && portConfig.PublishedPort == 0`
171+ if portConfig .PublishMode == api .PublishModeIngress && portConfig .PublishedPort == 0 {
172+ // If the portConfig is exactly the same as portState
173+ // except if SwarmPort is not user-define then prefer
174+ // portState to ensure sticky allocation of the same
175+ // port that was allocated before.
176+
177+ // Remove record from portState
178+ if portState := portStates .delState (portConfig ); portState != nil {
179+ portConfigs = append (portConfigs , portState )
180+ continue
181+ }
182+
183+ // For all other cases prefer the portConfig
184+ portConfigs = append (portConfigs , portConfig )
185+ }
128186 }
129187
130188 return portConfigs
@@ -213,40 +271,31 @@ func (pa *portAllocator) isPortsAllocated(s *api.Service) bool {
213271 return false
214272 }
215273
216- allocatedPorts := make ( map [api. PortConfig ] * api. PortConfig )
274+ portStates := allocatedPorts {}
217275 for _ , portState := range s .Endpoint .Ports {
218- if portState .PublishMode ! = api .PublishModeIngress {
219- continue
276+ if portState .PublishMode = = api .PublishModeIngress {
277+ portStates . addState ( portState )
220278 }
221-
222- allocatedPorts [getPortConfigKey (portState )] = portState
223279 }
224280
281+ // Iterate portConfigs with PublishedPort != 0 (high priority)
225282 for _ , portConfig := range s .Spec .Endpoint .Ports {
226283 // Ignore ports which are not PublishModeIngress
227284 if portConfig .PublishMode != api .PublishModeIngress {
228285 continue
229286 }
230-
231- portState , ok := allocatedPorts [getPortConfigKey (portConfig )]
232-
233- // If name, port, protocol values don't match then we
234- // are not allocated.
235- if ! ok {
287+ if portConfig .PublishedPort != 0 && portStates .delState (portConfig ) == nil {
236288 return false
237289 }
290+ }
238291
239- // If SwarmPort was user defined but the port state
240- // SwarmPort doesn't match we are not allocated.
241- if portConfig . PublishedPort != portState . PublishedPort &&
242- portConfig .PublishedPort != 0 {
243- return false
292+ // Iterate portConfigs with PublishedPort == 0 (low priority)
293+ for _ , portConfig := range s . Spec . Endpoint . Ports {
294+ // Ignore ports which are not PublishModeIngress
295+ if portConfig .PublishMode != api . PublishModeIngress {
296+ continue
244297 }
245-
246- // If SwarmPort was not defined by user and port state
247- // is not initialized with a valid SwarmPort value then
248- // we are not allocated.
249- if portConfig .PublishedPort == 0 && portState .PublishedPort == 0 {
298+ if portConfig .PublishedPort == 0 && portStates .delState (portConfig ) == nil {
250299 return false
251300 }
252301 }
0 commit comments