Browse code

Fix multinode mode for devstack

Extend the devstack job so that it can support both single and multinode
cases. Multinode mode require extra settings in devstack configuration,
some of which as subnode specific, some controller specific.

Also keep a simple devstack-multinode job defined for now so we can run
a multinode job in devstack gate, until the full tempest multinode job
is ready to match the old
gate-tempest-dsvm-neutron-multinode-full-ubuntu-xenial-nv.

Fixing multinode also requires sharing the CA configuration between
controller and peers, overlay network configuration for communication
between virtual machines and running discover_hosts for nova after the
subnode has been setup.

The extra orchestration required for multinode is encoded in a
dedicated role to allow for jobs in other repos to re-use it.

Change-Id: I2dcbd9bdb401860820e655d97aa3c4775af2827f

Andrea Frittoli authored on 2018/02/18 07:21:26
Showing 9 changed files
... ...
@@ -16,19 +16,24 @@
16 16
       - name: compute1
17 17
         label: ubuntu-xenial
18 18
     groups:
19
+      # Node where tests are executed and test results collected
19 20
       - name: tempest
20 21
         nodes:
21 22
           - controller
23
+      # Nodes running the compute service
22 24
       - name: compute
23 25
         nodes:
24 26
           - controller
25 27
           - compute1
28
+      # Nodes that are not the controller
26 29
       - name: subnode
27 30
         nodes:
28 31
           - compute1
32
+      # Switch node for multinode networking setup
29 33
       - name: switch
30 34
         nodes:
31 35
           - controller
36
+      # Peer nodes for multinode networking setup
32 37
       - name: peers
33 38
         nodes:
34 39
           - compute1
... ...
@@ -45,7 +50,7 @@
45 45
       all single Devstack jobs, single or multinode.
46 46
       Variables are defined in job.vars, which is what is then used by single
47 47
       node jobs and by multi node jobs for the controller, as well as in
48
-      job.group-vars.peers, which is what is used by multi node jobs for peer
48
+      job.group-vars.peers, which is what is used by multi node jobs for subnode
49 49
       nodes (everything but the controller).
50 50
     required-projects:
51 51
       - openstack-dev/devstack
... ...
@@ -76,7 +81,6 @@
76 76
         # from the location below for all the CI jobs.
77 77
         ETCD_DOWNLOAD_URL: http://tarballs.openstack.org/etcd/
78 78
       devstack_services:
79
-        # Ignore base set of services setup by test-matrix.
80 79
         # Ignore any default set by devstack. Emit a "disable_all_services".
81 80
         base: false
82 81
       zuul_copy_output:
... ...
@@ -119,7 +123,7 @@
119 119
         localrc: True
120 120
         stackenv: True
121 121
     group-vars:
122
-      peers:
122
+      subnode:
123 123
         devstack_localrc:
124 124
           DATABASE_PASSWORD: secretdatabase
125 125
           RABBIT_PASSWORD: secretrabbit
... ...
@@ -156,7 +160,9 @@
156 156
     name: devstack
157 157
     parent: devstack-base
158 158
     description: |
159
-      Single or multi node devstack job for integration gate.
159
+      Base devstack job for integration gate.
160
+
161
+      This base job can be used for single node and multinode devstack jobs.
160 162
     nodeset: openstack-single-node
161 163
     required-projects:
162 164
       - openstack/cinder
... ...
@@ -178,6 +184,15 @@
178 178
         NOVA_VNC_ENABLED: true
179 179
         VNCSERVER_LISTEN: 0.0.0.0
180 180
         VNCSERVER_PROXYCLIENT_ADDRESS: "{{ hostvars[inventory_hostname]['nodepool']['private_ipv4'] }}"
181
+        # Multinode specific settings
182
+        SERVICE_HOST: "{{ hostvars['controller']['nodepool']['private_ipv4'] }}"
183
+        HOST_IP: "{{ hostvars['controller']['nodepool']['private_ipv4'] }}"
184
+        PUBLIC_BRIDGE_MTU: "{{ external_bridge_mtu }}"
185
+      devstack_localconf:
186
+        post-config:
187
+          $NEUTRON_CONF:
188
+            DEFAULT:
189
+              global_physnet_mtu: "{{ external_bridge_mtu }}"
181 190
       devstack_services:
182 191
         # Core services enabled for this branch.
183 192
         # This list replaces the test-matrix.
... ...
@@ -254,16 +269,25 @@
254 254
           # Test matrix emits ceilometer but ceilomenter is not installed in the
255 255
           # integrated gate, so specifying the services has not effect.
256 256
           # ceilometer-*: false
257
+        devstack_localrc:
258
+          # Multinode specific settings
259
+          HOST_IP: "{{ hostvars[inventory_hostname]['nodepool']['private_ipv4'] }}"
260
+          SERVICE_HOST: "{{ hostvars['controller']['nodepool']['private_ipv4'] }}"
261
+          PUBLIC_BRIDGE_MTU: "{{ external_bridge_mtu }}"
262
+          # Subnode specific settings
263
+          DATABASE_TYPE: mysql
264
+          GLANCE_HOSTPORT: "{{ hostvars['controller']['nodepool']['private_ipv4'] }}:9292"
265
+          Q_HOST: "{{ hostvars['controller']['nodepool']['private_ipv4'] }}"
266
+          RABBIT_HOST: "{{ hostvars['controller']['nodepool']['private_ipv4'] }}"
267
+          DATABASE_HOST: "{{ hostvars['controller']['nodepool']['private_ipv4'] }}"
257 268
 
258 269
 - job:
259 270
     name: devstack-multinode
260
-    parent: devstack-base
261
-    description: Base devstack multinode job
271
+    parent: devstack
262 272
     nodeset: openstack-two-node
263
-    # NOTE(andreaf) The multinode job is useful to see the setup of different
264
-    # services on different nodes, however the subnode configuration is not
265
-    # ready yet. Until then this job should stay non-voting.
266
-    voting: false
273
+    description: |
274
+      Simple multinode test to verify multinode functionality on devstack side.
275
+      This is not meant to be used as a parent job.
267 276
 
268 277
 - job:
269 278
     name: devstack-tox-base
... ...
@@ -1,3 +1,3 @@
1 1
 - hosts: all
2 2
   roles:
3
-    - run-devstack
3
+    - orchestrate-devstack
... ...
@@ -1,15 +1,25 @@
1
-- hosts: controller
2
-  roles:
3
-    - role: test-matrix
4
-      test_matrix_role: primary 
5
-
6
-- hosts: subnode
7
-  roles:
8
-    - role: test-matrix
9
-      test_matrix_role: subnode
10
-
11 1
 - hosts: all
2
+  pre_tasks:
3
+    - name: Gather minimum local MTU
4
+      set_fact:
5
+        local_mtu: >
6
+          {% set mtus = [] -%}
7
+          {% for interface in ansible_interfaces -%}
8
+            {% set interface_variable = 'ansible_' + interface -%}
9
+            {% if interface_variable in hostvars[inventory_hostname] -%}
10
+              {% set _ = mtus.append(hostvars[inventory_hostname][interface_variable]['mtu']|int) -%}
11
+            {% endif -%}
12
+          {% endfor -%}
13
+          {{- mtus|min -}}
14
+    - name: Calculate external_bridge_mtu
15
+      # 50 bytes is overhead for vxlan (which is greater than GRE
16
+      # allowing us to use either overlay option with this MTU.
17
+      # TODO(andreaf) This should work, but it may have to be reconcilied with
18
+      # the MTU setting used by the multinode setup roles in multinode pre.yaml
19
+      set_fact:
20
+        external_bridge_mtu: "{{ local_mtu | int - 50 }}"
12 21
   roles:
22
+    - test-matrix
13 23
     - configure-swap
14 24
     - setup-stack-user
15 25
     - setup-tempest-user
16 26
new file mode 100644
... ...
@@ -0,0 +1,24 @@
0
+Orchestrate a devstack
1
+
2
+Runs devstack in a multinode scenario, with one controller node
3
+and a group of subnodes.
4
+
5
+The reason for this role is so that jobs in other repository may
6
+run devstack in their plays with no need for re-implementing the
7
+orchestration logic.
8
+
9
+The "run-devstack" role is available to run devstack with no
10
+orchestration.
11
+
12
+This role sets up the controller and CA first, it then pushes CA
13
+data to sub-nodes and run devstack there. The only requirement for
14
+this role is for the controller inventory_hostname to be "controller"
15
+and for all sub-nodes to be defined in a group called "subnode".
16
+
17
+
18
+**Role Variables**
19
+
20
+.. zuul:rolevar:: devstack_base_dir
21
+   :default: /opt/stack
22
+
23
+   The devstack base directory.
0 24
new file mode 100644
... ...
@@ -0,0 +1 @@
0
+devstack_base_dir: /opt/stack
0 1
new file mode 100644
... ...
@@ -0,0 +1,38 @@
0
+- name: Run devstack on the controller
1
+  include_role:
2
+    name: run-devstack
3
+  when: inventory_hostname == 'controller'
4
+
5
+- name: Setup devstack on sub-nodes
6
+  block:
7
+
8
+  - name: Sync CA data to subnodes (when any)
9
+    # Only do this if the tls-proxy service is defined and enabled
10
+    include_role:
11
+      name: sync-devstack-data
12
+    when: devstack_services['tls-proxy']|default(false)
13
+
14
+  - name: Run devstack on the sub-nodes
15
+    include_role:
16
+      name: run-devstack
17
+    when: inventory_hostname in groups['subnode']
18
+
19
+  - name: Discover hosts
20
+    # Discovers compute nodes (subnodes) and maps them to cells. Only run
21
+    # on the controller node.
22
+    # NOTE(mriedem): We want to remove this if/when nova supports
23
+    # auto-registration of computes with cells, but that's not happening in
24
+    # Ocata.
25
+    # NOTE(andreaf) This is taken (NOTE included) from the discover_hosts
26
+    # function in devstack gate. Since this is now in devstack, which is
27
+    # branched, we know that the discover_hosts tool exists.
28
+    become: true
29
+    become_user: stack
30
+    shell: ./tools/discover_hosts.sh
31
+    args:
32
+      chdir: "{{ devstack_base_dir }}/devstack"
33
+    when: inventory_hostname == 'controller'
34
+
35
+  when:
36
+    - '"controller" in hostvars'
37
+    - '"subnode" in groups'
0 38
new file mode 100644
... ...
@@ -0,0 +1,12 @@
0
+Sync devstack data for multinode configurations
1
+
2
+Sync any data files which include certificates to be used if TLS is enabled.
3
+This role must be executed on the controller and it pushes data to all
4
+subnodes.
5
+
6
+**Role Variables**
7
+
8
+.. zuul:rolevar:: devstack_base_dir
9
+   :default: /opt/stack
10
+
11
+   The devstack base directory.
0 12
new file mode 100644
... ...
@@ -0,0 +1 @@
0
+devstack_base_dir: /opt/stack
0 1
new file mode 100644
... ...
@@ -0,0 +1,48 @@
0
+- name: Ensure the data folder exists
1
+  become: true
2
+  file:
3
+    path: "{{ devstack_base_dir }}/data"
4
+    state: directory
5
+    owner: stack
6
+    group: stack
7
+    mode: 0755
8
+  when: 'inventory_hostname in groups["subnode"]|default([])'
9
+
10
+- name: Ensure the CA folder exists
11
+  become: true
12
+  file:
13
+    path: "{{ devstack_base_dir }}/data/CA"
14
+    state: directory
15
+    owner: stack
16
+    group: stack
17
+    mode: 0755
18
+  when: 'inventory_hostname in groups["subnode"]|default([])'
19
+
20
+- name: Pull the CA certificate and folder
21
+  become: true
22
+  synchronize:
23
+    src: "{{ item }}"
24
+    dest: "{{ zuul.executor.work_root }}/{{ item | basename }}"
25
+    mode: pull
26
+  with_items:
27
+    - "{{ devstack_base_dir }}/data/ca-bundle.pem"
28
+    - "{{ devstack_base_dir }}/data/CA"
29
+  when: inventory_hostname == 'controller'
30
+
31
+- name: Push the CA certificate
32
+  become: true
33
+  become_user: stack
34
+  synchronize:
35
+    src: "{{ zuul.executor.work_root }}/ca-bundle.pem"
36
+    dest: "{{ devstack_base_dir }}/data/ca-bundle.pem"
37
+    mode: push
38
+  when: 'inventory_hostname in groups["subnode"]|default([])'
39
+
40
+- name: Push the CA folder
41
+  become: true
42
+  become_user: stack
43
+  synchronize:
44
+    src: "{{ zuul.executor.work_root }}/CA/"
45
+    dest: "{{ devstack_base_dir }}/data/"
46
+    mode: push
47
+  when: 'inventory_hostname in groups["subnode"]|default([])'