Merge lp:~soren/nova/network-fixes into lp:~hudson-openstack/nova/trunk

Proposed by Soren Hansen
Status: Merged
Approved by: Soren Hansen
Approved revision: 304
Merged at revision: 317
Proposed branch: lp:~soren/nova/network-fixes
Merge into: lp:~hudson-openstack/nova/trunk
Diff against target: 202 lines (+64/-22)
5 files modified
nova/db/api.py (+12/-0)
nova/db/sqlalchemy/api.py (+12/-0)
nova/network/linux_net.py (+30/-20)
nova/network/manager.py (+8/-0)
nova/tests/network_unittest.py (+2/-2)
To merge this branch: bzr merge lp:~soren/nova/network-fixes
Reviewer Review Type Date Requested Status
Todd Willey (community) Approve
Vish Ishaya (community) Approve
Review via email: mp+36700@code.launchpad.net

Description of the change

Fixes to address the following issues:

 * nova-network no longer refrains from configuring bridges if it finds them already created. This solves a race condition with nova-network and nova-compute running on the same box. If nova-compute happened to do its network config first, nova-network would find the bridge already created and assume it was correctly setup. If nova-network got there first, it would apply the correct IP configuration to the interface. The assumption is that no harm will be done by reapplying the correct IP configuration, so we no longer make this check before doing so.

 * nova-network does not use persistent network configuration (like putting stuff in /etc/network/interfaces), so it needs to check at boot time whether it's already set as a network's designated network node and do the appropriate configuration.

 * If installed, dnsmasq wouldn't find nova-dhcpbridge properly (it would look for it in /usr/lib/python2.6/blahblahblha). Add a flag to specify its location (and make use of it in the packaging).

 * dnsmasq needs to be able to read the dhcp config written by nova. dnsmasq runs as user "nobody", so chmod 644 the config file so that it can be read.

 * dnsmasq needs to be sent a SIGHUP to reread its config. Wrap this call in sudo, because we may be running as non-root.

To post a comment you must log in.
Revision history for this message
Vish Ishaya (vishvananda) wrote :
Download full text (7.3 KiB)

This looks good. One issue:

We have a couple different solutions in the works for applying network configuration at service boot. In the branch I am working on lp:~vishvananda/nova/fix-iptables which fixes a number of isssues in devcamcar's version that is under review, we have added an explicitly called init_host() which is called when the manager is loaded from service.py. I don't want init to happen in two places, so we should move one or the other. Preference on whether we do it in init or an explicit method?

On Sep 27, 2010, at 4:57 AM, Soren Hansen wrote:

> Soren Hansen has proposed merging lp:~soren/nova/network-fixes into lp:nova.
>
> Requested reviews:
> Nova Core (nova-core)
>
>
> Fixes to address the following issues:
>
> * nova-network no longer refrains from configuring bridges if it finds them already created. This solves a race condition with nova-network and nova-compute running on the same box. If nova-compute happened to do its network config first, nova-network would find the bridge already created and assume it was correctly setup. If nova-network got there first, it would apply the correct IP configuration to the interface. The assumption is that no harm will be done by reapplying the correct IP configuration, so we no longer make this check before doing so.
>
> * nova-network does not use persistent network configuration (like putting stuff in /etc/network/interfaces), so it needs to check at boot time whether it's already set as a network's designated network node and do the appropriate configuration.
>
> * If installed, dnsmasq wouldn't find nova-dhcpbridge properly (it would look for it in /usr/lib/python2.6/blahblahblha). Add a flag to specify its location (and make use of it in the packaging).
>
> * dnsmasq needs to be able to read the dhcp config written by nova. dnsmasq runs as user "nobody", so chmod 644 the config file so that it can be read.
> --
> https://code.launchpad.net/~soren/nova/network-fixes/+merge/36700
> Your team Nova Core is requested to review the proposed merge of lp:~soren/nova/network-fixes into lp:nova.
> === modified file 'nova/db/api.py'
> --- nova/db/api.py 2010-09-23 19:31:17 +0000
> +++ nova/db/api.py 2010-09-27 11:57:40 +0000
> @@ -554,3 +554,15 @@
>
> """
> return IMPL.volume_update(context, volume_id, values)
> +
> +
> +###################
> +
> +
> +def host_get_networks(context, host):
> + """Return all networks for which the given host is the designated
> + network host
> + """
> + return IMPL.host_get_networks(context, host)
> +
> +
>
> === modified file 'nova/db/sqlalchemy/api.py'
> --- nova/db/sqlalchemy/api.py 2010-09-23 19:31:17 +0000
> +++ nova/db/sqlalchemy/api.py 2010-09-27 11:57:40 +0000
> @@ -848,3 +848,15 @@
> for (key, value) in values.iteritems():
> volume_ref[key] = value
> volume_ref.save(session=session)
> +
> +
> +###################
> +
> +
> +def host_get_networks(context, host):
> + session = get_session()
> + with session.begin():
> + return session.query(models.Network
> + ).filter_by(deleted=False
> + ).filter_by(host=host
> + ...

Read more...

Revision history for this message
Soren Hansen (soren) wrote :

Your approach sounds great. If your stuff lands first, I'll rework this branch to use init_host. If it doesn't, I'll do it once your stuff has landed and file a new merge proposal. Sounds good?

Revision history for this message
Vish Ishaya (vishvananda) wrote :

lgtm.

review: Approve
Revision history for this message
Vish Ishaya (vishvananda) wrote :

I am using this and it works fine for me. Someone else want to approve it?

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

The attempt to merge lp:~soren/nova/network-fixes into lp:nova failed.Below is the output from the failed tests.

nova.tests.access_unittest
  AccessTestCase
    test_001_allow_all ... [OK]
/var/lib/hudson/src/nova/hudson/nova/db/sqlalchemy/api.py:42: DeprecationWarning: Use of empty request context is deprecated
    test_002_allow_none ... [OK]
/var/lib/hudson/src/nova/hudson/nova/db/sqlalchemy/api.py:42: DeprecationWarning: Use of empty request context is deprecated
    test_003_allow_project_manager ... [OK]
/var/lib/hudson/src/nova/hudson/nova/db/sqlalchemy/api.py:42: DeprecationWarning: Use of empty request context is deprecated
    test_004_allow_sys_and_net ... [OK]
/var/lib/hudson/src/nova/hudson/nova/db/sqlalchemy/api.py:42: DeprecationWarning: Use of empty request context is deprecated
nova.tests.api_unittest
  ApiEc2TestCase
    test_describe_instances ... /var/lib/hudson/src/nova/hudson/nova/db/sqlalchemy/api.py:42: DeprecationWarning: Use of empty request context is deprecated
                                           [OK]
    test_get_all_key_pairs ... /var/lib/hudson/src/nova/hudson/nova/db/sqlalchemy/api.py:42: DeprecationWarning: Use of empty request context is deprecated
                                            [OK]
nova.tests.auth_unittest
  AuthManagerTestCase
    test_004_signature_is_valid ... [OK]
    test_005_can_get_credentials ... [OK]
    test_add_user_role_doesnt_infect_project_roles ... [OK]
/var/lib/hudson/src/nova/hudson/nova/db/sqlalchemy/api.py:42: DeprecationWarning: Use of empty request context is deprecated
    test_adding_role_to_project_is_ignored_unless_added_to_user ... [OK]
/var/lib/hudson/src/nova/hudson/nova/db/sqlalchemy/api.py:42: DeprecationWarning: Use of empty request context is deprecated
    test_can_add_and_remove_user_role ... [OK]
/var/lib/hudson/src/nova/hudson/nova/db/sqlalchemy/api.py:42: DeprecationWarning: Use of empty request context is deprecated
    test_can_add_remove_user_with_role ... [OK]
/var/lib/hudson/src/nova/hudson/nova/db/sqlalchemy/api.py:42: DeprecationWarning: Use of empty request context is deprecated
    test_can_add_user_to_project ... [OK]
/var/lib/hudson/src/nova/hudson/nova/db/sqlalchemy/api.py:42: DeprecationWarning: Use of empty request context is deprecated
    test_can_create_and_get_project ... [OK]
/var/lib/hudson/src/nova/hudson/nova/db/sqlalchemy/api.py:42: DeprecationWarning: Use of empty request context is deprecated
    test_can_create_and_get_project_with_attributes ... [OK]
/var/lib/hudson/src/nova/hudson/nova/db/sqlalchemy/api.py:42: DeprecationWarning: Use of empty request context is deprecated
    test_can_create_project_with_manager ... [OK]
/var/lib/hudson/src/nova/hudson/nova/db/sqlalchem...

Revision history for this message
Vish Ishaya (vishvananda) wrote :

merge failed because there is no networks directory in the core repo. This is one possible fix:

=== modified file 'nova/network/manager.py'
--- nova/network/manager.py 2010-10-01 16:20:34 +0000
+++ nova/network/manager.py 2010-10-01 16:52:35 +0000
@@ -378,7 +378,8 @@
         self.driver.ensure_vlan_bridge(network_ref['vlan'],
                                        network_ref['bridge'],
                                        network_ref)
- self.driver.update_dhcp(context, network_id)
+ if not FLAGS.fake_network:
+ self.driver.update_dhcp(context, network_id)

     @property
     def _bottom_reserved_ips(self):

Revision history for this message
Soren Hansen (soren) wrote :

There. That should do it.

Revision history for this message
Soren Hansen (soren) wrote :

Todd/Vish: If either of you could re-review and approve, that would be great. Thanks.

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

The attempt to merge lp:~soren/nova/network-fixes into lp:nova failed.Below is the output from the failed tests.

nova.tests.access_unittest
  AccessTestCase
    test_001_allow_all ... [OK]
/var/lib/hudson/src/nova/hudson/nova/db/sqlalchemy/api.py:42: DeprecationWarning: Use of empty request context is deprecated
    test_002_allow_none ... [OK]
/var/lib/hudson/src/nova/hudson/nova/db/sqlalchemy/api.py:42: DeprecationWarning: Use of empty request context is deprecated
    test_003_allow_project_manager ... [OK]
/var/lib/hudson/src/nova/hudson/nova/db/sqlalchemy/api.py:42: DeprecationWarning: Use of empty request context is deprecated
    test_004_allow_sys_and_net ... [OK]
/var/lib/hudson/src/nova/hudson/nova/db/sqlalchemy/api.py:42: DeprecationWarning: Use of empty request context is deprecated
nova.tests.api_unittest
  ApiEc2TestCase
    test_describe_instances ... /var/lib/hudson/src/nova/hudson/nova/db/sqlalchemy/api.py:42: DeprecationWarning: Use of empty request context is deprecated
                                           [OK]
    test_get_all_key_pairs ... /var/lib/hudson/src/nova/hudson/nova/db/sqlalchemy/api.py:42: DeprecationWarning: Use of empty request context is deprecated
                                            [OK]
nova.tests.auth_unittest
  AuthManagerTestCase
    test_004_signature_is_valid ... [OK]
    test_005_can_get_credentials ... [OK]
    test_add_user_role_doesnt_infect_project_roles ... [OK]
/var/lib/hudson/src/nova/hudson/nova/db/sqlalchemy/api.py:42: DeprecationWarning: Use of empty request context is deprecated
    test_adding_role_to_project_is_ignored_unless_added_to_user ... [OK]
/var/lib/hudson/src/nova/hudson/nova/db/sqlalchemy/api.py:42: DeprecationWarning: Use of empty request context is deprecated
    test_can_add_and_remove_user_role ... [OK]
/var/lib/hudson/src/nova/hudson/nova/db/sqlalchemy/api.py:42: DeprecationWarning: Use of empty request context is deprecated
    test_can_add_remove_user_with_role ... [OK]
/var/lib/hudson/src/nova/hudson/nova/db/sqlalchemy/api.py:42: DeprecationWarning: Use of empty request context is deprecated
    test_can_add_user_to_project ... [OK]
/var/lib/hudson/src/nova/hudson/nova/db/sqlalchemy/api.py:42: DeprecationWarning: Use of empty request context is deprecated
    test_can_create_and_get_project ... [OK]
/var/lib/hudson/src/nova/hudson/nova/db/sqlalchemy/api.py:42: DeprecationWarning: Use of empty request context is deprecated
    test_can_create_and_get_project_with_attributes ... [OK]
/var/lib/hudson/src/nova/hudson/nova/db/sqlalchemy/api.py:42: DeprecationWarning: Use of empty request context is deprecated
    test_can_create_project_with_manager ... [OK]
/var/lib/hudson/src/nova/hudson/nova/db/sqlalchem...

lp:~soren/nova/network-fixes updated
304. By Soren Hansen

s/APIRequestContext/get_admin_context/ <-- sudo for request contexts.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'nova/db/api.py'
2--- nova/db/api.py 2010-10-01 09:28:31 +0000
3+++ nova/db/api.py 2010-10-03 18:24:43 +0000
4@@ -565,3 +565,15 @@
5
6 """
7 return IMPL.volume_update(context, volume_id, values)
8+
9+
10+###################
11+
12+
13+def host_get_networks(context, host):
14+ """Return all networks for which the given host is the designated
15+ network host
16+ """
17+ return IMPL.host_get_networks(context, host)
18+
19+
20
21=== modified file 'nova/db/sqlalchemy/api.py'
22--- nova/db/sqlalchemy/api.py 2010-10-01 09:28:31 +0000
23+++ nova/db/sqlalchemy/api.py 2010-10-03 18:24:43 +0000
24@@ -1273,3 +1273,15 @@
25 for (key, value) in values.iteritems():
26 volume_ref[key] = value
27 volume_ref.save(session=session)
28+
29+
30+###################
31+
32+
33+def host_get_networks(context, host):
34+ session = get_session()
35+ with session.begin():
36+ return session.query(models.Network
37+ ).filter_by(deleted=False
38+ ).filter_by(host=host
39+ ).all()
40
41=== modified file 'nova/network/linux_net.py'
42--- nova/network/linux_net.py 2010-09-29 03:28:20 +0000
43+++ nova/network/linux_net.py 2010-10-03 18:24:43 +0000
44@@ -28,6 +28,11 @@
45 from nova import utils
46
47
48+def _bin_file(script):
49+ """Return the absolute path to scipt in the bin directory"""
50+ return os.path.abspath(os.path.join(__file__, "../../../bin", script))
51+
52+
53 FLAGS = flags.FLAGS
54 flags.DEFINE_string('dhcpbridge_flagfile',
55 '/etc/nova/nova-dhcpbridge.conf',
56@@ -38,7 +43,9 @@
57 flags.DEFINE_string('public_interface', 'vlan1',
58 'Interface for public IP addresses')
59 flags.DEFINE_string('bridge_dev', 'eth0',
60- 'network device for bridges')
61+ 'network device for bridges')
62+flags.DEFINE_string('dhcpbridge', _bin_file('nova-dhcpbridge'),
63+ 'location of nova-dhcpbridge')
64 flags.DEFINE_string('routing_source_ip', '127.0.0.1',
65 'Public IP of network host')
66 flags.DEFINE_bool('use_nova_chains', False,
67@@ -139,16 +146,16 @@
68 # _execute("sudo brctl setageing %s 10" % bridge)
69 _execute("sudo brctl stp %s off" % bridge)
70 _execute("sudo brctl addif %s %s" % (bridge, interface))
71- if net_attrs:
72- _execute("sudo ifconfig %s %s broadcast %s netmask %s up" % \
73- (bridge,
74- net_attrs['gateway'],
75- net_attrs['broadcast'],
76- net_attrs['netmask']))
77- else:
78- _execute("sudo ifconfig %s up" % bridge)
79- _confirm_rule("FORWARD", "--in-interface %s -j ACCEPT" % bridge)
80- _confirm_rule("FORWARD", "--out-interface %s -j ACCEPT" % bridge)
81+ if net_attrs:
82+ _execute("sudo ifconfig %s %s broadcast %s netmask %s up" % \
83+ (bridge,
84+ net_attrs['gateway'],
85+ net_attrs['broadcast'],
86+ net_attrs['netmask']))
87+ else:
88+ _execute("sudo ifconfig %s up" % bridge)
89+ _confirm_rule("FORWARD", "--in-interface %s -j ACCEPT" % bridge)
90+ _confirm_rule("FORWARD", "--out-interface %s -j ACCEPT" % bridge)
91
92
93 def get_dhcp_hosts(context, network_id):
94@@ -172,9 +179,14 @@
95 signal causing it to reload, otherwise spawn a new instance
96 """
97 network_ref = db.network_get(context, network_id)
98- with open(_dhcp_file(network_ref['vlan'], 'conf'), 'w') as f:
99+
100+ conffile = _dhcp_file(network_ref['vlan'], 'conf')
101+ with open(conffile, 'w') as f:
102 f.write(get_dhcp_hosts(context, network_id))
103
104+ # Make sure dnsmasq can actually read it (it setuid()s to "nobody")
105+ os.chmod(conffile, 0644)
106+
107 pid = _dnsmasq_pid_for(network_ref['vlan'])
108
109 # if dnsmasq is already running, then tell it to reload
110@@ -182,7 +194,7 @@
111 # TODO(ja): use "/proc/%d/cmdline" % (pid) to determine if pid refers
112 # correct dnsmasq process
113 try:
114- os.kill(pid, signal.SIGHUP)
115+ _execute('sudo kill -HUP %d' % pid)
116 return
117 except Exception as exc: # pylint: disable-msg=W0703
118 logging.debug("Hupping dnsmasq threw %s", exc)
119@@ -243,7 +255,7 @@
120 ' --except-interface=lo',
121 ' --dhcp-range=%s,static,120s' % net['dhcp_start'],
122 ' --dhcp-hostsfile=%s' % _dhcp_file(net['vlan'], 'conf'),
123- ' --dhcp-script=%s' % _bin_file('nova-dhcpbridge'),
124+ ' --dhcp-script=%s' % FLAGS.dhcpbridge,
125 ' --leasefile-ro']
126 return ''.join(cmd)
127
128@@ -254,7 +266,7 @@
129
130 if pid:
131 try:
132- os.kill(pid, signal.SIGTERM)
133+ _execute('sudo kill -TERM %d' % pid)
134 except Exception as exc: # pylint: disable-msg=W0703
135 logging.debug("Killing dnsmasq threw %s", exc)
136
137@@ -262,14 +274,12 @@
138 def _dhcp_file(vlan, kind):
139 """Return path to a pid, leases or conf file for a vlan"""
140
141+ if not os.path.exists(FLAGS.networks_path):
142+ os.makedirs(FLAGS.networks_path)
143+
144 return os.path.abspath("%s/nova-%s.%s" % (FLAGS.networks_path, vlan, kind))
145
146
147-def _bin_file(script):
148- """Return the absolute path to scipt in the bin directory"""
149- return os.path.abspath(os.path.join(__file__, "../../../bin", script))
150-
151-
152 def _dnsmasq_pid_for(vlan):
153 """Returns he pid for prior dnsmasq instance for a vlan
154
155
156=== modified file 'nova/network/manager.py'
157--- nova/network/manager.py 2010-10-01 09:28:31 +0000
158+++ nova/network/manager.py 2010-10-03 18:24:43 +0000
159@@ -85,6 +85,12 @@
160 self.driver = utils.import_object(network_driver)
161 super(NetworkManager, self).__init__(*args, **kwargs)
162
163+ def init_host(self):
164+ # Set up networking for the projects for which we're already
165+ # the designated network host.
166+ for network in self.db.host_get_networks(None, self.host):
167+ self._on_set_network_host(None, network['id'])
168+
169 def set_network_host(self, context, project_id):
170 """Safely sets the host of the projects network"""
171 logging.debug("setting network host")
172@@ -240,6 +246,7 @@
173 """Do any initialization that needs to be run if this is a
174 standalone service.
175 """
176+ super(VlanManager, self).init_host()
177 self.driver.init_host()
178
179 def allocate_fixed_ip(self, context, instance_id, *args, **kwargs):
180@@ -367,6 +374,7 @@
181 self.driver.ensure_vlan_bridge(network_ref['vlan'],
182 network_ref['bridge'],
183 network_ref)
184+ self.driver.update_dhcp(context, network_id)
185
186 @property
187 def _bottom_reserved_ips(self):
188
189=== modified file 'nova/tests/network_unittest.py'
190--- nova/tests/network_unittest.py 2010-10-01 09:28:31 +0000
191+++ nova/tests/network_unittest.py 2010-10-03 18:24:43 +0000
192@@ -56,8 +56,8 @@
193 'netuser',
194 name))
195 # create the necessary network data for the project
196- user_context = context.APIRequestContext(project=self.projects[i],
197- user=self.user)
198+ user_context = context.get_admin_context(user=self.user)
199+
200 self.network.set_network_host(user_context, self.projects[i].id)
201 instance_ref = self._create_instance(0)
202 self.instance_id = instance_ref['id']