Merge lp:~vishvananda/nova/ha-net into lp:~hudson-openstack/nova/trunk
- ha-net
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Devin Carlen |
Approved revision: | 1266 |
Merged at revision: | 1293 |
Proposed branch: | lp:~vishvananda/nova/ha-net |
Merge into: | lp:~hudson-openstack/nova/trunk |
Diff against target: |
1104 lines (+280/-175) 15 files modified
bin/nova-dhcpbridge (+1/-1) bin/nova-manage (+12/-7) nova/compute/manager.py (+9/-8) nova/db/api.py (+12/-6) nova/db/sqlalchemy/api.py (+32/-11) nova/db/sqlalchemy/migrate_repo/versions/033_ha_network.py (+44/-0) nova/db/sqlalchemy/models.py (+2/-0) nova/exception.py (+5/-0) nova/network/api.py (+14/-4) nova/network/linux_net.py (+20/-20) nova/network/manager.py (+121/-100) nova/tests/__init__.py (+2/-1) nova/tests/test_libvirt.py (+1/-0) nova/tests/test_network.py (+4/-15) nova/virt/libvirt/connection.py (+1/-2) |
To merge this branch: | bzr merge lp:~vishvananda/nova/ha-net |
Related bugs: | |
Related blueprints: |
High Availability FlatDHCP
(Medium)
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Devin Carlen (community) | Approve | ||
Dan Prince (community) | Approve | ||
Koji Iida (community) | Needs Information | ||
Review via email: mp+67078@code.launchpad.net |
Commit message
Adds HA networking (multi_host) option to networks.
* Adds extra flag for network creation: multi_host.
* Multi hosts networks will send all network related commands to the host that the vm is on.
* Requires nova-network to be run on every compute host.
* Non multi_host networks work the same way.
* Moved extra db access out of linux_net (there is still a little in the dhcp leases part that should probably be moved)
* Fixed the logic on auto_assign which was messed up
Description of the change
Adds HA networking option to networks.
* Adds extra flag for network creation: multi_host.
* Multi hosts networks will send all network related commands to the host that the vm is on.
* Requires nova-network to be run on every compute host.
* Non multi_host networks work the same way.
Other cleanup:
* Moved extra db access out of linux_net (there is still a little in the dhcp leases part that should probably be moved)
* Fixed the logic on auto_assign which was messed up
Potential issues:
* The flag version means I'm checking for multi_host in a number of places. Ideas for changes here welcome.
* Nova-manage positional changes are annoying, we need the kwarg version in place
* No tests added. Open to suggestions on some specific tests that could be added.
Jason Kölker (jason-koelker) wrote : | # |
Mandell (mdegerne) wrote : | # |
I like Jason's suggestion, although I would want to check for "y" as well.
I'm a bit concerned about the way which _on_set_
Lucky (luckythetourist) wrote : | # |
Other than the above I have a single nit:
On L583-584 the order of operations should be explicit
e.g.,
(foo and bar) or baz
or
foo and (bar or baz)
Vish Ishaya (vishvananda) wrote : | # |
On Jul 7, 2011, at 3:13 PM, Mandell wrote:
> I like Jason's suggestion, although I would want to check for "y" as well.
>
Will fix. I was following the use of T in a few other places, so switching the others should be done in the branch that is adding in better opt parsing
> I'm a bit concerned about the way which _on_set_
My current mental model says HA networks belong to all hosts. I think this is the most common use case. That said, I can change the init host to look for ha networks that already have an ip on this host, and only on_set_network_host there, then I can also call it from the associate call in _get_dhcp_ip. That should make the network only show up on the host if it is being used.
Vish
Vish Ishaya (vishvananda) wrote : | # |
Cleaned up stuff and made changes to make setup of networks automatic if an ip is allocated and the network has not been setup yet.
Koji Iida (iida-koji) wrote : | # |
I have a question.
I can't boot a instance under VlanManager and multi_host set to false.
2011-07-16 13:21:37,094 DEBUG nova.network.
2011-07-16 13:21:37,094 DEBUG nova.network.
2011-07-16 13:21:37,102 ERROR nova [-] Exception during message handling
(nova): TRACE: Traceback (most recent call last):
(nova): TRACE: File "/opt2/
(nova): TRACE: rval = node_func(
(nova): TRACE: File "/opt2/
(nova): TRACE: ips = super(FloatingIP, self).allocate_
(nova): TRACE: File "/opt2/
(nova): TRACE: project_id)
(nova): TRACE: File "/opt2/
(nova): TRACE: return self.db.
(nova): TRACE: File "/opt2/
(nova): TRACE: return IMPL.project_
(nova): TRACE: File "/opt2/
(nova): TRACE: return f(*args, **kwargs)
(nova): TRACE: File "/opt2/
(nova): TRACE: return [network_
(nova): TRACE: File "/opt2/
(nova): TRACE: return f(*args, **kwargs)
(nova): TRACE: File "/opt2/
(nova): TRACE: raise db.NoMoreNetworks()
(nova): TRACE: NoMoreNetworks: None
(nova): TRACE:
615 - # setup any new networks which have been created
616 - self.set_
set_network_hosts() is removed from periodic_tasks.
Are there any other mechanisms to allocate host to network?
Vish Ishaya (vishvananda) wrote : | # |
Hmm, this could be a bug. It is supposed to set_network_host in the allocate_
Vish
On Jul 15, 2011, at 11:33 PM, Koji Iida wrote:
> Review: Needs Information
> I have a question.
>
> I can't boot a instance under VlanManager and multi_host set to false.
>
> 2011-07-16 13:21:37,094 DEBUG nova.network.
> 2011-07-16 13:21:37,094 DEBUG nova.network.
> 2011-07-16 13:21:37,102 ERROR nova [-] Exception during message handling
> (nova): TRACE: Traceback (most recent call last):
> (nova): TRACE: File "/opt2/
> (nova): TRACE: rval = node_func(
> (nova): TRACE: File "/opt2/
> (nova): TRACE: ips = super(FloatingIP, self).allocate_
> (nova): TRACE: File "/opt2/
> (nova): TRACE: project_id)
> (nova): TRACE: File "/opt2/
> (nova): TRACE: return self.db.
> (nova): TRACE: File "/opt2/
> (nova): TRACE: return IMPL.project_
> (nova): TRACE: File "/opt2/
> (nova): TRACE: return f(*args, **kwargs)
> (nova): TRACE: File "/opt2/
> (nova): TRACE: return [network_
> (nova): TRACE: File "/opt2/
> (nova): TRACE: return f(*args, **kwargs)
> (nova): TRACE: File "/opt2/
> (nova): TRACE: raise db.NoMoreNetworks()
> (nova): TRACE: NoMoreNetworks: None
> (nova): TRACE:
>
>
> 615 - # setup any new networks which have been created
> 616 - self.set_
>
> set_network_hosts() is removed from periodic_tasks.
> Are there any other mechanisms to allocate host to network?
>
>
>
>
> --
> https:/
> You are the owner of lp:~vishvananda/nova/ha-net.
- 1259. By Vish Ishaya
-
fix issues that were breaking vlan mode
Vish Ishaya (vishvananda) wrote : | # |
koji. I fixed the issue with vlan mode. Can you try again?
- 1260. By Vish Ishaya
-
merged trunk
- 1261. By Vish Ishaya
-
change migration number
- 1262. By Vish Ishaya
-
fix bad merge
- 1263. By Vish Ishaya
-
missed the vpn kwarg in rpc
Dan Prince (dan-prince) wrote : | # |
Hey Vish,
Would you be up for adding a 'downgrade' to this migration. I know not all of our migrations have them but I'd prefer to follow that model.
Otherwise looks good. All functional tests appear to be passing on Smokestack too.
- 1264. By Vish Ishaya
-
add downgrade
Vish Ishaya (vishvananda) wrote : | # |
Hey Dan,
Added a downgrade.
Dan Prince (dan-prince) wrote : | # |
Great. Looks good.
- 1265. By Vish Ishaya
-
merged trunk
- 1266. By Vish Ishaya
-
pep8
Do Dinh Thang (thangdd-it49) wrote : | # |
Hi Vish,
I setup & run nova-network in multi_host mode.
when I restart service nova-network on Node1, i must rerun "euca-associate
Is it a bug?
Vish Ishaya (vishvananda) wrote : | # |
It should reassociate the floating ips on reboot. This sounds like a bug.
On Aug 16, 2011, at 2:11 AM, Do Dinh Thang wrote:
> Hi Vish,
> I setup & run nova-network in multi_host mode.
> when I restart service nova-network on Node1, i must rerun "euca-associate
> Is it a bug?
> --
> https:/
> You are the owner of lp:~vishvananda/nova/ha-net.
Preview Diff
1 | === modified file 'bin/nova-dhcpbridge' |
2 | --- bin/nova-dhcpbridge 2011-07-11 20:31:39 +0000 |
3 | +++ bin/nova-dhcpbridge 2011-07-20 18:28:31 +0000 |
4 | @@ -91,7 +91,7 @@ |
5 | """Get the list of hosts for an interface.""" |
6 | ctxt = context.get_admin_context() |
7 | network_ref = db.network_get_by_bridge(ctxt, interface) |
8 | - return linux_net.get_dhcp_leases(ctxt, network_ref['id']) |
9 | + return linux_net.get_dhcp_leases(ctxt, network_ref) |
10 | |
11 | |
12 | def main(): |
13 | |
14 | === modified file 'bin/nova-manage' |
15 | --- bin/nova-manage 2011-07-18 19:09:39 +0000 |
16 | +++ bin/nova-manage 2011-07-20 18:28:31 +0000 |
17 | @@ -479,7 +479,7 @@ |
18 | except db.api.NoMoreNetworks: |
19 | print _('No more networks available. If this is a new ' |
20 | 'installation, you need\nto call something like this:\n\n' |
21 | - ' nova-manage network create 10.0.0.0/8 10 64\n\n') |
22 | + ' nova-manage network create pvt 10.0.0.0/8 10 64\n\n') |
23 | except exception.ProcessExecutionError, e: |
24 | print e |
25 | print _("The above error may show that the certificate db has not " |
26 | @@ -500,7 +500,7 @@ |
27 | if host is None: |
28 | fixed_ips = db.fixed_ip_get_all(ctxt) |
29 | else: |
30 | - fixed_ips = db.fixed_ip_get_all_by_host(ctxt, host) |
31 | + fixed_ips = db.fixed_ip_get_all_by_instance_host(ctxt, host) |
32 | except exception.NotFound as ex: |
33 | print "error: %s" % ex |
34 | sys.exit(2) |
35 | @@ -564,17 +564,17 @@ |
36 | """Class for managing networks.""" |
37 | |
38 | def create(self, label=None, fixed_range=None, num_networks=None, |
39 | - network_size=None, vlan_start=None, |
40 | + network_size=None, multi_host=None, vlan_start=None, |
41 | vpn_start=None, fixed_range_v6=None, gateway_v6=None, |
42 | flat_network_bridge=None, bridge_interface=None): |
43 | """Creates fixed ips for host by range |
44 | arguments: label, fixed_range, [num_networks=FLAG], |
45 | - [network_size=FLAG], [vlan_start=FLAG], |
46 | + [network_size=FLAG], [multi_host=FLAG], [vlan_start=FLAG], |
47 | [vpn_start=FLAG], [fixed_range_v6=FLAG], [gateway_v6=FLAG], |
48 | [flat_network_bridge=FLAG], [bridge_interface=FLAG] |
49 | - If you wish to use a later argument fill in the gaps with 0s |
50 | - Ex: network create private 10.0.0.0/8 1 15 0 0 0 0 xenbr1 eth1 |
51 | - network create private 10.0.0.0/8 1 15 |
52 | + If you wish to use a later argument fill in the gaps with ""s |
53 | + Ex: network create private 10.0.0.0/8 1 16 T "" "" "" "" xenbr1 eth1 |
54 | + network create private 10.0.0.0/8 1 16 |
55 | """ |
56 | if not label: |
57 | msg = _('a label (ex: public) is required to create networks.') |
58 | @@ -589,6 +589,10 @@ |
59 | num_networks = FLAGS.num_networks |
60 | if not network_size: |
61 | network_size = FLAGS.network_size |
62 | + if not multi_host: |
63 | + multi_host = FLAGS.multi_host |
64 | + else: |
65 | + multi_host = multi_host == 'T' |
66 | if not vlan_start: |
67 | vlan_start = FLAGS.vlan_start |
68 | if not vpn_start: |
69 | @@ -607,6 +611,7 @@ |
70 | net_manager.create_networks(context.get_admin_context(), |
71 | label=label, |
72 | cidr=fixed_range, |
73 | + multi_host=multi_host, |
74 | num_networks=int(num_networks), |
75 | network_size=int(network_size), |
76 | vlan_start=int(vlan_start), |
77 | |
78 | === modified file 'nova/compute/manager.py' |
79 | --- nova/compute/manager.py 2011-07-19 20:21:39 +0000 |
80 | +++ nova/compute/manager.py 2011-07-20 18:28:31 +0000 |
81 | @@ -77,8 +77,6 @@ |
82 | flags.DEFINE_integer("rescue_timeout", 0, |
83 | "Automatically unrescue an instance after N seconds." |
84 | " Set to 0 to disable.") |
85 | -flags.DEFINE_bool('auto_assign_floating_ip', False, |
86 | - 'Autoassigning floating ip to VM') |
87 | flags.DEFINE_integer('host_state_interval', 120, |
88 | 'Interval in seconds for querying the host status') |
89 | |
90 | @@ -274,16 +272,19 @@ |
91 | """Launch a new instance with specified options.""" |
92 | context = context.elevated() |
93 | instance = self.db.instance_get(context, instance_id) |
94 | - instance.injected_files = kwargs.get('injected_files', []) |
95 | - instance.admin_pass = kwargs.get('admin_password', None) |
96 | if instance['name'] in self.driver.list_instances(): |
97 | raise exception.Error(_("Instance has already been created")) |
98 | LOG.audit(_("instance %s: starting..."), instance_id, |
99 | context=context) |
100 | - self.db.instance_update(context, |
101 | - instance_id, |
102 | - {'host': self.host, 'launched_on': self.host}) |
103 | - |
104 | + updates = {} |
105 | + updates['host'] = self.host |
106 | + updates['launched_on'] = self.host |
107 | + # NOTE(vish): used by virt but not in database |
108 | + updates['injected_files'] = kwargs.get('injected_files', []) |
109 | + updates['admin_pass'] = kwargs.get('admin_password', None) |
110 | + instance = self.db.instance_update(context, |
111 | + instance_id, |
112 | + updates) |
113 | self.db.instance_set_state(context, |
114 | instance_id, |
115 | power_state.NOSTATE, |
116 | |
117 | === modified file 'nova/db/api.py' |
118 | --- nova/db/api.py 2011-07-08 03:07:58 +0000 |
119 | +++ nova/db/api.py 2011-07-20 18:28:31 +0000 |
120 | @@ -332,13 +332,14 @@ |
121 | return IMPL.fixed_ip_associate(context, address, instance_id) |
122 | |
123 | |
124 | -def fixed_ip_associate_pool(context, network_id, instance_id): |
125 | - """Find free ip in network and associate it to instance. |
126 | +def fixed_ip_associate_pool(context, network_id, instance_id=None, host=None): |
127 | + """Find free ip in network and associate it to instance or host. |
128 | |
129 | Raises if one is not available. |
130 | |
131 | """ |
132 | - return IMPL.fixed_ip_associate_pool(context, network_id, instance_id) |
133 | + return IMPL.fixed_ip_associate_pool(context, network_id, |
134 | + instance_id, host) |
135 | |
136 | |
137 | def fixed_ip_create(context, values): |
138 | @@ -361,9 +362,9 @@ |
139 | return IMPL.fixed_ip_get_all(context) |
140 | |
141 | |
142 | -def fixed_ip_get_all_by_host(context, host): |
143 | - """Get all defined fixed ips used by a host.""" |
144 | - return IMPL.fixed_ip_get_all_by_host(context, host) |
145 | +def fixed_ip_get_all_by_instance_host(context, host): |
146 | + """Get all allocated fixed ips filtered by instance host.""" |
147 | + return IMPL.fixed_ip_get_all_instance_by_host(context, host) |
148 | |
149 | |
150 | def fixed_ip_get_by_address(context, address): |
151 | @@ -376,6 +377,11 @@ |
152 | return IMPL.fixed_ip_get_by_instance(context, instance_id) |
153 | |
154 | |
155 | +def fixed_ip_get_by_network_host(context, network_id, host): |
156 | + """Get fixed ip for a host in a network.""" |
157 | + return IMPL.fixed_ip_get_by_network_host(context, network_id, host) |
158 | + |
159 | + |
160 | def fixed_ip_get_by_virtual_interface(context, vif_id): |
161 | """Get fixed ips by virtual interface or raise if none exist.""" |
162 | return IMPL.fixed_ip_get_by_virtual_interface(context, vif_id) |
163 | |
164 | === modified file 'nova/db/sqlalchemy/api.py' |
165 | --- nova/db/sqlalchemy/api.py 2011-07-18 23:42:02 +0000 |
166 | +++ nova/db/sqlalchemy/api.py 2011-07-20 18:28:31 +0000 |
167 | @@ -18,7 +18,6 @@ |
168 | """ |
169 | Implementation of SQLAlchemy backend. |
170 | """ |
171 | -import traceback |
172 | import warnings |
173 | |
174 | from nova import db |
175 | @@ -33,7 +32,6 @@ |
176 | from sqlalchemy.exc import IntegrityError |
177 | from sqlalchemy.orm import joinedload |
178 | from sqlalchemy.orm import joinedload_all |
179 | -from sqlalchemy.sql import exists |
180 | from sqlalchemy.sql import func |
181 | from sqlalchemy.sql.expression import literal_column |
182 | |
183 | @@ -672,7 +670,7 @@ |
184 | |
185 | |
186 | @require_admin_context |
187 | -def fixed_ip_associate_pool(context, network_id, instance_id): |
188 | +def fixed_ip_associate_pool(context, network_id, instance_id=None, host=None): |
189 | session = get_session() |
190 | with session.begin(): |
191 | network_or_none = or_(models.FixedIp.network_id == network_id, |
192 | @@ -682,6 +680,7 @@ |
193 | filter_by(reserved=False).\ |
194 | filter_by(deleted=False).\ |
195 | filter_by(instance=None).\ |
196 | + filter_by(host=None).\ |
197 | with_lockmode('update').\ |
198 | first() |
199 | # NOTE(vish): if with_lockmode isn't supported, as in sqlite, |
200 | @@ -692,9 +691,12 @@ |
201 | fixed_ip_ref.network = network_get(context, |
202 | network_id, |
203 | session=session) |
204 | - fixed_ip_ref.instance = instance_get(context, |
205 | - instance_id, |
206 | - session=session) |
207 | + if instance_id: |
208 | + fixed_ip_ref.instance = instance_get(context, |
209 | + instance_id, |
210 | + session=session) |
211 | + if host: |
212 | + fixed_ip_ref.host = host |
213 | session.add(fixed_ip_ref) |
214 | return fixed_ip_ref['address'] |
215 | |
216 | @@ -750,7 +752,7 @@ |
217 | |
218 | |
219 | @require_admin_context |
220 | -def fixed_ip_get_all_by_host(context, host=None): |
221 | +def fixed_ip_get_all_by_instance_host(context, host=None): |
222 | session = get_session() |
223 | |
224 | result = session.query(models.FixedIp).\ |
225 | @@ -800,6 +802,20 @@ |
226 | |
227 | |
228 | @require_context |
229 | +def fixed_ip_get_by_network_host(context, network_id, host): |
230 | + session = get_session() |
231 | + rv = session.query(models.FixedIp).\ |
232 | + filter_by(network_id=network_id).\ |
233 | + filter_by(host=host).\ |
234 | + filter_by(deleted=False).\ |
235 | + first() |
236 | + if not rv: |
237 | + raise exception.FixedIpNotFoundForNetworkHost(network_id=network_id, |
238 | + host=host) |
239 | + return rv |
240 | + |
241 | + |
242 | +@require_context |
243 | def fixed_ip_get_by_virtual_interface(context, vif_id): |
244 | session = get_session() |
245 | rv = session.query(models.FixedIp).\ |
246 | @@ -1480,8 +1496,6 @@ |
247 | called by project_get_networks under certain conditions |
248 | and network manager add_network_to_project() |
249 | |
250 | - only associates projects with networks that have configured hosts |
251 | - |
252 | only associate if the project doesn't already have a network |
253 | or if force is True |
254 | |
255 | @@ -1497,7 +1511,6 @@ |
256 | def network_query(project_filter): |
257 | return session.query(models.Network).\ |
258 | filter_by(deleted=False).\ |
259 | - filter(models.Network.host != None).\ |
260 | filter_by(project_id=project_filter).\ |
261 | with_lockmode('update').\ |
262 | first() |
263 | @@ -1704,9 +1717,16 @@ |
264 | def network_get_all_by_host(context, host): |
265 | session = get_session() |
266 | with session.begin(): |
267 | + # NOTE(vish): return networks that have host set |
268 | + # or that have a fixed ip with host set |
269 | + host_filter = or_(models.Network.host == host, |
270 | + models.FixedIp.host == host) |
271 | + |
272 | return session.query(models.Network).\ |
273 | filter_by(deleted=False).\ |
274 | - filter_by(host=host).\ |
275 | + join(models.Network.fixed_ips).\ |
276 | + filter(host_filter).\ |
277 | + filter_by(deleted=False).\ |
278 | all() |
279 | |
280 | |
281 | @@ -1738,6 +1758,7 @@ |
282 | network_ref = network_get(context, network_id, session=session) |
283 | network_ref.update(values) |
284 | network_ref.save(session=session) |
285 | + return network_ref |
286 | |
287 | |
288 | ################### |
289 | |
290 | === added file 'nova/db/sqlalchemy/migrate_repo/versions/033_ha_network.py' |
291 | --- nova/db/sqlalchemy/migrate_repo/versions/033_ha_network.py 1970-01-01 00:00:00 +0000 |
292 | +++ nova/db/sqlalchemy/migrate_repo/versions/033_ha_network.py 2011-07-20 18:28:31 +0000 |
293 | @@ -0,0 +1,44 @@ |
294 | +# vim: tabstop=4 shiftwidth=4 softtabstop=4 |
295 | + |
296 | +# Copyright (c) 2011 OpenStack, LLC. |
297 | +# All Rights Reserved. |
298 | +# |
299 | +# Licensed under the Apache License, Version 2.0 (the "License"); you may |
300 | +# not use this file except in compliance with the License. You may obtain |
301 | +# a copy of the License at |
302 | +# |
303 | +# http://www.apache.org/licenses/LICENSE-2.0 |
304 | +# |
305 | +# Unless required by applicable law or agreed to in writing, software |
306 | +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
307 | +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
308 | +# License for the specific language governing permissions and limitations |
309 | +# under the License. |
310 | + |
311 | +from sqlalchemy import Column, Table, MetaData, Boolean, String |
312 | + |
313 | +meta = MetaData() |
314 | + |
315 | +fixed_ips_host = Column('host', String(255)) |
316 | + |
317 | +networks_multi_host = Column('multi_host', Boolean, default=False) |
318 | + |
319 | + |
320 | +def upgrade(migrate_engine): |
321 | + meta.bind = migrate_engine |
322 | + |
323 | + fixed_ips = Table('fixed_ips', meta, autoload=True) |
324 | + fixed_ips.create_column(fixed_ips_host) |
325 | + |
326 | + networks = Table('networks', meta, autoload=True) |
327 | + networks.create_column(networks_multi_host) |
328 | + |
329 | + |
330 | +def downgrade(migrate_engine): |
331 | + meta.bind = migrate_engine |
332 | + |
333 | + fixed_ips = Table('fixed_ips', meta, autoload=True) |
334 | + fixed_ips.drop_column(fixed_ips_host) |
335 | + |
336 | + networks = Table('networks', meta, autoload=True) |
337 | + networks.drop_column(networks_multi_host) |
338 | |
339 | === modified file 'nova/db/sqlalchemy/models.py' |
340 | --- nova/db/sqlalchemy/models.py 2011-07-08 03:07:58 +0000 |
341 | +++ nova/db/sqlalchemy/models.py 2011-07-20 18:28:31 +0000 |
342 | @@ -545,6 +545,7 @@ |
343 | injected = Column(Boolean, default=False) |
344 | cidr = Column(String(255), unique=True) |
345 | cidr_v6 = Column(String(255), unique=True) |
346 | + multi_host = Column(Boolean, default=False) |
347 | |
348 | gateway_v6 = Column(String(255)) |
349 | netmask_v6 = Column(String(255)) |
350 | @@ -603,6 +604,7 @@ |
351 | # leased means dhcp bridge has leased the ip |
352 | leased = Column(Boolean, default=False) |
353 | reserved = Column(Boolean, default=False) |
354 | + host = Column(String(255)) |
355 | |
356 | |
357 | class FloatingIp(BASE, NovaBase): |
358 | |
359 | === modified file 'nova/exception.py' |
360 | --- nova/exception.py 2011-07-13 18:19:32 +0000 |
361 | +++ nova/exception.py 2011-07-20 18:28:31 +0000 |
362 | @@ -408,6 +408,11 @@ |
363 | message = _("Instance %(instance_id)s has zero fixed ips.") |
364 | |
365 | |
366 | +class FixedIpNotFoundForNetworkHost(FixedIpNotFound): |
367 | + message = _("Network host %(host)s has zero fixed ips " |
368 | + "in network %(network_id)s.") |
369 | + |
370 | + |
371 | class FixedIpNotFoundForSpecificInstance(FixedIpNotFound): |
372 | message = _("Instance %(instance_id)s doesn't have fixed ip '%(ip)s'.") |
373 | |
374 | |
375 | === modified file 'nova/network/api.py' |
376 | --- nova/network/api.py 2011-07-19 20:49:05 +0000 |
377 | +++ nova/network/api.py 2011-07-20 18:28:31 +0000 |
378 | @@ -18,7 +18,6 @@ |
379 | |
380 | """Handles all requests relating to instances (guest vms).""" |
381 | |
382 | -from nova import db |
383 | from nova import exception |
384 | from nova import flags |
385 | from nova import log as logging |
386 | @@ -108,7 +107,11 @@ |
387 | '(%(project)s)') % |
388 | {'address': floating_ip['address'], |
389 | 'project': context.project_id}) |
390 | - host = fixed_ip['network']['host'] |
391 | + # NOTE(vish): if we are multi_host, send to the instances host |
392 | + if fixed_ip['network']['multi_host']: |
393 | + host = fixed_ip['instance']['host'] |
394 | + else: |
395 | + host = fixed_ip['network']['host'] |
396 | rpc.cast(context, |
397 | self.db.queue_get_for(context, FLAGS.network_topic, host), |
398 | {'method': 'associate_floating_ip', |
399 | @@ -123,7 +126,11 @@ |
400 | return |
401 | if not floating_ip.get('fixed_ip'): |
402 | raise exception.ApiError('Address is not associated.') |
403 | - host = floating_ip['fixed_ip']['network']['host'] |
404 | + # NOTE(vish): if we are multi_host, send to the instances host |
405 | + if floating_ip['fixed_ip']['network']['multi_host']: |
406 | + host = floating_ip['fixed_ip']['instance']['host'] |
407 | + else: |
408 | + host = floating_ip['fixed_ip']['network']['host'] |
409 | rpc.call(context, |
410 | self.db.queue_get_for(context, FLAGS.network_topic, host), |
411 | {'method': 'disassociate_floating_ip', |
412 | @@ -137,7 +144,9 @@ |
413 | args = kwargs |
414 | args['instance_id'] = instance['id'] |
415 | args['project_id'] = instance['project_id'] |
416 | + args['host'] = instance['host'] |
417 | args['instance_type_id'] = instance['instance_type_id'] |
418 | + |
419 | return rpc.call(context, FLAGS.network_topic, |
420 | {'method': 'allocate_for_instance', |
421 | 'args': args}) |
422 | @@ -176,7 +185,8 @@ |
423 | def get_instance_nw_info(self, context, instance): |
424 | """Returns all network info related to an instance.""" |
425 | args = {'instance_id': instance['id'], |
426 | - 'instance_type_id': instance['instance_type_id']} |
427 | + 'instance_type_id': instance['instance_type_id'], |
428 | + 'host': instance['host']} |
429 | return rpc.call(context, FLAGS.network_topic, |
430 | {'method': 'get_instance_nw_info', |
431 | 'args': args}) |
432 | |
433 | === modified file 'nova/network/linux_net.py' |
434 | --- nova/network/linux_net.py 2011-06-27 21:48:03 +0000 |
435 | +++ nova/network/linux_net.py 2011-07-20 18:28:31 +0000 |
436 | @@ -497,7 +497,7 @@ |
437 | suffix = net_attrs['cidr'].rpartition('/')[2] |
438 | out, err = _execute('sudo', 'ip', 'addr', 'add', |
439 | '%s/%s' % |
440 | - (net_attrs['gateway'], suffix), |
441 | + (net_attrs['dhcp_server'], suffix), |
442 | 'brd', |
443 | net_attrs['broadcast'], |
444 | 'dev', |
445 | @@ -551,21 +551,27 @@ |
446 | bridge) |
447 | |
448 | |
449 | -def get_dhcp_leases(context, network_id): |
450 | +def get_dhcp_leases(context, network_ref): |
451 | """Return a network's hosts config in dnsmasq leasefile format.""" |
452 | hosts = [] |
453 | - for fixed_ip_ref in db.network_get_associated_fixed_ips(context, |
454 | - network_id): |
455 | - hosts.append(_host_lease(fixed_ip_ref)) |
456 | + for fixed_ref in db.network_get_associated_fixed_ips(context, |
457 | + network_ref['id']): |
458 | + host = fixed_ref['instance']['host'] |
459 | + if network_ref['multi_host'] and FLAGS.host != host: |
460 | + continue |
461 | + hosts.append(_host_lease(fixed_ref)) |
462 | return '\n'.join(hosts) |
463 | |
464 | |
465 | -def get_dhcp_hosts(context, network_id): |
466 | +def get_dhcp_hosts(context, network_ref): |
467 | """Get network's hosts config in dhcp-host format.""" |
468 | hosts = [] |
469 | - for fixed_ip_ref in db.network_get_associated_fixed_ips(context, |
470 | - network_id): |
471 | - hosts.append(_host_dhcp(fixed_ip_ref)) |
472 | + for fixed_ref in db.network_get_associated_fixed_ips(context, |
473 | + network_ref['id']): |
474 | + host = fixed_ref['instance']['host'] |
475 | + if network_ref['multi_host'] and FLAGS.host != host: |
476 | + continue |
477 | + hosts.append(_host_dhcp(fixed_ref)) |
478 | return '\n'.join(hosts) |
479 | |
480 | |
481 | @@ -573,18 +579,16 @@ |
482 | # configuration options (like dchp-range, vlan, ...) |
483 | # aren't reloaded. |
484 | @utils.synchronized('dnsmasq_start') |
485 | -def update_dhcp(context, network_id): |
486 | +def update_dhcp(context, network_ref): |
487 | """(Re)starts a dnsmasq server for a given network. |
488 | |
489 | If a dnsmasq instance is already running then send a HUP |
490 | signal causing it to reload, otherwise spawn a new instance. |
491 | |
492 | """ |
493 | - network_ref = db.network_get(context, network_id) |
494 | - |
495 | conffile = _dhcp_file(network_ref['bridge'], 'conf') |
496 | with open(conffile, 'w') as f: |
497 | - f.write(get_dhcp_hosts(context, network_id)) |
498 | + f.write(get_dhcp_hosts(context, network_ref)) |
499 | |
500 | # Make sure dnsmasq can actually read it (it setuid()s to "nobody") |
501 | os.chmod(conffile, 0644) |
502 | @@ -612,9 +616,7 @@ |
503 | |
504 | |
505 | @utils.synchronized('radvd_start') |
506 | -def update_ra(context, network_id): |
507 | - network_ref = db.network_get(context, network_id) |
508 | - |
509 | +def update_ra(context, network_ref): |
510 | conffile = _ra_file(network_ref['bridge'], 'conf') |
511 | with open(conffile, 'w') as f: |
512 | conf_str = """ |
513 | @@ -650,9 +652,6 @@ |
514 | LOG.debug(_('Pid %d is stale, relaunching radvd'), pid) |
515 | command = _ra_cmd(network_ref) |
516 | _execute(*command) |
517 | - db.network_update(context, network_id, |
518 | - {'gateway_v6': |
519 | - utils.get_my_linklocal(network_ref['bridge'])}) |
520 | |
521 | |
522 | def _host_lease(fixed_ip_ref): |
523 | @@ -701,10 +700,11 @@ |
524 | cmd = ['sudo', '-E', 'dnsmasq', |
525 | '--strict-order', |
526 | '--bind-interfaces', |
527 | + '--interface=%s' % net['bridge'], |
528 | '--conf-file=%s' % FLAGS.dnsmasq_config_file, |
529 | '--domain=%s' % FLAGS.dhcp_domain, |
530 | '--pid-file=%s' % _dhcp_file(net['bridge'], 'pid'), |
531 | - '--listen-address=%s' % net['gateway'], |
532 | + '--listen-address=%s' % net['dhcp_server'], |
533 | '--except-interface=lo', |
534 | '--dhcp-range=%s,static,120s' % net['dhcp_start'], |
535 | '--dhcp-lease-max=%s' % len(netaddr.IPNetwork(net['cidr'])), |
536 | |
537 | === modified file 'nova/network/manager.py' |
538 | --- nova/network/manager.py 2011-07-19 19:29:44 +0000 |
539 | +++ nova/network/manager.py 2011-07-20 18:28:31 +0000 |
540 | @@ -28,7 +28,6 @@ |
541 | :flat_network_bridge: Bridge device for simple network instances |
542 | :flat_interface: FlatDhcp will bridge into this interface if set |
543 | :flat_network_dns: Dns for simple network |
544 | -:flat_network_dhcp_start: Dhcp start for FlatDhcp |
545 | :vlan_start: First VLAN for private networks |
546 | :vpn_ip: Public IP for the cloudpipe VPN servers |
547 | :vpn_start: First Vpn port for private networks |
548 | @@ -49,7 +48,6 @@ |
549 | import math |
550 | import netaddr |
551 | import socket |
552 | -import pickle |
553 | from eventlet import greenpool |
554 | |
555 | from nova import context |
556 | @@ -78,8 +76,6 @@ |
557 | 'Whether to attempt to inject network setup into guest') |
558 | flags.DEFINE_string('flat_interface', None, |
559 | 'FlatDhcp will bridge into this interface if set') |
560 | -flags.DEFINE_string('flat_network_dhcp_start', '10.0.0.2', |
561 | - 'Dhcp start for FlatDhcp') |
562 | flags.DEFINE_integer('vlan_start', 100, 'First VLAN for private networks') |
563 | flags.DEFINE_string('vlan_interface', None, |
564 | 'vlans will bridge into this interface if set') |
565 | @@ -87,6 +83,8 @@ |
566 | flags.DEFINE_string('vpn_ip', '$my_ip', |
567 | 'Public IP for the cloudpipe VPN servers') |
568 | flags.DEFINE_integer('vpn_start', 1000, 'First Vpn port for private networks') |
569 | +flags.DEFINE_bool('multi_host', False, |
570 | + 'Default value for multi_host in networks') |
571 | flags.DEFINE_integer('network_size', 256, |
572 | 'Number of addresses in each private subnet') |
573 | flags.DEFINE_string('floating_range', '4.4.4.0/24', |
574 | @@ -104,7 +102,8 @@ |
575 | 'Seconds after which a deallocated ip is disassociated') |
576 | flags.DEFINE_integer('create_unique_mac_address_attempts', 5, |
577 | 'Number of attempts to create unique mac address') |
578 | - |
579 | +flags.DEFINE_bool('auto_assign_floating_ip', False, |
580 | + 'Autoassigning floating ip to VM') |
581 | flags.DEFINE_bool('use_ipv6', False, |
582 | 'use the ipv6') |
583 | flags.DEFINE_string('network_host', socket.gethostname(), |
584 | @@ -124,16 +123,26 @@ |
585 | used since they share code to RPC.call allocate_fixed_ip on the |
586 | correct network host to configure dnsmasq |
587 | """ |
588 | - def _allocate_fixed_ips(self, context, instance_id, networks, **kwargs): |
589 | + def _allocate_fixed_ips(self, context, instance_id, host, networks, |
590 | + **kwargs): |
591 | """Calls allocate_fixed_ip once for each network.""" |
592 | green_pool = greenpool.GreenPool() |
593 | |
594 | vpn = kwargs.pop('vpn') |
595 | for network in networks: |
596 | - if network['host'] != self.host: |
597 | + # NOTE(vish): if we are not multi_host pass to the network host |
598 | + if not network['multi_host']: |
599 | + host = network['host'] |
600 | + # NOTE(vish): if there is no network host, set one |
601 | + if host == None: |
602 | + host = rpc.call(context, FLAGS.network_topic, |
603 | + {'method': 'set_network_host', |
604 | + 'args': {'network_ref': network}}) |
605 | + if host != self.host: |
606 | # need to call allocate_fixed_ip to correct network host |
607 | - topic = self.db.queue_get_for(context, FLAGS.network_topic, |
608 | - network['host']) |
609 | + topic = self.db.queue_get_for(context, |
610 | + FLAGS.network_topic, |
611 | + host) |
612 | args = {} |
613 | args['instance_id'] = instance_id |
614 | args['network_id'] = network['id'] |
615 | @@ -149,12 +158,13 @@ |
616 | # wait for all of the allocates (if any) to finish |
617 | green_pool.waitall() |
618 | |
619 | - def _rpc_allocate_fixed_ip(self, context, instance_id, network_id): |
620 | + def _rpc_allocate_fixed_ip(self, context, instance_id, network_id, |
621 | + **kwargs): |
622 | """Sits in between _allocate_fixed_ips and allocate_fixed_ip to |
623 | perform network lookup on the far side of rpc. |
624 | """ |
625 | network = self.db.network_get(context, network_id) |
626 | - self.allocate_fixed_ip(context, instance_id, network) |
627 | + self.allocate_fixed_ip(context, instance_id, network, **kwargs) |
628 | |
629 | |
630 | class FloatingIP(object): |
631 | @@ -193,7 +203,7 @@ |
632 | # which is currently the NetworkManager version |
633 | # do this first so fixed ip is already allocated |
634 | ips = super(FloatingIP, self).allocate_for_instance(context, **kwargs) |
635 | - if hasattr(FLAGS, 'auto_assign_floating_ip'): |
636 | + if FLAGS.auto_assign_floating_ip: |
637 | # allocate a floating ip (public_ip is just the address string) |
638 | public_ip = self.allocate_floating_ip(context, project_id) |
639 | # set auto_assigned column to true for the floating ip |
640 | @@ -300,15 +310,36 @@ |
641 | super(NetworkManager, self).__init__(service_name='network', |
642 | *args, **kwargs) |
643 | |
644 | + @utils.synchronized('get_dhcp') |
645 | + def _get_dhcp_ip(self, context, network_ref, host=None): |
646 | + """Get the proper dhcp address to listen on.""" |
647 | + # NOTE(vish): this is for compatibility |
648 | + if not network_ref['multi_host']: |
649 | + return network_ref['gateway'] |
650 | + |
651 | + if not host: |
652 | + host = self.host |
653 | + network_id = network_ref['id'] |
654 | + try: |
655 | + fip = self.db.fixed_ip_get_by_network_host(context, |
656 | + network_id, |
657 | + host) |
658 | + return fip['address'] |
659 | + except exception.FixedIpNotFoundForNetworkHost: |
660 | + elevated = context.elevated() |
661 | + return self.db.fixed_ip_associate_pool(elevated, |
662 | + network_id, |
663 | + host=host) |
664 | + |
665 | def init_host(self): |
666 | """Do any initialization that needs to be run if this is a |
667 | standalone service. |
668 | """ |
669 | - # Set up this host for networks in which it's already |
670 | - # the designated network host. |
671 | + # NOTE(vish): Set up networks for which this host already has |
672 | + # an ip address. |
673 | ctxt = context.get_admin_context() |
674 | for network in self.db.network_get_all_by_host(ctxt, self.host): |
675 | - self._on_set_network_host(ctxt, network['id']) |
676 | + self._setup_network(ctxt, network) |
677 | |
678 | def periodic_tasks(self, context=None): |
679 | """Tasks to be run at a periodic interval.""" |
680 | @@ -323,32 +354,13 @@ |
681 | if num: |
682 | LOG.debug(_('Dissassociated %s stale fixed ip(s)'), num) |
683 | |
684 | - # setup any new networks which have been created |
685 | - self.set_network_hosts(context) |
686 | - |
687 | - def set_network_host(self, context, network_id): |
688 | + def set_network_host(self, context, network_ref): |
689 | """Safely sets the host of the network.""" |
690 | LOG.debug(_('setting network host'), context=context) |
691 | host = self.db.network_set_host(context, |
692 | - network_id, |
693 | + network_ref['id'], |
694 | self.host) |
695 | - if host == self.host: |
696 | - self._on_set_network_host(context, network_id) |
697 | - |
698 | - def set_network_hosts(self, context): |
699 | - """Set the network hosts for any networks which are unset.""" |
700 | - try: |
701 | - networks = self.db.network_get_all(context) |
702 | - except exception.NoNetworksFound: |
703 | - # no networks found, nothing to do |
704 | - return |
705 | - |
706 | - for network in networks: |
707 | - host = network['host'] |
708 | - if not host: |
709 | - # break so worker will only grab 1 (to help scale flatter) |
710 | - self.set_network_host(context, network['id']) |
711 | - break |
712 | + return host |
713 | |
714 | def _get_networks_for_instance(self, context, instance_id, project_id): |
715 | """Determine & return which networks an instance should connect to.""" |
716 | @@ -361,9 +373,9 @@ |
717 | # we don't care if no networks are found |
718 | pass |
719 | |
720 | - # return only networks which are not vlan networks and have host set |
721 | + # return only networks which are not vlan networks |
722 | return [network for network in networks if |
723 | - not network['vlan'] and network['host']] |
724 | + not network['vlan']] |
725 | |
726 | def allocate_for_instance(self, context, **kwargs): |
727 | """Handles allocating the various network resources for an instance. |
728 | @@ -371,6 +383,7 @@ |
729 | rpc.called by network_api |
730 | """ |
731 | instance_id = kwargs.pop('instance_id') |
732 | + host = kwargs.pop('host') |
733 | project_id = kwargs.pop('project_id') |
734 | type_id = kwargs.pop('instance_type_id') |
735 | vpn = kwargs.pop('vpn') |
736 | @@ -379,9 +392,11 @@ |
737 | context=context) |
738 | networks = self._get_networks_for_instance(admin_context, instance_id, |
739 | project_id) |
740 | + LOG.warn(networks) |
741 | self._allocate_mac_addresses(context, instance_id, networks) |
742 | - self._allocate_fixed_ips(admin_context, instance_id, networks, vpn=vpn) |
743 | - return self.get_instance_nw_info(context, instance_id, type_id) |
744 | + self._allocate_fixed_ips(admin_context, instance_id, host, networks, |
745 | + vpn=vpn) |
746 | + return self.get_instance_nw_info(context, instance_id, type_id, host) |
747 | |
748 | def deallocate_for_instance(self, context, **kwargs): |
749 | """Handles deallocating various network resources for an instance. |
750 | @@ -401,7 +416,8 @@ |
751 | # deallocate vifs (mac addresses) |
752 | self.db.virtual_interface_delete_by_instance(context, instance_id) |
753 | |
754 | - def get_instance_nw_info(self, context, instance_id, instance_type_id): |
755 | + def get_instance_nw_info(self, context, instance_id, |
756 | + instance_type_id, host): |
757 | """Creates network info list for instance. |
758 | |
759 | called by allocate_for_instance and netowrk_api |
760 | @@ -445,9 +461,16 @@ |
761 | 'cidr': network['cidr'], |
762 | 'cidr_v6': network['cidr_v6'], |
763 | 'injected': network['injected']} |
764 | + if network['multi_host']: |
765 | + dhcp_server = self._get_dhcp_ip(context, network, host) |
766 | + else: |
767 | + dhcp_server = self._get_dhcp_ip(context, |
768 | + network, |
769 | + network['host']) |
770 | info = { |
771 | 'label': network['label'], |
772 | 'gateway': network['gateway'], |
773 | + 'dhcp_server': dhcp_server, |
774 | 'broadcast': network['broadcast'], |
775 | 'mac': vif['address'], |
776 | 'rxtx_cap': flavor['rxtx_cap'], |
777 | @@ -487,10 +510,10 @@ |
778 | random.randint(0x00, 0xff)] |
779 | return ':'.join(map(lambda x: "%02x" % x, mac)) |
780 | |
781 | - def add_fixed_ip_to_instance(self, context, instance_id, network_id): |
782 | + def add_fixed_ip_to_instance(self, context, instance_id, host, network_id): |
783 | """Adds a fixed ip to an instance from specified network.""" |
784 | networks = [self.db.network_get(context, network_id)] |
785 | - self._allocate_fixed_ips(context, instance_id, networks) |
786 | + self._allocate_fixed_ips(context, instance_id, host, networks) |
787 | |
788 | def remove_fixed_ip_from_instance(self, context, instance_id, address): |
789 | """Removes a fixed ip from an instance from specified network.""" |
790 | @@ -517,6 +540,7 @@ |
791 | values = {'allocated': True, |
792 | 'virtual_interface_id': vif['id']} |
793 | self.db.fixed_ip_update(context, address, values) |
794 | + self._setup_network(context, network) |
795 | return address |
796 | |
797 | def deallocate_fixed_ip(self, context, address, **kwargs): |
798 | @@ -562,10 +586,10 @@ |
799 | # means there will stale entries in the conf file |
800 | # the code below will update the file if necessary |
801 | if FLAGS.update_dhcp_on_disassociate: |
802 | - network = self.db.fixed_ip_get_network(context, address) |
803 | - self.driver.update_dhcp(context, network['id']) |
804 | + network_ref = self.db.fixed_ip_get_network(context, address) |
805 | + self._setup_network(context, network_ref) |
806 | |
807 | - def create_networks(self, context, label, cidr, num_networks, |
808 | + def create_networks(self, context, label, cidr, multi_host, num_networks, |
809 | network_size, cidr_v6, gateway_v6, bridge, |
810 | bridge_interface, **kwargs): |
811 | """Create networks based on parameters.""" |
812 | @@ -584,6 +608,7 @@ |
813 | net['bridge_interface'] = bridge_interface |
814 | net['dns'] = FLAGS.flat_network_dns |
815 | net['cidr'] = cidr |
816 | + net['multi_host'] = multi_host |
817 | net['netmask'] = str(project_net.netmask) |
818 | net['gateway'] = str(project_net[1]) |
819 | net['broadcast'] = str(project_net.broadcast) |
820 | @@ -659,12 +684,13 @@ |
821 | 'address': address, |
822 | 'reserved': reserved}) |
823 | |
824 | - def _allocate_fixed_ips(self, context, instance_id, networks, **kwargs): |
825 | + def _allocate_fixed_ips(self, context, instance_id, host, networks, |
826 | + **kwargs): |
827 | """Calls allocate_fixed_ip once for each network.""" |
828 | raise NotImplementedError() |
829 | |
830 | - def _on_set_network_host(self, context, network_id): |
831 | - """Called when this host becomes the host for a network.""" |
832 | + def _setup_network(self, context, network_ref): |
833 | + """Sets up network on this host.""" |
834 | raise NotImplementedError() |
835 | |
836 | def setup_compute_network(self, context, instance_id): |
837 | @@ -706,7 +732,8 @@ |
838 | |
839 | timeout_fixed_ips = False |
840 | |
841 | - def _allocate_fixed_ips(self, context, instance_id, networks, **kwargs): |
842 | + def _allocate_fixed_ips(self, context, instance_id, host, networks, |
843 | + **kwargs): |
844 | """Calls allocate_fixed_ip once for each network.""" |
845 | for network in networks: |
846 | self.allocate_fixed_ip(context, instance_id, network) |
847 | @@ -724,12 +751,12 @@ |
848 | """ |
849 | pass |
850 | |
851 | - def _on_set_network_host(self, context, network_id): |
852 | - """Called when this host becomes the host for a network.""" |
853 | + def _setup_network(self, context, network_ref): |
854 | + """Setup Network on this host.""" |
855 | net = {} |
856 | net['injected'] = FLAGS.flat_injected |
857 | net['dns'] = FLAGS.flat_network_dns |
858 | - self.db.network_update(context, network_id, net) |
859 | + self.db.network_update(context, network_ref['id'], net) |
860 | |
861 | |
862 | class FlatDHCPManager(FloatingIP, RPCAllocateFixedIP, NetworkManager): |
863 | @@ -760,30 +787,23 @@ |
864 | """ |
865 | networks = db.network_get_all_by_instance(context, instance_id) |
866 | for network in networks: |
867 | - self.driver.ensure_bridge(network['bridge'], |
868 | - network['bridge_interface']) |
869 | - |
870 | - def allocate_fixed_ip(self, context, instance_id, network, **kwargs): |
871 | - """Allocate flat_network fixed_ip, then setup dhcp for this network.""" |
872 | - address = super(FlatDHCPManager, self).allocate_fixed_ip(context, |
873 | - instance_id, |
874 | - network) |
875 | - if not FLAGS.fake_network: |
876 | - self.driver.update_dhcp(context, network['id']) |
877 | - |
878 | - def _on_set_network_host(self, context, network_id): |
879 | - """Called when this host becomes the host for a project.""" |
880 | - net = {} |
881 | - net['dhcp_start'] = FLAGS.flat_network_dhcp_start |
882 | - self.db.network_update(context, network_id, net) |
883 | - network = db.network_get(context, network_id) |
884 | - self.driver.ensure_bridge(network['bridge'], |
885 | - network['bridge_interface'], |
886 | - network) |
887 | - if not FLAGS.fake_network: |
888 | - self.driver.update_dhcp(context, network_id) |
889 | + if not network['multi_host']: |
890 | + self.driver.ensure_bridge(network['bridge'], |
891 | + network['bridge_interface']) |
892 | + |
893 | + def _setup_network(self, context, network_ref): |
894 | + """Sets up network on this host.""" |
895 | + network_ref['dhcp_server'] = self._get_dhcp_ip(context, network_ref) |
896 | + self.driver.ensure_bridge(network_ref['bridge'], |
897 | + network_ref['bridge_interface'], |
898 | + network_ref) |
899 | + if not FLAGS.fake_network: |
900 | + self.driver.update_dhcp(context, network_ref) |
901 | if(FLAGS.use_ipv6): |
902 | - self.driver.update_ra(context, network_id) |
903 | + self.driver.update_ra(context, network_ref) |
904 | + gateway = utils.get_my_linklocal(network_ref['bridge']) |
905 | + self.db.network_update(context, network_ref['id'], |
906 | + {'gateway_v6': gateway}) |
907 | |
908 | |
909 | class VlanManager(RPCAllocateFixedIP, FloatingIP, NetworkManager): |
910 | @@ -832,8 +852,8 @@ |
911 | values = {'allocated': True, |
912 | 'virtual_interface_id': vif['id']} |
913 | self.db.fixed_ip_update(context, address, values) |
914 | - if not FLAGS.fake_network: |
915 | - self.driver.update_dhcp(context, network['id']) |
916 | + self._setup_network(context, network) |
917 | + return address |
918 | |
919 | def add_network_to_project(self, context, project_id): |
920 | """Force adds another network to a project.""" |
921 | @@ -845,17 +865,15 @@ |
922 | """ |
923 | networks = self.db.network_get_all_by_instance(context, instance_id) |
924 | for network in networks: |
925 | - self.driver.ensure_vlan_bridge(network['vlan'], |
926 | - network['bridge'], |
927 | - network['bridge_interface']) |
928 | + if not network['multi_host']: |
929 | + self.driver.ensure_vlan_bridge(network['vlan'], |
930 | + network['bridge'], |
931 | + network['bridge_interface']) |
932 | |
933 | def _get_networks_for_instance(self, context, instance_id, project_id): |
934 | """Determine which networks an instance should connect to.""" |
935 | # get networks associated with project |
936 | - networks = self.db.project_get_networks(context, project_id) |
937 | - |
938 | - # return only networks which have host set |
939 | - return [network for network in networks if network['host']] |
940 | + return self.db.project_get_networks(context, project_id) |
941 | |
942 | def create_networks(self, context, **kwargs): |
943 | """Create networks based on parameters.""" |
944 | @@ -874,32 +892,35 @@ |
945 | |
946 | NetworkManager.create_networks(self, context, vpn=True, **kwargs) |
947 | |
948 | - def _on_set_network_host(self, context, network_id): |
949 | - """Called when this host becomes the host for a network.""" |
950 | - network = self.db.network_get(context, network_id) |
951 | - if not network['vpn_public_address']: |
952 | + def _setup_network(self, context, network_ref): |
953 | + """Sets up network on this host.""" |
954 | + network_ref['dhcp_server'] = self._get_dhcp_ip(context, network_ref) |
955 | + if not network_ref['vpn_public_address']: |
956 | net = {} |
957 | address = FLAGS.vpn_ip |
958 | net['vpn_public_address'] = address |
959 | - db.network_update(context, network_id, net) |
960 | + network_ref = db.network_update(context, network_ref['id'], net) |
961 | else: |
962 | - address = network['vpn_public_address'] |
963 | - self.driver.ensure_vlan_bridge(network['vlan'], |
964 | - network['bridge'], |
965 | - network['bridge_interface'], |
966 | - network) |
967 | + address = network_ref['vpn_public_address'] |
968 | + self.driver.ensure_vlan_bridge(network_ref['vlan'], |
969 | + network_ref['bridge'], |
970 | + network_ref['bridge_interface'], |
971 | + network_ref) |
972 | |
973 | # NOTE(vish): only ensure this forward if the address hasn't been set |
974 | # manually. |
975 | if address == FLAGS.vpn_ip and hasattr(self.driver, |
976 | "ensure_vlan_forward"): |
977 | self.driver.ensure_vlan_forward(FLAGS.vpn_ip, |
978 | - network['vpn_public_port'], |
979 | - network['vpn_private_address']) |
980 | + network_ref['vpn_public_port'], |
981 | + network_ref['vpn_private_address']) |
982 | if not FLAGS.fake_network: |
983 | - self.driver.update_dhcp(context, network_id) |
984 | + self.driver.update_dhcp(context, network_ref) |
985 | if(FLAGS.use_ipv6): |
986 | - self.driver.update_ra(context, network_id) |
987 | + self.driver.update_ra(context, network_ref) |
988 | + gateway = utils.get_my_linklocal(network_ref['bridge']) |
989 | + self.db.network_update(context, network_ref['id'], |
990 | + {'gateway_v6': gateway}) |
991 | |
992 | @property |
993 | def _bottom_reserved_ips(self): |
994 | |
995 | === modified file 'nova/tests/__init__.py' |
996 | --- nova/tests/__init__.py 2011-06-29 17:58:10 +0000 |
997 | +++ nova/tests/__init__.py 2011-07-20 18:28:31 +0000 |
998 | @@ -59,6 +59,7 @@ |
999 | network.create_networks(ctxt, |
1000 | label='test', |
1001 | cidr=FLAGS.fixed_range, |
1002 | + multi_host=FLAGS.multi_host, |
1003 | num_networks=FLAGS.num_networks, |
1004 | network_size=FLAGS.network_size, |
1005 | cidr_v6=FLAGS.fixed_range_v6, |
1006 | @@ -68,7 +69,7 @@ |
1007 | vpn_start=FLAGS.vpn_start, |
1008 | vlan_start=FLAGS.vlan_start) |
1009 | for net in db.network_get_all(ctxt): |
1010 | - network.set_network_host(ctxt, net['id']) |
1011 | + network.set_network_host(ctxt, net) |
1012 | |
1013 | cleandb = os.path.join(FLAGS.state_path, FLAGS.sqlite_clean_db) |
1014 | shutil.copyfile(testdb, cleandb) |
1015 | |
1016 | === modified file 'nova/tests/test_libvirt.py' |
1017 | --- nova/tests/test_libvirt.py 2011-06-28 16:20:02 +0000 |
1018 | +++ nova/tests/test_libvirt.py 2011-07-20 18:28:31 +0000 |
1019 | @@ -58,6 +58,7 @@ |
1020 | 'cidr': fake_ip, |
1021 | 'cidr_v6': fake_ip} |
1022 | mapping = {'mac': fake, |
1023 | + 'dhcp_server': fake, |
1024 | 'gateway': fake, |
1025 | 'gateway6': fake, |
1026 | 'ips': [{'ip': fake_ip}, {'ip': fake_ip}]} |
1027 | |
1028 | === modified file 'nova/tests/test_network.py' |
1029 | --- nova/tests/test_network.py 2011-07-11 14:49:34 +0000 |
1030 | +++ nova/tests/test_network.py 2011-07-20 18:28:31 +0000 |
1031 | @@ -45,6 +45,7 @@ |
1032 | networks = [{'id': 0, |
1033 | 'label': 'test0', |
1034 | 'injected': False, |
1035 | + 'multi_host': False, |
1036 | 'cidr': '192.168.0.0/24', |
1037 | 'cidr_v6': '2001:db8::/64', |
1038 | 'gateway_v6': '2001:db8::1', |
1039 | @@ -62,6 +63,7 @@ |
1040 | {'id': 1, |
1041 | 'label': 'test1', |
1042 | 'injected': False, |
1043 | + 'multi_host': False, |
1044 | 'cidr': '192.168.1.0/24', |
1045 | 'cidr_v6': '2001:db9::/64', |
1046 | 'gateway_v6': '2001:db9::1', |
1047 | @@ -122,20 +124,6 @@ |
1048 | self.network = network_manager.FlatManager(host=HOST) |
1049 | self.network.db = db |
1050 | |
1051 | - def test_set_network_hosts(self): |
1052 | - self.mox.StubOutWithMock(db, 'network_get_all') |
1053 | - self.mox.StubOutWithMock(db, 'network_set_host') |
1054 | - self.mox.StubOutWithMock(db, 'network_update') |
1055 | - |
1056 | - db.network_get_all(mox.IgnoreArg()).AndReturn([networks[0]]) |
1057 | - db.network_set_host(mox.IgnoreArg(), |
1058 | - networks[0]['id'], |
1059 | - mox.IgnoreArg()).AndReturn(HOST) |
1060 | - db.network_update(mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg()) |
1061 | - self.mox.ReplayAll() |
1062 | - |
1063 | - self.network.set_network_hosts(None) |
1064 | - |
1065 | def test_get_instance_nw_info(self): |
1066 | self.mox.StubOutWithMock(db, 'fixed_ip_get_by_instance') |
1067 | self.mox.StubOutWithMock(db, 'virtual_interface_get_by_instance') |
1068 | @@ -149,7 +137,7 @@ |
1069 | mox.IgnoreArg()).AndReturn(flavor) |
1070 | self.mox.ReplayAll() |
1071 | |
1072 | - nw_info = self.network.get_instance_nw_info(None, 0, 0) |
1073 | + nw_info = self.network.get_instance_nw_info(None, 0, 0, None) |
1074 | |
1075 | self.assertTrue(nw_info) |
1076 | |
1077 | @@ -164,6 +152,7 @@ |
1078 | self.assertDictMatch(nw[0], check) |
1079 | |
1080 | check = {'broadcast': '192.168.%s.255' % i, |
1081 | + 'dhcp_server': '192.168.%s.1' % i, |
1082 | 'dns': 'DONTCARE', |
1083 | 'gateway': '192.168.%s.1' % i, |
1084 | 'gateway6': '2001:db%s::1' % i8, |
1085 | |
1086 | === modified file 'nova/virt/libvirt/connection.py' |
1087 | --- nova/virt/libvirt/connection.py 2011-07-20 16:17:44 +0000 |
1088 | +++ nova/virt/libvirt/connection.py 2011-07-20 18:28:31 +0000 |
1089 | @@ -928,7 +928,6 @@ |
1090 | |
1091 | def _get_nic_for_xml(self, network, mapping): |
1092 | # Assume that the gateway also acts as the dhcp server. |
1093 | - dhcp_server = mapping['gateway'] |
1094 | gateway6 = mapping.get('gateway6') |
1095 | mac_id = mapping['mac'].replace(':', '') |
1096 | |
1097 | @@ -951,7 +950,7 @@ |
1098 | 'bridge_name': network['bridge'], |
1099 | 'mac_address': mapping['mac'], |
1100 | 'ip_address': mapping['ips'][0]['ip'], |
1101 | - 'dhcp_server': dhcp_server, |
1102 | + 'dhcp_server': mapping['dhcp_server'], |
1103 | 'extra_params': extra_params, |
1104 | } |
1105 |
48: multi_host = multi_host == 'T'
I think something like:
multi_host = multi_host. lower() [:1] == 't'
so it can accept any "truthy" value would be more user friendly.