Merge lp:~1chb1n/charms/trusty/cinder/amulet-fix-vol-from-img-lp1440948 into lp:~openstack-charmers-archive/charms/trusty/cinder/next
- Trusty Tahr (14.04)
- amulet-fix-vol-from-img-lp1440948
- Merge into next
Status: | Merged |
---|---|
Merged at revision: | 83 |
Proposed branch: | lp:~1chb1n/charms/trusty/cinder/amulet-fix-vol-from-img-lp1440948 |
Merge into: | lp:~openstack-charmers-archive/charms/trusty/cinder/next |
Diff against target: |
681 lines (+375/-95) 11 files modified
hooks/charmhelpers/contrib/openstack/amulet/deployment.py (+25/-2) hooks/charmhelpers/contrib/openstack/context.py (+149/-5) hooks/charmhelpers/contrib/openstack/templates/git.upstart (+13/-0) hooks/charmhelpers/contrib/openstack/templates/section-zeromq (+14/-0) hooks/charmhelpers/contrib/openstack/templates/zeromq (+0/-14) hooks/charmhelpers/contrib/openstack/utils.py (+132/-69) hooks/charmhelpers/core/hookenv.py (+14/-1) hooks/charmhelpers/core/unitdata.py (+1/-1) hooks/cinder_utils.py (+1/-0) tests/basic_deployment.py (+1/-1) tests/charmhelpers/contrib/openstack/amulet/deployment.py (+25/-2) |
To merge this branch: | bzr merge lp:~1chb1n/charms/trusty/cinder/amulet-fix-vol-from-img-lp1440948 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
James Page | Approve | ||
Review via email: mp+255705@code.launchpad.net |
Commit message
Description of the change
- Addresses bug 1440948 by explictly installing librbd1.
- Enables amulet debug logging.
- Sync charmhelpers.
Reveals a separate issue (bug 1442268), which is not related to the changes of this MP. http://
uosci-testing-bot (uosci-testing-bot) wrote : | # |
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #2981 cinder-next for 1chb1n mp255705
UNIT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #3003 cinder-next for 1chb1n mp255705
AMULET FAIL: amulet-test failed
AMULET Results (max last 2 lines):
make: *** [test] Error 1
ERROR:root:Make target returned non-zero.
Full amulet test output: http://
Build: http://
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #3194 cinder-next for 1chb1n mp255705
LINT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #2982 cinder-next for 1chb1n mp255705
UNIT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #3004 cinder-next for 1chb1n mp255705
AMULET FAIL: amulet-test failed
AMULET Results (max last 2 lines):
make: *** [test] Error 1
ERROR:root:Make target returned non-zero.
Full amulet test output: http://
Build: http://
Ryan Beisner (1chb1n) wrote : | # |
^ FYI amulet fail is expected due to a separate issue. See MP initial description.
James Page (james-page) : | # |
Preview Diff
1 | === modified file 'hooks/charmhelpers/contrib/openstack/amulet/deployment.py' | |||
2 | --- hooks/charmhelpers/contrib/openstack/amulet/deployment.py 2015-03-13 13:00:03 +0000 | |||
3 | +++ hooks/charmhelpers/contrib/openstack/amulet/deployment.py 2015-04-09 16:27:05 +0000 | |||
4 | @@ -15,6 +15,7 @@ | |||
5 | 15 | # along with charm-helpers. If not, see <http://www.gnu.org/licenses/>. | 15 | # along with charm-helpers. If not, see <http://www.gnu.org/licenses/>. |
6 | 16 | 16 | ||
7 | 17 | import six | 17 | import six |
8 | 18 | from collections import OrderedDict | ||
9 | 18 | from charmhelpers.contrib.amulet.deployment import ( | 19 | from charmhelpers.contrib.amulet.deployment import ( |
10 | 19 | AmuletDeployment | 20 | AmuletDeployment |
11 | 20 | ) | 21 | ) |
12 | @@ -100,12 +101,34 @@ | |||
13 | 100 | """ | 101 | """ |
14 | 101 | (self.precise_essex, self.precise_folsom, self.precise_grizzly, | 102 | (self.precise_essex, self.precise_folsom, self.precise_grizzly, |
15 | 102 | self.precise_havana, self.precise_icehouse, | 103 | self.precise_havana, self.precise_icehouse, |
17 | 103 | self.trusty_icehouse) = range(6) | 104 | self.trusty_icehouse, self.trusty_juno, self.trusty_kilo) = range(8) |
18 | 104 | releases = { | 105 | releases = { |
19 | 105 | ('precise', None): self.precise_essex, | 106 | ('precise', None): self.precise_essex, |
20 | 106 | ('precise', 'cloud:precise-folsom'): self.precise_folsom, | 107 | ('precise', 'cloud:precise-folsom'): self.precise_folsom, |
21 | 107 | ('precise', 'cloud:precise-grizzly'): self.precise_grizzly, | 108 | ('precise', 'cloud:precise-grizzly'): self.precise_grizzly, |
22 | 108 | ('precise', 'cloud:precise-havana'): self.precise_havana, | 109 | ('precise', 'cloud:precise-havana'): self.precise_havana, |
23 | 109 | ('precise', 'cloud:precise-icehouse'): self.precise_icehouse, | 110 | ('precise', 'cloud:precise-icehouse'): self.precise_icehouse, |
25 | 110 | ('trusty', None): self.trusty_icehouse} | 111 | ('trusty', None): self.trusty_icehouse, |
26 | 112 | ('trusty', 'cloud:trusty-juno'): self.trusty_juno, | ||
27 | 113 | ('trusty', 'cloud:trusty-kilo'): self.trusty_kilo} | ||
28 | 111 | return releases[(self.series, self.openstack)] | 114 | return releases[(self.series, self.openstack)] |
29 | 115 | |||
30 | 116 | def _get_openstack_release_string(self): | ||
31 | 117 | """Get openstack release string. | ||
32 | 118 | |||
33 | 119 | Return a string representing the openstack release. | ||
34 | 120 | """ | ||
35 | 121 | releases = OrderedDict([ | ||
36 | 122 | ('precise', 'essex'), | ||
37 | 123 | ('quantal', 'folsom'), | ||
38 | 124 | ('raring', 'grizzly'), | ||
39 | 125 | ('saucy', 'havana'), | ||
40 | 126 | ('trusty', 'icehouse'), | ||
41 | 127 | ('utopic', 'juno'), | ||
42 | 128 | ('vivid', 'kilo'), | ||
43 | 129 | ]) | ||
44 | 130 | if self.openstack: | ||
45 | 131 | os_origin = self.openstack.split(':')[1] | ||
46 | 132 | return os_origin.split('%s-' % self.series)[1].split('/')[0] | ||
47 | 133 | else: | ||
48 | 134 | return releases[self.series] | ||
49 | 112 | 135 | ||
50 | === modified file 'hooks/charmhelpers/contrib/openstack/context.py' | |||
51 | --- hooks/charmhelpers/contrib/openstack/context.py 2015-03-18 12:08:38 +0000 | |||
52 | +++ hooks/charmhelpers/contrib/openstack/context.py 2015-04-09 16:27:05 +0000 | |||
53 | @@ -47,6 +47,7 @@ | |||
54 | 47 | ) | 47 | ) |
55 | 48 | 48 | ||
56 | 49 | from charmhelpers.core.sysctl import create as sysctl_create | 49 | from charmhelpers.core.sysctl import create as sysctl_create |
57 | 50 | from charmhelpers.core.strutils import bool_from_string | ||
58 | 50 | 51 | ||
59 | 51 | from charmhelpers.core.host import ( | 52 | from charmhelpers.core.host import ( |
60 | 52 | list_nics, | 53 | list_nics, |
61 | @@ -67,6 +68,7 @@ | |||
62 | 67 | ) | 68 | ) |
63 | 68 | from charmhelpers.contrib.openstack.neutron import ( | 69 | from charmhelpers.contrib.openstack.neutron import ( |
64 | 69 | neutron_plugin_attribute, | 70 | neutron_plugin_attribute, |
65 | 71 | parse_data_port_mappings, | ||
66 | 70 | ) | 72 | ) |
67 | 71 | from charmhelpers.contrib.openstack.ip import ( | 73 | from charmhelpers.contrib.openstack.ip import ( |
68 | 72 | resolve_address, | 74 | resolve_address, |
69 | @@ -82,7 +84,6 @@ | |||
70 | 82 | is_bridge_member, | 84 | is_bridge_member, |
71 | 83 | ) | 85 | ) |
72 | 84 | from charmhelpers.contrib.openstack.utils import get_host_ip | 86 | from charmhelpers.contrib.openstack.utils import get_host_ip |
73 | 85 | |||
74 | 86 | CA_CERT_PATH = '/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt' | 87 | CA_CERT_PATH = '/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt' |
75 | 87 | ADDRESS_TYPES = ['admin', 'internal', 'public'] | 88 | ADDRESS_TYPES = ['admin', 'internal', 'public'] |
76 | 88 | 89 | ||
77 | @@ -319,14 +320,15 @@ | |||
78 | 319 | 320 | ||
79 | 320 | 321 | ||
80 | 321 | class IdentityServiceContext(OSContextGenerator): | 322 | class IdentityServiceContext(OSContextGenerator): |
81 | 322 | interfaces = ['identity-service'] | ||
82 | 323 | 323 | ||
84 | 324 | def __init__(self, service=None, service_user=None): | 324 | def __init__(self, service=None, service_user=None, rel_name='identity-service'): |
85 | 325 | self.service = service | 325 | self.service = service |
86 | 326 | self.service_user = service_user | 326 | self.service_user = service_user |
87 | 327 | self.rel_name = rel_name | ||
88 | 328 | self.interfaces = [self.rel_name] | ||
89 | 327 | 329 | ||
90 | 328 | def __call__(self): | 330 | def __call__(self): |
92 | 329 | log('Generating template context for identity-service', level=DEBUG) | 331 | log('Generating template context for ' + self.rel_name, level=DEBUG) |
93 | 330 | ctxt = {} | 332 | ctxt = {} |
94 | 331 | 333 | ||
95 | 332 | if self.service and self.service_user: | 334 | if self.service and self.service_user: |
96 | @@ -340,7 +342,7 @@ | |||
97 | 340 | 342 | ||
98 | 341 | ctxt['signing_dir'] = cachedir | 343 | ctxt['signing_dir'] = cachedir |
99 | 342 | 344 | ||
101 | 343 | for rid in relation_ids('identity-service'): | 345 | for rid in relation_ids(self.rel_name): |
102 | 344 | for unit in related_units(rid): | 346 | for unit in related_units(rid): |
103 | 345 | rdata = relation_get(rid=rid, unit=unit) | 347 | rdata = relation_get(rid=rid, unit=unit) |
104 | 346 | serv_host = rdata.get('service_host') | 348 | serv_host = rdata.get('service_host') |
105 | @@ -1162,3 +1164,145 @@ | |||
106 | 1162 | sysctl_create(sysctl_dict, | 1164 | sysctl_create(sysctl_dict, |
107 | 1163 | '/etc/sysctl.d/50-{0}.conf'.format(charm_name())) | 1165 | '/etc/sysctl.d/50-{0}.conf'.format(charm_name())) |
108 | 1164 | return {'sysctl': sysctl_dict} | 1166 | return {'sysctl': sysctl_dict} |
109 | 1167 | |||
110 | 1168 | |||
111 | 1169 | class NeutronAPIContext(OSContextGenerator): | ||
112 | 1170 | ''' | ||
113 | 1171 | Inspects current neutron-plugin-api relation for neutron settings. Return | ||
114 | 1172 | defaults if it is not present. | ||
115 | 1173 | ''' | ||
116 | 1174 | interfaces = ['neutron-plugin-api'] | ||
117 | 1175 | |||
118 | 1176 | def __call__(self): | ||
119 | 1177 | self.neutron_defaults = { | ||
120 | 1178 | 'l2_population': { | ||
121 | 1179 | 'rel_key': 'l2-population', | ||
122 | 1180 | 'default': False, | ||
123 | 1181 | }, | ||
124 | 1182 | 'overlay_network_type': { | ||
125 | 1183 | 'rel_key': 'overlay-network-type', | ||
126 | 1184 | 'default': 'gre', | ||
127 | 1185 | }, | ||
128 | 1186 | 'neutron_security_groups': { | ||
129 | 1187 | 'rel_key': 'neutron-security-groups', | ||
130 | 1188 | 'default': False, | ||
131 | 1189 | }, | ||
132 | 1190 | 'network_device_mtu': { | ||
133 | 1191 | 'rel_key': 'network-device-mtu', | ||
134 | 1192 | 'default': None, | ||
135 | 1193 | }, | ||
136 | 1194 | 'enable_dvr': { | ||
137 | 1195 | 'rel_key': 'enable-dvr', | ||
138 | 1196 | 'default': False, | ||
139 | 1197 | }, | ||
140 | 1198 | 'enable_l3ha': { | ||
141 | 1199 | 'rel_key': 'enable-l3ha', | ||
142 | 1200 | 'default': False, | ||
143 | 1201 | }, | ||
144 | 1202 | } | ||
145 | 1203 | ctxt = self.get_neutron_options({}) | ||
146 | 1204 | for rid in relation_ids('neutron-plugin-api'): | ||
147 | 1205 | for unit in related_units(rid): | ||
148 | 1206 | rdata = relation_get(rid=rid, unit=unit) | ||
149 | 1207 | if 'l2-population' in rdata: | ||
150 | 1208 | ctxt.update(self.get_neutron_options(rdata)) | ||
151 | 1209 | |||
152 | 1210 | return ctxt | ||
153 | 1211 | |||
154 | 1212 | def get_neutron_options(self, rdata): | ||
155 | 1213 | settings = {} | ||
156 | 1214 | for nkey in self.neutron_defaults.keys(): | ||
157 | 1215 | defv = self.neutron_defaults[nkey]['default'] | ||
158 | 1216 | rkey = self.neutron_defaults[nkey]['rel_key'] | ||
159 | 1217 | if rkey in rdata.keys(): | ||
160 | 1218 | if type(defv) is bool: | ||
161 | 1219 | settings[nkey] = bool_from_string(rdata[rkey]) | ||
162 | 1220 | else: | ||
163 | 1221 | settings[nkey] = rdata[rkey] | ||
164 | 1222 | else: | ||
165 | 1223 | settings[nkey] = defv | ||
166 | 1224 | return settings | ||
167 | 1225 | |||
168 | 1226 | |||
169 | 1227 | class ExternalPortContext(NeutronPortContext): | ||
170 | 1228 | |||
171 | 1229 | def __call__(self): | ||
172 | 1230 | ctxt = {} | ||
173 | 1231 | ports = config('ext-port') | ||
174 | 1232 | if ports: | ||
175 | 1233 | ports = [p.strip() for p in ports.split()] | ||
176 | 1234 | ports = self.resolve_ports(ports) | ||
177 | 1235 | if ports: | ||
178 | 1236 | ctxt = {"ext_port": ports[0]} | ||
179 | 1237 | napi_settings = NeutronAPIContext()() | ||
180 | 1238 | mtu = napi_settings.get('network_device_mtu') | ||
181 | 1239 | if mtu: | ||
182 | 1240 | ctxt['ext_port_mtu'] = mtu | ||
183 | 1241 | |||
184 | 1242 | return ctxt | ||
185 | 1243 | |||
186 | 1244 | |||
187 | 1245 | class DataPortContext(NeutronPortContext): | ||
188 | 1246 | |||
189 | 1247 | def __call__(self): | ||
190 | 1248 | ports = config('data-port') | ||
191 | 1249 | if ports: | ||
192 | 1250 | portmap = parse_data_port_mappings(ports) | ||
193 | 1251 | ports = portmap.values() | ||
194 | 1252 | resolved = self.resolve_ports(ports) | ||
195 | 1253 | normalized = {get_nic_hwaddr(port): port for port in resolved | ||
196 | 1254 | if port not in ports} | ||
197 | 1255 | normalized.update({port: port for port in resolved | ||
198 | 1256 | if port in ports}) | ||
199 | 1257 | if resolved: | ||
200 | 1258 | return {bridge: normalized[port] for bridge, port in | ||
201 | 1259 | six.iteritems(portmap) if port in normalized.keys()} | ||
202 | 1260 | |||
203 | 1261 | return None | ||
204 | 1262 | |||
205 | 1263 | |||
206 | 1264 | class PhyNICMTUContext(DataPortContext): | ||
207 | 1265 | |||
208 | 1266 | def __call__(self): | ||
209 | 1267 | ctxt = {} | ||
210 | 1268 | mappings = super(PhyNICMTUContext, self).__call__() | ||
211 | 1269 | if mappings and mappings.values(): | ||
212 | 1270 | ports = mappings.values() | ||
213 | 1271 | napi_settings = NeutronAPIContext()() | ||
214 | 1272 | mtu = napi_settings.get('network_device_mtu') | ||
215 | 1273 | if mtu: | ||
216 | 1274 | ctxt["devs"] = '\\n'.join(ports) | ||
217 | 1275 | ctxt['mtu'] = mtu | ||
218 | 1276 | |||
219 | 1277 | return ctxt | ||
220 | 1278 | |||
221 | 1279 | |||
222 | 1280 | class NetworkServiceContext(OSContextGenerator): | ||
223 | 1281 | |||
224 | 1282 | def __init__(self, rel_name='quantum-network-service'): | ||
225 | 1283 | self.rel_name = rel_name | ||
226 | 1284 | self.interfaces = [rel_name] | ||
227 | 1285 | |||
228 | 1286 | def __call__(self): | ||
229 | 1287 | for rid in relation_ids(self.rel_name): | ||
230 | 1288 | for unit in related_units(rid): | ||
231 | 1289 | rdata = relation_get(rid=rid, unit=unit) | ||
232 | 1290 | ctxt = { | ||
233 | 1291 | 'keystone_host': rdata.get('keystone_host'), | ||
234 | 1292 | 'service_port': rdata.get('service_port'), | ||
235 | 1293 | 'auth_port': rdata.get('auth_port'), | ||
236 | 1294 | 'service_tenant': rdata.get('service_tenant'), | ||
237 | 1295 | 'service_username': rdata.get('service_username'), | ||
238 | 1296 | 'service_password': rdata.get('service_password'), | ||
239 | 1297 | 'quantum_host': rdata.get('quantum_host'), | ||
240 | 1298 | 'quantum_port': rdata.get('quantum_port'), | ||
241 | 1299 | 'quantum_url': rdata.get('quantum_url'), | ||
242 | 1300 | 'region': rdata.get('region'), | ||
243 | 1301 | 'service_protocol': | ||
244 | 1302 | rdata.get('service_protocol') or 'http', | ||
245 | 1303 | 'auth_protocol': | ||
246 | 1304 | rdata.get('auth_protocol') or 'http', | ||
247 | 1305 | } | ||
248 | 1306 | if context_complete(ctxt): | ||
249 | 1307 | return ctxt | ||
250 | 1308 | return {} | ||
251 | 1165 | 1309 | ||
252 | === added file 'hooks/charmhelpers/contrib/openstack/templates/git.upstart' | |||
253 | --- hooks/charmhelpers/contrib/openstack/templates/git.upstart 1970-01-01 00:00:00 +0000 | |||
254 | +++ hooks/charmhelpers/contrib/openstack/templates/git.upstart 2015-04-09 16:27:05 +0000 | |||
255 | @@ -0,0 +1,13 @@ | |||
256 | 1 | description "{{ service_description }}" | ||
257 | 2 | author "Juju {{ service_name }} Charm <juju@localhost>" | ||
258 | 3 | |||
259 | 4 | start on runlevel [2345] | ||
260 | 5 | stop on runlevel [!2345] | ||
261 | 6 | |||
262 | 7 | respawn | ||
263 | 8 | |||
264 | 9 | exec start-stop-daemon --start --chuid {{ user_name }} \ | ||
265 | 10 | --chdir {{ start_dir }} --name {{ process_name }} \ | ||
266 | 11 | --exec {{ executable_name }} -- \ | ||
267 | 12 | --config-file={{ config_file }} \ | ||
268 | 13 | --log-file={{ log_file }} | ||
269 | 0 | 14 | ||
270 | === added file 'hooks/charmhelpers/contrib/openstack/templates/section-zeromq' | |||
271 | --- hooks/charmhelpers/contrib/openstack/templates/section-zeromq 1970-01-01 00:00:00 +0000 | |||
272 | +++ hooks/charmhelpers/contrib/openstack/templates/section-zeromq 2015-04-09 16:27:05 +0000 | |||
273 | @@ -0,0 +1,14 @@ | |||
274 | 1 | {% if zmq_host -%} | ||
275 | 2 | # ZeroMQ configuration (restart-nonce: {{ zmq_nonce }}) | ||
276 | 3 | rpc_backend = zmq | ||
277 | 4 | rpc_zmq_host = {{ zmq_host }} | ||
278 | 5 | {% if zmq_redis_address -%} | ||
279 | 6 | rpc_zmq_matchmaker = redis | ||
280 | 7 | matchmaker_heartbeat_freq = 15 | ||
281 | 8 | matchmaker_heartbeat_ttl = 30 | ||
282 | 9 | [matchmaker_redis] | ||
283 | 10 | host = {{ zmq_redis_address }} | ||
284 | 11 | {% else -%} | ||
285 | 12 | rpc_zmq_matchmaker = ring | ||
286 | 13 | {% endif -%} | ||
287 | 14 | {% endif -%} | ||
288 | 0 | 15 | ||
289 | === removed file 'hooks/charmhelpers/contrib/openstack/templates/zeromq' | |||
290 | --- hooks/charmhelpers/contrib/openstack/templates/zeromq 2015-02-24 12:37:30 +0000 | |||
291 | +++ hooks/charmhelpers/contrib/openstack/templates/zeromq 1970-01-01 00:00:00 +0000 | |||
292 | @@ -1,14 +0,0 @@ | |||
293 | 1 | {% if zmq_host -%} | ||
294 | 2 | # ZeroMQ configuration (restart-nonce: {{ zmq_nonce }}) | ||
295 | 3 | rpc_backend = zmq | ||
296 | 4 | rpc_zmq_host = {{ zmq_host }} | ||
297 | 5 | {% if zmq_redis_address -%} | ||
298 | 6 | rpc_zmq_matchmaker = oslo.messaging._drivers.matchmaker_redis.MatchMakerRedis | ||
299 | 7 | matchmaker_heartbeat_freq = 15 | ||
300 | 8 | matchmaker_heartbeat_ttl = 30 | ||
301 | 9 | [matchmaker_redis] | ||
302 | 10 | host = {{ zmq_redis_address }} | ||
303 | 11 | {% else -%} | ||
304 | 12 | rpc_zmq_matchmaker = oslo.messaging._drivers.matchmaker_ring.MatchMakerRing | ||
305 | 13 | {% endif -%} | ||
306 | 14 | {% endif -%} | ||
307 | 15 | 0 | ||
308 | === modified file 'hooks/charmhelpers/contrib/openstack/utils.py' | |||
309 | --- hooks/charmhelpers/contrib/openstack/utils.py 2015-03-13 13:00:03 +0000 | |||
310 | +++ hooks/charmhelpers/contrib/openstack/utils.py 2015-04-09 16:27:05 +0000 | |||
311 | @@ -30,6 +30,10 @@ | |||
312 | 30 | 30 | ||
313 | 31 | from charmhelpers.contrib.network import ip | 31 | from charmhelpers.contrib.network import ip |
314 | 32 | 32 | ||
315 | 33 | from charmhelpers.core import ( | ||
316 | 34 | unitdata, | ||
317 | 35 | ) | ||
318 | 36 | |||
319 | 33 | from charmhelpers.core.hookenv import ( | 37 | from charmhelpers.core.hookenv import ( |
320 | 34 | config, | 38 | config, |
321 | 35 | log as juju_log, | 39 | log as juju_log, |
322 | @@ -330,6 +334,21 @@ | |||
323 | 330 | error_out("Invalid openstack-release specified: %s" % rel) | 334 | error_out("Invalid openstack-release specified: %s" % rel) |
324 | 331 | 335 | ||
325 | 332 | 336 | ||
326 | 337 | def config_value_changed(option): | ||
327 | 338 | """ | ||
328 | 339 | Determine if config value changed since last call to this function. | ||
329 | 340 | """ | ||
330 | 341 | hook_data = unitdata.HookData() | ||
331 | 342 | with hook_data(): | ||
332 | 343 | db = unitdata.kv() | ||
333 | 344 | current = config(option) | ||
334 | 345 | saved = db.get(option) | ||
335 | 346 | db.set(option, current) | ||
336 | 347 | if saved is None: | ||
337 | 348 | return False | ||
338 | 349 | return current != saved | ||
339 | 350 | |||
340 | 351 | |||
341 | 333 | def save_script_rc(script_path="scripts/scriptrc", **env_vars): | 352 | def save_script_rc(script_path="scripts/scriptrc", **env_vars): |
342 | 334 | """ | 353 | """ |
343 | 335 | Write an rc file in the charm-delivered directory containing | 354 | Write an rc file in the charm-delivered directory containing |
344 | @@ -469,82 +488,103 @@ | |||
345 | 469 | 488 | ||
346 | 470 | 489 | ||
347 | 471 | def git_install_requested(): | 490 | def git_install_requested(): |
350 | 472 | """Returns true if openstack-origin-git is specified.""" | 491 | """ |
351 | 473 | return config('openstack-origin-git') != "None" | 492 | Returns true if openstack-origin-git is specified. |
352 | 493 | """ | ||
353 | 494 | return config('openstack-origin-git') is not None | ||
354 | 474 | 495 | ||
355 | 475 | 496 | ||
356 | 476 | requirements_dir = None | 497 | requirements_dir = None |
357 | 477 | 498 | ||
358 | 478 | 499 | ||
361 | 479 | def git_clone_and_install(file_name, core_project): | 500 | def git_clone_and_install(projects_yaml, core_project): |
362 | 480 | """Clone/install all OpenStack repos specified in yaml config file.""" | 501 | """ |
363 | 502 | Clone/install all specified OpenStack repositories. | ||
364 | 503 | |||
365 | 504 | The expected format of projects_yaml is: | ||
366 | 505 | repositories: | ||
367 | 506 | - {name: keystone, | ||
368 | 507 | repository: 'git://git.openstack.org/openstack/keystone.git', | ||
369 | 508 | branch: 'stable/icehouse'} | ||
370 | 509 | - {name: requirements, | ||
371 | 510 | repository: 'git://git.openstack.org/openstack/requirements.git', | ||
372 | 511 | branch: 'stable/icehouse'} | ||
373 | 512 | directory: /mnt/openstack-git | ||
374 | 513 | http_proxy: http://squid.internal:3128 | ||
375 | 514 | https_proxy: https://squid.internal:3128 | ||
376 | 515 | |||
377 | 516 | The directory, http_proxy, and https_proxy keys are optional. | ||
378 | 517 | """ | ||
379 | 481 | global requirements_dir | 518 | global requirements_dir |
380 | 519 | parent_dir = '/mnt/openstack-git' | ||
381 | 482 | 520 | ||
383 | 483 | if file_name == "None": | 521 | if not projects_yaml: |
384 | 484 | return | 522 | return |
385 | 485 | 523 | ||
444 | 486 | yaml_file = os.path.join(charm_dir(), file_name) | 524 | projects = yaml.load(projects_yaml) |
445 | 487 | 525 | _git_validate_projects_yaml(projects, core_project) | |
446 | 488 | # clone/install the requirements project first | 526 | |
447 | 489 | installed = _git_clone_and_install_subset(yaml_file, | 527 | if 'http_proxy' in projects.keys(): |
448 | 490 | whitelist=['requirements']) | 528 | os.environ['http_proxy'] = projects['http_proxy'] |
449 | 491 | if 'requirements' not in installed: | 529 | |
450 | 492 | error_out('requirements git repository must be specified') | 530 | if 'https_proxy' in projects.keys(): |
451 | 493 | 531 | os.environ['https_proxy'] = projects['https_proxy'] | |
452 | 494 | # clone/install all other projects except requirements and the core project | 532 | |
453 | 495 | blacklist = ['requirements', core_project] | 533 | if 'directory' in projects.keys(): |
454 | 496 | _git_clone_and_install_subset(yaml_file, blacklist=blacklist, | 534 | parent_dir = projects['directory'] |
455 | 497 | update_requirements=True) | 535 | |
456 | 498 | 536 | for p in projects['repositories']: | |
457 | 499 | # clone/install the core project | 537 | repo = p['repository'] |
458 | 500 | whitelist = [core_project] | 538 | branch = p['branch'] |
459 | 501 | installed = _git_clone_and_install_subset(yaml_file, whitelist=whitelist, | 539 | if p['name'] == 'requirements': |
460 | 502 | update_requirements=True) | 540 | repo_dir = _git_clone_and_install_single(repo, branch, parent_dir, |
461 | 503 | if core_project not in installed: | 541 | update_requirements=False) |
462 | 504 | error_out('{} git repository must be specified'.format(core_project)) | 542 | requirements_dir = repo_dir |
463 | 505 | 543 | else: | |
464 | 506 | 544 | repo_dir = _git_clone_and_install_single(repo, branch, parent_dir, | |
465 | 507 | def _git_clone_and_install_subset(yaml_file, whitelist=[], blacklist=[], | 545 | update_requirements=True) |
466 | 508 | update_requirements=False): | 546 | |
467 | 509 | """Clone/install subset of OpenStack repos specified in yaml config file.""" | 547 | |
468 | 510 | global requirements_dir | 548 | def _git_validate_projects_yaml(projects, core_project): |
469 | 511 | installed = [] | 549 | """ |
470 | 512 | 550 | Validate the projects yaml. | |
471 | 513 | with open(yaml_file, 'r') as fd: | 551 | """ |
472 | 514 | projects = yaml.load(fd) | 552 | _git_ensure_key_exists('repositories', projects) |
473 | 515 | for proj, val in projects.items(): | 553 | |
474 | 516 | # The project subset is chosen based on the following 3 rules: | 554 | for project in projects['repositories']: |
475 | 517 | # 1) If project is in blacklist, we don't clone/install it, period. | 555 | _git_ensure_key_exists('name', project.keys()) |
476 | 518 | # 2) If whitelist is empty, we clone/install everything else. | 556 | _git_ensure_key_exists('repository', project.keys()) |
477 | 519 | # 3) If whitelist is not empty, we clone/install everything in the | 557 | _git_ensure_key_exists('branch', project.keys()) |
478 | 520 | # whitelist. | 558 | |
479 | 521 | if proj in blacklist: | 559 | if projects['repositories'][0]['name'] != 'requirements': |
480 | 522 | continue | 560 | error_out('{} git repo must be specified first'.format('requirements')) |
481 | 523 | if whitelist and proj not in whitelist: | 561 | |
482 | 524 | continue | 562 | if projects['repositories'][-1]['name'] != core_project: |
483 | 525 | repo = val['repository'] | 563 | error_out('{} git repo must be specified last'.format(core_project)) |
484 | 526 | branch = val['branch'] | 564 | |
485 | 527 | repo_dir = _git_clone_and_install_single(repo, branch, | 565 | |
486 | 528 | update_requirements) | 566 | def _git_ensure_key_exists(key, keys): |
487 | 529 | if proj == 'requirements': | 567 | """ |
488 | 530 | requirements_dir = repo_dir | 568 | Ensure that key exists in keys. |
489 | 531 | installed.append(proj) | 569 | """ |
490 | 532 | return installed | 570 | if key not in keys: |
491 | 533 | 571 | error_out('openstack-origin-git key \'{}\' is missing'.format(key)) | |
492 | 534 | 572 | ||
493 | 535 | def _git_clone_and_install_single(repo, branch, update_requirements=False): | 573 | |
494 | 536 | """Clone and install a single git repository.""" | 574 | def _git_clone_and_install_single(repo, branch, parent_dir, update_requirements): |
495 | 537 | dest_parent_dir = "/mnt/openstack-git/" | 575 | """ |
496 | 538 | dest_dir = os.path.join(dest_parent_dir, os.path.basename(repo)) | 576 | Clone and install a single git repository. |
497 | 539 | 577 | """ | |
498 | 540 | if not os.path.exists(dest_parent_dir): | 578 | dest_dir = os.path.join(parent_dir, os.path.basename(repo)) |
499 | 541 | juju_log('Host dir not mounted at {}. ' | 579 | |
500 | 542 | 'Creating directory there instead.'.format(dest_parent_dir)) | 580 | if not os.path.exists(parent_dir): |
501 | 543 | os.mkdir(dest_parent_dir) | 581 | juju_log('Directory already exists at {}. ' |
502 | 582 | 'No need to create directory.'.format(parent_dir)) | ||
503 | 583 | os.mkdir(parent_dir) | ||
504 | 544 | 584 | ||
505 | 545 | if not os.path.exists(dest_dir): | 585 | if not os.path.exists(dest_dir): |
506 | 546 | juju_log('Cloning git repo: {}, branch: {}'.format(repo, branch)) | 586 | juju_log('Cloning git repo: {}, branch: {}'.format(repo, branch)) |
508 | 547 | repo_dir = install_remote(repo, dest=dest_parent_dir, branch=branch) | 587 | repo_dir = install_remote(repo, dest=parent_dir, branch=branch) |
509 | 548 | else: | 588 | else: |
510 | 549 | repo_dir = dest_dir | 589 | repo_dir = dest_dir |
511 | 550 | 590 | ||
512 | @@ -561,16 +601,39 @@ | |||
513 | 561 | 601 | ||
514 | 562 | 602 | ||
515 | 563 | def _git_update_requirements(package_dir, reqs_dir): | 603 | def _git_update_requirements(package_dir, reqs_dir): |
517 | 564 | """Update from global requirements. | 604 | """ |
518 | 605 | Update from global requirements. | ||
519 | 565 | 606 | ||
522 | 566 | Update an OpenStack git directory's requirements.txt and | 607 | Update an OpenStack git directory's requirements.txt and |
523 | 567 | test-requirements.txt from global-requirements.txt.""" | 608 | test-requirements.txt from global-requirements.txt. |
524 | 609 | """ | ||
525 | 568 | orig_dir = os.getcwd() | 610 | orig_dir = os.getcwd() |
526 | 569 | os.chdir(reqs_dir) | 611 | os.chdir(reqs_dir) |
528 | 570 | cmd = "python update.py {}".format(package_dir) | 612 | cmd = ['python', 'update.py', package_dir] |
529 | 571 | try: | 613 | try: |
531 | 572 | subprocess.check_call(cmd.split(' ')) | 614 | subprocess.check_call(cmd) |
532 | 573 | except subprocess.CalledProcessError: | 615 | except subprocess.CalledProcessError: |
533 | 574 | package = os.path.basename(package_dir) | 616 | package = os.path.basename(package_dir) |
534 | 575 | error_out("Error updating {} from global-requirements.txt".format(package)) | 617 | error_out("Error updating {} from global-requirements.txt".format(package)) |
535 | 576 | os.chdir(orig_dir) | 618 | os.chdir(orig_dir) |
536 | 619 | |||
537 | 620 | |||
538 | 621 | def git_src_dir(projects_yaml, project): | ||
539 | 622 | """ | ||
540 | 623 | Return the directory where the specified project's source is located. | ||
541 | 624 | """ | ||
542 | 625 | parent_dir = '/mnt/openstack-git' | ||
543 | 626 | |||
544 | 627 | if not projects_yaml: | ||
545 | 628 | return | ||
546 | 629 | |||
547 | 630 | projects = yaml.load(projects_yaml) | ||
548 | 631 | |||
549 | 632 | if 'directory' in projects.keys(): | ||
550 | 633 | parent_dir = projects['directory'] | ||
551 | 634 | |||
552 | 635 | for p in projects['repositories']: | ||
553 | 636 | if p['name'] == project: | ||
554 | 637 | return os.path.join(parent_dir, os.path.basename(p['repository'])) | ||
555 | 638 | |||
556 | 639 | return None | ||
557 | 577 | 640 | ||
558 | === modified file 'hooks/charmhelpers/core/hookenv.py' | |||
559 | --- hooks/charmhelpers/core/hookenv.py 2015-03-18 10:19:15 +0000 | |||
560 | +++ hooks/charmhelpers/core/hookenv.py 2015-04-09 16:27:05 +0000 | |||
561 | @@ -20,11 +20,13 @@ | |||
562 | 20 | # Authors: | 20 | # Authors: |
563 | 21 | # Charm Helpers Developers <juju@lists.ubuntu.com> | 21 | # Charm Helpers Developers <juju@lists.ubuntu.com> |
564 | 22 | 22 | ||
565 | 23 | from __future__ import print_function | ||
566 | 23 | import os | 24 | import os |
567 | 24 | import json | 25 | import json |
568 | 25 | import yaml | 26 | import yaml |
569 | 26 | import subprocess | 27 | import subprocess |
570 | 27 | import sys | 28 | import sys |
571 | 29 | import errno | ||
572 | 28 | from subprocess import CalledProcessError | 30 | from subprocess import CalledProcessError |
573 | 29 | 31 | ||
574 | 30 | import six | 32 | import six |
575 | @@ -87,7 +89,18 @@ | |||
576 | 87 | if not isinstance(message, six.string_types): | 89 | if not isinstance(message, six.string_types): |
577 | 88 | message = repr(message) | 90 | message = repr(message) |
578 | 89 | command += [message] | 91 | command += [message] |
580 | 90 | subprocess.call(command) | 92 | # Missing juju-log should not cause failures in unit tests |
581 | 93 | # Send log output to stderr | ||
582 | 94 | try: | ||
583 | 95 | subprocess.call(command) | ||
584 | 96 | except OSError as e: | ||
585 | 97 | if e.errno == errno.ENOENT: | ||
586 | 98 | if level: | ||
587 | 99 | message = "{}: {}".format(level, message) | ||
588 | 100 | message = "juju-log: {}".format(message) | ||
589 | 101 | print(message, file=sys.stderr) | ||
590 | 102 | else: | ||
591 | 103 | raise | ||
592 | 91 | 104 | ||
593 | 92 | 105 | ||
594 | 93 | class Serializable(UserDict): | 106 | class Serializable(UserDict): |
595 | 94 | 107 | ||
596 | === modified file 'hooks/charmhelpers/core/unitdata.py' | |||
597 | --- hooks/charmhelpers/core/unitdata.py 2015-02-19 03:38:40 +0000 | |||
598 | +++ hooks/charmhelpers/core/unitdata.py 2015-04-09 16:27:05 +0000 | |||
599 | @@ -443,7 +443,7 @@ | |||
600 | 443 | data = hookenv.execution_environment() | 443 | data = hookenv.execution_environment() |
601 | 444 | self.conf = conf_delta = self.kv.delta(data['conf'], 'config') | 444 | self.conf = conf_delta = self.kv.delta(data['conf'], 'config') |
602 | 445 | self.rels = rels_delta = self.kv.delta(data['rels'], 'rels') | 445 | self.rels = rels_delta = self.kv.delta(data['rels'], 'rels') |
604 | 446 | self.kv.set('env', data['env']) | 446 | self.kv.set('env', dict(data['env'])) |
605 | 447 | self.kv.set('unit', data['unit']) | 447 | self.kv.set('unit', data['unit']) |
606 | 448 | self.kv.set('relid', data.get('relid')) | 448 | self.kv.set('relid', data.get('relid')) |
607 | 449 | return conf_delta, rels_delta | 449 | return conf_delta, rels_delta |
608 | 450 | 450 | ||
609 | === modified file 'hooks/cinder_utils.py' | |||
610 | --- hooks/cinder_utils.py 2015-02-19 19:42:21 +0000 | |||
611 | +++ hooks/cinder_utils.py 2015-04-09 16:27:05 +0000 | |||
612 | @@ -69,6 +69,7 @@ | |||
613 | 69 | 'cinder-common', | 69 | 'cinder-common', |
614 | 70 | 'gdisk', | 70 | 'gdisk', |
615 | 71 | 'haproxy', | 71 | 'haproxy', |
616 | 72 | 'librbd1', # bug 1440948 vol-from-img | ||
617 | 72 | 'python-jinja2', | 73 | 'python-jinja2', |
618 | 73 | 'python-keystoneclient', | 74 | 'python-keystoneclient', |
619 | 74 | 'python-mysqldb', | 75 | 'python-mysqldb', |
620 | 75 | 76 | ||
621 | === modified file 'tests/basic_deployment.py' | |||
622 | --- tests/basic_deployment.py 2015-03-26 16:24:22 +0000 | |||
623 | +++ tests/basic_deployment.py 2015-04-09 16:27:05 +0000 | |||
624 | @@ -16,7 +16,7 @@ | |||
625 | 16 | ) | 16 | ) |
626 | 17 | 17 | ||
627 | 18 | # Use DEBUG to turn on debug logging | 18 | # Use DEBUG to turn on debug logging |
629 | 19 | u = OpenStackAmuletUtils(ERROR) | 19 | u = OpenStackAmuletUtils(DEBUG) |
630 | 20 | 20 | ||
631 | 21 | 21 | ||
632 | 22 | class CinderBasicDeployment(OpenStackAmuletDeployment): | 22 | class CinderBasicDeployment(OpenStackAmuletDeployment): |
633 | 23 | 23 | ||
634 | === modified file 'tests/charmhelpers/contrib/openstack/amulet/deployment.py' | |||
635 | --- tests/charmhelpers/contrib/openstack/amulet/deployment.py 2015-03-13 13:00:03 +0000 | |||
636 | +++ tests/charmhelpers/contrib/openstack/amulet/deployment.py 2015-04-09 16:27:05 +0000 | |||
637 | @@ -15,6 +15,7 @@ | |||
638 | 15 | # along with charm-helpers. If not, see <http://www.gnu.org/licenses/>. | 15 | # along with charm-helpers. If not, see <http://www.gnu.org/licenses/>. |
639 | 16 | 16 | ||
640 | 17 | import six | 17 | import six |
641 | 18 | from collections import OrderedDict | ||
642 | 18 | from charmhelpers.contrib.amulet.deployment import ( | 19 | from charmhelpers.contrib.amulet.deployment import ( |
643 | 19 | AmuletDeployment | 20 | AmuletDeployment |
644 | 20 | ) | 21 | ) |
645 | @@ -100,12 +101,34 @@ | |||
646 | 100 | """ | 101 | """ |
647 | 101 | (self.precise_essex, self.precise_folsom, self.precise_grizzly, | 102 | (self.precise_essex, self.precise_folsom, self.precise_grizzly, |
648 | 102 | self.precise_havana, self.precise_icehouse, | 103 | self.precise_havana, self.precise_icehouse, |
650 | 103 | self.trusty_icehouse) = range(6) | 104 | self.trusty_icehouse, self.trusty_juno, self.trusty_kilo) = range(8) |
651 | 104 | releases = { | 105 | releases = { |
652 | 105 | ('precise', None): self.precise_essex, | 106 | ('precise', None): self.precise_essex, |
653 | 106 | ('precise', 'cloud:precise-folsom'): self.precise_folsom, | 107 | ('precise', 'cloud:precise-folsom'): self.precise_folsom, |
654 | 107 | ('precise', 'cloud:precise-grizzly'): self.precise_grizzly, | 108 | ('precise', 'cloud:precise-grizzly'): self.precise_grizzly, |
655 | 108 | ('precise', 'cloud:precise-havana'): self.precise_havana, | 109 | ('precise', 'cloud:precise-havana'): self.precise_havana, |
656 | 109 | ('precise', 'cloud:precise-icehouse'): self.precise_icehouse, | 110 | ('precise', 'cloud:precise-icehouse'): self.precise_icehouse, |
658 | 110 | ('trusty', None): self.trusty_icehouse} | 111 | ('trusty', None): self.trusty_icehouse, |
659 | 112 | ('trusty', 'cloud:trusty-juno'): self.trusty_juno, | ||
660 | 113 | ('trusty', 'cloud:trusty-kilo'): self.trusty_kilo} | ||
661 | 111 | return releases[(self.series, self.openstack)] | 114 | return releases[(self.series, self.openstack)] |
662 | 115 | |||
663 | 116 | def _get_openstack_release_string(self): | ||
664 | 117 | """Get openstack release string. | ||
665 | 118 | |||
666 | 119 | Return a string representing the openstack release. | ||
667 | 120 | """ | ||
668 | 121 | releases = OrderedDict([ | ||
669 | 122 | ('precise', 'essex'), | ||
670 | 123 | ('quantal', 'folsom'), | ||
671 | 124 | ('raring', 'grizzly'), | ||
672 | 125 | ('saucy', 'havana'), | ||
673 | 126 | ('trusty', 'icehouse'), | ||
674 | 127 | ('utopic', 'juno'), | ||
675 | 128 | ('vivid', 'kilo'), | ||
676 | 129 | ]) | ||
677 | 130 | if self.openstack: | ||
678 | 131 | os_origin = self.openstack.split(':')[1] | ||
679 | 132 | return os_origin.split('%s-' % self.series)[1].split('/')[0] | ||
680 | 133 | else: | ||
681 | 134 | return releases[self.series] |
charm_lint_check #3193 cinder-next for 1chb1n mp255705
LINT OK: passed
Build: http:// 10.245. 162.77: 8080/job/ charm_lint_ check/3193/