Merge lp:~junaidali/charms/trusty/plumgrid-director/oil-sapi-changes into lp:charms/trusty/plumgrid-director

Proposed by Junaid Ali
Status: Needs review
Proposed branch: lp:~junaidali/charms/trusty/plumgrid-director/oil-sapi-changes
Merge into: lp:charms/trusty/plumgrid-director
Diff against target: 1050 lines (+649/-94)
12 files modified
Makefile (+2/-3)
README.md (+3/-2)
actions.yaml (+8/-2)
actions/actions.py (+36/-7)
bin/charm_helpers_sync.py (+253/-0)
config.yaml (+24/-0)
hooks/install (+20/-0)
hooks/pg_dir_context.py (+24/-0)
hooks/pg_dir_hooks.py (+37/-17)
hooks/pg_dir_utils.py (+235/-62)
metadata.yaml (+3/-0)
unit_tests/test_pg_dir_hooks.py (+4/-1)
To merge this branch: bzr merge lp:~junaidali/charms/trusty/plumgrid-director/oil-sapi-changes
Reviewer Review Type Date Requested Status
James Page Pending
Review via email: mp+308654@code.launchpad.net

Description of the change

Added charm series in metadata.yaml file
Updated README file
Added Solutions API support for PG-ONS 6.X.X
Added actions
Wrapper to deal with Ubuntu versions don't have py2 installed
Edge and gateway relations will also be used to get node's IPs
Catalyst OPSVM changes

To post a comment you must log in.

Unmerged revisions

22. By Junaid Ali

Changes:
  Added charm series in metadata.yaml file
  Updated README file
  Added Solutions API support for PG-ONS 6.X.X
  Added actions
  Wrapper to deal with Ubuntu versions don't have py2 installed
  Edge and gateway relations will also be used to get node's IPs
  Catalyst OPSVM changes

21. By Junaid Ali

Changes:
  Added charm series in metadata.yaml file
  Updated README file
  Added Solutions API support for PG-ONS 6.X.X
  Added actions
  Wrapper to deal with Ubuntu versions don't have py2 installed
  Edge and gateway relations will also be used to get node's IPs
  Catalyst OPSVM changes

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'Makefile'
--- Makefile 2016-05-25 16:30:35 +0000
+++ Makefile 2016-10-17 17:28:49 +0000
@@ -4,12 +4,11 @@
4virtualenv:4virtualenv:
5 virtualenv .venv5 virtualenv .venv
6 .venv/bin/pip install flake8 nose coverage mock pyyaml netifaces \6 .venv/bin/pip install flake8 nose coverage mock pyyaml netifaces \
7 netaddr jinja2 pyflakes pep8 six pbr funcsigs psutil charm-tools \7 netaddr jinja2 pyflakes pep8 six pbr funcsigs psutil
8 simplejson
98
10lint: virtualenv9lint: virtualenv
11 .venv/bin/flake8 --exclude hooks/charmhelpers hooks unit_tests tests --ignore E40210 .venv/bin/flake8 --exclude hooks/charmhelpers hooks unit_tests tests --ignore E402
12 @.venv/bin/charm-proof11 @charm proof
1312
14unit_test: virtualenv13unit_test: virtualenv
15 @echo Starting tests...14 @echo Starting tests...
1615
=== modified file 'README.md'
--- README.md 2016-03-03 20:56:40 +0000
+++ README.md 2016-10-17 17:28:49 +0000
@@ -26,7 +26,7 @@
2626
27# Known Limitations and Issues27# Known Limitations and Issues
2828
29This is an early access version of the PLUMgrid Director charm and it is not meant for production deployments. The charm only supports Kilo Openstack Release.29This charm currently is in an initial phase in supporting Ubuntu 16.04.
3030
31# Configuration31# Configuration
3232
@@ -58,4 +58,5 @@
58# Contact Information58# Contact Information
5959
60Bilal Baqar <bbaqar@plumgrid.com>60Bilal Baqar <bbaqar@plumgrid.com>
61Bilal Ahmad <bilal@plumgrid.com>61Javeria Khan <javeriak@plumgrid.com>
62Junaid Ali <junaidali@plumgrid.com>
6263
=== modified file 'actions.yaml'
--- actions.yaml 2016-07-27 09:39:41 +0000
+++ actions.yaml 2016-10-17 17:28:49 +0000
@@ -1,2 +1,8 @@
1restart:1restart-pg-service:
2 description: Restart the plumgrid-director unit. This action will restart related services.2 description: Restart the plumgrid-director unit's service.
3sapi-post-ips:
4 description: Post PLUMgrid nodes IPs to Solutions API server.
5sapi-post-zone-info:
6 description: Post PLUMgrid Zone info to Solutions API server.
7sapi-post-license:
8 description: Post PLUMgrid License to Solutions API server.
39
=== modified file 'actions/actions.py'
--- actions/actions.py 2016-07-27 09:39:41 +0000
+++ actions/actions.py 2016-10-17 17:28:49 +0000
@@ -7,20 +7,49 @@
77
8from charmhelpers.core.hookenv import action_fail8from charmhelpers.core.hookenv import action_fail
9from pg_dir_utils import (9from pg_dir_utils import (
10 restart_pg10 restart_pg,
11 sapi_post_zone_info,
12 sapi_post_license,
13 sapi_post_ips
11)14)
1215
1316
14def restart(args):17def restart_pg_service(args):
15 """Pause the Ceilometer services.18 """
16 @raises Exception should the service fail to stop.19 Restart PLUMgrid services.
17 """20 """
18 restart_pg('lxc')21 restart_pg()
22
23
24def post_ips(args):
25 """
26 POST PLUMgrid nodes IPs to solutions api server.
27 """
28 sapi_post_ips()
29
30
31def post_zone_info(args):
32 """
33 POST PLUMgrid zone information to solutions api server
34 """
35 sapi_post_zone_info()
36
37
38def post_license(args):
39 """
40 POST PLUMgrid License key to solutions api server
41 """
42 sapi_post_license()
1943
2044
21# A dictionary of all the defined actions to callables (which take45# A dictionary of all the defined actions to callables (which take
22# parsed arguments).46# parsed arguments).
23ACTIONS = {"restart": restart}47ACTIONS = {
48 "restart-pg-service": restart_pg_service,
49 "sapi-post-ips": post_ips,
50 "sapi-post-zone-info": post_zone_info,
51 "sapi-post-license": post_license
52}
2453
2554
26def main(args):55def main(args):
2756
=== removed symlink 'actions/restart'
=== target was u'actions.py'
=== added symlink 'actions/restart-pg-service'
=== target is u'actions.py'
=== added symlink 'actions/sapi-post-ips'
=== target is u'actions.py'
=== added symlink 'actions/sapi-post-license'
=== target is u'actions.py'
=== added symlink 'actions/sapi-post-zone-info'
=== target is u'actions.py'
=== added directory 'bin'
=== added file 'bin/charm_helpers_sync.py'
--- bin/charm_helpers_sync.py 1970-01-01 00:00:00 +0000
+++ bin/charm_helpers_sync.py 2016-10-17 17:28:49 +0000
@@ -0,0 +1,253 @@
1#!/usr/bin/python
2
3# Copyright 2014-2015 Canonical Limited.
4#
5# This file is part of charm-helpers.
6#
7# charm-helpers is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Lesser General Public License version 3 as
9# published by the Free Software Foundation.
10#
11# charm-helpers is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU Lesser General Public License for more details.
15#
16# You should have received a copy of the GNU Lesser General Public License
17# along with charm-helpers. If not, see <http://www.gnu.org/licenses/>.
18
19# Authors:
20# Adam Gandelman <adamg@ubuntu.com>
21
22import logging
23import optparse
24import os
25import subprocess
26import shutil
27import sys
28import tempfile
29import yaml
30from fnmatch import fnmatch
31
32import six
33
34CHARM_HELPERS_BRANCH = 'lp:charm-helpers'
35
36
37def parse_config(conf_file):
38 if not os.path.isfile(conf_file):
39 logging.error('Invalid config file: %s.' % conf_file)
40 return False
41 return yaml.load(open(conf_file).read())
42
43
44def clone_helpers(work_dir, branch):
45 dest = os.path.join(work_dir, 'charm-helpers')
46 logging.info('Checking out %s to %s.' % (branch, dest))
47 cmd = ['bzr', 'checkout', '--lightweight', branch, dest]
48 subprocess.check_call(cmd)
49 return dest
50
51
52def _module_path(module):
53 return os.path.join(*module.split('.'))
54
55
56def _src_path(src, module):
57 return os.path.join(src, 'charmhelpers', _module_path(module))
58
59
60def _dest_path(dest, module):
61 return os.path.join(dest, _module_path(module))
62
63
64def _is_pyfile(path):
65 return os.path.isfile(path + '.py')
66
67
68def ensure_init(path):
69 '''
70 ensure directories leading up to path are importable, omitting
71 parent directory, eg path='/hooks/helpers/foo'/:
72 hooks/
73 hooks/helpers/__init__.py
74 hooks/helpers/foo/__init__.py
75 '''
76 for d, dirs, files in os.walk(os.path.join(*path.split('/')[:2])):
77 _i = os.path.join(d, '__init__.py')
78 if not os.path.exists(_i):
79 logging.info('Adding missing __init__.py: %s' % _i)
80 open(_i, 'wb').close()
81
82
83def sync_pyfile(src, dest):
84 src = src + '.py'
85 src_dir = os.path.dirname(src)
86 logging.info('Syncing pyfile: %s -> %s.' % (src, dest))
87 if not os.path.exists(dest):
88 os.makedirs(dest)
89 shutil.copy(src, dest)
90 if os.path.isfile(os.path.join(src_dir, '__init__.py')):
91 shutil.copy(os.path.join(src_dir, '__init__.py'),
92 dest)
93 ensure_init(dest)
94
95
96def get_filter(opts=None):
97 opts = opts or []
98 if 'inc=*' in opts:
99 # do not filter any files, include everything
100 return None
101
102 def _filter(dir, ls):
103 incs = [opt.split('=').pop() for opt in opts if 'inc=' in opt]
104 _filter = []
105 for f in ls:
106 _f = os.path.join(dir, f)
107
108 if not os.path.isdir(_f) and not _f.endswith('.py') and incs:
109 if True not in [fnmatch(_f, inc) for inc in incs]:
110 logging.debug('Not syncing %s, does not match include '
111 'filters (%s)' % (_f, incs))
112 _filter.append(f)
113 else:
114 logging.debug('Including file, which matches include '
115 'filters (%s): %s' % (incs, _f))
116 elif (os.path.isfile(_f) and not _f.endswith('.py')):
117 logging.debug('Not syncing file: %s' % f)
118 _filter.append(f)
119 elif (os.path.isdir(_f) and not
120 os.path.isfile(os.path.join(_f, '__init__.py'))):
121 logging.debug('Not syncing directory: %s' % f)
122 _filter.append(f)
123 return _filter
124 return _filter
125
126
127def sync_directory(src, dest, opts=None):
128 if os.path.exists(dest):
129 logging.debug('Removing existing directory: %s' % dest)
130 shutil.rmtree(dest)
131 logging.info('Syncing directory: %s -> %s.' % (src, dest))
132
133 shutil.copytree(src, dest, ignore=get_filter(opts))
134 ensure_init(dest)
135
136
137def sync(src, dest, module, opts=None):
138
139 # Sync charmhelpers/__init__.py for bootstrap code.
140 sync_pyfile(_src_path(src, '__init__'), dest)
141
142 # Sync other __init__.py files in the path leading to module.
143 m = []
144 steps = module.split('.')[:-1]
145 while steps:
146 m.append(steps.pop(0))
147 init = '.'.join(m + ['__init__'])
148 sync_pyfile(_src_path(src, init),
149 os.path.dirname(_dest_path(dest, init)))
150
151 # Sync the module, or maybe a .py file.
152 if os.path.isdir(_src_path(src, module)):
153 sync_directory(_src_path(src, module), _dest_path(dest, module), opts)
154 elif _is_pyfile(_src_path(src, module)):
155 sync_pyfile(_src_path(src, module),
156 os.path.dirname(_dest_path(dest, module)))
157 else:
158 logging.warn('Could not sync: %s. Neither a pyfile or directory, '
159 'does it even exist?' % module)
160
161
162def parse_sync_options(options):
163 if not options:
164 return []
165 return options.split(',')
166
167
168def extract_options(inc, global_options=None):
169 global_options = global_options or []
170 if global_options and isinstance(global_options, six.string_types):
171 global_options = [global_options]
172 if '|' not in inc:
173 return (inc, global_options)
174 inc, opts = inc.split('|')
175 return (inc, parse_sync_options(opts) + global_options)
176
177
178def sync_helpers(include, src, dest, options=None):
179 if not os.path.isdir(dest):
180 os.makedirs(dest)
181
182 global_options = parse_sync_options(options)
183
184 for inc in include:
185 if isinstance(inc, str):
186 inc, opts = extract_options(inc, global_options)
187 sync(src, dest, inc, opts)
188 elif isinstance(inc, dict):
189 # could also do nested dicts here.
190 for k, v in six.iteritems(inc):
191 if isinstance(v, list):
192 for m in v:
193 inc, opts = extract_options(m, global_options)
194 sync(src, dest, '%s.%s' % (k, inc), opts)
195
196if __name__ == '__main__':
197 parser = optparse.OptionParser()
198 parser.add_option('-c', '--config', action='store', dest='config',
199 default=None, help='helper config file')
200 parser.add_option('-D', '--debug', action='store_true', dest='debug',
201 default=False, help='debug')
202 parser.add_option('-b', '--branch', action='store', dest='branch',
203 help='charm-helpers bzr branch (overrides config)')
204 parser.add_option('-d', '--destination', action='store', dest='dest_dir',
205 help='sync destination dir (overrides config)')
206 (opts, args) = parser.parse_args()
207
208 if opts.debug:
209 logging.basicConfig(level=logging.DEBUG)
210 else:
211 logging.basicConfig(level=logging.INFO)
212
213 if opts.config:
214 logging.info('Loading charm helper config from %s.' % opts.config)
215 config = parse_config(opts.config)
216 if not config:
217 logging.error('Could not parse config from %s.' % opts.config)
218 sys.exit(1)
219 else:
220 config = {}
221
222 if 'branch' not in config:
223 config['branch'] = CHARM_HELPERS_BRANCH
224 if opts.branch:
225 config['branch'] = opts.branch
226 if opts.dest_dir:
227 config['destination'] = opts.dest_dir
228
229 if 'destination' not in config:
230 logging.error('No destination dir. specified as option or config.')
231 sys.exit(1)
232
233 if 'include' not in config:
234 if not args:
235 logging.error('No modules to sync specified as option or config.')
236 sys.exit(1)
237 config['include'] = []
238 [config['include'].append(a) for a in args]
239
240 sync_options = None
241 if 'options' in config:
242 sync_options = config['options']
243 tmpd = tempfile.mkdtemp()
244 try:
245 checkout = clone_helpers(tmpd, config['branch'])
246 sync_helpers(config['include'], checkout, config['destination'],
247 options=sync_options)
248 except Exception as e:
249 logging.error("Could not sync: %s" % e)
250 raise e
251 finally:
252 logging.debug('Cleaning up %s' % tmpd)
253 shutil.rmtree(tmpd)
0254
=== modified file 'config.yaml'
--- config.yaml 2016-07-23 14:21:58 +0000
+++ config.yaml 2016-10-17 17:28:49 +0000
@@ -17,6 +17,7 @@
17 description: Public SSH key of PLUMgrid LCM which is running PG-Tools.17 description: Public SSH key of PLUMgrid LCM which is running PG-Tools.
18 mgmt-interface:18 mgmt-interface:
19 type: string19 type: string
20 default:
20 description: The interface connected to PLUMgrid Managment network.21 description: The interface connected to PLUMgrid Managment network.
21 fabric-interfaces:22 fabric-interfaces:
22 default: 'MANAGEMENT'23 default: 'MANAGEMENT'
@@ -56,3 +57,26 @@
56 default: 127.0.0.157 default: 127.0.0.1
57 type: string58 type: string
58 description: IP address of the PLUMgrid Operations VM Management interface.59 description: IP address of the PLUMgrid Operations VM Management interface.
60 lcm-ip:
61 type: string
62 default: 127.0.0.1
63 description: IP used by Solutions API to get/post cloud information.
64 sapi-port:
65 default: 8099
66 type: int
67 description: Port used by Solutions API to get/post cloud information.
68 sapi-zone:
69 default: pgzone
70 type: string
71 description: Zone name used by Solutions API to get/post cloud information.
72 openstack-release:
73 default: kilo
74 type: string
75 description: |
76 OpenStack release to determine solution version that will be posted to
77 Solutions API server.
78 enable-sapi:
79 default: false
80 type: boolean
81 description: |
82 Enable or disable Solutions API support.
5983
=== modified symlink 'hooks/install' (properties changed: -x to +x)
=== target was u'pg_dir_hooks.py'
--- hooks/install 1970-01-01 00:00:00 +0000
+++ hooks/install 2016-10-17 17:28:49 +0000
@@ -0,0 +1,20 @@
1#!/bin/bash
2# Wrapper to deal with newer Ubuntu versions that don't have py2 installed
3# by default.
4
5declare -a DEPS=('apt' 'netaddr' 'netifaces' 'pip' 'yaml')
6
7check_and_install() {
8 pkg="${1}-${2}"
9 if ! dpkg -s ${pkg} 2>&1 > /dev/null; then
10 apt-get -y install ${pkg}
11 fi
12}
13
14PYTHON="python"
15
16for dep in ${DEPS[@]}; do
17 check_and_install ${PYTHON} ${dep}
18done
19
20exec ./hooks/install.real
021
=== added symlink 'hooks/install.real'
=== target is u'pg_dir_hooks.py'
=== modified file 'hooks/pg_dir_context.py'
--- hooks/pg_dir_context.py 2016-03-26 22:04:58 +0000
+++ hooks/pg_dir_context.py 2016-10-17 17:28:49 +0000
@@ -26,6 +26,30 @@
26)26)
2727
2828
29def _pg_edge_ips():
30 '''
31 Inspects edge-peer relation and returns the
32 ips of the edge nodes
33 '''
34 return [get_host_ip(rdata['private-address'])
35 for rid in relation_ids("plumgrid")
36 for rdata in
37 (relation_get(rid=rid, unit=unit) for unit in related_units(rid))
38 if 'edge-peer' in rdata]
39
40
41def _pg_gateway_ips():
42 '''
43 Inspects gateway-peer relation and returns the
44 ips of the gateway nodes
45 '''
46 return [get_host_ip(rdata['private-address'])
47 for rid in relation_ids("plumgrid")
48 for rdata in
49 (relation_get(rid=rid, unit=unit) for unit in related_units(rid))
50 if 'gateway-peer' in rdata]
51
52
29def _pg_dir_ips():53def _pg_dir_ips():
30 '''54 '''
31 Inspects plumgrid-director peer relation and returns the55 Inspects plumgrid-director peer relation and returns the
3256
=== modified file 'hooks/pg_dir_hooks.py'
--- hooks/pg_dir_hooks.py 2016-07-28 19:27:47 +0000
+++ hooks/pg_dir_hooks.py 2016-10-17 17:28:49 +0000
@@ -9,7 +9,6 @@
9import time9import time
10from charmhelpers.core.host import service_running10from charmhelpers.core.host import service_running
11from charmhelpers.contrib.network.ip import is_ip11from charmhelpers.contrib.network.ip import is_ip
12
13from charmhelpers.core.hookenv import (12from charmhelpers.core.hookenv import (
14 Hooks,13 Hooks,
15 UnregisteredHookError,14 UnregisteredHookError,
@@ -41,15 +40,19 @@
41 load_iptables,40 load_iptables,
42 restart_on_change,41 restart_on_change,
43 director_cluster_ready,42 director_cluster_ready,
44 disable_apparmor_libvirt,43 configure_pg_sources,
45 configure_pg_sources44 configure_analyst_opsvm,
45 sapi_post_ips,
46 sapi_post_license,
47 sapi_post_zone_info,
48 disable_apparmor_libvirt
46)49)
4750
48hooks = Hooks()51hooks = Hooks()
49CONFIGS = register_configs()52CONFIGS = register_configs()
5053
5154
52@hooks.hook()55@hooks.hook('install.real')
53def install():56def install():
54 '''57 '''
55 Install hook is run when the charm is first deployed on a node.58 Install hook is run when the charm is first deployed on a node.
@@ -62,12 +65,13 @@
62 for pkg in pkgs:65 for pkg in pkgs:
63 apt_install(pkg, options=['--force-yes'], fatal=True)66 apt_install(pkg, options=['--force-yes'], fatal=True)
64 load_iovisor()67 load_iovisor()
65 ensure_mtu()
66 disable_apparmor_libvirt()68 disable_apparmor_libvirt()
69 ensure_mtu()
67 CONFIGS.write_all()70 CONFIGS.write_all()
6871
6972
70@hooks.hook('director-relation-joined')73@hooks.hook('director-relation-joined')
74@hooks.hook('director-relation-changed')
71@restart_on_change(restart_map())75@restart_on_change(restart_map())
72def dir_joined():76def dir_joined():
73 '''77 '''
@@ -76,19 +80,22 @@
76 if director_cluster_ready():80 if director_cluster_ready():
77 ensure_mtu()81 ensure_mtu()
78 CONFIGS.write_all()82 CONFIGS.write_all()
79 restart_pg('lxc')83
8084
8185@hooks.hook('plumgrid-relation-joined',
82@hooks.hook('plumgrid-relation-joined')86 'plumgrid-relation-changed',
87 'plumgrid-relation-departed')
83def plumgrid_joined(relation_id=None):88def plumgrid_joined(relation_id=None):
84 '''89 '''
85 This hook is run when relation with edge or gateway is created.90 This hook is run when relation with edge or gateway is created.
86 '''91 '''
87 opsvm_ip = config('opsvm-ip')92 opsvm_ip = config('opsvm-ip')
88 if not is_ip(opsvm_ip):93 if not is_ip(opsvm_ip):
89 raise ValueError('Incorrect OPSVM IP specified')94 raise ValueError('Invalid OPSVM IP specified!')
90 else:95 else:
91 relation_set(relation_id=relation_id, opsvm_ip=opsvm_ip)96 relation_set(relation_id=relation_id, opsvm_ip=opsvm_ip)
97 if is_leader():
98 sapi_post_ips()
9299
93100
94@hooks.hook('plumgrid-configs-relation-joined')101@hooks.hook('plumgrid-configs-relation-joined')
@@ -119,6 +126,8 @@
119 if charm_config.changed('plumgrid-license-key'):126 if charm_config.changed('plumgrid-license-key'):
120 if is_leader() and post_pg_license():127 if is_leader() and post_pg_license():
121 log("PLUMgrid License Posted")128 log("PLUMgrid License Posted")
129 # Post PG license to Sol-API
130 sapi_post_license()
122 if charm_config.changed('fabric-interfaces'):131 if charm_config.changed('fabric-interfaces'):
123 if not fabric_interface_changed():132 if not fabric_interface_changed():
124 log("Fabric interface already set")133 log("Fabric interface already set")
@@ -126,6 +135,8 @@
126 stop_pg()135 stop_pg()
127 if charm_config.changed('plumgrid-virtual-ip'):136 if charm_config.changed('plumgrid-virtual-ip'):
128 CONFIGS.write_all()137 CONFIGS.write_all()
138 for rid in relation_ids('plumgrid'):
139 plumgrid_joined(rid)
129 stop_pg()140 stop_pg()
130 for rid in relation_ids('plumgrid-configs'):141 for rid in relation_ids('plumgrid-configs'):
131 plumgrid_configs_joined(rid)142 plumgrid_configs_joined(rid)
@@ -151,10 +162,21 @@
151 for rid in relation_ids('plumgrid'):162 for rid in relation_ids('plumgrid'):
152 plumgrid_joined(rid)163 plumgrid_joined(rid)
153 stop_pg()164 stop_pg()
165 if (charm_config.changed('sapi-port') or
166 charm_config.changed('lcm-ip') or
167 charm_config.changed('sapi-zone') or
168 charm_config.changed('enable-sapi')):
169 if is_leader():
170 if is_ip(config('lcm-ip')):
171 sapi_post_zone_info()
172 else:
173 raise ValueError('Invalid LCM IP specified!')
174 for rid in relation_ids('plumgrid'):
175 plumgrid_joined(rid)
154 ensure_mtu()176 ensure_mtu()
155 CONFIGS.write_all()177 CONFIGS.write_all()
156 if not service_running('plumgrid'):178 if not service_running('plumgrid'):
157 restart_pg('lxc')179 restart_pg()
158180
159181
160@hooks.hook('start')182@hooks.hook('start')
@@ -162,16 +184,15 @@
162 '''184 '''
163 This hook is run when the charm is started.185 This hook is run when the charm is started.
164 '''186 '''
165 restart_pg('lxc')187 configure_analyst_opsvm()
166 time.sleep(15)
167 if config('plumgrid-license-key') is not None:188 if config('plumgrid-license-key') is not None:
168 count = 0189 count = 0
169 while (count < 15):190 while (count < 10):
191 time.sleep(15)
170 if post_pg_license():192 if post_pg_license():
171 break193 break
172 count += 1194 count += 1
173 time.sleep(15)195 if count == 10:
174 if count == 15:
175 raise ValueError("Error occurred while posting plumgrid license"196 raise ValueError("Error occurred while posting plumgrid license"
176 "key. Please check plumgrid services.")197 "key. Please check plumgrid services.")
177198
@@ -184,7 +205,6 @@
184 '''205 '''
185 ensure_mtu()206 ensure_mtu()
186 CONFIGS.write_all()207 CONFIGS.write_all()
187 restart_pg('lxc')
188208
189209
190@hooks.hook('stop')210@hooks.hook('stop')
191211
=== modified file 'hooks/pg_dir_utils.py'
--- hooks/pg_dir_utils.py 2016-08-29 10:03:28 +0000
+++ hooks/pg_dir_utils.py 2016-10-17 17:28:49 +0000
@@ -7,7 +7,6 @@
7import time7import time
8import os8import os
9import json9import json
10import shlex
11from collections import OrderedDict10from collections import OrderedDict
12from socket import gethostname as get_unit_hostname11from socket import gethostname as get_unit_hostname
13from copy import deepcopy12from copy import deepcopy
@@ -25,14 +24,16 @@
25 get_bridges,24 get_bridges,
26 get_bridge_nics,25 get_bridge_nics,
27 is_ip,26 is_ip,
27 get_iface_addr,
28 get_host_ip
28)29)
29from charmhelpers.core.host import (30from charmhelpers.core.host import (
30 service_start,31 service_start,
31 service_restart,
32 service_stop,32 service_stop,
33 service_running,33 service_running,
34 path_hash,34 path_hash,
35 set_nic_mtu35 set_nic_mtu,
36 service_restart
36)37)
37from charmhelpers.fetch import (38from charmhelpers.fetch import (
38 apt_cache,39 apt_cache,
@@ -41,6 +42,11 @@
41from charmhelpers.contrib.openstack.utils import (42from charmhelpers.contrib.openstack.utils import (
42 os_release,43 os_release,
43)44)
45from pg_dir_context import (
46 _pg_dir_ips,
47 _pg_edge_ips,
48 _pg_gateway_ips
49)
4450
45SOURCES_LIST = '/etc/apt/sources.list'51SOURCES_LIST = '/etc/apt/sources.list'
46LXC_CONF = '/etc/libvirt/lxc.conf'52LXC_CONF = '/etc/libvirt/lxc.conf'
@@ -57,6 +63,14 @@
57AUTH_KEY_PATH = '%s/root/.ssh/authorized_keys' % PG_LXC_DATA_PATH63AUTH_KEY_PATH = '%s/root/.ssh/authorized_keys' % PG_LXC_DATA_PATH
58TEMP_LICENSE_FILE = '/tmp/license'64TEMP_LICENSE_FILE = '/tmp/license'
5965
66# Constant values for OpenStack releases as Canonical-Ubuntu
67# doesn't have any specific solution version associated
68OPENSTACK_RELEASE_VERS = {
69 'kilo': '10',
70 'liberty': '11',
71 'mitaka': '12'
72}
73
60BASE_RESOURCE_MAP = OrderedDict([74BASE_RESOURCE_MAP = OrderedDict([
61 (PG_KA_CONF, {75 (PG_KA_CONF, {
62 'services': ['plumgrid'],76 'services': ['plumgrid'],
@@ -105,6 +119,31 @@
105 log('Unable to update /etc/apt/sources.list')119 log('Unable to update /etc/apt/sources.list')
106120
107121
122def configure_analyst_opsvm():
123 '''
124 Configures Anaylyst for OPSVM
125 '''
126 if not service_running('plumgrid'):
127 restart_pg()
128 NS_ENTER = ('/opt/local/bin/nsenter -t $(ps ho pid --ppid $(cat '
129 '/var/run/libvirt/lxc/plumgrid.pid)) -m -n -u -i -p ')
130 sigmund_stop = NS_ENTER + '/usr/bin/service plumgrid-sigmund stop'
131 sigmund_status = NS_ENTER \
132 + '/usr/bin/service plumgrid-sigmund status'
133 sigmund_autoboot = NS_ENTER \
134 + '/usr/bin/sigmund-configure --ip {0} --start --autoboot' \
135 .format(config('opsvm-ip'))
136 try:
137 status = subprocess.check_output(sigmund_status, shell=True)
138 if 'start/running' in status:
139 if subprocess.call(sigmund_stop, shell=True):
140 log('plumgrid-sigmund couldn\'t be stopped!')
141 return
142 subprocess.check_call(sigmund_autoboot, shell=True)
143 except:
144 log('plumgrid-sigmund couldn\'t be started!')
145
146
108def determine_packages():147def determine_packages():
109 '''148 '''
110 Returns list of packages required by PLUMgrid director as specified149 Returns list of packages required by PLUMgrid director as specified
@@ -131,6 +170,36 @@
131 return pkgs170 return pkgs
132171
133172
173def disable_apparmor_libvirt():
174 '''
175 Disables Apparmor profile of libvirtd.
176 '''
177 apt_install('apparmor-utils')
178 apt_install('cgroup-bin')
179 _exec_cmd(['sudo', 'aa-disable', '/usr/sbin/libvirtd'],
180 error_msg='Error disabling AppArmor profile of libvirtd')
181 disable_apparmor()
182 service_restart('libvirt-bin')
183
184
185def disable_apparmor():
186 '''
187 Disables Apparmor security for lxc.
188 '''
189 try:
190 f = open(LXC_CONF, 'r')
191 except IOError:
192 log('Libvirt not installed yet')
193 return 0
194 filedata = f.read()
195 f.close()
196 newdata = filedata.replace("security_driver = \"apparmor\"",
197 "#security_driver = \"apparmor\"")
198 f = open(LXC_CONF, 'w')
199 f.write(newdata)
200 f.close()
201
202
134def register_configs(release=None):203def register_configs(release=None):
135 '''204 '''
136 Returns an object of the Openstack Tempating Class which contains the205 Returns an object of the Openstack Tempating Class which contains the
@@ -161,31 +230,7 @@
161 return {cfg: rscs['services'] for cfg, rscs in resource_map().iteritems()}230 return {cfg: rscs['services'] for cfg, rscs in resource_map().iteritems()}
162231
163232
164def start_gateway():233def restart_pg():
165 '''
166 Brings up PE-gateway interface. Initial hack but will be solved when docker
167 plumgrid-director package will be used.
168 '''
169 count = 0
170 while (count < 7):
171 cmd = 'ps aux | grep launch_metadata_helper'
172 output = subprocess.check_output([cmd], shell=True)
173 roots = 0
174 v = shlex.split(output)
175 for i in v:
176 if i == 'root':
177 roots += 1
178 if roots < 3:
179 stop_pg()
180 time.sleep(3)
181 service_start('plumgrid')
182 else:
183 break
184 count += 1
185 time.sleep(20)
186
187
188def restart_pg(gateway=None):
189 '''234 '''
190 Stops and Starts PLUMgrid service after flushing iptables.235 Stops and Starts PLUMgrid service after flushing iptables.
191 '''236 '''
@@ -203,8 +248,6 @@
203 raise ValueError("plumgrid service couldn't be started")248 raise ValueError("plumgrid service couldn't be started")
204 else:249 else:
205 raise ValueError("libvirt-bin service couldn't be started")250 raise ValueError("libvirt-bin service couldn't be started")
206 if gateway:
207 start_gateway()
208 status_set('active', 'Unit is ready')251 status_set('active', 'Unit is ready')
209252
210253
@@ -251,8 +294,14 @@
251 '''294 '''
252 mgmt_interface = config('mgmt-interface')295 mgmt_interface = config('mgmt-interface')
253 if not mgmt_interface:296 if not mgmt_interface:
254 return get_iface_from_addr(unit_get('private-address'))297 try:
255 elif mgmt_interface and interface_exists(mgmt_interface):298 return get_iface_from_addr(unit_get('private-address'))
299 except:
300 for bridge_interface in get_bridges():
301 if (get_host_ip(unit_get('private-address'))
302 in get_iface_addr(bridge_interface)):
303 return bridge_interface
304 elif interface_exists(mgmt_interface):
256 return mgmt_interface305 return mgmt_interface
257 else:306 else:
258 log('Provided managment interface %s does not exist'307 log('Provided managment interface %s does not exist'
@@ -317,36 +366,6 @@
317 set_nic_mtu(fabric_interface, interface_mtu)366 set_nic_mtu(fabric_interface, interface_mtu)
318367
319368
320def disable_apparmor_libvirt():
321 '''
322 Disables Apparmor profile of libvirtd.
323 '''
324 apt_install('apparmor-utils')
325 apt_install('cgroup-bin')
326 _exec_cmd(['sudo', 'aa-disable', '/usr/sbin/libvirtd'],
327 error_msg='Error disabling AppArmor profile of libvirtd')
328 disable_apparmor()
329 service_restart('libvirt-bin')
330
331
332def disable_apparmor():
333 '''
334 Disables Apparmor security for lxc.
335 '''
336 try:
337 f = open(LXC_CONF, 'r')
338 except IOError:
339 log('Libvirt not installed yet')
340 return 0
341 filedata = f.read()
342 f.close()
343 newdata = filedata.replace("security_driver = \"apparmor\"",
344 "#security_driver = \"apparmor\"")
345 f = open(LXC_CONF, 'w')
346 f.write(newdata)
347 f.close()
348
349
350def _exec_cmd(cmd=None, error_msg='Command exited with ERRORs', fatal=False):369def _exec_cmd(cmd=None, error_msg='Command exited with ERRORs', fatal=False):
351 '''370 '''
352 Function to execute any bash command on the node.371 Function to execute any bash command on the node.
@@ -431,6 +450,160 @@
431 return 1450 return 1
432451
433452
453def sapi_post_ips():
454 """
455 Posts PLUMgrid nodes IPs to solutions api server.
456 """
457 if not config('enable-sapi'):
458 log('Solutions API support is disabled!')
459 return 1
460 pg_edge_ips = _pg_edge_ips()
461 pg_dir_ips = _pg_dir_ips()
462 pg_gateway_ips = _pg_gateway_ips()
463 pg_dir_ips.append(get_host_ip(unit_get('private-address')))
464 pg_edge_ips = '"edge_ips"' + ':' \
465 + '"{}"'.format(','.join(str(i) for i in pg_edge_ips))
466 pg_dir_ips = '"director_ips"' + ':' \
467 + '"{}"'.format(','.join(str(i) for i in pg_dir_ips))
468 pg_gateway_ips = '"gateway_ips"' + ':' \
469 + '"{}"'.format(','.join(str(i) for i in pg_gateway_ips))
470 opsvm_ip = '"opsvm_ip"' + ':' + '"{}"'.format(config('opsvm-ip'))
471 virtual_ip = '"virtual_ip"' + ':' \
472 + '"{}"'.format(config('plumgrid-virtual-ip'))
473 JSON_IPS = ','.join([pg_dir_ips, pg_edge_ips, pg_gateway_ips,
474 opsvm_ip, virtual_ip])
475 status = (
476 'curl -H \'Content-Type: application/json\' -X '
477 'PUT -d \'{{{0}}}\' http://{1}' + ':' + '{2}/v1/zones/{3}/allIps'
478 ).format(JSON_IPS, config('lcm-ip'), config('sapi-port'),
479 config('sapi-zone'))
480 POST_ZONE_IPs = _exec_cmd_output(
481 status,
482 'Posting Zone IPs to Solutions API server failed!')
483 if POST_ZONE_IPs:
484 if 'success' in POST_ZONE_IPs:
485 log('Successfully posted Zone IPs to Solutions API server!')
486 log(POST_ZONE_IPs)
487
488
489def _exec_cmd_output(cmd=None, error_msg='Command exited with ERRORs',
490 fatal=False):
491 '''
492 Function to get output from bash command executed on the node.
493 '''
494 if cmd is None:
495 log("No command specified")
496 else:
497 if fatal:
498 return subprocess.check_output(cmd, shell=True)
499 else:
500 try:
501 return subprocess.check_output(cmd, shell=True)
502 except subprocess.CalledProcessError:
503 log(error_msg)
504 return None
505
506
507def sapi_post_license():
508 '''
509 Posts PLUMgrid License to solutions api server
510 '''
511 if not config('enable-sapi'):
512 log('Solutions API support is disabled!')
513 return 1
514 username = '"user_name":' + '"{}"'.format(config('plumgrid-username'))
515 password = '"password":' + '"{}"'.format(config('plumgrid-password'))
516 license = '"license":' + '"{}"'.format(config('plumgrid-license-key'))
517 JSON_LICENSE = ','.join([username, password, license])
518 status = (
519 'curl -H \'Content-Type: application/json\' -X '
520 'PUT -d \'{{{0}}}\' http://{1}' + ':' + '{2}/v1/zones/{3}/pgLicense'
521 ).format(JSON_LICENSE, config('lcm-ip'), config('sapi-port'),
522 config('sapi-zone'))
523 POST_LICENSE = _exec_cmd_output(
524 status,
525 'Posting PLUMgrid License to Solutions API server failed!')
526 if POST_LICENSE:
527 if 'success' in POST_LICENSE:
528 log('Successfully posted license file for zone "{}"!'
529 .format(config('sapi-zone')))
530 log(POST_LICENSE)
531
532
533def sapi_post_zone_info():
534 '''
535 Posts zone information to solutions api server
536 '''
537 if not config('enable-sapi'):
538 log('Solutions API support is disabled!')
539 return 1
540 sol_name = '"solution_name":"Ubuntu OpenStack"'
541 release = config('openstack-release')
542 for key, value in OPENSTACK_RELEASE_VERS.iteritems():
543 if release == value:
544 sol_version = value
545 else:
546 sol_version = 10
547 sol_version = '"solution_version":"{}"'.format(sol_version)
548 pg_ons_version = _exec_cmd_output(
549 'dpkg -l | grep plumgrid | awk \'{print $3}\' | '
550 'sed \'s/-/./\' | cut -f1 -d"-"',
551 'Unable to obtain PG ONS version'
552 ).replace('\n', '')
553 pg_ons_version = \
554 '"pg_ons_version":"{}"'.format(pg_ons_version)
555 hypervisor = '"hypervisor":"Ubuntu"'
556 hypervisor_version = \
557 _exec_cmd_output('lsb_release -r | awk \'{print $2}\'',
558 'Unable to obtain solution version'
559 ).replace('\n', '')
560 hypervisor_version = '"hypervisor_version":"{}"' \
561 .format(hypervisor_version)
562 kernel_version = _exec_cmd_output(
563 'uname -r',
564 'Unable to obtain kernal version').replace('\n', '')
565 kernel_version = \
566 '"kernel_version":"{}"'.format(kernel_version)
567 cloudapex_path = '/var/lib/libvirt/filesystems/plumgrid/' \
568 'opt/pg/web/cloudApex/modules/appCloudApex' \
569 '/appCloudApex.js'
570 if os.path.isfile(cloudapex_path):
571 pg_cloudapex_version = 'cat ' \
572 + '{}'.format(cloudapex_path) \
573 + ' | grep -i appversion | awk \'{print $2}\''
574 pg_cloudapex_version = \
575 _exec_cmd_output(pg_cloudapex_version,
576 'Unable to retrieve CloudApex version'
577 ).replace('\n', '')
578 else:
579 log('CloudApex not installed!')
580 pg_cloudapex_version = ''
581 pg_cloudapex_version = \
582 '"pg_cloudapex_version":"{}"'.format(pg_cloudapex_version)
583 JSON_ZONE_INFO = ','.join([
584 sol_name,
585 sol_version,
586 pg_ons_version,
587 hypervisor,
588 hypervisor_version,
589 kernel_version,
590 pg_cloudapex_version,
591 ])
592 status = (
593 'curl -H \'Content-Type: application/json\' -X '
594 'PUT -d \'{{{0}}}\' http://{1}:{2}/v1/zones/{3}/zoneinfo'
595 ).format(JSON_ZONE_INFO, config('lcm-ip'), config('sapi-port'),
596 config('sapi-zone'))
597 POST_ZONE_INFO = _exec_cmd_output(
598 status,
599 'Posting Zone Information to Solutions API server failed!')
600 if POST_ZONE_INFO:
601 if 'success' in POST_ZONE_INFO:
602 log('Successfully posted Zone information to Solutions API'
603 ' server!')
604 log(POST_ZONE_INFO)
605
606
434def load_iptables():607def load_iptables():
435 '''608 '''
436 Loads iptables rules to allow all PLUMgrid communication.609 Loads iptables rules to allow all PLUMgrid communication.
437610
=== added symlink 'hooks/plumgrid-relation-changed'
=== target is u'pg_dir_hooks.py'
=== added symlink 'hooks/plumgrid-relation-departed'
=== target is u'pg_dir_hooks.py'
=== modified file 'metadata.yaml'
--- metadata.yaml 2016-05-04 06:47:43 +0000
+++ metadata.yaml 2016-10-17 17:28:49 +0000
@@ -7,6 +7,9 @@
7 The configuration of the virtual network infrastructure for tenants is7 The configuration of the virtual network infrastructure for tenants is
8 done through the PLUMgrid Director. The PLUMgrid Director is typically8 done through the PLUMgrid Director. The PLUMgrid Director is typically
9 co-located on the OpenStack controller nodes.9 co-located on the OpenStack controller nodes.
10series:
11 - xenial
12 - trusty
10tags:13tags:
11 - openstack14 - openstack
12requires:15requires:
1316
=== modified file 'unit_tests/test_pg_dir_hooks.py'
--- unit_tests/test_pg_dir_hooks.py 2016-05-01 02:16:59 +0000
+++ unit_tests/test_pg_dir_hooks.py 2016-10-17 17:28:49 +0000
@@ -32,7 +32,10 @@
32 'post_pg_license',32 'post_pg_license',
33 'config',33 'config',
34 'load_iptables',34 'load_iptables',
35 'status_set'35 'status_set',
36 'configure_analyst_opsvm',
37 'sapi_post_zone_info',
38 'disable_apparmor_libvirt'
36]39]
37NEUTRON_CONF_DIR = "/etc/neutron"40NEUTRON_CONF_DIR = "/etc/neutron"
3841

Subscribers

People subscribed via source and target branches

to all changes: