~junaidali/charms/trusty/plumgrid-edge/trunk

« back to all changes in this revision

Viewing changes to hooks/pg_edge_utils.py

  • Committer: Bilal Baqar
  • Date: 2016-03-25 16:57:36 UTC
  • mfrom: (23.1.6 plumgrid-edge)
  • Revision ID: bbaqar@plumgrid.com-20160325165736-nixoiemeskvychcc
Improved config-changed hook to perform steps according to the config changed

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 
3
3
# This file contains functions used by the hooks to deploy PLUMgrid Edge.
4
4
 
 
5
import pg_edge_context
 
6
import subprocess
 
7
import time
 
8
import os
 
9
import json
 
10
from collections import OrderedDict
 
11
from socket import gethostname as get_unit_hostname
 
12
from copy import deepcopy
5
13
from charmhelpers.contrib.openstack.neutron import neutron_plugin_attribute
6
 
from copy import deepcopy
 
14
from charmhelpers.contrib.storage.linux.ceph import modprobe
 
15
from charmhelpers.core.host import set_nic_mtu
 
16
from charmhelpers.contrib.openstack import templating
7
17
from charmhelpers.core.hookenv import (
8
18
    log,
9
19
    config,
 
20
    unit_get
 
21
)
 
22
from charmhelpers.contrib.network.ip import (
 
23
    get_iface_from_addr,
 
24
    get_bridges,
 
25
    get_bridge_nics,
 
26
    is_address_in_network,
 
27
    get_iface_addr
10
28
)
11
29
from charmhelpers.core.host import (
12
30
    write_file,
13
31
    service_restart,
14
32
    service_start,
15
33
    service_stop,
16
 
)
17
 
from charmhelpers.contrib.storage.linux.ceph import modprobe
18
 
from charmhelpers.core.host import set_nic_mtu
19
 
from charmhelpers.fetch import apt_install
20
 
from charmhelpers.contrib.openstack import templating
21
 
from collections import OrderedDict
 
34
    service_running,
 
35
)
 
36
from charmhelpers.fetch import (
 
37
    apt_cache,
 
38
    apt_install
 
39
)
22
40
from charmhelpers.contrib.openstack.utils import (
23
41
    os_release,
24
42
)
25
 
import pg_edge_context
26
 
import subprocess
27
 
import time
28
 
import os
29
43
 
30
44
SHARED_SECRET = "/etc/nova/secret.txt"
31
45
LXC_CONF = '/etc/libvirt/lxc.conf'
32
46
TEMPLATES = 'templates/'
33
47
PG_LXC_DATA_PATH = '/var/lib/libvirt/filesystems/plumgrid-data'
34
 
 
35
48
PG_CONF = '%s/conf/pg/plumgrid.conf' % PG_LXC_DATA_PATH
36
49
PG_HN_CONF = '%s/conf/etc/hostname' % PG_LXC_DATA_PATH
37
50
PG_HS_CONF = '%s/conf/etc/hosts' % PG_LXC_DATA_PATH
38
51
PG_IFCS_CONF = '%s/conf/pg/ifcs.conf' % PG_LXC_DATA_PATH
39
52
AUTH_KEY_PATH = '%s/root/.ssh/authorized_keys' % PG_LXC_DATA_PATH
40
 
 
41
53
SUDOERS_CONF = '/etc/sudoers.d/ifc_ctl_sudoers'
42
54
FILTERS_CONF_DIR = '/etc/nova/rootwrap.d'
43
55
FILTERS_CONF = '%s/network.filters' % FILTERS_CONF_DIR
71
83
    Returns list of packages required by PLUMgrid Edge as specified
72
84
    in the neutron_plugins dictionary in charmhelpers.
73
85
    '''
74
 
    return neutron_plugin_attribute('plumgrid', 'packages', 'neutron')
 
86
    pkgs = []
 
87
    tag = 'latest'
 
88
    for pkg in neutron_plugin_attribute('plumgrid', 'packages', 'neutron'):
 
89
        if 'plumgrid' in pkg:
 
90
            tag = config('plumgrid-build')
 
91
        elif pkg == 'iovisor-dkms':
 
92
            tag = config('iovisor-build')
 
93
 
 
94
        if tag == 'latest':
 
95
            pkgs.append(pkg)
 
96
        else:
 
97
            if tag in [i.ver_str for i in apt_cache()[pkg].version_list]:
 
98
                pkgs.append('%s=%s' % (pkg, tag))
 
99
            else:
 
100
                error_msg = \
 
101
                    "Build version '%s' for package '%s' not available" \
 
102
                    % (tag, pkg)
 
103
                raise ValueError(error_msg)
 
104
    return pkgs
75
105
 
76
106
 
77
107
def register_configs(release=None):
80
110
    the context required for all templates of this charm.
81
111
    '''
82
112
    release = release or os_release('nova-compute', base='kilo')
 
113
    if release < 'kilo':
 
114
        raise ValueError('OpenStack %s release not supported' % release)
 
115
 
83
116
    configs = templating.OSConfigRenderer(templates_dir=TEMPLATES,
84
117
                                          openstack_release=release)
85
118
    for cfg, rscs in resource_map().iteritems():
111
144
    release = os_release('nova-compute', base='kilo')
112
145
    if release == 'kilo':
113
146
        disable_apparmor_libvirt()
114
 
    write_file(SUDOERS_CONF, "\nnova ALL=(root) NOPASSWD: /opt/pg/bin/ifc_ctl_pp *\n", owner='root', group='root', perms=0o644)
 
147
    write_file(SUDOERS_CONF,
 
148
               "\nnova ALL=(root) NOPASSWD: /opt/pg/bin/ifc_ctl_pp *\n",
 
149
               owner='root', group='root', perms=0o644)
115
150
    _exec_cmd(cmd=['mkdir', '-p', FILTERS_CONF_DIR])
116
151
    _exec_cmd(cmd=['touch', FILTERS_CONF])
117
152
 
120
155
    '''
121
156
    Stops and Starts PLUMgrid service after flushing iptables.
122
157
    '''
123
 
    service_stop('plumgrid')
124
 
    time.sleep(2)
125
 
    _exec_cmd(cmd=['iptables', '-F'])
 
158
    stop_pg()
126
159
    service_start('plumgrid')
127
 
    time.sleep(5)
 
160
    time.sleep(3)
 
161
    if not service_running('plumgrid'):
 
162
        if service_running('libvirt-bin'):
 
163
            raise ValueError("plumgrid service couldn't be started")
 
164
        else:
 
165
            if service_start('libvirt-bin'):
 
166
                time.sleep(3)
 
167
                if not service_running('plumgrid'):
 
168
                    raise ValueError("plumgrid service couldn't be started")
 
169
            else:
 
170
                raise ValueError("libvirt-bin service couldn't be started")
128
171
 
129
172
 
130
173
def stop_pg():
146
189
    '''
147
190
    Removes iovisor kernel module.
148
191
    '''
149
 
    _exec_cmd(cmd=['rmmod', 'iovisor'], error_msg='Error Loading Iovisor Kernel Module')
 
192
    _exec_cmd(cmd=['rmmod', 'iovisor'],
 
193
              error_msg='Error Removing IOVisor Kernel Module')
 
194
    time.sleep(1)
 
195
 
 
196
 
 
197
def interface_exists(interface):
 
198
    '''
 
199
    Checks if interface exists on node.
 
200
    '''
 
201
    try:
 
202
        subprocess.check_call(['ip', 'link', 'show', interface],
 
203
                              stdout=open(os.devnull, 'w'),
 
204
                              stderr=subprocess.STDOUT)
 
205
    except subprocess.CalledProcessError:
 
206
        return False
 
207
    return True
 
208
 
 
209
 
 
210
def get_mgmt_interface():
 
211
    '''
 
212
    Returns the managment interface.
 
213
    '''
 
214
    mgmt_interface = config('mgmt-interface')
 
215
    if interface_exists(mgmt_interface):
 
216
        return mgmt_interface
 
217
    else:
 
218
        log('Provided managment interface %s does not exist'
 
219
            % mgmt_interface)
 
220
        return get_iface_from_addr(unit_get('private-address'))
 
221
 
 
222
 
 
223
def fabric_interface_changed():
 
224
    '''
 
225
    Returns true if interface for node changed.
 
226
    '''
 
227
    fabric_interface = get_fabric_interface()
 
228
    try:
 
229
        with open(PG_IFCS_CONF, 'r') as ifcs:
 
230
            for line in ifcs:
 
231
                if 'fabric_core' in line:
 
232
                    if line.split()[0] == fabric_interface:
 
233
                        return False
 
234
    except IOError:
 
235
        return True
 
236
    return True
 
237
 
 
238
 
 
239
def get_fabric_interface():
 
240
    '''
 
241
    Returns the fabric interface.
 
242
    '''
 
243
    fabric_interfaces = config('fabric-interfaces')
 
244
    if fabric_interfaces == 'MANAGEMENT':
 
245
        return get_mgmt_interface()
 
246
    else:
 
247
        try:
 
248
            all_fabric_interfaces = json.loads(fabric_interfaces)
 
249
        except ValueError:
 
250
            raise ValueError('Invalid json provided for fabric interfaces')
 
251
        hostname = get_unit_hostname()
 
252
        if hostname in all_fabric_interfaces:
 
253
            node_fabric_interface = all_fabric_interfaces[hostname]
 
254
        elif 'DEFAULT' in all_fabric_interfaces:
 
255
            node_fabric_interface = all_fabric_interfaces['DEFAULT']
 
256
        else:
 
257
            raise ValueError('No fabric interface provided for node')
 
258
        if interface_exists(node_fabric_interface):
 
259
            if is_address_in_network(config('os-data-network'),
 
260
                                     get_iface_addr(node_fabric_interface)[0]):
 
261
                return node_fabric_interface
 
262
            else:
 
263
                raise ValueError('Fabric interface not in fabric network')
 
264
        else:
 
265
            log('Provided fabric interface %s does not exist'
 
266
                % node_fabric_interface)
 
267
            raise ValueError('Provided fabric interface does not exist')
 
268
        return node_fabric_interface
150
269
 
151
270
 
152
271
def ensure_mtu():
153
272
    '''
154
273
    Ensures required MTU of the underlying networking of the node.
155
274
    '''
156
 
    log("Changing MTU of juju-br0 and all attached interfaces")
157
275
    interface_mtu = config('network-device-mtu')
158
 
    cmd = subprocess.check_output(["brctl", "show", "juju-br0"])
159
 
    words = cmd.split()
160
 
    for word in words:
161
 
        if 'eth' in word:
162
 
            set_nic_mtu(word, interface_mtu)
163
 
    set_nic_mtu('juju-br0', interface_mtu)
164
 
 
165
 
 
166
 
def _exec_cmd(cmd=None, error_msg='Command exited with ERRORs', fatal=False):
 
276
    fabric_interface = get_fabric_interface()
 
277
    if fabric_interface in get_bridges():
 
278
        attached_interfaces = get_bridge_nics(fabric_interface)
 
279
        for interface in attached_interfaces:
 
280
            set_nic_mtu(interface, interface_mtu)
 
281
    set_nic_mtu(fabric_interface, interface_mtu)
 
282
 
 
283
 
 
284
def _exec_cmd(cmd=None, error_msg='Command exited with ERRORs', fatal=False,
 
285
              verbose=False):
167
286
    '''
168
287
    Function to execute any bash command on the node.
169
288
    '''
170
289
    if cmd is None:
171
290
        log("No command specified")
172
291
    else:
173
 
        if fatal:
 
292
        if fatal and verbose:
 
293
            subprocess.check_call(cmd, stdout=open(os.devnull, 'w'),
 
294
                                  stderr=subprocess.STDOUT)
 
295
        elif fatal and not verbose:
174
296
            subprocess.check_call(cmd)
175
297
        else:
176
298
            try:
177
 
                subprocess.check_call(cmd)
 
299
                if verbose:
 
300
                    subprocess.check_call(cmd, stdout=open(os.devnull, 'w'),
 
301
                                          stderr=subprocess.STDOUT)
 
302
                else:
 
303
                    subprocess.check_call(cmd)
178
304
            except subprocess.CalledProcessError:
179
305
                log(error_msg)
180
306
 
184
310
    Disables Apparmor profile of libvirtd.
185
311
    '''
186
312
    apt_install('apparmor-utils')
187
 
    _exec_cmd(['sudo', 'aa-disable', '/usr/sbin/libvirtd'], error_msg='Error disabling AppArmor profile of libvirtd')
 
313
    apt_install('cgroup-bin')
 
314
    _exec_cmd(['sudo', 'aa-disable', '/usr/sbin/libvirtd'],
 
315
              error_msg='Error disabling AppArmor profile of libvirtd',
 
316
              verbose=True)
188
317
    disable_apparmor()
189
318
    service_restart('libvirt-bin')
190
319
 
200
329
        return 0
201
330
    filedata = f.read()
202
331
    f.close()
203
 
    newdata = filedata.replace("security_driver = \"apparmor\"", "#security_driver = \"apparmor\"")
 
332
    newdata = filedata.replace("security_driver = \"apparmor\"",
 
333
                               "#security_driver = \"apparmor\"")
204
334
    f = open(LXC_CONF, 'w')
205
335
    f.write(newdata)
206
336
    f.close()
234
364
    fa.write(key)
235
365
    fa.write('\n')
236
366
    fa.close()
 
367
    return 1
 
368
 
 
369
 
 
370
def load_iptables():
 
371
    '''
 
372
    Loads iptables rules to allow all PLUMgrid communication.
 
373
    '''
 
374
    network = get_cidr_from_iface(get_mgmt_interface())
 
375
    if network:
 
376
        _exec_cmd(['sudo', 'iptables', '-A', 'INPUT', '-p', 'tcp',
 
377
                   '-j', 'ACCEPT', '-s', network, '-d',
 
378
                   network, '-m', 'state', '--state', 'NEW'])
 
379
        _exec_cmd(['sudo', 'iptables', '-A', 'INPUT', '-p', 'udp', '-j',
 
380
                   'ACCEPT', '-s', network, '-d', network,
 
381
                   '-m', 'state', '--state', 'NEW'])
 
382
        apt_install('iptables-persistent')
 
383
 
 
384
 
 
385
def get_cidr_from_iface(interface):
 
386
    '''
 
387
    Determines Network CIDR from interface.
 
388
    '''
 
389
    if not interface:
 
390
        return None
 
391
    apt_install('ohai')
 
392
    try:
 
393
        os_info = subprocess.check_output(['ohai', '-l', 'fatal'])
 
394
    except OSError:
 
395
        log('Unable to get operating system information')
 
396
        return None
 
397
    try:
 
398
        os_info_json = json.loads(os_info)
 
399
    except ValueError:
 
400
        log('Unable to determine network')
 
401
        return None
 
402
    device = os_info_json['network']['interfaces'].get(interface)
 
403
    if device is not None:
 
404
        if device.get('routes'):
 
405
            routes = device['routes']
 
406
            for net in routes:
 
407
                if 'scope' in net:
 
408
                    return net.get('destination')
 
409
        else:
 
410
            return None
 
411
    else:
 
412
        return None