Merge lp:~james-page/charms/precise/quantum-gateway/cond-restart into lp:~openstack-charmers/charms/precise/quantum-gateway/ha-support

Proposed by James Page
Status: Merged
Approved by: Adam Gandelman
Approved revision: 64
Merged at revision: 55
Proposed branch: lp:~james-page/charms/precise/quantum-gateway/cond-restart
Merge into: lp:~openstack-charmers/charms/precise/quantum-gateway/ha-support
Diff against target: 275 lines (+137/-13)
5 files modified
.pydevproject (+2/-3)
hooks/hooks.py (+14/-8)
hooks/lib/utils.py (+27/-0)
hooks/quantum_utils.py (+24/-2)
templates/evacuate_unit.py (+70/-0)
To merge this branch: bzr merge lp:~james-page/charms/precise/quantum-gateway/cond-restart
Reviewer Review Type Date Requested Status
OpenStack Charmers Pending
Review via email: mp+158791@code.launchpad.net

Description of the change

This change adds support for intelligent restarting of daemons based on configuration files actually changing.

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.pydevproject'
2--- .pydevproject 2012-12-06 10:22:24 +0000
3+++ .pydevproject 2013-04-14 17:42:26 +0000
4@@ -1,10 +1,9 @@
5 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
6-<?eclipse-pydev version="1.0"?>
7-
8-<pydev_project>
9+<?eclipse-pydev version="1.0"?><pydev_project>
10 <pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
11 <pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
12 <pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
13 <path>/quantum-gateway/hooks</path>
14+<path>/quantum-gateway/templates</path>
15 </pydev_pathproperty>
16 </pydev_project>
17
18=== modified file 'hooks/hooks.py'
19--- hooks/hooks.py 2013-03-20 16:54:49 +0000
20+++ hooks/hooks.py 2013-04-14 17:42:26 +0000
21@@ -22,6 +22,7 @@
22 sys.exit(1)
23
24
25+@utils.inteli_restart(qutils.RESTART_MAP)
26 def config_changed():
27 if PLUGIN in qutils.GATEWAY_PKGS.keys():
28 render_quantum_conf()
29@@ -31,13 +32,13 @@
30 render_metadata_api_conf()
31 render_plugin_conf()
32 render_ext_port_upstart()
33+ render_evacuate_unit()
34 if PLUGIN == qutils.OVS:
35 qutils.add_bridge(qutils.INT_BRIDGE)
36 qutils.add_bridge(qutils.EXT_BRIDGE)
37 ext_port = utils.config_get('ext-port')
38 if ext_port:
39 qutils.add_bridge_port(qutils.EXT_BRIDGE, ext_port)
40- restart_agents()
41 else:
42 utils.juju_log('ERROR',
43 'Please provide a valid plugin config')
44@@ -143,6 +144,14 @@
45 )
46
47
48+def render_evacuate_unit():
49+ context = get_keystone_conf()
50+ if context:
51+ with open('/usr/local/bin/quantum-evacuate-unit', "w") as conf:
52+ conf.write(utils.render_template('evacuate_unit.py', context))
53+ os.chmod('/usr/local/bin/quantum-evacuate-unit', 0700)
54+
55+
56 def get_keystone_conf():
57 for relid in utils.relation_ids('quantum-network-service'):
58 for unit in utils.relation_list(relid):
59@@ -181,10 +190,10 @@
60 nova_hostname=utils.unit_get('private-address'))
61
62
63+@utils.inteli_restart(qutils.RESTART_MAP)
64 def db_changed():
65 render_plugin_conf()
66 render_metadata_api_conf()
67- restart_agents()
68
69
70 def get_quantum_db_conf():
71@@ -224,11 +233,11 @@
72 vhost=qutils.RABBIT_VHOST)
73
74
75+@utils.inteli_restart(qutils.RESTART_MAP)
76 def amqp_changed():
77 render_dhcp_agent_conf()
78 render_quantum_conf()
79 render_metadata_api_conf()
80- restart_agents()
81
82
83 def get_rabbit_conf():
84@@ -250,13 +259,14 @@
85 return None
86
87
88+@utils.inteli_restart(qutils.RESTART_MAP)
89 def nm_changed():
90 render_dhcp_agent_conf()
91 render_l3_agent_conf()
92 render_metadata_agent_conf()
93 render_metadata_api_conf()
94+ render_evacuate_unit()
95 store_ca_cert()
96- restart_agents()
97
98
99 def store_ca_cert():
100@@ -274,10 +284,6 @@
101 return None
102
103
104-def restart_agents():
105- utils.restart(*qutils.GATEWAY_AGENTS[PLUGIN])
106-
107-
108 def cluster_departed():
109 conf = get_keystone_conf()
110 if conf and cluster.eligible_leader(None):
111
112=== modified file 'hooks/lib/utils.py'
113--- hooks/lib/utils.py 2013-03-22 16:56:56 +0000
114+++ hooks/lib/utils.py 2013-04-14 17:42:26 +0000
115@@ -14,6 +14,7 @@
116 import subprocess
117 import socket
118 import sys
119+import hashlib
120
121
122 def do_hooks(hooks):
123@@ -324,6 +325,32 @@
124 return False
125
126
127+def file_hash(path):
128+ if os.path.exists(path):
129+ h = hashlib.md5()
130+ with open(path, 'r') as source:
131+ h.update(source.read()) # IGNORE:E1101 - it does have update
132+ return h.hexdigest()
133+ else:
134+ return None
135+
136+
137+def inteli_restart(restart_map):
138+ def wrap(f):
139+ def wrapped_f(*args):
140+ checksums = {}
141+ for path in restart_map:
142+ checksums[path] = file_hash(path)
143+ f(*args)
144+ restarts = []
145+ for path in restart_map:
146+ if checksums[path] != file_hash(path):
147+ restarts += restart_map[path]
148+ restart(*list(set(restarts)))
149+ return wrapped_f
150+ return wrap
151+
152+
153 def is_relation_made(relation, key='private-address'):
154 for r_id in (relation_ids(relation) or []):
155 for unit in (relation_list(r_id) or []):
156
157=== modified file 'hooks/quantum_utils.py'
158--- hooks/quantum_utils.py 2013-03-20 17:09:29 +0000
159+++ hooks/quantum_utils.py 2013-04-14 17:42:26 +0000
160@@ -3,9 +3,7 @@
161 import uuid
162 import base64
163 import apt_pkg as apt
164-from random import randint
165 from lib.utils import (
166- unit_get,
167 juju_log as log
168 )
169
170@@ -72,6 +70,30 @@
171 METADATA_AGENT_CONF = "/etc/quantum/metadata_agent.ini"
172 NOVA_CONF = "/etc/nova/nova.conf"
173
174+RESTART_MAP = {
175+ QUANTUM_CONF: [
176+ 'quantum-l3-agent',
177+ 'quantum-dhcp-agent',
178+ 'quantum-metadata-agent',
179+ 'quantum-plugin-openvswitch-agent'
180+ ],
181+ DHCP_AGENT_CONF: [
182+ 'quantum-dhcp-agent'
183+ ],
184+ L3_AGENT_CONF: [
185+ 'quantum-l3-agent'
186+ ],
187+ METADATA_AGENT_CONF: [
188+ 'quantum-metadata-agent'
189+ ],
190+ OVS_PLUGIN_CONF: [
191+ 'quantum-plugin-openvswitch-agent'
192+ ],
193+ NOVA_CONF: [
194+ 'nova-api-metadata'
195+ ]
196+ }
197+
198 RABBIT_USER = "nova"
199 RABBIT_VHOST = "nova"
200
201
202=== added file 'templates/evacuate_unit.py'
203--- templates/evacuate_unit.py 1970-01-01 00:00:00 +0000
204+++ templates/evacuate_unit.py 2013-04-14 17:42:26 +0000
205@@ -0,0 +1,70 @@
206+#!/usr/bin/python
207+
208+import subprocess
209+
210+
211+def log(priority, message):
212+ print "{}: {}".format(priority, message)
213+
214+DHCP_AGENT = "DHCP Agent"
215+L3_AGENT = "L3 Agent"
216+
217+
218+def evacuate_unit(unit):
219+ ''' Use agent scheduler API to detect down agents and re-schedule '''
220+ from quantumclient.v2_0 import client
221+ # TODO: Fixup for https keystone
222+ auth_url = 'http://{{ keystone_host }}:{{ auth_port }}/v2.0'
223+ quantum = client.Client(username='{{ service_username }}',
224+ password='{{ service_password }}',
225+ tenant_name='{{ service_tenant }}',
226+ auth_url=auth_url,
227+ region_name='{{ region }}')
228+
229+ agents = quantum.list_agents(agent_type=DHCP_AGENT)
230+ dhcp_agents = []
231+ l3_agents = []
232+ networks = {}
233+ for agent in agents['agents']:
234+ if agent['alive'] and agent['host'] != unit:
235+ dhcp_agents.append(agent['id'])
236+ elif agent['host'] == unit:
237+ for network in \
238+ quantum.list_networks_on_dhcp_agent(agent['id'])['networks']:
239+ networks[network['id']] = agent['id']
240+
241+ agents = quantum.list_agents(agent_type=L3_AGENT)
242+ routers = {}
243+ for agent in agents['agents']:
244+ if agent['alive'] and agent['host'] != unit:
245+ l3_agents.append(agent['id'])
246+ elif agent['host'] == unit:
247+ for router in \
248+ quantum.list_routers_on_l3_agent(agent['id'])['routers']:
249+ routers[router['id']] = agent['id']
250+
251+ index = 0
252+ for router_id in routers:
253+ agent = index % len(l3_agents)
254+ log('INFO',
255+ 'Moving router %s from %s to %s' % \
256+ (router_id, routers[router_id], l3_agents[agent]))
257+ quantum.remove_router_from_l3_agent(l3_agent=routers[router_id],
258+ router_id=router_id)
259+ quantum.add_router_to_l3_agent(l3_agent=l3_agents[agent],
260+ body={'router_id': router_id})
261+ index += 1
262+
263+ index = 0
264+ for network_id in networks:
265+ agent = index % len(dhcp_agents)
266+ log('INFO',
267+ 'Moving network %s from %s to %s' % \
268+ (network_id, networks[network_id], dhcp_agents[agent]))
269+ quantum.remove_network_from_dhcp_agent(dhcp_agent=networks[network_id],
270+ network_id=network_id)
271+ quantum.add_network_to_dhcp_agent(dhcp_agent=dhcp_agents[agent],
272+ body={'network_id': network_id})
273+ index += 1
274+
275+evacuate_unit(subprocess.check_output(['hostname', '-f']).strip())

Subscribers

People subscribed via source and target branches