@@ -38,6 +38,71 @@ type portSpace struct {
3838 dynamicPortSpace * idm.Idm
3939}
4040
41+ type allocatedPorts map [api.PortConfig ]map [uint32 ]* api.PortConfig
42+
43+ // addState add the state of an allocated port to the collection.
44+ // `allocatedPorts` is a map of portKey:publishedPort:portState.
45+ // In case the value of the portKey is missing, the map
46+ // publishedPort:portState is created automatically
47+ func (ps allocatedPorts ) addState (p * api.PortConfig ) {
48+ portKey := getPortConfigKey (p )
49+ if _ , ok := ps [portKey ]; ! ok {
50+ ps [portKey ] = make (map [uint32 ]* api.PortConfig )
51+ }
52+ ps [portKey ][p.PublishedPort ] = p
53+ }
54+
55+ // delState delete the state of an allocated port from the collection.
56+ // `allocatedPorts` is a map of portKey:publishedPort:portState.
57+ //
58+ // If publishedPort is non-zero, then it is user defined. We will try to
59+ // remove the portState from `allocatedPorts` directly and return
60+ // the portState (or nil if no portState exists)
61+ //
62+ // If publishedPort is zero, then it is dynamically allocated. We will try
63+ // to remove the portState from `allocatedPorts`, as long as there is
64+ // a portState associated with a non-zero publishedPort.
65+ // Note multiple dynamically allocated ports might exists. In this case,
66+ // we will remove only at a time so both allocated ports are tracked.
67+ //
68+ // Note because of the potential co-existence of user-defined and dynamically
69+ // allocated ports, delState has to be called for user-defined port first.
70+ // dynamically allocated ports should be removed later.
71+ func (ps allocatedPorts ) delState (p * api.PortConfig ) * api.PortConfig {
72+ portKey := getPortConfigKey (p )
73+
74+ portStateMap , ok := ps [portKey ]
75+
76+ // If name, port, protocol values don't match then we
77+ // are not allocated.
78+ if ! ok {
79+ return nil
80+ }
81+
82+ if p .PublishedPort != 0 {
83+ // If SwarmPort was user defined but the port state
84+ // SwarmPort doesn't match we are not allocated.
85+ v := portStateMap [p .PublishedPort ]
86+
87+ // Delete state from allocatedPorts
88+ delete (portStateMap , p .PublishedPort )
89+
90+ return v
91+ }
92+
93+ // If PublishedPort == 0 and we don't have non-zero port
94+ // then we are not allocated
95+ for publishedPort , v := range portStateMap {
96+ if publishedPort != 0 {
97+ // Delete state from allocatedPorts
98+ delete (portStateMap , publishedPort )
99+ return v
100+ }
101+ }
102+
103+ return nil
104+ }
105+
41106func newPortAllocator () (* portAllocator , error ) {
42107 portSpaces := make (map [api.PortConfig_Protocol ]* portSpace )
43108 for _ , protocol := range []api.PortConfig_Protocol {api .ProtocolTCP , api .ProtocolUDP } {
0 commit comments