Merge lp:~tilmanbaumann/charms/trusty/contrail-control/trunk into lp:~sdn-charmers/charms/trusty/contrail-control/trunk

Proposed by Tilman Baumann
Status: Needs review
Proposed branch: lp:~tilmanbaumann/charms/trusty/contrail-control/trunk
Merge into: lp:~sdn-charmers/charms/trusty/contrail-control/trunk
Diff against target: 688 lines (+264/-75)
5 files modified
config.yaml (+6/-0)
hooks/contrail_control_hooks.py (+85/-13)
hooks/contrail_control_utils.py (+161/-61)
metadata.yaml (+2/-0)
templates/control-node.conf (+10/-1)
To merge this branch: bzr merge lp:~tilmanbaumann/charms/trusty/contrail-control/trunk
Reviewer Review Type Date Requested Status
Tilman Baumann (community) Approve
Robert Ayres Pending
Review via email: mp+340110@code.launchpad.net

Description of the change

Previously xmpp-auth was only set to true when tls certificates are set.

There is, however, no strong link between the two settings.

This change allows setting this independently as required.

It would undoubtedly be nicer to have this option only in contrail-contrail and read it via context relation from there. This is rather quick and dirty and a bit redundant.
But it is what I built so far...

To post a comment you must log in.
Revision history for this message
Tilman Baumann (tilmanbaumann) wrote :

Please merge

review: Approve

Unmerged revisions

33. By Tilman Baumann

Adding xmpp_auth option

Sparating xmpp_auth_enable from tls settings
Making it switchable via xmpp_auth config option

32. 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.

XMPP clients are vrouter agents on compute nodes. XMPP servers are
contrail-control nodes.

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.

Using a Subject Alternative Name (SAN) with an IP address avoids a
dependency on a DNS infrastructure while keeping the communication
secure between endpoints that are related.

Client authentication by XMPP servers was not supported at the time of
writing hence there is no mention of that in the code.

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).

31. By Dmitrii Shcherbakov

hooks: pep8 refactoring

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'config.yaml'
--- config.yaml 2017-03-10 12:54:47 +0000
+++ config.yaml 2018-02-28 14:49:00 +0000
@@ -14,6 +14,12 @@
14 The IP address and netmask of the control network (e.g. 192.168.0.0/24).14 The IP address and netmask of the control network (e.g. 192.168.0.0/24).
15 This network will be used for Contrail endpoints.15 This network will be used for Contrail endpoints.
16 If not specified, default network will be used.16 If not specified, default network will be used.
17 As of Juju 2.x, use network spaces instead and bind the control-node endpoint
18 to your desired network space instead.
17 ssl-ca:19 ssl-ca:
18 type: string20 type: string
19 description: PEM encoded X.509 CA certificate for use in SSL.21 description: PEM encoded X.509 CA certificate for use in SSL.
22 xmpp_auth:
23 type: boolean
24 default: False
25 description: Use authentication for XMPP vrouter communication
2026
=== modified file 'hooks/contrail_control_hooks.py'
--- hooks/contrail_control_hooks.py 2017-03-10 12:54:47 +0000
+++ hooks/contrail_control_hooks.py 2018-02-28 14:49:00 +0000
@@ -12,7 +12,7 @@
12 log,12 log,
13 relation_get,13 relation_get,
14 relation_ids,14 relation_ids,
15 relation_set15 relation_set,
16)16)
1717
18from charmhelpers.core.host import (18from charmhelpers.core.host import (
@@ -39,46 +39,52 @@
39 write_control_config,39 write_control_config,
40 write_nodemgr_config,40 write_nodemgr_config,
41 write_ssl_ca_certificate,41 write_ssl_ca_certificate,
42 write_vnc_api_config42 write_vnc_api_config,
43 write_xmpp_tls_files,
43)44)
4445
45PACKAGES = [ "contrail-control", "contrail-utils", "contrail-nodemgr" ]46PACKAGES = ["contrail-control", "contrail-utils", "contrail-nodemgr"]
4647
47hooks = Hooks()48hooks = Hooks()
48config = config()49config = config()
4950
51
50def add_control():52def add_control():
51 # check relation dependencies53 # check relation dependencies
52 if not config_get("control-provisioned") \54 if not config_get("control-provisioned") \
53 and config_get("contrail-api-ready") \55 and config_get("contrail-api-ready") \
54 and config_get("contrail-discovery-ready") \56 and config_get("contrail-discovery-ready") \
55 and config_get("contrail-ifmap-ready") \57 and config_get("contrail-ifmap-ready") \
56 and config_get("identity-admin-ready"):58 and config_get("identity-admin-ready") \
59 and config_get("tls-certificates-ready"):
57 provision_control()60 provision_control()
58 config["control-provisioned"] = True61 config["control-provisioned"] = True
5962
63
60@hooks.hook("config-changed")64@hooks.hook("config-changed")
61def config_changed():65def config_changed():
62 write_config()66 write_config()
63 configure_ssl()67 configure_ssl()
64 if config.get("control-provisioned"):68 if config.get("control-provisioned"):
65 configure_control_network()69 configure_control_network()
6670 settings = {"private-address": control_network_ip()}
67 settings = { "private-address": control_network_ip() }
68 for rid in relation_ids("control-node"):71 for rid in relation_ids("control-node"):
69 relation_set(relation_id=rid, relation_settings=settings)72 relation_set(relation_id=rid, relation_settings=settings)
7073
74
71def config_get(key):75def config_get(key):
72 try:76 try:
73 return config[key]77 return config[key]
74 except KeyError:78 except KeyError:
75 return None79 return None
7680
81
77def configure_control_network():82def configure_control_network():
78 if control_network_ip() != config["provisioned-host-ip"]:83 if control_network_ip() != config["provisioned-host-ip"]:
79 unprovision_control()84 unprovision_control()
80 provision_control()85 provision_control()
8186
87
82def configure_ssl():88def configure_ssl():
83 cert = config.get("ssl-ca")89 cert = config.get("ssl-ca")
84 if cert:90 if cert:
@@ -86,6 +92,7 @@
86 else:92 else:
87 remove_ssl_ca_certificate()93 remove_ssl_ca_certificate()
8894
95
89@hooks.hook("contrail-api-relation-changed")96@hooks.hook("contrail-api-relation-changed")
90def contrail_api_changed():97def contrail_api_changed():
91 if not relation_get("port"):98 if not relation_get("port"):
@@ -95,6 +102,7 @@
95 config["contrail-api-ready"] = True102 config["contrail-api-ready"] = True
96 add_control()103 add_control()
97104
105
98@hooks.hook("contrail-api-relation-departed")106@hooks.hook("contrail-api-relation-departed")
99@hooks.hook("contrail-api-relation-broken")107@hooks.hook("contrail-api-relation-broken")
100def contrail_api_departed():108def contrail_api_departed():
@@ -103,6 +111,7 @@
103 config["contrail-api-ready"] = False111 config["contrail-api-ready"] = False
104 write_vnc_api_config()112 write_vnc_api_config()
105113
114
106@hooks.hook("contrail-discovery-relation-changed")115@hooks.hook("contrail-discovery-relation-changed")
107def contrail_discovery_changed():116def contrail_discovery_changed():
108 if not relation_get("port"):117 if not relation_get("port"):
@@ -112,6 +121,7 @@
112 config["contrail-discovery-ready"] = True121 config["contrail-discovery-ready"] = True
113 add_control()122 add_control()
114123
124
115@hooks.hook("contrail-discovery-relation-departed")125@hooks.hook("contrail-discovery-relation-departed")
116@hooks.hook("contrail-discovery-relation-broken")126@hooks.hook("contrail-discovery-relation-broken")
117def contrail_discovery_departed():127def contrail_discovery_departed():
@@ -120,13 +130,18 @@
120 config["contrail-discovery-ready"] = False130 config["contrail-discovery-ready"] = False
121 contrail_discovery_relation()131 contrail_discovery_relation()
122132
123@restart_on_change({"/etc/contrail/contrail-control.conf": ["contrail-control"],133
124 "/etc/contrail/control-node.conf": ["contrail-control"],134@restart_on_change(
125 "/etc/contrail/contrail-control-nodemgr.conf": ["contrail-control-nodemgr"]})135 {
136 "/etc/contrail/contrail-control.conf": ["contrail-control"],
137 "/etc/contrail/control-node.conf": ["contrail-control"],
138 "/etc/contrail/contrail-control-nodemgr.conf":
139 ["contrail-control-nodemgr"]})
126def contrail_discovery_relation():140def contrail_discovery_relation():
127 write_control_config()141 write_control_config()
128 write_nodemgr_config()142 write_nodemgr_config()
129143
144
130@hooks.hook("contrail-ifmap-relation-changed")145@hooks.hook("contrail-ifmap-relation-changed")
131def contrail_ifmap_changed():146def contrail_ifmap_changed():
132 creds = relation_get("creds")147 creds = relation_get("creds")
@@ -138,6 +153,7 @@
138 config["contrail-ifmap-ready"] = True153 config["contrail-ifmap-ready"] = True
139 add_control()154 add_control()
140155
156
141@hooks.hook("contrail-ifmap-relation-departed")157@hooks.hook("contrail-ifmap-relation-departed")
142@hooks.hook("contrail-ifmap-relation-broken")158@hooks.hook("contrail-ifmap-relation-broken")
143def contrail_ifmap_departed():159def contrail_ifmap_departed():
@@ -146,16 +162,21 @@
146 config["contrail-ifmap-ready"] = False162 config["contrail-ifmap-ready"] = False
147 contrail_ifmap_relation()163 contrail_ifmap_relation()
148164
149@restart_on_change({"/etc/contrail/contrail-control.conf": ["contrail-control"],165
150 "/etc/contrail/control-node.conf": ["contrail-control"]})166@restart_on_change(
167 {
168 "/etc/contrail/contrail-control.conf": ["contrail-control"],
169 "/etc/contrail/control-node.conf": ["contrail-control"]})
151def contrail_ifmap_relation():170def contrail_ifmap_relation():
152 write_control_config()171 write_control_config()
153172
173
154@hooks.hook("control-node-relation-joined")174@hooks.hook("control-node-relation-joined")
155def control_node_joined():175def control_node_joined():
156 settings = { "private-address": control_network_ip() }176 settings = {"private-address": control_network_ip()}
157 relation_set(relation_settings=settings)177 relation_set(relation_settings=settings)
158178
179
159@hooks.hook("identity-admin-relation-changed")180@hooks.hook("identity-admin-relation-changed")
160def identity_admin_changed():181def identity_admin_changed():
161 if not relation_get("service_hostname"):182 if not relation_get("service_hostname"):
@@ -165,6 +186,7 @@
165 config["identity-admin-ready"] = True186 config["identity-admin-ready"] = True
166 add_control()187 add_control()
167188
189
168@hooks.hook("identity-admin-relation-departed")190@hooks.hook("identity-admin-relation-departed")
169@hooks.hook("identity-admin-relation-broken")191@hooks.hook("identity-admin-relation-broken")
170def identity_admin_departed():192def identity_admin_departed():
@@ -173,6 +195,50 @@
173 config["identity-admin-ready"] = False195 config["identity-admin-ready"] = False
174 write_vnc_api_config()196 write_vnc_api_config()
175197
198
199@hooks.hook('tls-certificates-relation-joined')
200def tls_certificates_relation_joined():
201 # a hostname could also be provided as a SAN
202 # (Subject Alternative Name) but having this one
203 # has certain implications
204 # https://tools.ietf.org/html/rfc2818#section-3.1
205 # "If a subjectAltName extension of type dNSName
206 # is present, that MUST be used as the identity"
207 # Therefore it is not used here as we don't need
208 # a DNS infrastructure dependency
209 ip_san = control_network_ip()
210 settings = {
211 'sans': json.dumps([ip_san, '127.0.0.1']),
212 'common_name': ip_san,
213 'certificate_name': local_unit().replace('/', '_')
214 }
215 relation_set(relation_settings=settings)
216
217
218@hooks.hook('tls-certificates-relation-changed')
219def tls_certificates_relation_changed():
220 # check that the -provides side have set the data we need
221 # and render the affected files
222 unitname = local_unit().replace('/', '_')
223 cert = '{0}.server.cert'.format(unitname)
224 key = '{0}.server.key'.format(unitname)
225 certv = relation_get(cert)
226 keyv = relation_get(key)
227 ca = relation_get('ca')
228
229 if certv and keyv and ca:
230 write_xmpp_tls_files(certv, keyv, ca)
231 config["tls-certificates-ready"] = True
232 else:
233 log('tls-certificates relation data is not fully available')
234 config["tls-certificates-ready"] = False
235
236
237@hooks.hook('tls-certificates-relation-departed')
238def tls_certificates_relation_departed():
239 config["tls-certificates-ready"] = False
240
241
176@hooks.hook()242@hooks.hook()
177def install():243def install():
178 configure_sources(True, "install-sources", "install-keys")244 configure_sources(True, "install-sources", "install-keys")
@@ -182,26 +248,32 @@
182 fix_permissions()248 fix_permissions()
183 fix_nodemgr()249 fix_nodemgr()
184250
251
185def main():252def main():
186 try:253 try:
187 hooks.execute(sys.argv)254 hooks.execute(sys.argv)
188 except UnregisteredHookError as e:255 except UnregisteredHookError as e:
189 log("Unknown hook {} - skipping.".format(e))256 log("Unknown hook {} - skipping.".format(e))
190257
258
191def remove_control():259def remove_control():
192 if config_get("control-provisioned"):260 if config_get("control-provisioned"):
193 unprovision_control()261 unprovision_control()
194 config["control-provisioned"] = False262 config["control-provisioned"] = False
195263
264
196@hooks.hook("upgrade-charm")265@hooks.hook("upgrade-charm")
197def upgrade_charm():266def upgrade_charm():
198 write_control_config()267 write_control_config()
199 write_nodemgr_config()268 write_nodemgr_config()
200 service_restart("supervisor-control")269 service_restart("supervisor-control")
201270
202@restart_on_change({"/etc/contrail/contrail-control.conf": ["contrail-control"]})271
272@restart_on_change(
273 {"/etc/contrail/contrail-control.conf": ["contrail-control"]})
203def write_config():274def write_config():
204 write_control_config()275 write_control_config()
205276
277
206if __name__ == "__main__":278if __name__ == "__main__":
207 main()279 main()
208280
=== modified file 'hooks/contrail_control_utils.py'
--- hooks/contrail_control_utils.py 2017-03-10 12:54:47 +0000
+++ hooks/contrail_control_utils.py 2018-02-28 14:49:00 +0000
@@ -21,26 +21,32 @@
21 log,21 log,
22 related_units,22 related_units,
23 relation_get,23 relation_get,
24 relation_set,
24 relation_ids,25 relation_ids,
25 relation_type,26 relation_type,
26 remote_unit,27 remote_unit,
27 unit_get28 unit_private_ip,
29 network_get_primary_address,
28)30)
29from charmhelpers.core.host import service_restart31from charmhelpers.core.host import service_restart
30from charmhelpers.core.templating import render32from charmhelpers.core.templating import render
3133
32apt_pkg.init()34apt_pkg.init()
3335
36
34def dpkg_version(pkg):37def dpkg_version(pkg):
35 try:38 try:
36 return check_output(["dpkg-query", "-f", "${Version}\\n", "-W", pkg]).rstrip()39 return check_output(
40 ["dpkg-query", "-f", "${Version}\\n", "-W", pkg]).rstrip()
37 except CalledProcessError:41 except CalledProcessError:
38 return None42 return None
3943
44
40CONTRAIL_VERSION = dpkg_version("contrail-control")45CONTRAIL_VERSION = dpkg_version("contrail-control")
4146
42config = config()47config = config()
4348
49
44def retry(f=None, timeout=10, delay=2):50def retry(f=None, timeout=10, delay=2):
45 """Retry decorator.51 """Retry decorator.
4652
@@ -64,6 +70,7 @@
64 """70 """
65 if not f:71 if not f:
66 return functools.partial(retry, timeout=timeout, delay=delay)72 return functools.partial(retry, timeout=timeout, delay=delay)
73
67 @functools.wraps(f)74 @functools.wraps(f)
68 def func(*args, **kwargs):75 def func(*args, **kwargs):
69 start = time()76 start = time()
@@ -84,29 +91,36 @@
84 raise error91 raise error
85 return func92 return func
8693
94
87def contrail_api_ctx():95def contrail_api_ctx():
88 ctxs = [ { "api_server": gethostbyname(relation_get("private-address", unit, rid)),96 ctxs = [{"api_server": gethostbyname(relation_get("private-address",
89 "api_port": port }97 unit, rid)),
90 for rid in relation_ids("contrail-api")98 "api_port": port}
91 for unit, port in99 for rid in relation_ids("contrail-api")
92 ((unit, relation_get("port", unit, rid)) for unit in related_units(rid))100 for unit, port in
93 if port ]101 ((unit, relation_get("port", unit, rid))
102 for unit in related_units(rid))
103 if port]
94 return ctxs[0] if ctxs else {}104 return ctxs[0] if ctxs else {}
95105
106
96def contrail_ctx():107def contrail_ctx():
97 return { "host_ip": control_network_ip() }108 return {"host_ip": control_network_ip()}
109
98110
99def contrail_discovery_ctx():111def contrail_discovery_ctx():
100 ctxs = [ { "discovery_server": vip if vip \112 ctxs = [{"discovery_server": vip if vip
101 else gethostbyname(relation_get("private-address", unit, rid)),113 else gethostbyname(relation_get("private-address", unit, rid)),
102 "discovery_port": port }114 "discovery_port": port}
103 for rid in relation_ids("contrail-discovery")115 for rid in relation_ids("contrail-discovery")
104 for unit, port, vip in116 for unit, port, vip in
105 ((unit, relation_get("port", unit, rid), relation_get("vip", unit, rid))117 ((unit, relation_get("port", unit, rid),
106 for unit in related_units(rid))118 relation_get("vip", unit, rid))
107 if port ]119 for unit in related_units(rid))
120 if port]
108 return ctxs[0] if ctxs else {}121 return ctxs[0] if ctxs else {}
109122
123
110def contrail_ifmap_ctx():124def contrail_ifmap_ctx():
111 ctxs = []125 ctxs = []
112 unit = local_unit()126 unit = local_unit()
@@ -123,6 +137,7 @@
123 ctxs.append(ctx)137 ctxs.append(ctx)
124 return ctxs[0] if ctxs else {}138 return ctxs[0] if ctxs else {}
125139
140
126@retry(timeout=300)141@retry(timeout=300)
127def contrail_provision_control(hostname, ip, router_asn, api_ip, api_port, op,142def contrail_provision_control(hostname, ip, router_asn, api_ip, api_port, op,
128 user, password, tenant):143 user, password, tenant):
@@ -137,19 +152,42 @@
137 "--admin_password", password,152 "--admin_password", password,
138 "--admin_tenant_name", tenant])153 "--admin_tenant_name", tenant])
139154
155
140def control_network_ip():156def control_network_ip():
141 fallback = gethostbyname(unit_get("private-address"))157 '''
142 network = config.get("control-network")158 With Juju 2.x, uses an endpoint (relation)
143 if network:159 network space binding if unspecified will use a "unit private address"
144 return get_address_in_network(network, fallback)160 which is far less explicit if you look at the Juju implementation.
145 else:161 If you use Juju 2.x and above - bind the control-node endpoint to a network
146 return fallback162 space to get a proper address in this function.
163
164 If network-get throws an exception (juju 1.x or spaces are not supported)
165 will try to fall back to the control-network parameter or a private-address
166 as returned by Juju.
167 '''
168 try:
169 address = network_get_primary_address('control-node')
170 except NotImplementedError:
171 log('Network spaces are not implemented - falling back to'
172 ' getting a private address')
173 address = None
174
175 if not address:
176 fallback = gethostbyname(unit_private_ip())
177 network = config.get("control-network")
178 if network:
179 address = get_address_in_network(network, fallback)
180 else:
181 address = fallback
182
183 return address
184
147185
148def fix_nodemgr():186def fix_nodemgr():
149 # add files missing from contrail-nodemgr package187 # add files missing from contrail-nodemgr package
150 dest = "/etc/contrail/supervisord_control_files/" \188 dest = "/etc/contrail/supervisord_control_files/" \
151 + ("contrail-control-nodemgr.ini" \189 + ("contrail-control-nodemgr.ini"
152 if version_compare(CONTRAIL_VERSION, "3.1") >= 0 \190 if version_compare(CONTRAIL_VERSION, "3.1") >= 0
153 else "contrail-nodemgr-control.ini")191 else "contrail-nodemgr-control.ini")
154 shutil.copy("files/contrail-nodemgr-control.ini", dest)192 shutil.copy("files/contrail-nodemgr-control.ini", dest)
155 pw = pwd.getpwnam("contrail")193 pw = pwd.getpwnam("contrail")
@@ -159,7 +197,7 @@
159 if version_compare(CONTRAIL_VERSION, "3.1") >= 0 \197 if version_compare(CONTRAIL_VERSION, "3.1") >= 0 \
160 else "files/contrail-control-nodemgr"198 else "files/contrail-control-nodemgr"
161 shutil.copy(src, "/etc/init.d/contrail-control-nodemgr")199 shutil.copy(src, "/etc/init.d/contrail-control-nodemgr")
162 os.chmod("/etc/init.d/contrail-control-nodemgr", 0755)200 os.chmod("/etc/init.d/contrail-control-nodemgr", 0o755)
163201
164 # fake ntp status when inside a container202 # fake ntp status when inside a container
165 if is_container():203 if is_container():
@@ -167,20 +205,24 @@
167205
168 service_restart("supervisor-control")206 service_restart("supervisor-control")
169207
208
170def fix_permissions():209def fix_permissions():
171 os.chmod("/etc/contrail", 0755)210 os.chmod("/etc/contrail", 0o755)
172 os.chown("/etc/contrail", 0, 0)211 os.chown("/etc/contrail", 0, 0)
173212
213
174def identity_admin_ctx():214def identity_admin_ctx():
175 ctxs = [ { "auth_host": gethostbyname(hostname),215 ctxs = [{"auth_host": gethostbyname(hostname),
176 "auth_port": relation_get("service_port", unit, rid),216 "auth_port": relation_get("service_port", unit, rid),
177 "auth_protocol": relation_get("service_protocol", unit, rid) }217 "auth_protocol": relation_get("service_protocol", unit, rid)}
178 for rid in relation_ids("identity-admin")218 for rid in relation_ids("identity-admin")
179 for unit, hostname in219 for unit, hostname in
180 ((unit, relation_get("service_hostname", unit, rid)) for unit in related_units(rid))220 ((unit, relation_get("service_hostname", unit, rid))
181 if hostname ]221 for unit in related_units(rid))
222 if hostname]
182 return ctxs[0] if ctxs else {}223 return ctxs[0] if ctxs else {}
183224
225
184def is_container():226def is_container():
185 """Return boolean determining if inside container"""227 """Return boolean determining if inside container"""
186 try:228 try:
@@ -189,26 +231,36 @@
189 except CalledProcessError:231 except CalledProcessError:
190 return False232 return False
191233
234
192def provision_control():235def provision_control():
193 hostname = gethostname()236 hostname = gethostname()
194 ip = control_network_ip()237 ip = control_network_ip()
195 api_ip, api_port = [ (gethostbyname(relation_get("private-address", unit, rid)),238 api_ip, api_port = [(gethostbyname(relation_get("private-address",
196 port)239 unit, rid)), port)
197 for rid in relation_ids("contrail-api")240 for rid in relation_ids("contrail-api")
198 for unit, port in241 for unit, port in
199 ((unit, relation_get("port", unit, rid)) for unit in related_units(rid))242 ((unit, relation_get("port", unit, rid))
200 if port ][0]243 for unit in related_units(rid))
201 user, password, tenant = [ (relation_get("service_username", unit, rid),244 if port][0]
202 relation_get("service_password", unit, rid),245 user, password, tenant = [(relation_get("service_username", unit, rid),
203 relation_get("service_tenant_name", unit, rid))246 relation_get("service_password", unit, rid),
204 for rid in relation_ids("identity-admin")247 relation_get("service_tenant_name", unit, rid))
205 for unit in related_units(rid)248 for rid in relation_ids("identity-admin")
206 if relation_get("service_hostname", unit, rid) ][0]249 for unit in related_units(rid)
250 if relation_get("service_hostname",
251 unit, rid)][0]
207 log("Provisioning control {}".format(ip))252 log("Provisioning control {}".format(ip))
208 contrail_provision_control(hostname, ip, 64512, api_ip, api_port, "add",253 contrail_provision_control(hostname, ip, 64512, api_ip, api_port, "add",
209 user, password, tenant)254 user, password, tenant)
255
256 # support for network spaces
257 # see control_network_ip implementation
258 for rid in relation_ids("control-node"):
259 relation_set(rid, {'control_node_ip': ip})
260
210 config["provisioned-host-ip"] = ip261 config["provisioned-host-ip"] = ip
211262
263
212def remove_ssl_ca_certificate():264def remove_ssl_ca_certificate():
213 if os.path.exists("/usr/local/share/ca-certificates/contrail-juju.crt"):265 if os.path.exists("/usr/local/share/ca-certificates/contrail-juju.crt"):
214 os.remove("/usr/local/share/ca-certificates/contrail-juju.crt")266 os.remove("/usr/local/share/ca-certificates/contrail-juju.crt")
@@ -217,10 +269,12 @@
217 else:269 else:
218 return False270 return False
219271
272
220def units(relation):273def units(relation):
221 """Return a list of units for the specified relation"""274 """Return a list of units for the specified relation"""
222 return [ unit for rid in relation_ids(relation)275 return [unit for rid in relation_ids(relation)
223 for unit in related_units(rid) ]276 for unit in related_units(rid)]
277
224278
225def unprovision_control():279def unprovision_control():
226 relation = relation_type()280 relation = relation_type()
@@ -234,10 +288,11 @@
234 api_ip = gethostbyname(relation_get("private-address"))288 api_ip = gethostbyname(relation_get("private-address"))
235 api_port = relation_get("port")289 api_port = relation_get("port")
236 else:290 else:
237 api_ip, api_port = [ (gethostbyname(relation_get("private-address", unit, rid)),291 api_ip, api_port = [(gethostbyname(relation_get("private-address",
238 relation_get("port", unit, rid))292 unit, rid)),
239 for rid in relation_ids("contrail-api")293 relation_get("port", unit, rid))
240 for unit in related_units(rid) ][0]294 for rid in relation_ids("contrail-api")
295 for unit in related_units(rid)][0]
241 user = None296 user = None
242 password = None297 password = None
243 tenant = None298 tenant = None
@@ -246,37 +301,58 @@
246 password = relation_get("service_password")301 password = relation_get("service_password")
247 tenant = relation_get("service_tenant_name")302 tenant = relation_get("service_tenant_name")
248 else:303 else:
249 user, password, tenant = [ (relation_get("service_username", unit, rid),304 user, password, tenant = [(relation_get("service_username", unit, rid),
250 relation_get("service_password", unit, rid),305 relation_get("service_password", unit, rid),
251 relation_get("service_tenant_name", unit, rid))306 relation_get("service_tenant_name",
252 for rid in relation_ids("identity-admin")307 unit, rid))
253 for unit in related_units(rid) ][0]308 for rid in relation_ids("identity-admin")
309 for unit in related_units(rid)][0]
254 log("Unprovisioning control {}".format(ip))310 log("Unprovisioning control {}".format(ip))
255 try:311 try:
256 contrail_provision_control(hostname, ip, 64512, api_ip, api_port, "del",312 contrail_provision_control(
257 user, password, tenant)313 hostname,
314 ip,
315 64512,
316 api_ip,
317 api_port,
318 "del",
319 user,
320 password,
321 tenant)
258 except CalledProcessError:322 except CalledProcessError:
259 pass323 pass
260 del config["provisioned-host-ip"]324 del config["provisioned-host-ip"]
261325
326
262def write_control_config():327def write_control_config():
263 ctx = {}328 ctx = {}
264 ctx.update(contrail_ctx())329 ctx.update(contrail_ctx())
265 ctx.update(contrail_discovery_ctx())330 ctx.update(contrail_discovery_ctx())
266 ctx.update(contrail_ifmap_ctx())331 ctx.update(contrail_ifmap_ctx())
332
333 xmpp_auth_enable = config.get('xmpp_auth')
334 ctx.update({"xmpp_auth_enable": xmpp_auth_enable})
335
336 # a tls-certificates guard here is for the upgrade scenario
337 tls_implemented = version_compare(CONTRAIL_VERSION, "3.0") >= 0 and\
338 config.get("tls-certificates-ready")
339 ctx.update({'tls_implemented': tls_implemented})
267 target = "/etc/contrail/contrail-control.conf" \340 target = "/etc/contrail/contrail-control.conf" \
268 if version_compare(CONTRAIL_VERSION, "2.0") >= 0 \341 if version_compare(CONTRAIL_VERSION, "2.0") >= 0 \
269 else "/etc/contrail/control-node.conf"342 else "/etc/contrail/control-node.conf"
270 render("control-node.conf", target, ctx, "root", "contrail", 0440)343 render("control-node.conf", target, ctx, "root", "contrail", 0o440)
344
271345
272def write_nodemgr_config():346def write_nodemgr_config():
273 ctx = contrail_discovery_ctx()347 ctx = contrail_discovery_ctx()
274 render("contrail-control-nodemgr.conf",348 render("contrail-control-nodemgr.conf",
275 "/etc/contrail/contrail-control-nodemgr.conf", ctx)349 "/etc/contrail/contrail-control-nodemgr.conf", ctx)
276350
351
277def write_ssl_ca_certificate(cert):352def write_ssl_ca_certificate(cert):
278 if os.path.exists("/usr/local/share/ca-certificates/contrail-juju.crt"):353 if os.path.exists("/usr/local/share/ca-certificates/contrail-juju.crt"):
279 with open("/usr/local/share/ca-certificates/contrail-juju.crt", "r") as f:354 with open("/usr/local/share/ca-certificates/contrail-juju.crt", "r") \
355 as f:
280 c = f.read()356 c = f.read()
281 if c == cert:357 if c == cert:
282 return False358 return False
@@ -285,6 +361,30 @@
285 check_call(["update-ca-certificates"])361 check_call(["update-ca-certificates"])
286 return True362 return True
287363
364
365def write_xmpp_tls_files(serv_cert, priv_key, ca):
366 prefix = '/etc/contrail/ssl'
367 certs = os.path.join(prefix, 'certs')
368 private = os.path.join(prefix, 'private')
369
370 entry = pwd.getpwnam('contrail')
371 for p in [prefix, certs, private]:
372 if not os.path.exists(p):
373 os.makedirs(p, 0o750)
374 os.chown(p, entry.pw_uid, entry.pw_gid)
375
376 fcontent = {
377 os.path.join(certs, 'server.pem'): serv_cert,
378 os.path.join(private, 'server-privkey.pem'): priv_key,
379 os.path.join(certs, 'ca-cert.pem'): ca,
380 }
381
382 for filepath, content in fcontent.iteritems():
383 with open(filepath, 'w+') as f:
384 f.truncate(0)
385 f.write(content)
386
387
288def write_vnc_api_config():388def write_vnc_api_config():
289 ctx = {}389 ctx = {}
290 ctx.update(contrail_api_ctx())390 ctx.update(contrail_api_ctx())
291391
=== added symlink 'hooks/tls-certificates-relation-changed'
=== target is u'contrail_control_hooks.py'
=== added symlink 'hooks/tls-certificates-relation-departed'
=== target is u'contrail_control_hooks.py'
=== added symlink 'hooks/tls-certificates-relation-joined'
=== target is u'contrail_control_hooks.py'
=== modified file 'metadata.yaml'
--- metadata.yaml 2015-09-17 21:09:59 +0000
+++ metadata.yaml 2018-02-28 14:49:00 +0000
@@ -20,3 +20,5 @@
20 interface: contrail-ifmap20 interface: contrail-ifmap
21 identity-admin:21 identity-admin:
22 interface: keystone-admin22 interface: keystone-admin
23 tls-certificates:
24 interface: tls-certificates
2325
=== modified file 'templates/control-node.conf'
--- templates/control-node.conf 2015-10-01 12:29:04 +0000
+++ templates/control-node.conf 2018-02-28 14:49:00 +0000
@@ -6,6 +6,16 @@
6[DEFAULT]6[DEFAULT]
7hostip = {{ host_ip }}7hostip = {{ host_ip }}
88
9{% if xmpp_auth_enable -%}
10xmpp_auth_enable=true
11{% endif -%}
12
13{% if tls_implemented -%}
14xmpp_server_cert=/etc/contrail/ssl/certs/server.pem
15xmpp_server_key=/etc/contrail/ssl/private/server-privkey.pem
16xmpp_ca_cert=/etc/contrail/ssl/certs/ca-cert.pem
17{% endif -%}
18
9[DISCOVERY]19[DISCOVERY]
10server = {{ discovery_server }}20server = {{ discovery_server }}
11port = {{ discovery_port }}21port = {{ discovery_port }}
@@ -13,4 +23,3 @@
13[IFMAP]23[IFMAP]
14user = {{ ifmap_user }}24user = {{ ifmap_user }}
15password = {{ ifmap_password }}25password = {{ ifmap_password }}
16

Subscribers

People subscribed via source and target branches

to all changes: