@@ -38,6 +38,54 @@ 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 , ok := portStateMap [p .PublishedPort ]
66+
67+ if ! ok {
68+ return nil
69+ }
70+ // Dlete state from allocatedPorts
71+ delete (ps [portKey ], p .PublishedPort )
72+
73+ return v
74+ }
75+
76+ // If PublishedPort == 0 and we don't have non-zero port
77+ // then we are not allocated
78+ for publishedPort , v := range portStateMap {
79+ if publishedPort != 0 {
80+ // Dlete state from allocatedPorts
81+ delete (ps [portKey ], publishedPort )
82+ return v
83+ }
84+ }
85+
86+ return nil
87+ }
88+
4189func newPortAllocator () (* portAllocator , error ) {
4290 portSpaces := make (map [api.PortConfig_Protocol ]* portSpace )
4391 for _ , protocol := range []api.PortConfig_Protocol {api .ProtocolTCP , api .ProtocolUDP } {
@@ -73,7 +121,7 @@ func newPortSpace(protocol api.PortConfig_Protocol) (*portSpace, error) {
73121 }, nil
74122}
75123
76- // getPortConfigKey returns a map key for doing set operations with
124+ // getPortConfigkey returns a map key for doing set operations with
77125// ports. The key consists of name, protocol and target port which
78126// uniquely identifies a port within a single Endpoint.
79127func getPortConfigKey (p * api.PortConfig ) api.PortConfig {
@@ -91,40 +139,55 @@ func reconcilePortConfigs(s *api.Service) []*api.PortConfig {
91139 return s .Spec .Endpoint .Ports
92140 }
93141
94- allocatedPorts := make ( map [api. PortConfig ] * api. PortConfig )
142+ portStates := allocatedPorts {}
95143 for _ , portState := range s .Endpoint .Ports {
96144 if portState .PublishMode != api .PublishModeIngress {
97145 continue
98146 }
99-
100- allocatedPorts [getPortConfigKey (portState )] = portState
147+ portStates .addState (portState )
101148 }
102149
103150 var portConfigs []* api.PortConfig
151+
152+ // Process the portConfig with portConfig.PublishMode != api.PublishModeIngress
153+ // and PublishedPort != 0 (high priority)
104154 for _ , portConfig := range s .Spec .Endpoint .Ports {
105155 // If the PublishMode is not Ingress simply pick up
106156 // the port config.
107157 if portConfig .PublishMode != api .PublishModeIngress {
108158 portConfigs = append (portConfigs , portConfig )
109159 continue
110160 }
161+ if portConfig .PublishedPort != 0 {
162+ // Remove record from portState
163+ portStates .delState (portConfig )
111164
112- portState , ok := allocatedPorts [getPortConfigKey (portConfig )]
165+ // For PublishedPort != 0 prefer the portConfig
166+ portConfigs = append (portConfigs , portConfig )
167+ }
168+ }
169+
170+ // Iterate portConfigs with PublishedPort == 0 (low priority)
171+ for _ , portConfig := range s .Spec .Endpoint .Ports {
172+ // Ignore ports which are not PublishModeIngress (already processed)
173+ if portConfig .PublishMode != api .PublishModeIngress {
174+ continue
175+ }
113176
114177 // If the portConfig is exactly the same as portState
115178 // except if SwarmPort is not user-define then prefer
116179 // portState to ensure sticky allocation of the same
117180 // 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
124- }
181+ if portConfig .PublishedPort == 0 {
182+ // Remove record from portState
183+ if portState := portStates .delState (portConfig ); portState != nil {
184+ portConfigs = append (portConfigs , portState )
185+ continue
186+ }
125187
126- // For all other cases prefer the portConfig
127- portConfigs = append (portConfigs , portConfig )
188+ // For all other cases prefer the portConfig
189+ portConfigs = append (portConfigs , portConfig )
190+ }
128191 }
129192
130193 return portConfigs
@@ -213,40 +276,32 @@ func (pa *portAllocator) isPortsAllocated(s *api.Service) bool {
213276 return false
214277 }
215278
216- allocatedPorts := make ( map [api. PortConfig ] * api. PortConfig )
279+ portStates := allocatedPorts {}
217280 for _ , portState := range s .Endpoint .Ports {
218281 if portState .PublishMode != api .PublishModeIngress {
219282 continue
220283 }
221-
222- allocatedPorts [getPortConfigKey (portState )] = portState
284+ portStates .addState (portState )
223285 }
224286
287+ // Iterate portConfigs with PublishedPort != 0 (high priority)
225288 for _ , portConfig := range s .Spec .Endpoint .Ports {
226289 // Ignore ports which are not PublishModeIngress
227290 if portConfig .PublishMode != api .PublishModeIngress {
228291 continue
229292 }
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 {
293+ if portConfig .PublishedPort != 0 && portStates .delState (portConfig ) == nil {
236294 return false
237295 }
296+ }
238297
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
298+ // Iterate portConfigs with PublishedPort == 0 (low priority)
299+ for _ , portConfig := range s . Spec . Endpoint . Ports {
300+ // Ignore ports which are not PublishModeIngress
301+ if portConfig .PublishMode != api . PublishModeIngress {
302+ continue
244303 }
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 {
304+ if portConfig .PublishedPort == 0 && portStates .delState (portConfig ) == nil {
250305 return false
251306 }
252307 }
0 commit comments