Merge lp:~plumgrid-team/charms/trusty/plumgrid-gateway/trunk into lp:charms/trusty/plumgrid-gateway

Proposed by Bilal Baqar
Status: Superseded
Proposed branch: lp:~plumgrid-team/charms/trusty/plumgrid-gateway/trunk
Merge into: lp:charms/trusty/plumgrid-gateway
Diff against target: 1122 lines (+571/-168) (has conflicts)
16 files modified
Makefile (+1/-1)
README.md (+2/-2)
config.yaml (+38/-4)
hooks/charmhelpers/contrib/openstack/neutron.py (+2/-2)
hooks/pg_gw_context.py (+41/-28)
hooks/pg_gw_hooks.py (+55/-28)
hooks/pg_gw_utils.py (+252/-44)
templates/kilo/00-pg.conf (+2/-0)
templates/kilo/hosts (+1/-1)
templates/kilo/ifcs.conf (+5/-4)
templates/kilo/plumgrid.conf (+1/-1)
tests/files/plumgrid-gateway-dense.yaml (+133/-0)
tests/tests.yaml (+3/-0)
unit_tests/test_pg_gw_context.py (+24/-23)
unit_tests/test_pg_gw_hooks.py (+8/-29)
unit_tests/test_pg_gw_utils.py (+3/-1)
Conflict adding file tests/files/plumgrid-gateway-dense.yaml.  Moved existing file to tests/files/plumgrid-gateway-dense.yaml.moved.
Conflict adding file tests/tests.yaml.  Moved existing file to tests/tests.yaml.moved.
To merge this branch: bzr merge lp:~plumgrid-team/charms/trusty/plumgrid-gateway/trunk
Reviewer Review Type Date Requested Status
Review Queue (community) automated testing Needs Fixing
charmers Pending
Review via email: mp+282844@code.launchpad.net

This proposal has been superseded by a proposal from 2016-05-18.

Description of the change

Needs sync

To post a comment you must log in.
Revision history for this message
Review Queue (review-queue) wrote :

This item has failed automated testing! Results available here http://juju-ci.vapour.ws:8080/job/charm-bundle-test-lxc/2222/

review: Needs Fixing (automated testing)
Revision history for this message
Review Queue (review-queue) wrote :

This item has failed automated testing! Results available here http://juju-ci.vapour.ws:8080/job/charm-bundle-test-aws/2201/

review: Needs Fixing (automated testing)
21. By Bilal Baqar

Fixing lint

Revision history for this message
Bilal Baqar (bbaqar) wrote :

tests/files/plumgrid-edge-dense.yaml and tests/tests.yaml in both branches are identical. Dont know the reason for the conflict. Please resolve it before merging.

22. By Bilal Baqar

Made the following changes:
1. Reordered file and module imports
2. Sorted director IPs
3. Added unit fqdn in /etc/hosts of plumgrid-lxc
4. Loading plumgrid specific iptables on install
5. Added temporary upgrade hook to load iptables
6. stop_pg() is being used in restart_pg()
7. persistant iptables

23. By Bilal Baqar

Improved config-changed hook to perform steps according to the config changed

24. By Bilal Baqar

OPSVM Changes - Ticket: [SOL-830]
- Getting OPSVM IP from director relation
- Making OPSVM specific changes
- Cleaned code in various functions
- Added restart_on_change decorater function that restarts plumgrid service only when there has been any change in the configuration files
- Removed restart of plumgrid service when only two directors are available
- Fixed unit tests accordingly

25. By Bilal Baqar

restart_on_stop Ticket: [SOL-950]
- Added restart_on_stop decorator function which starts plumgrid service is it has been stopped in the function
- Added restart_on_change to config-changed hook so that any config changes result in plugrid restart
- ifc_list_gateway only removed when change in ifcs.conf

26. By Bilal Baqar

Adding status messages in charms - Ticket:[SOL-949]

27. By Bilal Baqar

Merge: Liberty/Mitaka support

28. By Bilal Baqar

Merge - Charmhelpers sync and improved pg-restart

29. By Bilal Baqar

5.1 changes
- configure-pg-sources added
- updated templates

30. By Junaid Ali

L3 fabric changes

31. By Junaid Ali

Changes:
    - Default value for management interface removed as
      'juju-br0' has been changed to 'br-eth0' in Juju 2.0
    - Updated get_mgmt_interface method

Unmerged revisions

31. By Junaid Ali

Changes:
    - Default value for management interface removed as
      'juju-br0' has been changed to 'br-eth0' in Juju 2.0
    - Updated get_mgmt_interface method

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Makefile'
2--- Makefile 2015-08-24 16:24:20 +0000
3+++ Makefile 2016-04-08 08:36:52 +0000
4@@ -7,7 +7,7 @@
5 netaddr jinja2
6
7 lint: virtualenv
8- .venv/bin/flake8 --exclude hooks/charmhelpers hooks unit_tests tests
9+ .venv/bin/flake8 --exclude hooks/charmhelpers hooks unit_tests tests --ignore E402
10 @charm proof
11
12 unit_test: virtualenv
13
14=== modified file 'README.md'
15--- README.md 2015-09-01 18:08:51 +0000
16+++ README.md 2016-04-08 08:36:52 +0000
17@@ -36,7 +36,7 @@
18 Example Config
19
20 plumgrid-gateway:
21- external-interface: eth1
22+ external-interfaces: '{"node01":"eth5,eth2","node02":"eth4,eth8"}'
23 install_sources: 'ppa:plumgrid-team/stable'
24 install_keys: 'null'
25 plumgrid-edge:
26@@ -54,7 +54,7 @@
27 neutron-plugin: "plumgrid"
28 plumgrid-virtual-ip: "192.168.100.250"
29
30-The "external-interface" config parameter should be the interface that will provide external connectivity.
31+The "external-interfaces" config parameter should be the interfaces that will provide external connectivity on each of the gateway nodes. Should be provided as a json in a string with hostname and interface names.
32 Provide the source repo path for PLUMgrid Debs in 'install_sources' and the corresponding keys in 'install_keys'.
33 The virtual IP passed on in the neutron-api charm has to be same as the one passed in the plumgrid-director charm.
34
35
36=== modified file 'config.yaml'
37--- config.yaml 2015-07-29 18:23:55 +0000
38+++ config.yaml 2016-04-08 08:36:52 +0000
39@@ -1,16 +1,40 @@
40 options:
41- external-interface:
42- default: eth1
43+ external-interfaces:
44+ default: '{"hostname":"eth1,eth2"}'
45 type: string
46- description: The interface that will provide external connectivity
47+ description: |
48+ One or multiple interfaces that will provide external connectivity on
49+ each of the gateway nodes. Provided in form of json in a string.
50 lcm-ssh-key:
51 default: 'null'
52 type: string
53 description: Public SSH key of PLUMgrid LCM which is running PG-Tools
54+ mgmt-interface:
55+ type: string
56+ default: 'juju-br0'
57+ description: The interface connected to PLUMgrid Managment network.
58+ os-data-network:
59+ type: string
60+ default:
61+ description: |
62+ The IP address and netmask of the OpenStack Data network (e.g.,
63+ 192.168.0.0/24)
64+ .
65+ This network will be used for tenant network traffic in overlay
66+ networks.
67+ fabric-interfaces:
68+ default: 'MANAGEMENT'
69+ type: string
70+ description: |
71+ Interfaces that will provide fabric connectivity on the gateway nodes.
72+ Provided in form of json in a string. These interfaces have to be connected
73+ to the os-data-network specified in the config. Default value is MANAGEMENT which
74+ will configure the management interface as the fabric interface on each
75+ director.
76 network-device-mtu:
77 type: string
78 default: '1580'
79- description: The MTU size for interfaces managed by director.
80+ description: The MTU size for interfaces managed by gateway.
81 install_sources:
82 default: 'ppa:plumgrid-team/stable'
83 type: string
84@@ -19,3 +43,13 @@
85 default: null
86 type: string
87 description: Provide the respective keys of the install sources
88+ plumgrid-build:
89+ default: 'latest'
90+ type: string
91+ description: |
92+ Provide the build version of PLUMgrid packages that needs to be installed
93+ iovisor-build:
94+ default: 'latest'
95+ type: string
96+ description: |
97+ Provide the build version of iovisor package that needs to be installed
98
99=== modified file 'hooks/charmhelpers/contrib/openstack/neutron.py'
100--- hooks/charmhelpers/contrib/openstack/neutron.py 2015-07-29 18:23:55 +0000
101+++ hooks/charmhelpers/contrib/openstack/neutron.py 2016-04-08 08:36:52 +0000
102@@ -204,8 +204,8 @@
103 database=config('database'),
104 ssl_dir=NEUTRON_CONF_DIR)],
105 'services': [],
106- 'packages': [['plumgrid-lxc'],
107- ['iovisor-dkms']],
108+ 'packages': ['plumgrid-lxc',
109+ 'iovisor-dkms'],
110 'server_packages': ['neutron-server',
111 'neutron-plugin-plumgrid'],
112 'server_services': ['neutron-server']
113
114=== modified file 'hooks/pg_gw_context.py'
115--- hooks/pg_gw_context.py 2015-08-24 16:24:20 +0000
116+++ hooks/pg_gw_context.py 2016-04-08 08:36:52 +0000
117@@ -3,27 +3,36 @@
118 # This file contains the class that generates context for
119 # PLUMgrid template files.
120
121+from charmhelpers.contrib.openstack import context
122+from charmhelpers.contrib.openstack.utils import get_host_ip
123 from charmhelpers.core.hookenv import (
124 relation_ids,
125 related_units,
126 relation_get,
127- config,
128-)
129-from charmhelpers.contrib.openstack import context
130-
131-from socket import gethostname as get_unit_hostname
132-
133-
134-def _pg_dir_settings():
135+)
136+from socket import (
137+ gethostname,
138+ getfqdn
139+)
140+
141+
142+def _pg_dir_context():
143 '''
144 Inspects relation with PLUMgrid director.
145 '''
146- director_ips = []
147+ ctxt = {
148+ 'opsvm_ip': '127.0.0.1',
149+ 'director_ips': [],
150+ }
151 for rid in relation_ids('plumgrid'):
152 for unit in related_units(rid):
153 rdata = relation_get(rid=rid, unit=unit)
154- director_ips.append(str(rdata['private-address']))
155- return director_ips
156+ ctxt['director_ips'
157+ ].append(str(get_host_ip(rdata['private-address'])))
158+ if "opsvm_ip" in rdata:
159+ ctxt['opsvm_ip'] = \
160+ rdata['opsvm_ip']
161+ return ctxt
162
163
164 class PGGwContext(context.NeutronContext):
165@@ -60,25 +69,29 @@
166 if not pg_ctxt:
167 return {}
168
169- conf = config()
170- pg_dir_ips = ''
171- pg_dir_settings = _pg_dir_settings()
172- single_ip = True
173- for ip in pg_dir_settings:
174- if single_ip:
175- pg_dir_ips = str(ip)
176- single_ip = False
177- else:
178- pg_dir_ips = pg_dir_ips + ',' + str(ip)
179- pg_ctxt['local_ip'] = pg_dir_ips
180- unit_hostname = get_unit_hostname()
181+ pg_dir_context = _pg_dir_context()
182+ pg_dir_ips = sorted(pg_dir_context['director_ips'])
183+ dir_count = len(pg_dir_ips)
184+ pg_ctxt['director_ips_string'] = (str(pg_dir_ips[0]) + ',' +
185+ str(pg_dir_ips[1]) + ',' +
186+ str(pg_dir_ips[2])
187+ if dir_count == 3 else
188+ str(pg_dir_ips[0])
189+ if dir_count == 1 else
190+ '')
191+ unit_hostname = gethostname()
192 pg_ctxt['pg_hostname'] = unit_hostname
193- from pg_gw_utils import check_interface_type
194- interface_type = check_interface_type()
195- pg_ctxt['interface'] = interface_type
196+ pg_ctxt['pg_fqdn'] = getfqdn()
197+ from pg_gw_utils import (
198+ get_mgmt_interface,
199+ get_gw_interfaces,
200+ get_fabric_interface
201+ )
202+ pg_ctxt['interface'] = get_mgmt_interface()
203+ pg_ctxt['fabric_interface'] = get_fabric_interface()
204 pg_ctxt['label'] = unit_hostname
205 pg_ctxt['fabric_mode'] = 'host'
206-
207- pg_ctxt['ext_interface'] = conf['external-interface']
208+ pg_ctxt['ext_interfaces'] = get_gw_interfaces()
209+ pg_ctxt['opsvm_ip'] = pg_dir_context['opsvm_ip']
210
211 return pg_ctxt
212
213=== modified file 'hooks/pg_gw_hooks.py'
214--- hooks/pg_gw_hooks.py 2015-08-16 19:08:38 +0000
215+++ hooks/pg_gw_hooks.py 2016-04-08 08:36:52 +0000
216@@ -6,29 +6,35 @@
217 # in this file.
218
219 import sys
220-
221+from charmhelpers.core.host import service_running
222 from charmhelpers.core.hookenv import (
223 Hooks,
224 UnregisteredHookError,
225 log,
226+ config,
227+ status_set
228 )
229
230 from charmhelpers.fetch import (
231 apt_install,
232- apt_purge,
233 configure_sources,
234 )
235
236 from pg_gw_utils import (
237 register_configs,
238 ensure_files,
239- restart_pg,
240+ restart_map,
241 stop_pg,
242 determine_packages,
243 load_iovisor,
244 remove_iovisor,
245 ensure_mtu,
246 add_lcm_key,
247+ fabric_interface_changed,
248+ load_iptables,
249+ restart_on_change,
250+ restart_on_stop,
251+ director_cluster_ready
252 )
253
254 hooks = Hooks()
255@@ -40,7 +46,10 @@
256 '''
257 Install hook is run when the charm is first deployed on a node.
258 '''
259+ status_set('maintenance', 'Executing pre-install')
260+ load_iptables()
261 configure_sources(update=True)
262+ status_set('maintenance', 'Installing apt packages')
263 pkgs = determine_packages()
264 for pkg in pkgs:
265 apt_install(pkg, options=['--force-yes'], fatal=True)
266@@ -50,40 +59,54 @@
267 add_lcm_key()
268
269
270-@hooks.hook('plumgrid-relation-joined')
271 @hooks.hook('plumgrid-relation-changed')
272-def plumgrid_joined():
273+@restart_on_change(restart_map())
274+def plumgrid_changed():
275 '''
276 This hook is run when relation between plumgrid-gateway and
277 plumgrid-director is made.
278 '''
279- ensure_mtu()
280- ensure_files()
281- add_lcm_key()
282- CONFIGS.write_all()
283- restart_pg()
284+ if director_cluster_ready():
285+ ensure_mtu()
286+ CONFIGS.write_all()
287
288
289 @hooks.hook('config-changed')
290+@restart_on_stop()
291+@restart_on_change(restart_map())
292 def config_changed():
293 '''
294 This hook is run when a config parameter is changed.
295 It also runs on node reboot.
296 '''
297- if add_lcm_key():
298- log("PLUMgrid LCM Key added")
299- return 1
300- stop_pg()
301- configure_sources(update=True)
302- pkgs = determine_packages()
303- for pkg in pkgs:
304- apt_install(pkg, options=['--force-yes'], fatal=True)
305- load_iovisor()
306- ensure_mtu()
307- ensure_files()
308- add_lcm_key()
309- CONFIGS.write_all()
310- restart_pg()
311+ charm_config = config()
312+ if charm_config.changed('lcm-ssh-key'):
313+ if add_lcm_key():
314+ log("PLUMgrid LCM Key added")
315+ if charm_config.changed('fabric-interfaces'):
316+ if not fabric_interface_changed():
317+ log("Fabric interface already set")
318+ if (charm_config.changed('install_sources') or
319+ charm_config.changed('plumgrid-build') or
320+ charm_config.changed('install_keys') or
321+ charm_config.changed('iovisor-build')):
322+ stop_pg()
323+ status_set('maintenance', 'Upgrading apt packages')
324+ configure_sources(update=True)
325+ pkgs = determine_packages()
326+ for pkg in pkgs:
327+ apt_install(pkg, options=['--force-yes'], fatal=True)
328+ remove_iovisor()
329+ load_iovisor()
330+ ensure_mtu()
331+ CONFIGS.write_all()
332+
333+
334+@hooks.hook('upgrade-charm')
335+@restart_on_change(restart_map())
336+def upgrade_charm():
337+ ensure_mtu()
338+ CONFIGS.write_all()
339
340
341 @hooks.hook('stop')
342@@ -92,10 +115,14 @@
343 This hook is run when the charm is destroyed.
344 '''
345 stop_pg()
346- remove_iovisor()
347- pkgs = determine_packages()
348- for pkg in pkgs:
349- apt_purge(pkg, fatal=False)
350+
351+
352+@hooks.hook('update-status')
353+def update_status():
354+ if service_running('plumgrid'):
355+ status_set('active', 'Unit is ready')
356+ else:
357+ status_set('blocked', 'plumgrid service not running')
358
359
360 def main():
361
362=== modified file 'hooks/pg_gw_utils.py'
363--- hooks/pg_gw_utils.py 2015-08-24 16:24:20 +0000
364+++ hooks/pg_gw_utils.py 2016-04-08 08:36:52 +0000
365@@ -2,40 +2,56 @@
366
367 # This file contains functions used by the hooks to deploy PLUMgrid Gateway.
368
369+import pg_gw_context
370+import subprocess
371+import time
372+import os
373+import json
374+from collections import OrderedDict
375+from socket import gethostname as get_unit_hostname
376+from copy import deepcopy
377 from charmhelpers.contrib.openstack.neutron import neutron_plugin_attribute
378-from copy import deepcopy
379+from charmhelpers.contrib.storage.linux.ceph import modprobe
380+from charmhelpers.contrib.openstack import templating
381 from charmhelpers.core.hookenv import (
382 log,
383 config,
384+ unit_get,
385+ status_set
386+)
387+from charmhelpers.contrib.network.ip import (
388+ get_iface_from_addr,
389+ get_bridges,
390+ get_bridge_nics,
391+ is_address_in_network,
392+ get_iface_addr
393 )
394 from charmhelpers.core.host import (
395 write_file,
396 service_start,
397 service_stop,
398-)
399-from charmhelpers.contrib.storage.linux.ceph import modprobe
400-from charmhelpers.core.host import set_nic_mtu
401-from charmhelpers.contrib.openstack import templating
402-from collections import OrderedDict
403+ service_running,
404+ path_hash,
405+ set_nic_mtu
406+)
407+from charmhelpers.fetch import (
408+ apt_cache,
409+ apt_install
410+)
411 from charmhelpers.contrib.openstack.utils import (
412 os_release,
413 )
414-import pg_gw_context
415-import subprocess
416-import time
417-import os
418-import re
419
420 LXC_CONF = "/etc/libvirt/lxc.conf"
421 TEMPLATES = 'templates/'
422 PG_LXC_DATA_PATH = '/var/lib/libvirt/filesystems/plumgrid-data'
423-
424 PG_CONF = '%s/conf/pg/plumgrid.conf' % PG_LXC_DATA_PATH
425 PG_HN_CONF = '%s/conf/etc/hostname' % PG_LXC_DATA_PATH
426 PG_HS_CONF = '%s/conf/etc/hosts' % PG_LXC_DATA_PATH
427 PG_IFCS_CONF = '%s/conf/pg/ifcs.conf' % PG_LXC_DATA_PATH
428+OPS_CONF = '%s/conf/etc/00-pg.conf' % PG_LXC_DATA_PATH
429 AUTH_KEY_PATH = '%s/root/.ssh/authorized_keys' % PG_LXC_DATA_PATH
430-
431+IFC_LIST_GW = '/var/run/plumgrid/lxc/ifc_list_gateway'
432 SUDOERS_CONF = '/etc/sudoers.d/ifc_ctl_sudoers'
433
434 BASE_RESOURCE_MAP = OrderedDict([
435@@ -51,6 +67,10 @@
436 'services': ['plumgrid'],
437 'contexts': [pg_gw_context.PGGwContext()],
438 }),
439+ (OPS_CONF, {
440+ 'services': ['plumgrid'],
441+ 'contexts': [pg_gw_context.PGGwContext()],
442+ }),
443 (PG_IFCS_CONF, {
444 'services': [],
445 'contexts': [pg_gw_context.PGGwContext()],
446@@ -63,7 +83,25 @@
447 Returns list of packages required by PLUMgrid Gateway as specified
448 in the neutron_plugins dictionary in charmhelpers.
449 '''
450- return neutron_plugin_attribute('plumgrid', 'packages', 'neutron')
451+ pkgs = []
452+ tag = 'latest'
453+ for pkg in neutron_plugin_attribute('plumgrid', 'packages', 'neutron'):
454+ if 'plumgrid' in pkg:
455+ tag = config('plumgrid-build')
456+ elif pkg == 'iovisor-dkms':
457+ tag = config('iovisor-build')
458+
459+ if tag == 'latest':
460+ pkgs.append(pkg)
461+ else:
462+ if tag in [i.ver_str for i in apt_cache()[pkg].version_list]:
463+ pkgs.append('%s=%s' % (pkg, tag))
464+ else:
465+ error_msg = \
466+ "Build version '%s' for package '%s' not available" \
467+ % (tag, pkg)
468+ raise ValueError(error_msg)
469+ return pkgs
470
471
472 def register_configs(release=None):
473@@ -103,17 +141,27 @@
474 write_file(SUDOERS_CONF,
475 "\nnova ALL=(root) NOPASSWD: /opt/pg/bin/ifc_ctl_pp *\n",
476 owner='root', group='root', perms=0o644)
477+ _exec_cmd(cmd=['rm', '-f', IFC_LIST_GW])
478
479
480 def restart_pg():
481 '''
482 Stops and Starts PLUMgrid service after flushing iptables.
483 '''
484- service_stop('plumgrid')
485- time.sleep(2)
486- _exec_cmd(cmd=['iptables', '-F'])
487+ stop_pg()
488 service_start('plumgrid')
489- time.sleep(5)
490+ time.sleep(3)
491+ if not service_running('plumgrid'):
492+ if service_running('libvirt-bin'):
493+ raise ValueError("plumgrid service couldn't be started")
494+ else:
495+ if service_start('libvirt-bin'):
496+ time.sleep(3)
497+ if not service_running('plumgrid'):
498+ raise ValueError("plumgrid service couldn't be started")
499+ else:
500+ raise ValueError("libvirt-bin service couldn't be started")
501+ status_set('active', 'Unit is ready')
502
503
504 def stop_pg():
505@@ -136,39 +184,118 @@
506 Removes iovisor kernel module.
507 '''
508 _exec_cmd(cmd=['rmmod', 'iovisor'],
509- error_msg='Error Loading Iovisor Kernel Module')
510-
511-
512-def check_interface_type():
513- '''
514- Checks the interface. Support added for AWS deployments. There are 2
515- possible interfaces "juju-br0" and "eth0". The default being juju-br0
516- '''
517- log("Checking Interface Type")
518- default_interface = "juju-br0"
519- AWS_interface = "eth0"
520- shell_output = subprocess.check_output(['brctl', 'show', 'juju-br0'])
521- output = re.split(' |\n|\t', shell_output)
522- if output[10] == '':
523- return AWS_interface
524- else:
525- return default_interface
526+ error_msg='Error Removing IOVisor Kernel Module')
527+ time.sleep(1)
528+
529+
530+def interface_exists(interface):
531+ '''
532+ Checks if interface exists on node.
533+ '''
534+ try:
535+ subprocess.check_call(['ip', 'link', 'show', interface],
536+ stdout=open(os.devnull, 'w'),
537+ stderr=subprocess.STDOUT)
538+ except subprocess.CalledProcessError:
539+ return False
540+ return True
541+
542+
543+def get_mgmt_interface():
544+ '''
545+ Returns the managment interface.
546+ '''
547+ mgmt_interface = config('mgmt-interface')
548+ if interface_exists(mgmt_interface):
549+ return mgmt_interface
550+ else:
551+ log('Provided managment interface %s does not exist'
552+ % mgmt_interface)
553+ return get_iface_from_addr(unit_get('private-address'))
554+
555+
556+def fabric_interface_changed():
557+ '''
558+ Returns true if interface for node changed.
559+ '''
560+ fabric_interface = get_fabric_interface()
561+ try:
562+ with open(PG_IFCS_CONF, 'r') as ifcs:
563+ for line in ifcs:
564+ if 'fabric_core' in line:
565+ if line.split()[0] == fabric_interface:
566+ return False
567+ except IOError:
568+ return True
569+ return True
570+
571+
572+def get_fabric_interface():
573+ '''
574+ Returns the fabric interface.
575+ '''
576+ fabric_interfaces = config('fabric-interfaces')
577+ if fabric_interfaces == 'MANAGEMENT':
578+ return get_mgmt_interface()
579+ else:
580+ try:
581+ all_fabric_interfaces = json.loads(fabric_interfaces)
582+ except ValueError:
583+ raise ValueError('Invalid json provided for fabric interfaces')
584+ hostname = get_unit_hostname()
585+ if hostname in all_fabric_interfaces:
586+ node_fabric_interface = all_fabric_interfaces[hostname]
587+ elif 'DEFAULT' in all_fabric_interfaces:
588+ node_fabric_interface = all_fabric_interfaces['DEFAULT']
589+ else:
590+ raise ValueError('No fabric interface provided for node')
591+ if interface_exists(node_fabric_interface):
592+ if is_address_in_network(config('os-data-network'),
593+ get_iface_addr(node_fabric_interface)[0]):
594+ return node_fabric_interface
595+ else:
596+ raise ValueError('Fabric interface not in fabric network')
597+ else:
598+ log('Provided fabric interface %s does not exist'
599+ % node_fabric_interface)
600+ raise ValueError('Provided fabric interface does not exist')
601+ return node_fabric_interface
602+
603+
604+def get_gw_interfaces():
605+ '''
606+ Gateway node can have multiple interfaces. This function parses json
607+ provided in config to get all gateway interfaces for this node.
608+ '''
609+ node_interfaces = []
610+ try:
611+ all_interfaces = json.loads(config('external-interfaces'))
612+ except ValueError:
613+ raise ValueError("Invalid json provided for gateway interfaces")
614+ hostname = get_unit_hostname()
615+ if hostname in all_interfaces:
616+ node_interfaces = all_interfaces[hostname].split(',')
617+ elif 'DEFAULT' in all_interfaces:
618+ node_interfaces = all_interfaces['DEFAULT'].split(',')
619+ for interface in node_interfaces:
620+ if not interface_exists(interface):
621+ log('Provided gateway interface %s does not exist'
622+ % interface)
623+ raise ValueError('Provided gateway interface does not exist')
624+ return node_interfaces
625
626
627 def ensure_mtu():
628 '''
629 Ensures required MTU of the underlying networking of the node.
630 '''
631- log("Changing MTU of juju-br0 and all attached interfaces")
632 interface_mtu = config('network-device-mtu')
633- interface_type = check_interface_type()
634- if interface_type == "juju-br0":
635- cmd = subprocess.check_output(["brctl", "show", interface_type])
636- words = cmd.split()
637- for word in words:
638- if 'eth' in word:
639- set_nic_mtu(word, interface_mtu)
640- set_nic_mtu(interface_type, interface_mtu)
641+ fabric_interface = get_fabric_interface()
642+ if fabric_interface in get_bridges():
643+ attached_interfaces = get_bridge_nics(fabric_interface)
644+ for interface in attached_interfaces:
645+ set_nic_mtu(interface, interface_mtu)
646+ set_nic_mtu(fabric_interface, interface_mtu)
647
648
649 def _exec_cmd(cmd=None, error_msg='Command exited with ERRORs', fatal=False):
650@@ -216,3 +343,84 @@
651 fa.write('\n')
652 fa.close()
653 return 1
654+
655+
656+def load_iptables():
657+ '''
658+ Loads iptables rules to allow all PLUMgrid communication.
659+ '''
660+ network = get_cidr_from_iface(get_mgmt_interface())
661+ if network:
662+ _exec_cmd(['sudo', 'iptables', '-A', 'INPUT', '-p', 'tcp',
663+ '-j', 'ACCEPT', '-s', network, '-d',
664+ network, '-m', 'state', '--state', 'NEW'])
665+ _exec_cmd(['sudo', 'iptables', '-A', 'INPUT', '-p', 'udp', '-j',
666+ 'ACCEPT', '-s', network, '-d', network,
667+ '-m', 'state', '--state', 'NEW'])
668+ apt_install('iptables-persistent')
669+
670+
671+def get_cidr_from_iface(interface):
672+ '''
673+ Determines Network CIDR from interface.
674+ '''
675+ if not interface:
676+ return None
677+ apt_install('ohai')
678+ try:
679+ os_info = subprocess.check_output(['ohai', '-l', 'fatal'])
680+ except OSError:
681+ log('Unable to get operating system information')
682+ return None
683+ try:
684+ os_info_json = json.loads(os_info)
685+ except ValueError:
686+ log('Unable to determine network')
687+ return None
688+ device = os_info_json['network']['interfaces'].get(interface)
689+ if device is not None:
690+ if device.get('routes'):
691+ routes = device['routes']
692+ for net in routes:
693+ if 'scope' in net:
694+ return net.get('destination')
695+ else:
696+ return None
697+ else:
698+ return None
699+
700+
701+def director_cluster_ready():
702+ dirs_count = len(pg_gw_context._pg_dir_context()['director_ips'])
703+ return True if dirs_count == 1 or dirs_count == 3 else False
704+
705+
706+def restart_on_stop():
707+ """
708+ Starts plumgrid service if it is stopped
709+ """
710+ def wrap(f):
711+ def wrapped_f(*args, **kwargs):
712+ f(*args, **kwargs)
713+ if not service_running('plumgrid'):
714+ restart_pg()
715+ return wrapped_f
716+ return wrap
717+
718+
719+def restart_on_change(restart_map):
720+ """
721+ Restart services based on configuration files changing
722+ """
723+ def wrap(f):
724+ def wrapped_f(*args, **kwargs):
725+ checksums = {path: path_hash(path) for path in restart_map}
726+ f(*args, **kwargs)
727+ for path in restart_map:
728+ if path_hash(path) != checksums[path]:
729+ if path == PG_IFCS_CONF:
730+ ensure_files()
731+ restart_pg()
732+ break
733+ return wrapped_f
734+ return wrap
735
736=== removed symlink 'hooks/plumgrid-relation-joined'
737=== target was u'pg_gw_hooks.py'
738=== added symlink 'hooks/update-status'
739=== target is u'pg_gw_hooks.py'
740=== added symlink 'hooks/upgrade-charm'
741=== target is u'pg_gw_hooks.py'
742=== added file 'templates/kilo/00-pg.conf'
743--- templates/kilo/00-pg.conf 1970-01-01 00:00:00 +0000
744+++ templates/kilo/00-pg.conf 2016-04-08 08:36:52 +0000
745@@ -0,0 +1,2 @@
746+$template ls_json,"{{'{'}}{{'%'}}timestamp:::date-rfc3339,jsonf:@timestamp%,%source:::jsonf:@source_host%,%msg:::json%}"
747+:syslogtag,isequal,"pg:" @{{ opsvm_ip }}:6000;ls_json
748
749=== modified file 'templates/kilo/hosts'
750--- templates/kilo/hosts 2015-07-29 18:23:55 +0000
751+++ templates/kilo/hosts 2016-04-08 08:36:52 +0000
752@@ -1,5 +1,5 @@
753 127.0.0.1 localhost
754-127.0.1.1 {{ pg_hostname }}
755+127.0.1.1 {{ pg_fqdn }} {{ pg_hostname }}
756
757 # The following lines are desirable for IPv6 capable hosts
758 ::1 ip6-localhost ip6-loopback
759
760=== modified file 'templates/kilo/ifcs.conf'
761--- templates/kilo/ifcs.conf 2015-07-29 18:23:55 +0000
762+++ templates/kilo/ifcs.conf 2016-04-08 08:36:52 +0000
763@@ -1,6 +1,7 @@
764-{{ interface }} = fabric_core host
765-{% if ext_interface -%}
766-{{ ext_interface }} = access_phys
767-
768+{{ fabric_interface }} = fabric_core host
769+{% if ext_interfaces -%}
770+{% for ip in ext_interfaces -%}
771+{{ ip }} = access_phys
772+{% endfor -%}
773 {% endif -%}
774
775
776=== modified file 'templates/kilo/plumgrid.conf'
777--- templates/kilo/plumgrid.conf 2015-07-29 18:23:55 +0000
778+++ templates/kilo/plumgrid.conf 2016-04-08 08:36:52 +0000
779@@ -1,4 +1,4 @@
780-plumgrid_ip={{ local_ip }}
781+plumgrid_ip={{ director_ips_string }}
782 plumgrid_port=8001
783 mgmt_dev={{ interface }}
784 label={{ label}}
785
786=== added file 'tests/files/plumgrid-gateway-dense.yaml'
787--- tests/files/plumgrid-gateway-dense.yaml 1970-01-01 00:00:00 +0000
788+++ tests/files/plumgrid-gateway-dense.yaml 2016-04-08 08:36:52 +0000
789@@ -0,0 +1,133 @@
790+test:
791+ series: 'trusty'
792+ relations:
793+ - - mysql
794+ - keystone
795+ - - nova-cloud-controller
796+ - mysql
797+ - - nova-cloud-controller
798+ - rabbitmq-server
799+ - - nova-cloud-controller
800+ - glance
801+ - - nova-cloud-controller
802+ - keystone
803+ - - nova-compute
804+ - nova-cloud-controller
805+ - - nova-compute
806+ - mysql
807+ - - nova-compute
808+ - rabbitmq-server
809+ - - nova-compute
810+ - glance
811+ - - glance
812+ - mysql
813+ - - glance
814+ - keystone
815+ - - glance
816+ - cinder
817+ - - mysql
818+ - cinder
819+ - - cinder
820+ - rabbitmq-server
821+ - - cinder
822+ - nova-cloud-controller
823+ - - cinder
824+ - keystone
825+ - - openstack-dashboard
826+ - keystone
827+ - - neutron-api
828+ - mysql
829+ - - neutron-api
830+ - keystone
831+ - - neutron-api
832+ - rabbitmq-server
833+ - - neutron-api
834+ - nova-cloud-controller
835+ - - neutron-api
836+ - neutron-api-plumgrid
837+ - - neutron-api-plumgrid
838+ - plumgrid-edge
839+ - - plumgrid-director
840+ - plumgrid-edge
841+ - - nova-compute
842+ - plumgrid-edge
843+ - - plumgrid-director
844+ - plumgrid-gateway
845+ services:
846+ mysql:
847+ charm: cs:trusty/mysql
848+ num_units: 1
849+ to: 'lxc:plumgrid-director=0'
850+ rabbitmq-server:
851+ charm: cs:trusty/rabbitmq-server
852+ num_units: 1
853+ to: 'lxc:plumgrid-director=0'
854+ keystone:
855+ charm: cs:trusty/keystone
856+ num_units: 1
857+ options:
858+ admin-password: plumgrid
859+ openstack-origin: cloud:trusty-kilo
860+ to: 'lxc:plumgrid-director=0'
861+ nova-cloud-controller:
862+ charm: cs:trusty/nova-cloud-controller
863+ num_units: 1
864+ options:
865+ console-access-protocol: novnc
866+ network-manager: Neutron
867+ openstack-origin: cloud:trusty-kilo
868+ quantum-security-groups: 'yes'
869+ to: 'lxc:plumgrid-director=0'
870+ glance:
871+ charm: cs:trusty/glance
872+ num_units: 1
873+ options:
874+ openstack-origin: cloud:trusty-kilo
875+ to: 'lxc:plumgrid-director=0'
876+ openstack-dashboard:
877+ charm: cs:trusty/openstack-dashboard
878+ num_units: 1
879+ options:
880+ openstack-origin: cloud:trusty-kilo
881+ to: 'lxc:plumgrid-director=0'
882+ cinder:
883+ charm: cs:trusty/cinder
884+ num_units: 1
885+ options:
886+ openstack-origin: cloud:trusty-kilo
887+ to: 'lxc:plumgrid-director=0'
888+ neutron-api:
889+ charm: cs:~plumgrid-team/trusty/neutron-api
890+ num_units: 1
891+ options:
892+ neutron-plugin: plumgrid
893+ neutron-security-groups: false
894+ openstack-origin: cloud:trusty-kilo
895+ plumgrid-password: plumgrid
896+ plumgrid-username: plumgrid
897+ plumgrid-virtual-ip: 192.168.100.250
898+ to: 'lxc:plumgrid-director=0'
899+ neutron-api-plumgrid:
900+ charm: cs:~plumgrid-team/trusty/neutron-api-plumgrid
901+ options:
902+ enable-metadata: True
903+ plumgrid-director:
904+ charm: cs:~plumgrid-team/trusty/plumgrid-director
905+ num_units: 1
906+ constraints: "mem=8G root-disk=30G cpu-cores=8"
907+ options:
908+ plumgrid-virtual-ip: 192.168.100.250
909+ nova-compute:
910+ charm: cs:~plumgrid-team/trusty/nova-compute
911+ num_units: 1
912+ options:
913+ enable-live-migration: true
914+ enable-resize: true
915+ migration-auth-type: ssh
916+ openstack-origin: cloud:trusty-kilo
917+ to: '0'
918+ plumgrid-edge:
919+ charm: cs:~plumgrid-team/trusty/plumgrid-edge
920+ plumgrid-gateway:
921+ charm: cs:~plumgrid-team/trusty/plumgrid-gateway
922+ num_units: 1
923
924=== renamed file 'tests/files/plumgrid-gateway-dense.yaml' => 'tests/files/plumgrid-gateway-dense.yaml.moved'
925=== added file 'tests/tests.yaml'
926--- tests/tests.yaml 1970-01-01 00:00:00 +0000
927+++ tests/tests.yaml 2016-04-08 08:36:52 +0000
928@@ -0,0 +1,3 @@
929+makefile:
930+ - lint
931+
932
933=== renamed file 'tests/tests.yaml' => 'tests/tests.yaml.moved'
934=== modified file 'unit_tests/test_pg_gw_context.py'
935--- unit_tests/test_pg_gw_context.py 2015-08-24 16:24:20 +0000
936+++ unit_tests/test_pg_gw_context.py 2016-04-08 08:36:52 +0000
937@@ -5,8 +5,8 @@
938 import charmhelpers
939
940 TO_PATCH = [
941- 'config',
942- 'get_unit_hostname',
943+ 'gethostname',
944+ 'getfqdn'
945 ]
946
947
948@@ -22,8 +22,6 @@
949
950 def setUp(self):
951 super(PGGwContextTest, self).setUp(context, TO_PATCH)
952- self.config.side_effect = self.test_config.get
953- self.test_config.set('external-interface', 'eth1')
954
955 def tearDown(self):
956 super(PGGwContextTest, self).tearDown()
957@@ -37,11 +35,14 @@
958 @patch.object(charmhelpers.contrib.openstack.context,
959 'config_flags_parser')
960 @patch.object(context.PGGwContext, '_save_flag_file')
961- @patch.object(context, '_pg_dir_settings')
962+ @patch.object(context, '_pg_dir_context')
963 @patch.object(charmhelpers.contrib.openstack.context,
964 'neutron_plugin_attribute')
965- @patch.object(utils, 'check_interface_type')
966- def test_neutroncc_context_api_rel(self, _int_type, _npa, _pg_dir_settings,
967+ @patch.object(utils, 'get_mgmt_interface')
968+ @patch.object(utils, 'get_fabric_interface')
969+ @patch.object(utils, 'get_gw_interfaces')
970+ def test_neutroncc_context_api_rel(self, _gw_int, _fabric_int,
971+ _mgmt_int, _npa, _pg_dir_context,
972 _save_flag_file, _config_flag,
973 _unit_get, _unit_priv_ip, _config,
974 _is_clus, _https, _ens_pkgs):
975@@ -50,38 +51,38 @@
976 return "neutron.randomdriver"
977 if section == "config":
978 return "neutron.randomconfig"
979- config = {'external-interface': "eth1"}
980-
981- def mock_config(key=None):
982- if key:
983- return config.get(key)
984-
985- return config
986
987 self.maxDiff = None
988- self.config.side_effect = mock_config
989 _npa.side_effect = mock_npa
990- _unit_get.return_value = '192.168.100.201'
991- _unit_priv_ip.return_value = '192.168.100.201'
992- self.get_unit_hostname.return_value = 'node0'
993+ _unit_get.return_value = '192.168.100.203'
994+ _unit_priv_ip.return_value = '192.168.100.203'
995+ self.gethostname.return_value = 'node0'
996+ self.getfqdn.return_value = 'node0'
997 _is_clus.return_value = False
998 _config_flag.return_value = False
999- _pg_dir_settings.return_value = {'pg_dir_ip': '192.168.100.201'}
1000- _int_type.return_value = 'juju-br0'
1001+ _pg_dir_context.return_value = {'director_ips': ['192.168.100.201'],
1002+ 'opsvm_ip': '127.0.0.1'}
1003+ _mgmt_int.return_value = 'juju-br0'
1004+ _fabric_int.return_value = 'juju-br0'
1005+ _gw_int.return_value = ['eth1']
1006 napi_ctxt = context.PGGwContext()
1007 expect = {
1008- 'ext_interface': "eth1",
1009+ 'ext_interfaces': ['eth1'],
1010 'config': 'neutron.randomconfig',
1011 'core_plugin': 'neutron.randomdriver',
1012- 'local_ip': 'pg_dir_ip',
1013+ 'local_ip': '192.168.100.203',
1014+ 'director_ips_string': '192.168.100.201',
1015 'network_manager': 'neutron',
1016 'neutron_plugin': 'plumgrid',
1017 'neutron_security_groups': None,
1018- 'neutron_url': 'https://192.168.100.201:9696',
1019+ 'neutron_url': 'https://192.168.100.203:9696',
1020 'pg_hostname': 'node0',
1021+ 'pg_fqdn': 'node0',
1022 'interface': 'juju-br0',
1023+ 'fabric_interface': 'juju-br0',
1024 'label': 'node0',
1025 'fabric_mode': 'host',
1026 'neutron_alchemy_flags': False,
1027+ 'opsvm_ip': '127.0.0.1',
1028 }
1029 self.assertEquals(expect, napi_ctxt())
1030
1031=== modified file 'unit_tests/test_pg_gw_hooks.py'
1032--- unit_tests/test_pg_gw_hooks.py 2015-08-24 16:24:20 +0000
1033+++ unit_tests/test_pg_gw_hooks.py 2016-04-08 08:36:52 +0000
1034@@ -1,5 +1,6 @@
1035 from mock import MagicMock, patch, call
1036 from test_utils import CharmTestCase
1037+
1038 with patch('charmhelpers.core.hookenv.config') as config:
1039 config.return_value = 'neutron'
1040 import pg_gw_utils as utils
1041@@ -18,17 +19,17 @@
1042 TO_PATCH = [
1043 'remove_iovisor',
1044 'apt_install',
1045- 'apt_purge',
1046 'CONFIGS',
1047 'log',
1048 'configure_sources',
1049 'ensure_files',
1050 'stop_pg',
1051- 'restart_pg',
1052 'load_iovisor',
1053 'ensure_mtu',
1054 'add_lcm_key',
1055 'determine_packages',
1056+ 'load_iptables',
1057+ 'director_cluster_ready'
1058 ]
1059 NEUTRON_CONF_DIR = "/etc/neutron"
1060
1061@@ -60,34 +61,12 @@
1062 self.ensure_files.assert_called_with()
1063 self.add_lcm_key.assert_called_with()
1064
1065- def test_plumgrid_joined(self):
1066- self._call_hook('plumgrid-relation-joined')
1067- self.ensure_mtu.assert_called_with()
1068- self.ensure_files.assert_called_with()
1069- self.add_lcm_key.assert_called_with()
1070- self.CONFIGS.write_all.assert_called_with()
1071- self.restart_pg.assert_called_with()
1072-
1073- def test_config_changed_hook(self):
1074- _pkgs = ['plumgrid-lxc', 'iovisor-dkms']
1075- self.add_lcm_key.return_value = 0
1076- self.determine_packages.return_value = [_pkgs]
1077- self._call_hook('config-changed')
1078- self.stop_pg.assert_called_with()
1079- self.configure_sources.assert_called_with(update=True)
1080- self.apt_install.assert_has_calls([
1081- call(_pkgs, fatal=True,
1082- options=['--force-yes']),
1083- ])
1084- self.load_iovisor.assert_called_with()
1085- self.ensure_mtu.assert_called_with()
1086- self.ensure_files.assert_called_with()
1087- self.CONFIGS.write_all.assert_called_with()
1088- self.restart_pg.assert_called_with()
1089+ def test_plumgrid_changed(self):
1090+ self._call_hook('plumgrid-relation-changed')
1091+ self.director_cluster_ready.return_value = True
1092+ self.ensure_mtu.assert_called_with()
1093+ self.CONFIGS.write_all.assert_called_with()
1094
1095 def test_stop(self):
1096- _pkgs = ['plumgrid-lxc', 'iovisor-dkms']
1097 self._call_hook('stop')
1098 self.stop_pg.assert_called_with()
1099- self.remove_iovisor.assert_called_with()
1100- self.determine_packages.return_value = _pkgs
1101
1102=== modified file 'unit_tests/test_pg_gw_utils.py'
1103--- unit_tests/test_pg_gw_utils.py 2015-08-24 16:24:20 +0000
1104+++ unit_tests/test_pg_gw_utils.py 2016-04-08 08:36:52 +0000
1105@@ -53,7 +53,8 @@
1106 confs = [nutils.PG_CONF,
1107 nutils.PG_HN_CONF,
1108 nutils.PG_HS_CONF,
1109- nutils.PG_IFCS_CONF]
1110+ nutils.PG_IFCS_CONF,
1111+ nutils.OPS_CONF]
1112 self.assertItemsEqual(_regconfs.configs, confs)
1113
1114 def test_resource_map(self):
1115@@ -69,6 +70,7 @@
1116 (nutils.PG_CONF, ['plumgrid']),
1117 (nutils.PG_HN_CONF, ['plumgrid']),
1118 (nutils.PG_HS_CONF, ['plumgrid']),
1119+ (nutils.OPS_CONF, ['plumgrid']),
1120 (nutils.PG_IFCS_CONF, []),
1121 ])
1122 self.assertEqual(expect, _restart_map)

Subscribers

People subscribed via source and target branches