Browse Source

Fixing sleep

Bilal Baqar 3 years ago
parent
commit
84b1cd152e

+ 1
- 1
Makefile View File

@@ -7,7 +7,7 @@ virtualenv:
7 7
         netaddr jinja2
8 8
 
9 9
 lint: virtualenv
10
-	.venv/bin/flake8 --exclude hooks/charmhelpers hooks unit_tests tests
10
+	.venv/bin/flake8 --exclude hooks/charmhelpers hooks unit_tests tests --ignore E402
11 11
 	@charm proof
12 12
 
13 13
 unit_test: virtualenv

+ 19
- 1
config.yaml View File

@@ -13,10 +13,28 @@ options:
13 13
     type: string
14 14
     default: 'juju-br0'
15 15
     description: The interface connected to PLUMgrid Managment network.
16
+  os-data-network:
17
+    type: string
18
+    default:
19
+    description: |
20
+      The IP address and netmask of the OpenStack Data network (e.g.,
21
+      192.168.0.0/24)
22
+      .
23
+      This network will be used for tenant network traffic in overlay
24
+      networks.
25
+  fabric-interfaces:
26
+    default: 'MANAGEMENT'
27
+    type: string
28
+    description: |
29
+       Interfaces that will provide fabric connectivity on the gateway nodes.
30
+       Provided in form of json in a string. These interfaces have to be connected 
31
+       to the os-data-network specified in the config. Default value is MANAGEMENT which
32
+       will configure the management interface as the fabric interface on each
33
+       director.
16 34
   network-device-mtu:
17 35
     type: string
18 36
     default: '1580'
19
-    description: The MTU size for interfaces managed by director.
37
+    description: The MTU size for interfaces managed by gateway.
20 38
   install_sources:
21 39
     default: 'ppa:plumgrid-team/stable'
22 40
     type: string

+ 15
- 6
hooks/pg_gw_context.py View File

@@ -3,14 +3,17 @@
3 3
 # This file contains the class that generates context for
4 4
 # PLUMgrid template files.
5 5
 
6
+from charmhelpers.contrib.openstack import context
7
+from charmhelpers.contrib.openstack.utils import get_host_ip
6 8
 from charmhelpers.core.hookenv import (
7 9
     relation_ids,
8 10
     related_units,
9 11
     relation_get,
10 12
 )
11
-from charmhelpers.contrib.openstack import context
12
-from charmhelpers.contrib.openstack.utils import get_host_ip
13
-from socket import gethostname as get_unit_hostname
13
+from socket import (
14
+    gethostname,
15
+    getfqdn
16
+)
14 17
 
15 18
 
16 19
 def _pg_dir_settings():
@@ -60,7 +63,7 @@ class PGGwContext(context.NeutronContext):
60 63
             return {}
61 64
 
62 65
         pg_dir_ips = ''
63
-        pg_dir_settings = _pg_dir_settings()
66
+        pg_dir_settings = sorted(_pg_dir_settings())
64 67
         single_ip = True
65 68
         for ip in pg_dir_settings:
66 69
             if single_ip:
@@ -69,10 +72,16 @@ class PGGwContext(context.NeutronContext):
69 72
             else:
70 73
                 pg_dir_ips = pg_dir_ips + ',' + str(ip)
71 74
         pg_ctxt['local_ip'] = pg_dir_ips
72
-        unit_hostname = get_unit_hostname()
75
+        unit_hostname = gethostname()
73 76
         pg_ctxt['pg_hostname'] = unit_hostname
74
-        from pg_gw_utils import get_mgmt_interface, get_gw_interfaces
77
+        pg_ctxt['pg_fqdn'] = getfqdn()
78
+        from pg_gw_utils import (
79
+            get_mgmt_interface,
80
+            get_gw_interfaces,
81
+            get_fabric_interface
82
+        )
75 83
         pg_ctxt['interface'] = get_mgmt_interface()
84
+        pg_ctxt['fabric_interface'] = get_fabric_interface()
76 85
         pg_ctxt['label'] = unit_hostname
77 86
         pg_ctxt['fabric_mode'] = 'host'
78 87
         pg_ctxt['ext_interfaces'] = get_gw_interfaces()

+ 18
- 0
hooks/pg_gw_hooks.py View File

@@ -11,6 +11,7 @@ from charmhelpers.core.hookenv import (
11 11
     Hooks,
12 12
     UnregisteredHookError,
13 13
     log,
14
+    config,
14 15
 )
15 16
 
16 17
 from charmhelpers.fetch import (
@@ -29,6 +30,8 @@ from pg_gw_utils import (
29 30
     remove_iovisor,
30 31
     ensure_mtu,
31 32
     add_lcm_key,
33
+    fabric_interface_changed,
34
+    load_iptables,
32 35
 )
33 36
 
34 37
 hooks = Hooks()
@@ -40,6 +43,7 @@ def install():
40 43
     '''
41 44
     Install hook is run when the charm is first deployed on a node.
42 45
     '''
46
+    load_iptables()
43 47
     configure_sources(update=True)
44 48
     pkgs = determine_packages()
45 49
     for pkg in pkgs:
@@ -73,6 +77,15 @@ def config_changed():
73 77
     if add_lcm_key():
74 78
         log("PLUMgrid LCM Key added")
75 79
         return 1
80
+    charm_config = config()
81
+    if charm_config.changed('fabric-interfaces'):
82
+        if not fabric_interface_changed():
83
+            log("Fabric interface already set")
84
+            return 1
85
+    if charm_config.changed('os-data-network'):
86
+        if charm_config['fabric-interfaces'] == 'MANAGEMENT':
87
+            log('Fabric running on managment network')
88
+            return 1
76 89
     stop_pg()
77 90
     configure_sources(update=True)
78 91
     pkgs = determine_packages()
@@ -87,6 +100,11 @@ def config_changed():
87 100
     restart_pg()
88 101
 
89 102
 
103
+@hooks.hook('upgrade-charm')
104
+def upgrade_charm():
105
+    load_iptables()
106
+
107
+
90 108
 @hooks.hook('stop')
91 109
 def stop():
92 110
     '''

+ 137
- 38
hooks/pg_gw_utils.py View File

@@ -2,8 +2,18 @@
2 2
 
3 3
 # This file contains functions used by the hooks to deploy PLUMgrid Gateway.
4 4
 
5
-from charmhelpers.contrib.openstack.neutron import neutron_plugin_attribute
5
+import pg_gw_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
6 12
 from copy import deepcopy
13
+from charmhelpers.contrib.openstack.neutron import neutron_plugin_attribute
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,
@@ -13,6 +23,8 @@ from charmhelpers.contrib.network.ip import (
13 23
     get_iface_from_addr,
14 24
     get_bridges,
15 25
     get_bridge_nics,
26
+    is_address_in_network,
27
+    get_iface_addr
16 28
 )
17 29
 from charmhelpers.core.host import (
18 30
     write_file,
@@ -20,33 +32,22 @@ from charmhelpers.core.host import (
20 32
     service_stop,
21 33
 )
22 34
 from charmhelpers.fetch import (
23
-    apt_cache
35
+    apt_cache,
36
+    apt_install
24 37
 )
25
-from charmhelpers.contrib.storage.linux.ceph import modprobe
26
-from charmhelpers.core.host import set_nic_mtu
27
-from charmhelpers.contrib.openstack import templating
28
-from collections import OrderedDict
29 38
 from charmhelpers.contrib.openstack.utils import (
30 39
     os_release,
31 40
 )
32
-from socket import gethostname as get_unit_hostname
33
-import pg_gw_context
34
-import subprocess
35
-import time
36
-import os
37
-import json
38 41
 
39 42
 LXC_CONF = "/etc/libvirt/lxc.conf"
40 43
 TEMPLATES = 'templates/'
41 44
 PG_LXC_DATA_PATH = '/var/lib/libvirt/filesystems/plumgrid-data'
42
-
43 45
 PG_CONF = '%s/conf/pg/plumgrid.conf' % PG_LXC_DATA_PATH
44 46
 PG_HN_CONF = '%s/conf/etc/hostname' % PG_LXC_DATA_PATH
45 47
 PG_HS_CONF = '%s/conf/etc/hosts' % PG_LXC_DATA_PATH
46 48
 PG_IFCS_CONF = '%s/conf/pg/ifcs.conf' % PG_LXC_DATA_PATH
47 49
 AUTH_KEY_PATH = '%s/root/.ssh/authorized_keys' % PG_LXC_DATA_PATH
48 50
 IFC_LIST_GW = '/var/run/plumgrid/lxc/ifc_list_gateway'
49
-
50 51
 SUDOERS_CONF = '/etc/sudoers.d/ifc_ctl_sudoers'
51 52
 
52 53
 BASE_RESOURCE_MAP = OrderedDict([
@@ -139,9 +140,7 @@ def restart_pg():
139 140
     '''
140 141
     Stops and Starts PLUMgrid service after flushing iptables.
141 142
     '''
142
-    service_stop('plumgrid')
143
-    time.sleep(30)
144
-    _exec_cmd(cmd=['iptables', '-F'])
143
+    stop_pg()
145 144
     service_start('plumgrid')
146 145
     time.sleep(30)
147 146
 
@@ -151,7 +150,7 @@ def stop_pg():
151 150
     Stops PLUMgrid service.
152 151
     '''
153 152
     service_stop('plumgrid')
154
-    time.sleep(2)
153
+    time.sleep(30)
155 154
 
156 155
 
157 156
 def load_iovisor():
@@ -166,26 +165,27 @@ def remove_iovisor():
166 165
     Removes iovisor kernel module.
167 166
     '''
168 167
     _exec_cmd(cmd=['rmmod', 'iovisor'],
169
-              error_msg='Error Loading Iovisor Kernel Module')
168
+              error_msg='Error Removing IOVisor Kernel Module')
170 169
     time.sleep(1)
171 170
 
172 171
 
172
+def interface_exists(interface):
173
+    '''
174
+    Checks if interface exists on node.
175
+    '''
176
+    try:
177
+        subprocess.check_call(['ip', 'link', 'show', interface],
178
+                              stdout=open(os.devnull, 'w'),
179
+                              stderr=subprocess.STDOUT)
180
+    except subprocess.CalledProcessError:
181
+        return False
182
+    return True
183
+
184
+
173 185
 def get_mgmt_interface():
174 186
     '''
175 187
     Returns the managment interface.
176 188
     '''
177
-    def interface_exists(interface):
178
-        '''
179
-        Checks if interface exists on node.
180
-        '''
181
-        try:
182
-            subprocess.check_call(['ip', 'link', 'show', interface],
183
-                                  stdout=open(os.devnull, 'w'),
184
-                                  stderr=subprocess.STDOUT)
185
-        except subprocess.CalledProcessError:
186
-            return False
187
-        return True
188
-
189 189
     mgmt_interface = config('mgmt-interface')
190 190
     if interface_exists(mgmt_interface):
191 191
         return mgmt_interface
@@ -195,20 +195,74 @@ def get_mgmt_interface():
195 195
         return get_iface_from_addr(unit_get('private-address'))
196 196
 
197 197
 
198
+def fabric_interface_changed():
199
+    '''
200
+    Returns true if interface for node changed.
201
+    '''
202
+    fabric_interface = get_fabric_interface()
203
+    try:
204
+        with open(PG_IFCS_CONF, 'r') as ifcs:
205
+            for line in ifcs:
206
+                if 'fabric_core' in line:
207
+                    if line.split()[0] == fabric_interface:
208
+                        return False
209
+    except IOError:
210
+        return True
211
+    return True
212
+
213
+
214
+def get_fabric_interface():
215
+    '''
216
+    Returns the fabric interface.
217
+    '''
218
+    fabric_interfaces = config('fabric-interfaces')
219
+    if fabric_interfaces == 'MANAGEMENT':
220
+        return get_mgmt_interface()
221
+    else:
222
+        try:
223
+            all_fabric_interfaces = json.loads(fabric_interfaces)
224
+        except ValueError:
225
+            raise ValueError('Invalid json provided for fabric interfaces')
226
+        hostname = get_unit_hostname()
227
+        if hostname in all_fabric_interfaces:
228
+            node_fabric_interface = all_fabric_interfaces[hostname]
229
+        elif 'DEFAULT' in all_fabric_interfaces:
230
+            node_fabric_interface = all_fabric_interfaces['DEFAULT']
231
+        else:
232
+            raise ValueError('No fabric interface provided for node')
233
+        if interface_exists(node_fabric_interface):
234
+            if is_address_in_network(config('os-data-network'),
235
+                                     get_iface_addr(node_fabric_interface)[0]):
236
+                return node_fabric_interface
237
+            else:
238
+                raise ValueError('Fabric interface not in fabric network')
239
+        else:
240
+            log('Provided fabric interface %s does not exist'
241
+                % node_fabric_interface)
242
+            raise ValueError('Provided fabric interface does not exist')
243
+        return node_fabric_interface
244
+
245
+
198 246
 def get_gw_interfaces():
199 247
     '''
200 248
     Gateway node can have multiple interfaces. This function parses json
201 249
     provided in config to get all gateway interfaces for this node.
202 250
     '''
203
-    node_interfaces = ['eth1']
251
+    node_interfaces = []
204 252
     try:
205 253
         all_interfaces = json.loads(config('external-interfaces'))
206 254
     except ValueError:
207
-        log("Invalid JSON")
208
-        return node_interfaces
255
+        raise ValueError("Invalid json provided for gateway interfaces")
209 256
     hostname = get_unit_hostname()
210 257
     if hostname in all_interfaces:
211 258
         node_interfaces = all_interfaces[hostname].split(',')
259
+    elif 'DEFAULT' in all_interfaces:
260
+        node_interfaces = all_interfaces['DEFAULT'].split(',')
261
+    for interface in node_interfaces:
262
+        if not interface_exists(interface):
263
+            log('Provided gateway interface %s does not exist'
264
+                % interface)
265
+            raise ValueError('Provided gateway interface does not exist')
212 266
     return node_interfaces
213 267
 
214 268
 
@@ -217,12 +271,12 @@ def ensure_mtu():
217 271
     Ensures required MTU of the underlying networking of the node.
218 272
     '''
219 273
     interface_mtu = config('network-device-mtu')
220
-    mgmt_interface = get_mgmt_interface()
221
-    if mgmt_interface in get_bridges():
222
-        attached_interfaces = get_bridge_nics(mgmt_interface)
274
+    fabric_interface = get_fabric_interface()
275
+    if fabric_interface in get_bridges():
276
+        attached_interfaces = get_bridge_nics(fabric_interface)
223 277
         for interface in attached_interfaces:
224 278
             set_nic_mtu(interface, interface_mtu)
225
-    set_nic_mtu(mgmt_interface, interface_mtu)
279
+    set_nic_mtu(fabric_interface, interface_mtu)
226 280
 
227 281
 
228 282
 def _exec_cmd(cmd=None, error_msg='Command exited with ERRORs', fatal=False):
@@ -270,3 +324,48 @@ def add_lcm_key():
270 324
     fa.write('\n')
271 325
     fa.close()
272 326
     return 1
327
+
328
+
329
+def load_iptables():
330
+    '''
331
+    Loads iptables rules to allow all PLUMgrid communication.
332
+    '''
333
+    network = get_cidr_from_iface(get_mgmt_interface())
334
+    if network:
335
+        _exec_cmd(['sudo', 'iptables', '-A', 'INPUT', '-p', 'tcp',
336
+                   '-j', 'ACCEPT', '-s', network, '-d',
337
+                   network, '-m', 'state', '--state', 'NEW'])
338
+        _exec_cmd(['sudo', 'iptables', '-A', 'INPUT', '-p', 'udp', '-j',
339
+                   'ACCEPT', '-s', network, '-d', network,
340
+                   '-m', 'state', '--state', 'NEW'])
341
+        apt_install('iptables-persistent')
342
+
343
+
344
+def get_cidr_from_iface(interface):
345
+    '''
346
+    Determines Network CIDR from interface.
347
+    '''
348
+    if not interface:
349
+        return None
350
+    apt_install('ohai')
351
+    try:
352
+        os_info = subprocess.check_output(['ohai', '-l', 'fatal'])
353
+    except OSError:
354
+        log('Unable to get operating system information')
355
+        return None
356
+    try:
357
+        os_info_json = json.loads(os_info)
358
+    except ValueError:
359
+        log('Unable to determine network')
360
+        return None
361
+    device = os_info_json['network']['interfaces'].get(interface)
362
+    if device is not None:
363
+        if device.get('routes'):
364
+            routes = device['routes']
365
+            for net in routes:
366
+                if 'scope' in net:
367
+                    return net.get('destination')
368
+        else:
369
+            return None
370
+    else:
371
+        return None

+ 1
- 0
hooks/upgrade-charm View File

@@ -0,0 +1 @@
1
+pg_gw_hooks.py

+ 1
- 1
templates/kilo/hosts View File

@@ -1,5 +1,5 @@
1 1
 127.0.0.1   localhost
2
-127.0.1.1   {{ pg_hostname }}
2
+127.0.1.1   {{ pg_fqdn }}   {{ pg_hostname }}
3 3
 
4 4
 # The following lines are desirable for IPv6 capable hosts
5 5
 ::1     ip6-localhost ip6-loopback

+ 1
- 1
templates/kilo/ifcs.conf View File

@@ -1,4 +1,4 @@
1
-{{ interface }} = fabric_core host
1
+{{ fabric_interface }} = fabric_core host
2 2
 {% if ext_interfaces -%}
3 3
 {% for ip in ext_interfaces -%}
4 4
 {{ ip }} = access_phys

+ 10
- 4
unit_tests/test_pg_gw_context.py View File

@@ -5,7 +5,8 @@ import pg_gw_utils as utils
5 5
 import charmhelpers
6 6
 
7 7
 TO_PATCH = [
8
-    'get_unit_hostname',
8
+    'gethostname',
9
+    'getfqdn'
9 10
 ]
10 11
 
11 12
 
@@ -38,9 +39,10 @@ class PGGwContextTest(CharmTestCase):
38 39
     @patch.object(charmhelpers.contrib.openstack.context,
39 40
                   'neutron_plugin_attribute')
40 41
     @patch.object(utils, 'get_mgmt_interface')
42
+    @patch.object(utils, 'get_fabric_interface')
41 43
     @patch.object(utils, 'get_gw_interfaces')
42
-    def test_neutroncc_context_api_rel(self, _gw_int, _mgmt_int,
43
-                                       _npa, _pg_dir_settings,
44
+    def test_neutroncc_context_api_rel(self, _gw_int, _fabric_int,
45
+                                       _mgmt_int, _npa, _pg_dir_settings,
44 46
                                        _save_flag_file, _config_flag,
45 47
                                        _unit_get, _unit_priv_ip, _config,
46 48
                                        _is_clus, _https, _ens_pkgs):
@@ -54,11 +56,13 @@ class PGGwContextTest(CharmTestCase):
54 56
         _npa.side_effect = mock_npa
55 57
         _unit_get.return_value = '192.168.100.201'
56 58
         _unit_priv_ip.return_value = '192.168.100.201'
57
-        self.get_unit_hostname.return_value = 'node0'
59
+        self.gethostname.return_value = 'node0'
60
+        self.getfqdn.return_value = 'node0'
58 61
         _is_clus.return_value = False
59 62
         _config_flag.return_value = False
60 63
         _pg_dir_settings.return_value = {'pg_dir_ip': '192.168.100.201'}
61 64
         _mgmt_int.return_value = 'juju-br0'
65
+        _fabric_int.return_value = 'juju-br0'
62 66
         _gw_int.return_value = ['eth1']
63 67
         napi_ctxt = context.PGGwContext()
64 68
         expect = {
@@ -71,7 +75,9 @@ class PGGwContextTest(CharmTestCase):
71 75
             'neutron_security_groups': None,
72 76
             'neutron_url': 'https://192.168.100.201:9696',
73 77
             'pg_hostname': 'node0',
78
+            'pg_fqdn': 'node0',
74 79
             'interface': 'juju-br0',
80
+            'fabric_interface': 'juju-br0',
75 81
             'label': 'node0',
76 82
             'fabric_mode': 'host',
77 83
             'neutron_alchemy_flags': False,

+ 3
- 14
unit_tests/test_pg_gw_hooks.py View File

@@ -1,5 +1,6 @@
1 1
 from mock import MagicMock, patch, call
2 2
 from test_utils import CharmTestCase
3
+
3 4
 with patch('charmhelpers.core.hookenv.config') as config:
4 5
     config.return_value = 'neutron'
5 6
     import pg_gw_utils as utils
@@ -29,6 +30,7 @@ TO_PATCH = [
29 30
     'ensure_mtu',
30 31
     'add_lcm_key',
31 32
     'determine_packages',
33
+    'load_iptables'
32 34
 ]
33 35
 NEUTRON_CONF_DIR = "/etc/neutron"
34 36
 
@@ -69,21 +71,8 @@ class PGGwHooksTests(CharmTestCase):
69 71
         self.restart_pg.assert_called_with()
70 72
 
71 73
     def test_config_changed_hook(self):
72
-        _pkgs = ['plumgrid-lxc', 'iovisor-dkms']
73
-        self.add_lcm_key.return_value = 0
74
-        self.determine_packages.return_value = [_pkgs]
74
+        self.add_lcm_key.return_value = 1
75 75
         self._call_hook('config-changed')
76
-        self.stop_pg.assert_called_with()
77
-        self.configure_sources.assert_called_with(update=True)
78
-        self.apt_install.assert_has_calls([
79
-            call(_pkgs, fatal=True,
80
-                 options=['--force-yes']),
81
-        ])
82
-        self.load_iovisor.assert_called_with()
83
-        self.ensure_mtu.assert_called_with()
84
-        self.ensure_files.assert_called_with()
85
-        self.CONFIGS.write_all.assert_called_with()
86
-        self.restart_pg.assert_called_with()
87 76
 
88 77
     def test_stop(self):
89 78
         _pkgs = ['plumgrid-lxc', 'iovisor-dkms']

Loading…
Cancel
Save