Merge lp:~vishvananda/nova/fix-dhcpbridge into lp:~hudson-openstack/nova/trunk
- fix-dhcpbridge
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Vish Ishaya |
Approved revision: | 237 |
Merged at revision: | 241 |
Proposed branch: | lp:~vishvananda/nova/fix-dhcpbridge |
Merge into: | lp:~hudson-openstack/nova/trunk |
Prerequisite: | lp:~vishvananda/nova/fix-hostname |
Diff against target: |
252 lines (+47/-36) 5 files modified
bin/nova-dhcpbridge (+1/-1) nova/endpoint/cloud.py (+3/-3) nova/network/linux_net.py (+2/-6) nova/network/model.py (+37/-22) nova/network/service.py (+4/-4) |
To merge this branch: | bzr merge lp:~vishvananda/nova/fix-dhcpbridge |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Devin Carlen (community) | Approve | ||
Jesse Andrews (community) | Approve | ||
Review via email: mp+32518@code.launchpad.net |
Commit message
Fixes issues with allocation and deallocation of fixed and elastic addresses.
Description of the change
Fixes issues with allocation and deallocation of fixed and elastic addresses.
I ended up merging in fix-hostname while i was testing, so I'm resubmitting this branch with that one as a prereq.
OpenStack Infra (hudson-openstack) wrote : | # |
The attempt to merge lp:~vishvananda/nova/fix-dhcpbridge into lp:nova failed.Below is the output from the failed tests.
nova.tests.
AccessTestCase
test_
test_
test_
test_
test_
nova.tests.
ApiEc2TestCase
test_
test_
nova.tests.
AuthTestCase
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
nova.tests.
CloudTestCase
test_
test_
test_
Preview Diff
1 | === modified file 'bin/nova-dhcpbridge' | |||
2 | --- bin/nova-dhcpbridge 2010-08-12 21:22:40 +0000 | |||
3 | +++ bin/nova-dhcpbridge 2010-08-12 21:22:40 +0000 | |||
4 | @@ -69,7 +69,7 @@ | |||
5 | 69 | """Get the list of hosts for an interface.""" | 69 | """Get the list of hosts for an interface.""" |
6 | 70 | net = model.get_network_by_interface(interface) | 70 | net = model.get_network_by_interface(interface) |
7 | 71 | res = "" | 71 | res = "" |
9 | 72 | for address in net.address_objs: | 72 | for address in net.assigned_objs: |
10 | 73 | res += "%s\n" % linux_net.host_dhcp(address) | 73 | res += "%s\n" % linux_net.host_dhcp(address) |
11 | 74 | return res | 74 | return res |
12 | 75 | 75 | ||
13 | 76 | 76 | ||
14 | === modified file 'nova/endpoint/cloud.py' | |||
15 | --- nova/endpoint/cloud.py 2010-08-12 21:22:40 +0000 | |||
16 | +++ nova/endpoint/cloud.py 2010-08-12 21:22:40 +0000 | |||
17 | @@ -126,7 +126,7 @@ | |||
18 | 126 | else: | 126 | else: |
19 | 127 | keys = '' | 127 | keys = '' |
20 | 128 | 128 | ||
22 | 129 | address_record = network_model.Address(i['private_dns_name']) | 129 | address_record = network_model.FixedIp(i['private_dns_name']) |
23 | 130 | if address_record: | 130 | if address_record: |
24 | 131 | hostname = address_record['hostname'] | 131 | hostname = address_record['hostname'] |
25 | 132 | else: | 132 | else: |
26 | @@ -311,7 +311,7 @@ | |||
27 | 311 | 311 | ||
28 | 312 | def _get_address(self, context, public_ip): | 312 | def _get_address(self, context, public_ip): |
29 | 313 | # FIXME(vish) this should move into network.py | 313 | # FIXME(vish) this should move into network.py |
31 | 314 | address = network_model.PublicAddress.lookup(public_ip) | 314 | address = network_model.ElasticIp.lookup(public_ip) |
32 | 315 | if address and (context.user.is_admin() or address['project_id'] == context.project.id): | 315 | if address and (context.user.is_admin() or address['project_id'] == context.project.id): |
33 | 316 | return address | 316 | return address |
34 | 317 | raise exception.NotFound("Address at ip %s not found" % public_ip) | 317 | raise exception.NotFound("Address at ip %s not found" % public_ip) |
35 | @@ -456,7 +456,7 @@ | |||
36 | 456 | 456 | ||
37 | 457 | def format_addresses(self, context): | 457 | def format_addresses(self, context): |
38 | 458 | addresses = [] | 458 | addresses = [] |
40 | 459 | for address in network_model.PublicAddress.all(): | 459 | for address in network_model.ElasticIp.all(): |
41 | 460 | # TODO(vish): implement a by_project iterator for addresses | 460 | # TODO(vish): implement a by_project iterator for addresses |
42 | 461 | if (context.user.is_admin() or | 461 | if (context.user.is_admin() or |
43 | 462 | address['project_id'] == context.project.id): | 462 | address['project_id'] == context.project.id): |
44 | 463 | 463 | ||
45 | === modified file 'nova/network/linux_net.py' | |||
46 | --- nova/network/linux_net.py 2010-08-12 21:22:40 +0000 | |||
47 | +++ nova/network/linux_net.py 2010-08-12 21:22:40 +0000 | |||
48 | @@ -116,7 +116,7 @@ | |||
49 | 116 | ' --pid-file=%s' % dhcp_file(net['vlan'], 'pid'), | 116 | ' --pid-file=%s' % dhcp_file(net['vlan'], 'pid'), |
50 | 117 | ' --listen-address=%s' % net.dhcp_listen_address, | 117 | ' --listen-address=%s' % net.dhcp_listen_address, |
51 | 118 | ' --except-interface=lo', | 118 | ' --except-interface=lo', |
53 | 119 | ' --dhcp-range=%s,static,600s' % net.dhcp_range_start, | 119 | ' --dhcp-range=%s,static,120s' % net.dhcp_range_start, |
54 | 120 | ' --dhcp-hostsfile=%s' % dhcp_file(net['vlan'], 'conf'), | 120 | ' --dhcp-hostsfile=%s' % dhcp_file(net['vlan'], 'conf'), |
55 | 121 | ' --dhcp-script=%s' % bin_file('nova-dhcpbridge'), | 121 | ' --dhcp-script=%s' % bin_file('nova-dhcpbridge'), |
56 | 122 | ' --leasefile-ro'] | 122 | ' --leasefile-ro'] |
57 | @@ -153,14 +153,10 @@ | |||
58 | 153 | # correct dnsmasq process | 153 | # correct dnsmasq process |
59 | 154 | try: | 154 | try: |
60 | 155 | os.kill(pid, signal.SIGHUP) | 155 | os.kill(pid, signal.SIGHUP) |
61 | 156 | return | ||
62 | 156 | except Exception as exc: # pylint: disable=W0703 | 157 | except Exception as exc: # pylint: disable=W0703 |
63 | 157 | logging.debug("Hupping dnsmasq threw %s", exc) | 158 | logging.debug("Hupping dnsmasq threw %s", exc) |
64 | 158 | 159 | ||
65 | 159 | # otherwise delete the existing leases file and start dnsmasq | ||
66 | 160 | lease_file = dhcp_file(network['vlan'], 'leases') | ||
67 | 161 | if os.path.exists(lease_file): | ||
68 | 162 | os.unlink(lease_file) | ||
69 | 163 | |||
70 | 164 | # FLAGFILE and DNSMASQ_INTERFACE in env | 160 | # FLAGFILE and DNSMASQ_INTERFACE in env |
71 | 165 | env = {'FLAGFILE': FLAGS.dhcpbridge_flagfile, | 161 | env = {'FLAGFILE': FLAGS.dhcpbridge_flagfile, |
72 | 166 | 'DNSMASQ_INTERFACE': network['bridge_name']} | 162 | 'DNSMASQ_INTERFACE': network['bridge_name']} |
73 | 167 | 163 | ||
74 | === modified file 'nova/network/model.py' | |||
75 | --- nova/network/model.py 2010-08-12 21:22:40 +0000 | |||
76 | +++ nova/network/model.py 2010-08-12 21:22:40 +0000 | |||
77 | @@ -143,25 +143,26 @@ | |||
78 | 143 | network[start + FLAGS.network_size - 1]) | 143 | network[start + FLAGS.network_size - 1]) |
79 | 144 | 144 | ||
80 | 145 | 145 | ||
82 | 146 | class Address(datastore.BasicModel): | 146 | class FixedIp(datastore.BasicModel): |
83 | 147 | """Represents a fixed ip in the datastore""" | 147 | """Represents a fixed ip in the datastore""" |
84 | 148 | override_type = "address" | ||
85 | 149 | 148 | ||
86 | 150 | def __init__(self, address): | 149 | def __init__(self, address): |
87 | 151 | self.address = address | 150 | self.address = address |
89 | 152 | super(Address, self).__init__() | 151 | super(FixedIp, self).__init__() |
90 | 153 | 152 | ||
91 | 154 | @property | 153 | @property |
92 | 155 | def identifier(self): | 154 | def identifier(self): |
93 | 156 | return self.address | 155 | return self.address |
94 | 157 | 156 | ||
95 | 157 | # NOTE(vish): address states allocated, leased, deallocated | ||
96 | 158 | def default_state(self): | 158 | def default_state(self): |
98 | 159 | return {'address': self.address} | 159 | return {'address': self.address, |
99 | 160 | 'state': 'none'} | ||
100 | 160 | 161 | ||
101 | 161 | @classmethod | 162 | @classmethod |
102 | 162 | # pylint: disable=R0913 | 163 | # pylint: disable=R0913 |
103 | 163 | def create(cls, user_id, project_id, address, mac, hostname, network_id): | 164 | def create(cls, user_id, project_id, address, mac, hostname, network_id): |
105 | 164 | """Creates an Address object""" | 165 | """Creates an FixedIp object""" |
106 | 165 | addr = cls(address) | 166 | addr = cls(address) |
107 | 166 | addr['user_id'] = user_id | 167 | addr['user_id'] = user_id |
108 | 167 | addr['project_id'] = project_id | 168 | addr['project_id'] = project_id |
109 | @@ -170,21 +171,22 @@ | |||
110 | 170 | hostname = "ip-%s" % address.replace('.', '-') | 171 | hostname = "ip-%s" % address.replace('.', '-') |
111 | 171 | addr['hostname'] = hostname | 172 | addr['hostname'] = hostname |
112 | 172 | addr['network_id'] = network_id | 173 | addr['network_id'] = network_id |
113 | 174 | addr['state'] = 'allocated' | ||
114 | 173 | addr.save() | 175 | addr.save() |
115 | 174 | return addr | 176 | return addr |
116 | 175 | 177 | ||
117 | 176 | def save(self): | 178 | def save(self): |
118 | 177 | is_new = self.is_new_record() | 179 | is_new = self.is_new_record() |
120 | 178 | success = super(Address, self).save() | 180 | success = super(FixedIp, self).save() |
121 | 179 | if success and is_new: | 181 | if success and is_new: |
122 | 180 | self.associate_with("network", self['network_id']) | 182 | self.associate_with("network", self['network_id']) |
123 | 181 | 183 | ||
124 | 182 | def destroy(self): | 184 | def destroy(self): |
125 | 183 | self.unassociate_with("network", self['network_id']) | 185 | self.unassociate_with("network", self['network_id']) |
130 | 184 | super(Address, self).destroy() | 186 | super(FixedIp, self).destroy() |
131 | 185 | 187 | ||
132 | 186 | 188 | ||
133 | 187 | class PublicAddress(Address): | 189 | class ElasticIp(FixedIp): |
134 | 188 | """Represents an elastic ip in the datastore""" | 190 | """Represents an elastic ip in the datastore""" |
135 | 189 | override_type = "address" | 191 | override_type = "address" |
136 | 190 | 192 | ||
137 | @@ -200,7 +202,7 @@ | |||
138 | 200 | class BaseNetwork(datastore.BasicModel): | 202 | class BaseNetwork(datastore.BasicModel): |
139 | 201 | """Implements basic logic for allocating ips in a network""" | 203 | """Implements basic logic for allocating ips in a network""" |
140 | 202 | override_type = 'network' | 204 | override_type = 'network' |
142 | 203 | address_class = Address | 205 | address_class = FixedIp |
143 | 204 | 206 | ||
144 | 205 | @property | 207 | @property |
145 | 206 | def identifier(self): | 208 | def identifier(self): |
146 | @@ -268,12 +270,12 @@ | |||
147 | 268 | # pylint: disable=R0913 | 270 | # pylint: disable=R0913 |
148 | 269 | def _add_host(self, user_id, project_id, ip_address, mac, hostname): | 271 | def _add_host(self, user_id, project_id, ip_address, mac, hostname): |
149 | 270 | """Add a host to the datastore""" | 272 | """Add a host to the datastore""" |
151 | 271 | Address.create(user_id, project_id, ip_address, | 273 | self.address_class.create(user_id, project_id, ip_address, |
152 | 272 | mac, hostname, self.identifier) | 274 | mac, hostname, self.identifier) |
153 | 273 | 275 | ||
154 | 274 | def _rem_host(self, ip_address): | 276 | def _rem_host(self, ip_address): |
155 | 275 | """Remove a host from the datastore""" | 277 | """Remove a host from the datastore""" |
157 | 276 | Address(ip_address).destroy() | 278 | self.address_class(ip_address).destroy() |
158 | 277 | 279 | ||
159 | 278 | @property | 280 | @property |
160 | 279 | def assigned(self): | 281 | def assigned(self): |
161 | @@ -322,7 +324,13 @@ | |||
162 | 322 | 324 | ||
163 | 323 | def lease_ip(self, ip_str): | 325 | def lease_ip(self, ip_str): |
164 | 324 | """Called when DHCP lease is activated""" | 326 | """Called when DHCP lease is activated""" |
166 | 325 | logging.debug("Leasing allocated IP %s", ip_str) | 327 | if not ip_str in self.assigned: |
167 | 328 | raise exception.AddressNotAllocated() | ||
168 | 329 | address = self.get_address(ip_str) | ||
169 | 330 | if address: | ||
170 | 331 | logging.debug("Leasing allocated IP %s", ip_str) | ||
171 | 332 | address['state'] = 'leased' | ||
172 | 333 | address.save() | ||
173 | 326 | 334 | ||
174 | 327 | def release_ip(self, ip_str): | 335 | def release_ip(self, ip_str): |
175 | 328 | """Called when DHCP lease expires | 336 | """Called when DHCP lease expires |
176 | @@ -330,16 +338,23 @@ | |||
177 | 330 | Removes the ip from the assigned list""" | 338 | Removes the ip from the assigned list""" |
178 | 331 | if not ip_str in self.assigned: | 339 | if not ip_str in self.assigned: |
179 | 332 | raise exception.AddressNotAllocated() | 340 | raise exception.AddressNotAllocated() |
180 | 341 | logging.debug("Releasing IP %s", ip_str) | ||
181 | 333 | self._rem_host(ip_str) | 342 | self._rem_host(ip_str) |
182 | 334 | self.deexpress(address=ip_str) | 343 | self.deexpress(address=ip_str) |
183 | 335 | logging.debug("Releasing IP %s", ip_str) | ||
184 | 336 | 344 | ||
185 | 337 | def deallocate_ip(self, ip_str): | 345 | def deallocate_ip(self, ip_str): |
186 | 338 | """Deallocates an allocated ip""" | 346 | """Deallocates an allocated ip""" |
191 | 339 | # NOTE(vish): Perhaps we should put the ip into an intermediate | 347 | if not ip_str in self.assigned: |
192 | 340 | # state, so we know that we are pending waiting for | 348 | raise exception.AddressNotAllocated() |
193 | 341 | # dnsmasq to confirm that it has been released. | 349 | address = self.get_address(ip_str) |
194 | 342 | logging.debug("Deallocating allocated IP %s", ip_str) | 350 | if address: |
195 | 351 | if address['state'] != 'leased': | ||
196 | 352 | # NOTE(vish): address hasn't been leased, so release it | ||
197 | 353 | self.release_ip(ip_str) | ||
198 | 354 | else: | ||
199 | 355 | logging.debug("Deallocating allocated IP %s", ip_str) | ||
200 | 356 | address['state'] == 'deallocated' | ||
201 | 357 | address.save() | ||
202 | 343 | 358 | ||
203 | 344 | def express(self, address=None): | 359 | def express(self, address=None): |
204 | 345 | """Set up network. Implemented in subclasses""" | 360 | """Set up network. Implemented in subclasses""" |
205 | @@ -462,7 +477,7 @@ | |||
206 | 462 | class PublicNetworkController(BaseNetwork): | 477 | class PublicNetworkController(BaseNetwork): |
207 | 463 | """Handles elastic ips""" | 478 | """Handles elastic ips""" |
208 | 464 | override_type = 'network' | 479 | override_type = 'network' |
210 | 465 | address_class = PublicAddress | 480 | address_class = ElasticIp |
211 | 466 | 481 | ||
212 | 467 | def __init__(self, *args, **kwargs): | 482 | def __init__(self, *args, **kwargs): |
213 | 468 | network_id = "public:default" | 483 | network_id = "public:default" |
214 | @@ -597,7 +612,7 @@ | |||
215 | 597 | 612 | ||
216 | 598 | def get_network_by_address(address): | 613 | def get_network_by_address(address): |
217 | 599 | """Gets the network for a given private ip""" | 614 | """Gets the network for a given private ip""" |
219 | 600 | address_record = Address.lookup(address) | 615 | address_record = FixedIp.lookup(address) |
220 | 601 | if not address_record: | 616 | if not address_record: |
221 | 602 | raise exception.AddressNotAllocated() | 617 | raise exception.AddressNotAllocated() |
222 | 603 | return get_project_network(address_record['project_id']) | 618 | return get_project_network(address_record['project_id']) |
223 | @@ -613,6 +628,6 @@ | |||
224 | 613 | def get_public_ip_for_instance(instance_id): | 628 | def get_public_ip_for_instance(instance_id): |
225 | 614 | """Gets the public ip for a given instance""" | 629 | """Gets the public ip for a given instance""" |
226 | 615 | # FIXME(josh): this should be a lookup - iteration won't scale | 630 | # FIXME(josh): this should be a lookup - iteration won't scale |
228 | 616 | for address_record in PublicAddress.all(): | 631 | for address_record in ElasticIp.all(): |
229 | 617 | if address_record.get('instance_id', 'available') == instance_id: | 632 | if address_record.get('instance_id', 'available') == instance_id: |
230 | 618 | return address_record['address'] | 633 | return address_record['address'] |
231 | 619 | 634 | ||
232 | === modified file 'nova/network/service.py' | |||
233 | --- nova/network/service.py 2010-08-12 21:22:40 +0000 | |||
234 | +++ nova/network/service.py 2010-08-12 21:22:40 +0000 | |||
235 | @@ -226,13 +226,13 @@ | |||
236 | 226 | """Returns an ip to the pool""" | 226 | """Returns an ip to the pool""" |
237 | 227 | return model.get_network_by_address(fixed_ip).deallocate_ip(fixed_ip) | 227 | return model.get_network_by_address(fixed_ip).deallocate_ip(fixed_ip) |
238 | 228 | 228 | ||
240 | 229 | def lease_ip(self, address): | 229 | def lease_ip(self, fixed_ip): |
241 | 230 | """Called by bridge when ip is leased""" | 230 | """Called by bridge when ip is leased""" |
243 | 231 | return model.get_network_by_address(address).lease_ip(address) | 231 | return model.get_network_by_address(fixed_ip).lease_ip(fixed_ip) |
244 | 232 | 232 | ||
246 | 233 | def release_ip(self, address): | 233 | def release_ip(self, fixed_ip): |
247 | 234 | """Called by bridge when ip is released""" | 234 | """Called by bridge when ip is released""" |
249 | 235 | return model.get_network_by_address(address).release_ip(address) | 235 | return model.get_network_by_address(fixed_ip).release_ip(fixed_ip) |
250 | 236 | 236 | ||
251 | 237 | def restart_nets(self): | 237 | def restart_nets(self): |
252 | 238 | """Ensure the network for each user is enabled""" | 238 | """Ensure the network for each user is enabled""" |
lgtm