Merge lp:~vishvananda/nova/fix-dhcpbridge into lp:~hudson-openstack/nova/trunk

Proposed by Vish Ishaya
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
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.

To post a comment you must log in.
Revision history for this message
Jesse Andrews (anotherjesse) wrote :

lgtm

review: Approve
Revision history for this message
Devin Carlen (devcamcar) wrote :

lgtm

review: Approve
Revision history for this message
OpenStack Infra (hudson-openstack) wrote :
Download full text (10.6 KiB)

The attempt to merge lp:~vishvananda/nova/fix-dhcpbridge into lp:nova failed.Below is the output from the failed tests.

nova.tests.access_unittest
  AccessTestCase
    test_001_allow_all ... [OK]
    test_002_allow_none ... [OK]
    test_003_allow_project_manager ... [OK]
    test_004_allow_sys_and_net ... [OK]
    test_005_allow_sys_no_pm ... [OK]
nova.tests.api_unittest
  ApiEc2TestCase
    test_describe_instances ... [OK]
    test_get_all_key_pairs ... [OK]
nova.tests.auth_unittest
  AuthTestCase
    test_001_can_create_users ... [OK]
    test_002_can_get_user ... [OK]
    test_003_can_retreive_properties ... [OK]
    test_004_signature_is_valid ... [OK]
    test_005_can_get_credentials ... [OK]
    test_006_test_key_storage ... [OK]
    test_007_test_key_generation ... [OK]
    test_008_can_list_key_pairs ... [OK]
    test_009_can_delete_key_pair ... [OK]
    test_010_can_list_users ... [OK]
    test_101_can_add_user_role ... [OK]
    test_199_can_remove_user_role ... [OK]
    test_201_can_create_project ... [OK]
    test_202_user1_is_project_member ... [OK]
    test_203_user2_is_not_project_member ... [OK]
    test_204_user1_is_project_manager ... [OK]
    test_205_user2_is_not_project_manager ... [OK]
    test_206_can_add_user_to_project ... [OK]
    test_207_can_remove_user_from_project ... [OK]
    test_208_can_remove_add_user_with_role ... [OK]
    test_209_can_generate_x509 ... [OK]
    test_210_can_add_project_role ... [OK]
    test_211_can_list_project_roles ... [OK]
    test_212_can_remove_project_role ... [OK]
    test_214_can_retrieve_project_by_user ... [OK]
    test_299_can_delete_project ... [OK]
    test_999_can_delete_users ... [OK]
nova.tests.cloud_unittest
  CloudTestCase
    test_console_output ... [OK]
    test_instance_update_state ... [OK]
    test_run_instances ... ...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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 """Get the list of hosts for an interface."""
6 net = model.get_network_by_interface(interface)
7 res = ""
8- for address in net.address_objs:
9+ for address in net.assigned_objs:
10 res += "%s\n" % linux_net.host_dhcp(address)
11 return res
12
13
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 else:
19 keys = ''
20
21- address_record = network_model.Address(i['private_dns_name'])
22+ address_record = network_model.FixedIp(i['private_dns_name'])
23 if address_record:
24 hostname = address_record['hostname']
25 else:
26@@ -311,7 +311,7 @@
27
28 def _get_address(self, context, public_ip):
29 # FIXME(vish) this should move into network.py
30- address = network_model.PublicAddress.lookup(public_ip)
31+ address = network_model.ElasticIp.lookup(public_ip)
32 if address and (context.user.is_admin() or address['project_id'] == context.project.id):
33 return address
34 raise exception.NotFound("Address at ip %s not found" % public_ip)
35@@ -456,7 +456,7 @@
36
37 def format_addresses(self, context):
38 addresses = []
39- for address in network_model.PublicAddress.all():
40+ for address in network_model.ElasticIp.all():
41 # TODO(vish): implement a by_project iterator for addresses
42 if (context.user.is_admin() or
43 address['project_id'] == context.project.id):
44
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 ' --pid-file=%s' % dhcp_file(net['vlan'], 'pid'),
50 ' --listen-address=%s' % net.dhcp_listen_address,
51 ' --except-interface=lo',
52- ' --dhcp-range=%s,static,600s' % net.dhcp_range_start,
53+ ' --dhcp-range=%s,static,120s' % net.dhcp_range_start,
54 ' --dhcp-hostsfile=%s' % dhcp_file(net['vlan'], 'conf'),
55 ' --dhcp-script=%s' % bin_file('nova-dhcpbridge'),
56 ' --leasefile-ro']
57@@ -153,14 +153,10 @@
58 # correct dnsmasq process
59 try:
60 os.kill(pid, signal.SIGHUP)
61+ return
62 except Exception as exc: # pylint: disable=W0703
63 logging.debug("Hupping dnsmasq threw %s", exc)
64
65- # otherwise delete the existing leases file and start dnsmasq
66- lease_file = dhcp_file(network['vlan'], 'leases')
67- if os.path.exists(lease_file):
68- os.unlink(lease_file)
69-
70 # FLAGFILE and DNSMASQ_INTERFACE in env
71 env = {'FLAGFILE': FLAGS.dhcpbridge_flagfile,
72 'DNSMASQ_INTERFACE': network['bridge_name']}
73
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 network[start + FLAGS.network_size - 1])
79
80
81-class Address(datastore.BasicModel):
82+class FixedIp(datastore.BasicModel):
83 """Represents a fixed ip in the datastore"""
84- override_type = "address"
85
86 def __init__(self, address):
87 self.address = address
88- super(Address, self).__init__()
89+ super(FixedIp, self).__init__()
90
91 @property
92 def identifier(self):
93 return self.address
94
95+ # NOTE(vish): address states allocated, leased, deallocated
96 def default_state(self):
97- return {'address': self.address}
98+ return {'address': self.address,
99+ 'state': 'none'}
100
101 @classmethod
102 # pylint: disable=R0913
103 def create(cls, user_id, project_id, address, mac, hostname, network_id):
104- """Creates an Address object"""
105+ """Creates an FixedIp object"""
106 addr = cls(address)
107 addr['user_id'] = user_id
108 addr['project_id'] = project_id
109@@ -170,21 +171,22 @@
110 hostname = "ip-%s" % address.replace('.', '-')
111 addr['hostname'] = hostname
112 addr['network_id'] = network_id
113+ addr['state'] = 'allocated'
114 addr.save()
115 return addr
116
117 def save(self):
118 is_new = self.is_new_record()
119- success = super(Address, self).save()
120+ success = super(FixedIp, self).save()
121 if success and is_new:
122 self.associate_with("network", self['network_id'])
123
124 def destroy(self):
125 self.unassociate_with("network", self['network_id'])
126- super(Address, self).destroy()
127-
128-
129-class PublicAddress(Address):
130+ super(FixedIp, self).destroy()
131+
132+
133+class ElasticIp(FixedIp):
134 """Represents an elastic ip in the datastore"""
135 override_type = "address"
136
137@@ -200,7 +202,7 @@
138 class BaseNetwork(datastore.BasicModel):
139 """Implements basic logic for allocating ips in a network"""
140 override_type = 'network'
141- address_class = Address
142+ address_class = FixedIp
143
144 @property
145 def identifier(self):
146@@ -268,12 +270,12 @@
147 # pylint: disable=R0913
148 def _add_host(self, user_id, project_id, ip_address, mac, hostname):
149 """Add a host to the datastore"""
150- Address.create(user_id, project_id, ip_address,
151+ self.address_class.create(user_id, project_id, ip_address,
152 mac, hostname, self.identifier)
153
154 def _rem_host(self, ip_address):
155 """Remove a host from the datastore"""
156- Address(ip_address).destroy()
157+ self.address_class(ip_address).destroy()
158
159 @property
160 def assigned(self):
161@@ -322,7 +324,13 @@
162
163 def lease_ip(self, ip_str):
164 """Called when DHCP lease is activated"""
165- logging.debug("Leasing allocated IP %s", ip_str)
166+ if not ip_str in self.assigned:
167+ raise exception.AddressNotAllocated()
168+ address = self.get_address(ip_str)
169+ if address:
170+ logging.debug("Leasing allocated IP %s", ip_str)
171+ address['state'] = 'leased'
172+ address.save()
173
174 def release_ip(self, ip_str):
175 """Called when DHCP lease expires
176@@ -330,16 +338,23 @@
177 Removes the ip from the assigned list"""
178 if not ip_str in self.assigned:
179 raise exception.AddressNotAllocated()
180+ logging.debug("Releasing IP %s", ip_str)
181 self._rem_host(ip_str)
182 self.deexpress(address=ip_str)
183- logging.debug("Releasing IP %s", ip_str)
184
185 def deallocate_ip(self, ip_str):
186 """Deallocates an allocated ip"""
187- # NOTE(vish): Perhaps we should put the ip into an intermediate
188- # state, so we know that we are pending waiting for
189- # dnsmasq to confirm that it has been released.
190- logging.debug("Deallocating allocated IP %s", ip_str)
191+ if not ip_str in self.assigned:
192+ raise exception.AddressNotAllocated()
193+ address = self.get_address(ip_str)
194+ if address:
195+ if address['state'] != 'leased':
196+ # NOTE(vish): address hasn't been leased, so release it
197+ self.release_ip(ip_str)
198+ else:
199+ logging.debug("Deallocating allocated IP %s", ip_str)
200+ address['state'] == 'deallocated'
201+ address.save()
202
203 def express(self, address=None):
204 """Set up network. Implemented in subclasses"""
205@@ -462,7 +477,7 @@
206 class PublicNetworkController(BaseNetwork):
207 """Handles elastic ips"""
208 override_type = 'network'
209- address_class = PublicAddress
210+ address_class = ElasticIp
211
212 def __init__(self, *args, **kwargs):
213 network_id = "public:default"
214@@ -597,7 +612,7 @@
215
216 def get_network_by_address(address):
217 """Gets the network for a given private ip"""
218- address_record = Address.lookup(address)
219+ address_record = FixedIp.lookup(address)
220 if not address_record:
221 raise exception.AddressNotAllocated()
222 return get_project_network(address_record['project_id'])
223@@ -613,6 +628,6 @@
224 def get_public_ip_for_instance(instance_id):
225 """Gets the public ip for a given instance"""
226 # FIXME(josh): this should be a lookup - iteration won't scale
227- for address_record in PublicAddress.all():
228+ for address_record in ElasticIp.all():
229 if address_record.get('instance_id', 'available') == instance_id:
230 return address_record['address']
231
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 """Returns an ip to the pool"""
237 return model.get_network_by_address(fixed_ip).deallocate_ip(fixed_ip)
238
239- def lease_ip(self, address):
240+ def lease_ip(self, fixed_ip):
241 """Called by bridge when ip is leased"""
242- return model.get_network_by_address(address).lease_ip(address)
243+ return model.get_network_by_address(fixed_ip).lease_ip(fixed_ip)
244
245- def release_ip(self, address):
246+ def release_ip(self, fixed_ip):
247 """Called by bridge when ip is released"""
248- return model.get_network_by_address(address).release_ip(address)
249+ return model.get_network_by_address(fixed_ip).release_ip(fixed_ip)
250
251 def restart_nets(self):
252 """Ensure the network for each user is enabled"""