Merge lp:~dmitriis/charms/trusty/neutron-contrail/trunk into lp:~sdn-charmers/charms/trusty/neutron-contrail/trunk

Proposed by Dmitrii Shcherbakov
Status: Superseded
Proposed branch: lp:~dmitriis/charms/trusty/neutron-contrail/trunk
Merge into: lp:~sdn-charmers/charms/trusty/neutron-contrail/trunk
Diff against target: 1024 lines (+356/-150)
4 files modified
hooks/neutron_contrail_hooks.py (+149/-59)
hooks/neutron_contrail_utils.py (+196/-91)
metadata.yaml (+2/-0)
templates/contrail-vrouter-agent.conf (+9/-0)
To merge this branch: bzr merge lp:~dmitriis/charms/trusty/neutron-contrail/trunk
Reviewer Review Type Date Requested Status
Ante Karamatić Pending
Review via email: mp+320499@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Dmitrii Shcherbakov (dmitriis) wrote :

Note: easyrsa charm should be used for PKI https://jujucharms.com/u/containers/easyrsa/

juju add-relation contrail-control easyrsa
juju add-relation neutron-contrail easyrsa

67. By Dmitrii Shcherbakov

enable TLS for XMPP communication as of contrail 3

TLS is enabled unconditionally for contail 3.0 and above deployments to
make sure communication is secure by default.

Certificates are generated automatically from a PKI charm (e.g. easyrsa
with a subject alternative name field containing an IP address on a
control network which is used by both contrail-control and
neutron-contrail to communicate with each other.

As of Juju 2.x network spaces can be used if an underlying cloud
supports them. In order to facilitate that support one should bind
control-node endpoint to a specific network space. Otherwise, old
mechanisms such as unit private address are going to be used to retrieve
an ip address to be included into a certificate.

Control node address fetching mechanism has changed as well: instead of
just doing a relation-get for a private IP address of a control-node
unit a different value is taken from the relation data called
control_node_ip (available due to modifications on the contrail-control
side) - it is either an address in the network space which control-node
endpoint is bound to or a fall-back address (unit private address).

Unmerged revisions

67. By Dmitrii Shcherbakov

enable TLS for XMPP communication as of contrail 3

TLS is enabled unconditionally for contail 3.0 and above deployments to
make sure communication is secure by default.

Certificates are generated automatically from a PKI charm (e.g. easyrsa
with a subject alternative name field containing an IP address on a
control network which is used by both contrail-control and
neutron-contrail to communicate with each other.

As of Juju 2.x network spaces can be used if an underlying cloud
supports them. In order to facilitate that support one should bind
control-node endpoint to a specific network space. Otherwise, old
mechanisms such as unit private address are going to be used to retrieve
an ip address to be included into a certificate.

Control node address fetching mechanism has changed as well: instead of
just doing a relation-get for a private IP address of a control-node
unit a different value is taken from the relation data called
control_node_ip (available due to modifications on the contrail-control
side) - it is either an address in the network space which control-node
endpoint is bound to or a fall-back address (unit private address).

66. By Dmitrii Shcherbakov

hooks,utils: pep8 refactoring

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'hooks/neutron_contrail_hooks.py'
2--- hooks/neutron_contrail_hooks.py 2017-03-10 12:57:45 +0000
3+++ hooks/neutron_contrail_hooks.py 2017-03-26 17:44:17 +0000
4@@ -18,7 +18,8 @@
5 log,
6 relation_get,
7 relation_ids,
8- relation_set
9+ relation_set,
10+ local_unit,
11 )
12
13 from charmhelpers.core.host import (
14@@ -37,6 +38,7 @@
15 CONTRAIL_VERSION,
16 OPENSTACK_VERSION,
17 configure_vrouter,
18+ control_network_ip,
19 disable_vrouter_vgw,
20 dpkg_version,
21 drop_caches,
22@@ -57,23 +59,25 @@
23 write_nodemgr_config,
24 write_vnc_api_config,
25 write_vrouter_config,
26- write_vrouter_vgw_interfaces
27+ write_vrouter_vgw_interfaces,
28+ write_xmpp_tls_files,
29 )
30
31-PACKAGES = [ "contrail-vrouter-dkms", "contrail-vrouter-agent",
32- "contrail-utils", "python-jinja2", "python-netifaces",
33- "python-netaddr", "contrail-nodemgr" ]
34-
35-PACKAGES_LBAAS = [ "python-barbicanclient", "haproxy" ]
36-
37-PACKAGES_VROUTER = [ "contrail-nova-driver" ]
38-
39-PACKAGES_VROUTER_3_2 = [ "contrail-nova-vif", "contrail-vrouter-init",
40- "contrail-vrouter-common" ]
41+PACKAGES = ["contrail-vrouter-dkms", "contrail-vrouter-agent",
42+ "contrail-utils", "python-jinja2", "python-netifaces",
43+ "python-netaddr", "contrail-nodemgr"]
44+
45+PACKAGES_LBAAS = ["python-barbicanclient", "haproxy"]
46+
47+PACKAGES_VROUTER = ["contrail-nova-driver"]
48+
49+PACKAGES_VROUTER_3_2 = ["contrail-nova-vif", "contrail-vrouter-init",
50+ "contrail-vrouter-common"]
51
52 hooks = Hooks()
53 config = config()
54
55+
56 def check_local_metadata():
57 if not is_leader():
58 return
59@@ -95,11 +99,13 @@
60 unprovision_local_metadata()
61 leader_set({"local-metadata-provisioned": ""})
62
63+
64 def check_vrouter():
65 # check relation dependencies
66 if config_get("contrail-api-ready") \
67 and config_get("control-node-ready") \
68- and config_get("identity-admin-ready"):
69+ and config_get("identity-admin-ready") \
70+ and config_get("tls-certificates-ready"):
71 if not config_get("vrouter-provisioned"):
72 provision_vrouter()
73 config["vrouter-provisioned"] = True
74@@ -107,33 +113,36 @@
75 unprovision_vrouter()
76 config["vrouter-provisioned"] = False
77
78+
79 @hooks.hook("config-changed")
80 def config_changed():
81 configure_local_metadata()
82 configure_virtual_gateways()
83 write_config()
84 if not units("contrail-discovery") and not units("control-node"):
85- config["control-node-ready"] = True if config.get("discovery-server-ip") \
86- else False
87+ config["control-node-ready"] = True \
88+ if config.get("discovery-server-ip") else False
89 if not units("contrail-api"):
90 config["contrail-api-ready"] = True if config.get("contrail-api-ip") \
91- else False
92+ else False
93 check_vrouter()
94 check_local_metadata()
95
96+
97 def config_get(key):
98 try:
99 return config[key]
100 except KeyError:
101 return None
102
103+
104 def configure_local_metadata():
105 if config["local-metadata-server"]:
106 if "local-metadata-secret" not in config:
107 # generate secret
108 secret = str(uuid.uuid4())
109 config["local-metadata-secret"] = secret
110- settings = { "metadata-shared-secret": secret }
111+ settings = {"metadata-shared-secret": secret}
112 # inform relations
113 for rid in relation_ids("neutron-plugin"):
114 relation_set(relation_id=rid, relation_settings=settings)
115@@ -141,42 +150,47 @@
116 if "local-metadata-secret" in config:
117 # remove secret
118 del config["local-metadata-secret"]
119- settings = { "metadata-shared-secret": None }
120+ settings = {"metadata-shared-secret": None}
121 # inform relations
122 for rid in relation_ids("neutron-plugin"):
123 relation_set(relation_id=rid, relation_settings=settings)
124
125+
126 def configure_virtual_gateways():
127 gateways = config.get("virtual-gateways")
128 previous_gateways = config_get("virtual-gateways-prev")
129 if gateways != previous_gateways:
130 # create/destroy virtual gateway interfaces according to new value
131- interfaces = { gateway["interface"]: set(gateway["subnets"])
132- for gateway in yaml.safe_load(gateways) } \
133- if gateways else {}
134- previous_interfaces = { gateway["interface"]: set(gateway["subnets"])
135- for gateway in yaml.safe_load(previous_gateways) } \
136- if previous_gateways else {}
137- ifaces = [ interface for interface, subnets in previous_interfaces.iteritems()
138- if interface not in interfaces
139- or subnets != interfaces[interface] ]
140+ interfaces = {gateway["interface"]: set(gateway["subnets"])
141+ for gateway in yaml.safe_load(gateways)} \
142+ if gateways else {}
143+ previous_interfaces = {gateway["interface"]: set(gateway["subnets"])
144+ for gateway
145+ in yaml.safe_load(previous_gateways)} \
146+ if previous_gateways else {}
147+ ifaces = [interface for interface, subnets
148+ in previous_interfaces.iteritems()
149+ if interface not in interfaces
150+ or subnets != interfaces[interface]]
151 if ifaces:
152 ifdown(ifaces)
153
154- write_vrouter_vgw_interfaces()
155-
156- ifaces = [ interface for interface, subnets in interfaces.iteritems()
157- if interface not in previous_interfaces
158- or subnets != previous_interfaces[interface] ]
159- if ifaces:
160- ifup(ifaces)
161-
162- if interfaces:
163- enable_vrouter_vgw()
164- else:
165- disable_vrouter_vgw()
166-
167- config["virtual-gateways-prev"] = gateways
168+ write_vrouter_vgw_interfaces()
169+
170+ ifaces = [interface for interface, subnets
171+ in interfaces.iteritems()
172+ if interface not in previous_interfaces
173+ or subnets != previous_interfaces[interface]]
174+ if ifaces:
175+ ifup(ifaces)
176+
177+ if interfaces:
178+ enable_vrouter_vgw()
179+ else:
180+ disable_vrouter_vgw()
181+
182+ config["virtual-gateways-prev"] = gateways
183+
184
185 @hooks.hook("contrail-api-relation-departed")
186 @hooks.hook("contrail-api-relation-broken")
187@@ -187,6 +201,7 @@
188 check_local_metadata()
189 write_vnc_api_config()
190
191+
192 @hooks.hook("contrail-api-relation-changed")
193 def contrail_api_changed():
194 if not relation_get("port"):
195@@ -197,6 +212,7 @@
196 check_vrouter()
197 check_local_metadata()
198
199+
200 @hooks.hook("contrail-discovery-relation-changed")
201 def contrail_discovery_changed():
202 if not relation_get("port"):
203@@ -207,6 +223,7 @@
204 check_vrouter()
205 check_local_metadata()
206
207+
208 @hooks.hook("contrail-discovery-relation-departed")
209 @hooks.hook("contrail-discovery-relation-broken")
210 def contrail_discovery_departed():
211@@ -218,12 +235,18 @@
212 check_local_metadata()
213 contrail_discovery_relation()
214
215-@restart_on_change({"/etc/contrail/contrail-vrouter-agent.conf": ["contrail-vrouter-agent"],
216- "/etc/contrail/contrail-vrouter-nodemgr.conf": ["contrail-vrouter-nodemgr"]})
217+
218+@restart_on_change(
219+ {
220+ "/etc/contrail/contrail-vrouter-agent.conf":
221+ ["contrail-vrouter-agent"],
222+ "/etc/contrail/contrail-vrouter-nodemgr.conf":
223+ ["contrail-vrouter-nodemgr"]})
224 def contrail_discovery_relation():
225 write_vrouter_config()
226 write_nodemgr_config()
227
228+
229 @hooks.hook("control-node-relation-departed")
230 @hooks.hook("control-node-relation-broken")
231 def control_node_departed():
232@@ -235,6 +258,7 @@
233 check_local_metadata()
234 control_node_relation()
235
236+
237 @hooks.hook("control-node-relation-changed")
238 def control_node_changed():
239 control_node_relation()
240@@ -242,10 +266,13 @@
241 check_vrouter()
242 check_local_metadata()
243
244-@restart_on_change({"/etc/contrail/contrail-vrouter-agent.conf": ["contrail-vrouter-agent"]})
245+
246+@restart_on_change(
247+ {"/etc/contrail/contrail-vrouter-agent.conf": ["contrail-vrouter-agent"]})
248 def control_node_relation():
249 write_vrouter_config()
250
251+
252 @hooks.hook("identity-admin-relation-changed")
253 def identity_admin_changed():
254 if not relation_get("service_hostname"):
255@@ -258,6 +285,7 @@
256 check_vrouter()
257 check_local_metadata()
258
259+
260 @hooks.hook("identity-admin-relation-departed")
261 @hooks.hook("identity-admin-relation-broken")
262 def identity_admin_departed():
263@@ -269,11 +297,12 @@
264 if version_compare(CONTRAIL_VERSION, "3.0.2.0-34") >= 0:
265 write_barbican_auth_config()
266
267+
268 @hooks.hook()
269 def install():
270 configure_sources(True, "install-sources", "install-keys")
271 apt_upgrade(fatal=True, dist=True)
272- fix_vrouter_scripts() # bug in 2.0+20141015.1 packages
273+ fix_vrouter_scripts() # bug in 2.0+20141015.1 packages
274 apt_install(PACKAGES, fatal=True)
275 utils.CONTRAIL_VERSION = dpkg_version("contrail-vrouter-agent")
276 if version_compare(utils.CONTRAIL_VERSION, "3.2") >= 0:
277@@ -293,13 +322,15 @@
278 try:
279 modprobe("vrouter")
280 except CalledProcessError:
281- log("vrouter kernel module failed to load, clearing pagecache and retrying")
282+ log("vrouter kernel module failed to load,"
283+ " clearing pagecache and retrying")
284 drop_caches()
285 modprobe("vrouter")
286 modprobe("vrouter", True, True)
287 configure_vrouter()
288 service_restart("nova-compute")
289
290+
291 @hooks.hook("neutron-metadata-relation-changed")
292 def neutron_metadata_changed():
293 if not relation_get("shared-secret"):
294@@ -307,43 +338,96 @@
295 return
296 neutron_metadata_relation()
297
298+
299 @hooks.hook("neutron-metadata-relation-departed")
300 @hooks.hook("neutron-metadata-relation-broken")
301-@restart_on_change({"/etc/contrail/contrail-vrouter-agent.conf": ["contrail-vrouter-agent"]})
302+@restart_on_change(
303+ {"/etc/contrail/contrail-vrouter-agent.conf": ["contrail-vrouter-agent"]})
304 def neutron_metadata_relation():
305 write_vrouter_config()
306
307+
308 @hooks.hook("neutron-plugin-relation-joined")
309 def neutron_plugin_joined():
310 # create plugin config
311 section = []
312 if version_compare(OPENSTACK_VERSION, "1:2015.1~") < 0:
313 if version_compare(OPENSTACK_VERSION, "1:2014.2") >= 0:
314- section.append(("network_api_class", "nova_contrail_vif.contrailvif.ContrailNetworkAPI"))
315+ section.append(("network_api_class",
316+ "nova_contrail_vif.contrailvif"
317+ ".ContrailNetworkAPI"))
318 else:
319- section.append(("libvirt_vif_driver", "nova_contrail_vif.contrailvif.VRouterVIFDriver"))
320- section.append(("firewall_driver", "nova.virt.firewall.NoopFirewallDriver"))
321+ section.append(("libvirt_vif_driver",
322+ "nova_contrail_vif.contrailvif.VRouterVIFDriver"))
323+ section.append(
324+ ("firewall_driver",
325+ "nova.virt.firewall.NoopFirewallDriver"))
326 conf = {
327- "nova-compute": {
328- "/etc/nova/nova.conf": {
329- "sections": {
330- "DEFAULT": section
331- }
332+ "nova-compute": {
333+ "/etc/nova/nova.conf": {
334+ "sections": {
335+ "DEFAULT": section
336+ }
337+ }
338 }
339- }
340 }
341 relation_set(subordinate_configuration=json.dumps(conf))
342
343 if config["local-metadata-server"]:
344- settings = { "metadata-shared-secret": config["local-metadata-secret"] }
345+ settings = {"metadata-shared-secret": config["local-metadata-secret"]}
346 relation_set(relation_settings=settings)
347
348+
349+@hooks.hook('tls-certificates-relation-joined')
350+def tls_certificates_relation_joined():
351+ # a hostname could also be provided as a SAN
352+ # (Subject Alternative Name) but having this one
353+ # has certain implications
354+ # https://tools.ietf.org/html/rfc2818#section-3.1
355+ # "If a subjectAltName extension of type dNSName
356+ # is present, that MUST be used as the identity"
357+ # Therefore it is not used here as we don't need
358+ # a DNS infrastructure dependency
359+ ip_san = control_network_ip()
360+ settings = {
361+ 'sans': json.dumps([ip_san, '127.0.0.1']),
362+ 'common_name': ip_san,
363+ 'certificate_name': local_unit().replace('/', '_')
364+ }
365+ relation_set(relation_settings=settings)
366+
367+
368+@hooks.hook('tls-certificates-relation-changed')
369+def tls_certificates_relation_changed():
370+ # check that the -provides side have set the data we need
371+ # and render the affected files
372+ unitname = local_unit().replace('/', '_')
373+ cert = '{0}.server.cert'.format(unitname)
374+ key = '{0}.server.key'.format(unitname)
375+ certv = relation_get(cert)
376+ keyv = relation_get(key)
377+ ca = relation_get('ca')
378+
379+ if certv and keyv and ca:
380+ write_xmpp_tls_files(certv, keyv, ca)
381+ config["tls-certificates-ready"] = True
382+ else:
383+ log('tls-certificates relation data is not fully available')
384+ config["tls-certificates-ready"] = False
385+
386+
387+@hooks.hook('tls-certificates-relation-departed')
388+def tls_certificates_relation_departed():
389+ config["tls-certificates-ready"] = False
390+
391+
392 def main():
393 try:
394 hooks.execute(sys.argv)
395 except UnregisteredHookError as e:
396 log("Unknown hook {} - skipping.".format(e))
397
398+
399 @hooks.hook("upgrade-charm")
400 def upgrade_charm():
401 write_vrouter_config()
402@@ -351,12 +435,18 @@
403 write_nodemgr_config()
404 service_restart("supervisor-vrouter")
405
406-@restart_on_change({"/etc/contrail/contrail-vrouter-agent.conf": ["contrail-vrouter-agent"],
407- "/etc/contrail/contrail-vrouter-nodemgr.conf": ["contrail-vrouter-nodemgr"]})
408+
409+@restart_on_change(
410+ {
411+ "/etc/contrail/contrail-vrouter-agent.conf":
412+ ["contrail-vrouter-agent"],
413+ "/etc/contrail/contrail-vrouter-nodemgr.conf":
414+ ["contrail-vrouter-nodemgr"]})
415 def write_config():
416 write_vrouter_config()
417 write_vnc_api_config()
418 write_nodemgr_config()
419
420+
421 if __name__ == "__main__":
422 main()
423
424=== modified file 'hooks/neutron_contrail_utils.py'
425--- hooks/neutron_contrail_utils.py 2017-03-10 12:57:45 +0000
426+++ hooks/neutron_contrail_utils.py 2017-03-26 17:44:17 +0000
427@@ -24,7 +24,9 @@
428 relation_get,
429 relation_ids,
430 relation_type,
431- remote_unit
432+ remote_unit,
433+ unit_private_ip,
434+ network_get_primary_address,
435 )
436
437 from charmhelpers.core.host import service_restart, service_start
438@@ -33,17 +35,21 @@
439
440 apt_pkg.init()
441
442+
443 def dpkg_version(pkg):
444 try:
445- return check_output(["dpkg-query", "-f", "${Version}\\n", "-W", pkg]).rstrip()
446+ return check_output(
447+ ["dpkg-query", "-f", "${Version}\\n", "-W", pkg]).rstrip()
448 except CalledProcessError:
449 return None
450
451+
452 CONTRAIL_VERSION = dpkg_version("contrail-vrouter-agent")
453 OPENSTACK_VERSION = dpkg_version("nova-compute")
454
455 config = config()
456
457+
458 def retry(f=None, timeout=10, delay=2):
459 """Retry decorator.
460
461@@ -67,6 +73,7 @@
462 """
463 if not f:
464 return functools.partial(retry, timeout=timeout, delay=delay)
465+
466 @functools.wraps(f)
467 def func(*args, **kwargs):
468 start = time()
469@@ -87,6 +94,7 @@
470 raise error
471 return func
472
473+
474 def configure_vrouter():
475 # run external script to configure vrouter
476 args = ["./create-vrouter.sh"]
477@@ -97,37 +105,43 @@
478 args.append(iface)
479 check_call(args, cwd="scripts")
480
481+
482 def contrail_api_ctx():
483 ip = config.get("contrail-api-ip")
484 if ip:
485 port = config.get("contrail-api-port")
486- return { "api_server": ip,
487- "api_port": port if port is not None else 8082 }
488+ return {"api_server": ip,
489+ "api_port": port if port is not None else 8082}
490
491- ctxs = [ { "api_server": gethostbyname(relation_get("private-address", unit, rid)),
492- "api_port": port }
493- for rid in relation_ids("contrail-api")
494- for unit, port in
495- ((unit, relation_get("port", unit, rid)) for unit in related_units(rid))
496- if port ]
497+ ctxs = [{"api_server": gethostbyname(relation_get("private-address",
498+ unit, rid)),
499+ "api_port": port}
500+ for rid in relation_ids("contrail-api")
501+ for unit, port in
502+ ((unit, relation_get("port", unit, rid))
503+ for unit in related_units(rid))
504+ if port]
505 return ctxs[0] if ctxs else {}
506
507+
508 def contrail_discovery_ctx():
509 ip = config.get("discovery-server-ip")
510 if ip:
511- return { "discovery_server": ip,
512- "discovery_port": 5998 }
513+ return {"discovery_server": ip,
514+ "discovery_port": 5998}
515
516- ctxs = [ { "discovery_server": vip if vip \
517- else gethostbyname(relation_get("private-address", unit, rid)),
518- "discovery_port": port }
519- for rid in relation_ids("contrail-discovery")
520- for unit, port, vip in
521- ((unit, relation_get("port", unit, rid), relation_get("vip", unit, rid))
522- for unit in related_units(rid))
523- if port ]
524+ ctxs = [{"discovery_server": vip if vip
525+ else gethostbyname(relation_get("private-address", unit, rid)),
526+ "discovery_port": port}
527+ for rid in relation_ids("contrail-discovery")
528+ for unit, port, vip in
529+ ((unit, relation_get("port", unit, rid),
530+ relation_get("vip", unit, rid))
531+ for unit in related_units(rid))
532+ if port]
533 return ctxs[0] if ctxs else {}
534
535+
536 @retry(timeout=300)
537 def contrail_provision_linklocal(api_ip, api_port, service_name, service_ip,
538 service_port, fabric_ip, fabric_port, op,
539@@ -144,6 +158,7 @@
540 "--admin_user", user,
541 "--admin_password", password])
542
543+
544 @retry(timeout=300)
545 def contrail_provision_vrouter(hostname, ip, api_ip, api_port, op,
546 user, password, tenant):
547@@ -157,10 +172,13 @@
548 "--admin_password", password,
549 "--admin_tenant_name", tenant])
550
551+
552 def control_node_ctx():
553- return { "control_nodes": [ gethostbyname(relation_get("private-address", unit, rid))
554- for rid in relation_ids("control-node")
555- for unit in related_units(rid) ] }
556+ return {"control_nodes": [gethostbyname(relation_get("control_node_ip",
557+ unit, rid))
558+ for rid in relation_ids("control-node")
559+ for unit in related_units(rid)]}
560+
561
562 def disable_vrouter_vgw():
563 if os.path.exists("/etc/sysctl.d/60-vrouter-vgw.conf"):
564@@ -168,6 +186,7 @@
565 os.remove("/etc/sysctl.d/60-vrouter-vgw.conf")
566 check_call(["sysctl", "-qw", "net.ipv4.ip_forward=0"])
567
568+
569 def drop_caches():
570 """Clears OS pagecache"""
571 log("Clearing pagecache")
572@@ -175,25 +194,29 @@
573 with open("/proc/sys/vm/drop_caches", "w") as f:
574 f.write("3\n")
575
576+
577 def enable_vrouter_vgw():
578 if not os.path.exists("/etc/sysctl.d/60-vrouter-vgw.conf"):
579 # set sysctl options
580 shutil.copy("files/60-vrouter-vgw.conf", "/etc/sysctl.d")
581 service_start("procps")
582
583+
584 def fix_kexec_tools():
585 if version_compare(CONTRAIL_VERSION, "3.2") >= 0:
586 # remove crashkernel grub entry
587 check_call(["sed", "-i", "-e",
588- "s/^GRUB_CMDLINE_LINUX_DEFAULT=/#GRUB_CMDLINE_LINUX_DEFAULT=/",
589+ "s/^GRUB_CMDLINE_LINUX_DEFAULT=/"
590+ "#GRUB_CMDLINE_LINUX_DEFAULT=/",
591 "/etc/default/grub.d/kexec-tools.cfg"])
592 check_call(["update-grub2"])
593
594+
595 def fix_nodemgr():
596 # add files missing from contrail-nodemgr package
597 dest = "/etc/contrail/supervisord_vrouter_files/" \
598- + ("contrail-vrouter-nodemgr.ini" \
599- if version_compare(CONTRAIL_VERSION, "3.1") >= 0 \
600+ + ("contrail-vrouter-nodemgr.ini"
601+ if version_compare(CONTRAIL_VERSION, "3.1") >= 0
602 else "contrail-nodemgr-vrouter.ini")
603 shutil.copy("files/contrail-nodemgr-vrouter.ini", dest)
604 pw = pwd.getpwnam("contrail")
605@@ -208,14 +231,16 @@
606 if version_compare(CONTRAIL_VERSION, "3.1") >= 0 \
607 else "files/contrail-vrouter-nodemgr"
608 shutil.copy(src, "/etc/init.d/contrail-vrouter-nodemgr")
609- os.chmod("/etc/init.d/contrail-vrouter-nodemgr", 0755)
610+ os.chmod("/etc/init.d/contrail-vrouter-nodemgr", 0o755)
611
612 service_restart("supervisor-vrouter")
613
614+
615 def fix_permissions():
616- os.chmod("/etc/contrail", 0755)
617+ os.chmod("/etc/contrail", 0o755)
618 os.chown("/etc/contrail", 0, 0)
619
620+
621 def fix_vrouter_scripts():
622 # certain files need to be present for packages
623 if not os.path.exists("/opt/contrail/bin"):
624@@ -224,30 +249,36 @@
625 os.symlink("/bin/true", "/opt/contrail/bin/vrouter-post-start.sh")
626 os.symlink("/bin/true", "/opt/contrail/bin/vrouter-pre-stop.sh")
627
628+
629 def identity_admin_ctx():
630- ctxs = [ { "auth_host": gethostbyname(hostname),
631- "auth_port": relation_get("service_port", unit, rid),
632- "auth_protocol": relation_get("service_protocol", unit, rid),
633- "admin_user": relation_get("service_username", unit, rid),
634- "admin_password": relation_get("service_password", unit, rid),
635- "admin_tenant_name": relation_get("service_tenant_name", unit, rid),
636- "auth_region": relation_get("service_region", unit, rid) }
637- for rid in relation_ids("identity-admin")
638- for unit, hostname in
639- ((unit, relation_get("service_hostname", unit, rid)) for unit in related_units(rid))
640- if hostname ]
641+ ctxs = [{"auth_host": gethostbyname(hostname),
642+ "auth_port": relation_get("service_port", unit, rid),
643+ "auth_protocol": relation_get("service_protocol", unit, rid),
644+ "admin_user": relation_get("service_username", unit, rid),
645+ "admin_password": relation_get("service_password", unit, rid),
646+ "admin_tenant_name": relation_get("service_tenant_name",
647+ unit, rid),
648+ "auth_region": relation_get("service_region", unit, rid)}
649+ for rid in relation_ids("identity-admin")
650+ for unit, hostname in
651+ ((unit, relation_get("service_hostname", unit, rid))
652+ for unit in related_units(rid))
653+ if hostname]
654 return ctxs[0] if ctxs else {}
655
656+
657 def ifdown(interfaces=None):
658 """ifdown an interface or all interfaces"""
659 log("Taking down {}".format(interfaces if interfaces else "interfaces"))
660 check_call(["ifdown"] + interfaces if interfaces else ["-a"])
661
662+
663 def ifup(interfaces=None):
664 """ifup an interface or all interfaces"""
665 log("Bringing up {}".format(interfaces if interfaces else "interfaces"))
666 check_call(["ifup"] + interfaces if interfaces else ["-a"])
667
668+
669 def lsmod(module):
670 """Check if a kernel module is loaded"""
671 with open("/proc/modules", "r") as modules:
672@@ -256,6 +287,7 @@
673 return True
674 return False
675
676+
677 def modprobe(module, auto_load=False, dkms_autoinstall=False):
678 """Load a kernel module.
679
680@@ -287,19 +319,23 @@
681 log("DKMS auto installing for kernel {}".format(kernel))
682 check_call(["dkms", "autoinstall", "-k", kernel])
683
684+
685 def network_ctx():
686 iface = config.get("control-interface")
687- return { "control_network_ip": netifaces.ifaddresses(iface)[netifaces.AF_INET][0]["addr"] }
688+ return {"control_network_ip": netifaces.ifaddresses(
689+ iface)[netifaces.AF_INET][0]["addr"]}
690+
691
692 def neutron_metadata_ctx():
693 if "local-metadata-secret" in config:
694- return { "metadata_secret": config["local-metadata-secret"] }
695+ return {"metadata_secret": config["local-metadata-secret"]}
696
697- ctxs = [ { "metadata_secret": relation_get("shared-secret", unit, rid) }
698- for rid in relation_ids("neutron-metadata")
699- for unit in related_units(rid) ]
700+ ctxs = [{"metadata_secret": relation_get("shared-secret", unit, rid)}
701+ for rid in relation_ids("neutron-metadata")
702+ for unit in related_units(rid)]
703 return ctxs[0] if ctxs else {}
704
705+
706 def provision_local_metadata():
707 api_port = None
708 api_ip = config.get("contrail-api-ip")
709@@ -308,22 +344,25 @@
710 if api_port is None:
711 api_port = 8082
712 else:
713- api_ip, api_port = [ (gethostbyname(relation_get("private-address", unit, rid)),
714- port)
715- for rid in relation_ids("contrail-api")
716- for unit, port in
717- ((unit, relation_get("port", unit, rid)) for unit in related_units(rid))
718- if port ][0]
719- user, password = [ (relation_get("service_username", unit, rid),
720- relation_get("service_password", unit, rid))
721- for rid in relation_ids("identity-admin")
722- for unit in related_units(rid)
723- if relation_get("service_hostname", unit, rid) ][0]
724+ api_ip, api_port = [(gethostbyname(relation_get("private-address",
725+ unit, rid)),
726+ port)
727+ for rid in relation_ids("contrail-api")
728+ for unit, port in
729+ ((unit, relation_get("port", unit, rid))
730+ for unit in related_units(rid))
731+ if port][0]
732+ user, password = [(relation_get("service_username", unit, rid),
733+ relation_get("service_password", unit, rid))
734+ for rid in relation_ids("identity-admin")
735+ for unit in related_units(rid)
736+ if relation_get("service_hostname", unit, rid)][0]
737 log("Provisioning local metadata service 127.0.0.1:8775")
738 contrail_provision_linklocal(api_ip, api_port, "metadata",
739 "169.254.169.254", 80, "127.0.0.1", 8775,
740 "add", user, password)
741
742+
743 def provision_vrouter():
744 hostname = gethostname()
745 ip = netifaces.ifaddresses("vhost0")[netifaces.AF_INET][0]["addr"]
746@@ -334,26 +373,30 @@
747 if api_port is None:
748 api_port = 8082
749 else:
750- api_ip, api_port = [ (gethostbyname(relation_get("private-address", unit, rid)),
751- port)
752- for rid in relation_ids("contrail-api")
753- for unit, port in
754- ((unit, relation_get("port", unit, rid)) for unit in related_units(rid))
755- if port ][0]
756- user, password, tenant = [ (relation_get("service_username", unit, rid),
757- relation_get("service_password", unit, rid),
758- relation_get("service_tenant_name", unit, rid))
759- for rid in relation_ids("identity-admin")
760- for unit in related_units(rid)
761- if relation_get("service_hostname", unit, rid) ][0]
762+ api_ip, api_port = [(gethostbyname(relation_get("private-address",
763+ unit, rid)), port)
764+ for rid in relation_ids("contrail-api")
765+ for unit, port in
766+ ((unit, relation_get("port", unit, rid))
767+ for unit in related_units(rid))
768+ if port][0]
769+ user, password, tenant = [(relation_get("service_username", unit, rid),
770+ relation_get("service_password", unit, rid),
771+ relation_get("service_tenant_name", unit, rid))
772+ for rid in relation_ids("identity-admin")
773+ for unit in related_units(rid)
774+ if relation_get("service_hostname",
775+ unit, rid)][0]
776 log("Provisioning vrouter {}".format(ip))
777 contrail_provision_vrouter(hostname, ip, api_ip, api_port, "add",
778 user, password, tenant)
779
780+
781 def units(relation):
782 """Return a list of units for the specified relation"""
783- return [ unit for rid in relation_ids(relation)
784- for unit in related_units(rid) ]
785+ return [unit for rid in relation_ids(relation)
786+ for unit in related_units(rid)]
787+
788
789 def unprovision_local_metadata():
790 relation = relation_type()
791@@ -369,20 +412,21 @@
792 api_ip = gethostbyname(relation_get("private-address"))
793 api_port = relation_get("port")
794 else:
795- api_ip, api_port = [ (gethostbyname(relation_get("private-address", unit, rid)),
796- relation_get("port", unit, rid))
797- for rid in relation_ids("contrail-api")
798- for unit in related_units(rid) ][0]
799+ api_ip, api_port = [(gethostbyname(relation_get("private-address",
800+ unit, rid)),
801+ relation_get("port", unit, rid))
802+ for rid in relation_ids("contrail-api")
803+ for unit in related_units(rid)][0]
804 user = None
805 password = None
806 if relation == "identity-admin":
807 user = relation_get("service_username")
808 password = relation_get("service_password")
809 else:
810- user, password = [ (relation_get("service_username", unit, rid),
811- relation_get("service_password", unit, rid))
812- for rid in relation_ids("identity-admin")
813- for unit in related_units(rid) ][0]
814+ user, password = [(relation_get("service_username", unit, rid),
815+ relation_get("service_password", unit, rid))
816+ for rid in relation_ids("identity-admin")
817+ for unit in related_units(rid)][0]
818 log("Unprovisioning local metadata service 127.0.0.1:8775")
819 try:
820 contrail_provision_linklocal(api_ip, api_port, "metadata",
821@@ -391,6 +435,7 @@
822 except CalledProcessError:
823 pass
824
825+
826 def unprovision_vrouter():
827 relation = relation_type()
828 if relation and not remote_unit():
829@@ -407,10 +452,11 @@
830 api_ip = gethostbyname(relation_get("private-address"))
831 api_port = relation_get("port")
832 else:
833- api_ip, api_port = [ (gethostbyname(relation_get("private-address", unit, rid)),
834- relation_get("port", unit, rid))
835- for rid in relation_ids("contrail-api")
836- for unit in related_units(rid) ][0]
837+ api_ip, api_port = [(gethostbyname(relation_get("private-address",
838+ unit, rid)),
839+ relation_get("port", unit, rid))
840+ for rid in relation_ids("contrail-api")
841+ for unit in related_units(rid)][0]
842 user = None
843 password = None
844 tenant = None
845@@ -419,11 +465,12 @@
846 password = relation_get("service_password")
847 tenant = relation_get("service_tenant_name")
848 else:
849- user, password, tenant = [ (relation_get("service_username", unit, rid),
850- relation_get("service_password", unit, rid),
851- relation_get("service_tenant_name", unit, rid))
852- for rid in relation_ids("identity-admin")
853- for unit in related_units(rid) ][0]
854+ user, password, tenant = [(relation_get("service_username", unit, rid),
855+ relation_get("service_password", unit, rid),
856+ relation_get("service_tenant_name",
857+ unit, rid))
858+ for rid in relation_ids("identity-admin")
859+ for unit in related_units(rid)][0]
860 log("Unprovisioning vrouter {}".format(ip))
861 try:
862 contrail_provision_vrouter(hostname, ip, api_ip, api_port, "del",
863@@ -431,6 +478,7 @@
864 except CalledProcessError:
865 pass
866
867+
868 def vhost_gateway():
869 # determine vhost gateway
870 gateway = config.get("vhost-gateway")
871@@ -442,6 +490,7 @@
872 gateway = None
873 return gateway
874
875+
876 def vhost_ip(iface):
877 # return a vhost formatted address and mask - x.x.x.x/xx
878 addr = netifaces.ifaddresses(iface)[netifaces.AF_INET][0]
879@@ -449,14 +498,17 @@
880 cidr = netaddr.IPNetwork(ip + "/" + addr["netmask"]).prefixlen
881 return ip + "/" + str(cidr)
882
883+
884 def vhost_phys():
885 # run external script to determine physical interface of vhost0
886 return check_output(["scripts/vhost-phys.sh"]).rstrip()
887
888+
889 def vrouter_ctx():
890- return { "vhost_ip": vhost_ip("vhost0"),
891- "vhost_gateway": vhost_gateway(),
892- "vhost_physical": vhost_phys() }
893+ return {"vhost_ip": vhost_ip("vhost0"),
894+ "vhost_gateway": vhost_gateway(),
895+ "vhost_physical": vhost_phys()}
896+
897
898 def vrouter_vgw_ctx():
899 ctx = {}
900@@ -467,23 +519,27 @@
901 ctx["vgws"] = vgws
902 return ctx
903
904+
905 def write_barbican_auth_config():
906 ctx = identity_admin_ctx()
907 render("contrail-lbaas-auth.conf",
908 "/etc/contrail/contrail-lbaas-auth.conf", ctx, "root", "contrail",
909- 0440)
910+ 0o440)
911+
912
913 def write_nodemgr_config():
914 ctx = contrail_discovery_ctx()
915 render("contrail-vrouter-nodemgr.conf",
916 "/etc/contrail/contrail-vrouter-nodemgr.conf", ctx)
917
918+
919 def write_vnc_api_config():
920 ctx = {}
921 ctx.update(contrail_api_ctx())
922 ctx.update(identity_admin_ctx())
923 render("vnc_api_lib.ini", "/etc/contrail/vnc_api_lib.ini", ctx)
924
925+
926 def write_vrouter_config():
927 ctx = {}
928 ctx.update(control_node_ctx())
929@@ -492,9 +548,58 @@
930 ctx.update(network_ctx())
931 ctx.update(vrouter_ctx())
932 ctx.update(vrouter_vgw_ctx())
933+
934+ # a tls-certificates guard here is for the upgrade scenario
935+ tls_implemented = version_compare(CONTRAIL_VERSION, "3.0") >= 0 and\
936+ config.get("tls-certificates-ready")
937+ ctx.update({'tls_implemented': tls_implemented})
938 render("contrail-vrouter-agent.conf",
939- "/etc/contrail/contrail-vrouter-agent.conf", ctx, perms=0440)
940+ "/etc/contrail/contrail-vrouter-agent.conf", ctx, perms=0o440)
941+
942
943 def write_vrouter_vgw_interfaces():
944 ctx = vrouter_vgw_ctx()
945 render("vrouter-vgw.cfg", "/etc/network/interfaces.d/vrouter-vgw.cfg", ctx)
946+
947+
948+def control_network_ip():
949+ '''
950+ With Juju 2.x, uses an endpoint (relation)
951+ network space binding if unspecified will use a "unit private address"
952+ which is far less explicit if you look at the Juju implementation.
953+ If you use Juju 2.x and above - bind the control-node endpoint to a network
954+ space to get a proper address in this function.
955+
956+ If network-get throws an exception (juju 1.x or spaces are not supported)
957+ will try to fall back to a private-address as returned by Juju.
958+ '''
959+ try:
960+ address = network_get_primary_address('control-node')
961+ except NotImplementedError:
962+ log('Network spaces are not implemented - falling back to'
963+ ' getting a private address')
964+ address = unit_private_ip()
965+ return address
966+
967+
968+def write_xmpp_tls_files(serv_cert, priv_key, ca):
969+ prefix = '/etc/contrail/ssl'
970+ certs = os.path.join(prefix, 'certs')
971+ private = os.path.join(prefix, 'private')
972+
973+ entry = pwd.getpwnam('contrail')
974+ for p in [prefix, certs, private]:
975+ if not os.path.exists(p):
976+ os.makedirs(p, 0o750)
977+ os.chown(p, entry.pw_uid, entry.pw_gid)
978+
979+ fcontent = {
980+ os.path.join(certs, 'server.pem'): serv_cert,
981+ os.path.join(private, 'server-privkey.pem'): priv_key,
982+ os.path.join(certs, 'ca-cert.pem'): ca,
983+ }
984+
985+ for filepath, content in fcontent.iteritems():
986+ with open(filepath, 'w+') as f:
987+ f.truncate(0)
988+ f.write(content)
989
990=== added symlink 'hooks/tls-certificates-relation-changed'
991=== target is u'neutron_contrail_hooks.py'
992=== added symlink 'hooks/tls-certificates-relation-departed'
993=== target is u'neutron_contrail_hooks.py'
994=== added symlink 'hooks/tls-certificates-relation-joined'
995=== target is u'neutron_contrail_hooks.py'
996=== modified file 'metadata.yaml'
997--- metadata.yaml 2015-10-13 11:03:57 +0000
998+++ metadata.yaml 2017-03-26 17:44:17 +0000
999@@ -37,3 +37,5 @@
1000 interface: keystone-admin
1001 neutron-metadata:
1002 interface: neutron-metadata
1003+ tls-certificates:
1004+ interface: tls-certificates
1005
1006=== modified file 'templates/contrail-vrouter-agent.conf'
1007--- templates/contrail-vrouter-agent.conf 2016-02-05 00:31:01 +0000
1008+++ templates/contrail-vrouter-agent.conf 2017-03-26 17:44:17 +0000
1009@@ -3,6 +3,15 @@
1010 # Configuration file maintained by Juju. Local changes may be overwritten.
1011 ###############################################################################
1012
1013+
1014+{% if tls_implemented -%}
1015+[DEFAULT]
1016+xmpp_auth_enable=true
1017+xmpp_server_cert=/etc/contrail/ssl/certs/server.pem
1018+xmpp_server_key=/etc/contrail/ssl/private/server-privkey.pem
1019+xmpp_ca_cert=/etc/contrail/ssl/certs/ca-cert.pem
1020+{% endif -%}
1021+
1022 {%- if control_nodes %}
1023
1024 [CONTROL-NODE]

Subscribers

People subscribed via source and target branches