Merge "Create cells before starting nova services"
This commit is contained in:
commit
a4bddfdb36
@ -72,6 +72,11 @@ options:
|
|||||||
- The username used to authenticate
|
- The username used to authenticate
|
||||||
required: False
|
required: False
|
||||||
type: str
|
type: str
|
||||||
|
command:
|
||||||
|
description:
|
||||||
|
- The command to execute in the container
|
||||||
|
required: False
|
||||||
|
type: str
|
||||||
detach:
|
detach:
|
||||||
description:
|
description:
|
||||||
- Detach from the container after it is created
|
- Detach from the container after it is created
|
||||||
@ -214,6 +219,7 @@ EXAMPLES = '''
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import shlex
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
import docker
|
import docker
|
||||||
@ -229,6 +235,8 @@ class DockerWorker(object):
|
|||||||
self.module = module
|
self.module = module
|
||||||
self.params = self.module.params
|
self.params = self.module.params
|
||||||
self.changed = False
|
self.changed = False
|
||||||
|
# Use this to store arguments to pass to exit_json().
|
||||||
|
self.result = {}
|
||||||
|
|
||||||
# TLS not fully implemented
|
# TLS not fully implemented
|
||||||
# tls_config = self.generate_tls()
|
# tls_config = self.generate_tls()
|
||||||
@ -315,7 +323,8 @@ class DockerWorker(object):
|
|||||||
self.compare_volumes_from(container_info) or
|
self.compare_volumes_from(container_info) or
|
||||||
self.compare_environment(container_info) or
|
self.compare_environment(container_info) or
|
||||||
self.compare_container_state(container_info) or
|
self.compare_container_state(container_info) or
|
||||||
self.compare_dimensions(container_info)
|
self.compare_dimensions(container_info) or
|
||||||
|
self.compare_command(container_info)
|
||||||
)
|
)
|
||||||
|
|
||||||
def compare_ipc_mode(self, container_info):
|
def compare_ipc_mode(self, container_info):
|
||||||
@ -482,6 +491,16 @@ class DockerWorker(object):
|
|||||||
# '' or 0 - both falsey.
|
# '' or 0 - both falsey.
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def compare_command(self, container_info):
|
||||||
|
new_command = self.params.get('command')
|
||||||
|
if new_command is not None:
|
||||||
|
new_command_split = shlex.split(new_command)
|
||||||
|
new_path = new_command_split[0]
|
||||||
|
new_args = new_command_split[1:]
|
||||||
|
if (new_path != container_info['Path'] or
|
||||||
|
new_args != container_info['Args']):
|
||||||
|
return True
|
||||||
|
|
||||||
def parse_image(self):
|
def parse_image(self):
|
||||||
full_image = self.params.get('image')
|
full_image = self.params.get('image')
|
||||||
|
|
||||||
@ -638,6 +657,7 @@ class DockerWorker(object):
|
|||||||
def build_container_options(self):
|
def build_container_options(self):
|
||||||
volumes, binds = self.generate_volumes()
|
volumes, binds = self.generate_volumes()
|
||||||
return {
|
return {
|
||||||
|
'command': self.params.get('command'),
|
||||||
'detach': self.params.get('detach'),
|
'detach': self.params.get('detach'),
|
||||||
'environment': self._format_env_vars(),
|
'environment': self._format_env_vars(),
|
||||||
'host_config': self.build_host_config(binds),
|
'host_config': self.build_host_config(binds),
|
||||||
@ -697,15 +717,22 @@ class DockerWorker(object):
|
|||||||
# dict all the time.
|
# dict all the time.
|
||||||
if isinstance(rc, dict):
|
if isinstance(rc, dict):
|
||||||
rc = rc['StatusCode']
|
rc = rc['StatusCode']
|
||||||
if rc != 0:
|
# Include container's return code, standard output and error in the
|
||||||
self.module.fail_json(
|
# result.
|
||||||
failed=True,
|
self.result['rc'] = rc
|
||||||
changed=True,
|
self.result['stdout'] = self.dc.logs(self.params.get('name'),
|
||||||
msg="Container exited with non-zero return code %s" % rc
|
stdout=True, stderr=False)
|
||||||
)
|
self.result['stderr'] = self.dc.logs(self.params.get('name'),
|
||||||
|
stdout=False, stderr=True)
|
||||||
if self.params.get('remove_on_exit'):
|
if self.params.get('remove_on_exit'):
|
||||||
self.stop_container()
|
self.stop_container()
|
||||||
self.remove_container()
|
self.remove_container()
|
||||||
|
if rc != 0:
|
||||||
|
self.module.fail_json(
|
||||||
|
changed=True,
|
||||||
|
msg="Container exited with non-zero return code %s" % rc,
|
||||||
|
**self.result
|
||||||
|
)
|
||||||
|
|
||||||
def get_container_env(self):
|
def get_container_env(self):
|
||||||
name = self.params.get('name')
|
name = self.params.get('name')
|
||||||
@ -817,6 +844,7 @@ def generate_module():
|
|||||||
auth_password=dict(required=False, type='str', no_log=True),
|
auth_password=dict(required=False, type='str', no_log=True),
|
||||||
auth_registry=dict(required=False, type='str'),
|
auth_registry=dict(required=False, type='str'),
|
||||||
auth_username=dict(required=False, type='str'),
|
auth_username=dict(required=False, type='str'),
|
||||||
|
command=dict(required=False, type='str'),
|
||||||
detach=dict(required=False, type='bool', default=True),
|
detach=dict(required=False, type='bool', default=True),
|
||||||
labels=dict(required=False, type='dict', default=dict()),
|
labels=dict(required=False, type='dict', default=dict()),
|
||||||
name=dict(required=False, type='str'),
|
name=dict(required=False, type='str'),
|
||||||
@ -905,10 +933,10 @@ def main():
|
|||||||
# types. If we ever add method that will have to return some
|
# types. If we ever add method that will have to return some
|
||||||
# meaningful data, we need to refactor all methods to return dicts.
|
# meaningful data, we need to refactor all methods to return dicts.
|
||||||
result = bool(getattr(dw, module.params.get('action'))())
|
result = bool(getattr(dw, module.params.get('action'))())
|
||||||
module.exit_json(changed=dw.changed, result=result)
|
module.exit_json(changed=dw.changed, result=result, **dw.result)
|
||||||
except Exception:
|
except Exception:
|
||||||
module.exit_json(failed=True, changed=True,
|
module.fail_json(changed=True, msg=repr(traceback.format_exc()),
|
||||||
msg=repr(traceback.format_exc()))
|
**dw.result)
|
||||||
|
|
||||||
# import module snippets
|
# import module snippets
|
||||||
from ansible.module_utils.basic import * # noqa
|
from ansible.module_utils.basic import * # noqa
|
||||||
|
51
ansible/roles/nova/tasks/create_cells.yml
Normal file
51
ansible/roles/nova/tasks/create_cells.yml
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
---
|
||||||
|
- name: Create cell0 mappings
|
||||||
|
vars:
|
||||||
|
nova_api: "{{ nova_services['nova-api'] }}"
|
||||||
|
become: true
|
||||||
|
kolla_docker:
|
||||||
|
action: "start_container"
|
||||||
|
command: bash -c 'sudo -E kolla_set_configs && nova-manage cell_v2 map_cell0'
|
||||||
|
common_options: "{{ docker_common_options }}"
|
||||||
|
detach: False
|
||||||
|
image: "{{ nova_api.image }}"
|
||||||
|
labels:
|
||||||
|
BOOTSTRAP:
|
||||||
|
name: "create_cell0_nova"
|
||||||
|
restart_policy: "never"
|
||||||
|
volumes: "{{ nova_api.volumes|reject('equalto', '')|list }}"
|
||||||
|
register: map_cell0
|
||||||
|
changed_when:
|
||||||
|
- map_cell0 is success
|
||||||
|
- '"Cell0 is already setup" not in map_cell0.stdout'
|
||||||
|
failed_when:
|
||||||
|
- map_cell0.rc != 0
|
||||||
|
run_once: True
|
||||||
|
delegate_to: "{{ groups[nova_api.group][0] }}"
|
||||||
|
|
||||||
|
- include_tasks: bootstrap_service.yml
|
||||||
|
when: map_cell0.changed
|
||||||
|
|
||||||
|
- name: Create base cell for legacy instances
|
||||||
|
vars:
|
||||||
|
nova_api: "{{ nova_services['nova-api'] }}"
|
||||||
|
become: true
|
||||||
|
kolla_docker:
|
||||||
|
action: "start_container"
|
||||||
|
command: bash -c 'sudo -E kolla_set_configs && nova-manage cell_v2 create_cell'
|
||||||
|
common_options: "{{ docker_common_options }}"
|
||||||
|
detach: False
|
||||||
|
image: "{{ nova_api.image }}"
|
||||||
|
labels:
|
||||||
|
BOOTSTRAP:
|
||||||
|
name: "create_cell_nova"
|
||||||
|
restart_policy: "never"
|
||||||
|
volumes: "{{ nova_api.volumes|reject('equalto', '')|list }}"
|
||||||
|
register: base_cell
|
||||||
|
changed_when:
|
||||||
|
- base_cell is success
|
||||||
|
failed_when:
|
||||||
|
- base_cell.rc != 0
|
||||||
|
- '"already exists" not in base_cell.stdout'
|
||||||
|
run_once: True
|
||||||
|
delegate_to: "{{ groups[nova_api.group][0] }}"
|
@ -21,7 +21,9 @@
|
|||||||
when: inventory_hostname in groups['nova-api'] or
|
when: inventory_hostname in groups['nova-api'] or
|
||||||
inventory_hostname in groups['compute']
|
inventory_hostname in groups['compute']
|
||||||
|
|
||||||
|
- include_tasks: create_cells.yml
|
||||||
|
|
||||||
- name: Flush handlers
|
- name: Flush handlers
|
||||||
meta: flush_handlers
|
meta: flush_handlers
|
||||||
|
|
||||||
- include_tasks: simple_cell_setup.yml
|
- include_tasks: discover_computes.yml
|
||||||
|
@ -1,31 +1,4 @@
|
|||||||
---
|
---
|
||||||
- name: Create cell0 mappings
|
|
||||||
command: >
|
|
||||||
docker exec nova_api nova-manage cell_v2 map_cell0
|
|
||||||
register: map_cell0
|
|
||||||
changed_when:
|
|
||||||
- map_cell0 is success
|
|
||||||
- '"Cell0 is already setup" not in map_cell0.stdout'
|
|
||||||
failed_when:
|
|
||||||
- map_cell0.rc != 0
|
|
||||||
run_once: True
|
|
||||||
delegate_to: "{{ groups['nova-api'][0] }}"
|
|
||||||
|
|
||||||
- include_tasks: bootstrap_service.yml
|
|
||||||
when: map_cell0.changed
|
|
||||||
|
|
||||||
- name: Create base cell for legacy instances
|
|
||||||
command: >
|
|
||||||
docker exec nova_api nova-manage cell_v2 create_cell
|
|
||||||
register: base_cell
|
|
||||||
changed_when:
|
|
||||||
- base_cell is success
|
|
||||||
failed_when:
|
|
||||||
- base_cell.rc != 0
|
|
||||||
- '"already exists" not in base_cell.stdout'
|
|
||||||
run_once: True
|
|
||||||
delegate_to: "{{ groups['nova-api'][0] }}"
|
|
||||||
|
|
||||||
- name: Waiting for nova-compute service up
|
- name: Waiting for nova-compute service up
|
||||||
command: >
|
command: >
|
||||||
docker exec kolla_toolbox openstack
|
docker exec kolla_toolbox openstack
|
@ -52,6 +52,7 @@ class ModuleArgsTest(base.BaseTestCase):
|
|||||||
auth_password=dict(required=False, type='str', no_log=True),
|
auth_password=dict(required=False, type='str', no_log=True),
|
||||||
auth_registry=dict(required=False, type='str'),
|
auth_registry=dict(required=False, type='str'),
|
||||||
auth_username=dict(required=False, type='str'),
|
auth_username=dict(required=False, type='str'),
|
||||||
|
command=dict(required=False, type='str'),
|
||||||
detach=dict(required=False, type='bool', default=True),
|
detach=dict(required=False, type='bool', default=True),
|
||||||
labels=dict(required=False, type='dict', default=dict()),
|
labels=dict(required=False, type='dict', default=dict()),
|
||||||
name=dict(required=False, type='str'),
|
name=dict(required=False, type='str'),
|
||||||
@ -114,6 +115,7 @@ class ModuleArgsTest(base.BaseTestCase):
|
|||||||
FAKE_DATA = {
|
FAKE_DATA = {
|
||||||
|
|
||||||
'params': {
|
'params': {
|
||||||
|
'command': None,
|
||||||
'detach': True,
|
'detach': True,
|
||||||
'environment': {},
|
'environment': {},
|
||||||
'host_config': {
|
'host_config': {
|
||||||
@ -133,6 +135,7 @@ FAKE_DATA = {
|
|||||||
'vendor': 'ubuntuOS'},
|
'vendor': 'ubuntuOS'},
|
||||||
'image': 'myregistrydomain.com:5000/ubuntu:16.04',
|
'image': 'myregistrydomain.com:5000/ubuntu:16.04',
|
||||||
'name': 'test_container',
|
'name': 'test_container',
|
||||||
|
'remove_on_exit': True,
|
||||||
'volumes': None,
|
'volumes': None,
|
||||||
'tty': False,
|
'tty': False,
|
||||||
},
|
},
|
||||||
@ -210,8 +213,10 @@ class TestContainer(base.BaseTestCase):
|
|||||||
self.assertTrue(self.dw.changed)
|
self.assertTrue(self.dw.changed)
|
||||||
self.fake_data['params'].pop('dimensions')
|
self.fake_data['params'].pop('dimensions')
|
||||||
self.fake_data['params']['host_config']['blkio_weight'] = '10'
|
self.fake_data['params']['host_config']['blkio_weight'] = '10'
|
||||||
|
expected_args = {'command', 'detach', 'environment', 'host_config',
|
||||||
|
'image', 'labels', 'name', 'tty', 'volumes'}
|
||||||
self.dw.dc.create_container.assert_called_once_with(
|
self.dw.dc.create_container.assert_called_once_with(
|
||||||
**self.fake_data['params'])
|
**{k: self.fake_data['params'][k] for k in expected_args})
|
||||||
self.dw.dc.create_host_config.assert_called_with(
|
self.dw.dc.create_host_config.assert_called_with(
|
||||||
cap_add=None, network_mode='host', ipc_mode=None,
|
cap_add=None, network_mode='host', ipc_mode=None,
|
||||||
pid_mode=None, volumes_from=None, blkio_weight=10,
|
pid_mode=None, volumes_from=None, blkio_weight=10,
|
||||||
@ -295,6 +300,31 @@ class TestContainer(base.BaseTestCase):
|
|||||||
self.dw.dc.start.assert_called_once_with(
|
self.dw.dc.start.assert_called_once_with(
|
||||||
container=self.fake_data['params'].get('name'))
|
container=self.fake_data['params'].get('name'))
|
||||||
|
|
||||||
|
def test_start_container_no_detach(self):
|
||||||
|
self.fake_data['params'].update({'name': 'my_container',
|
||||||
|
'detach': False})
|
||||||
|
self.dw = get_DockerWorker(self.fake_data['params'])
|
||||||
|
self.dw.dc.images = mock.MagicMock(
|
||||||
|
return_value=self.fake_data['images'])
|
||||||
|
self.dw.dc.containers = mock.MagicMock(side_effect=[
|
||||||
|
[], self.fake_data['containers'], self.fake_data['containers'],
|
||||||
|
self.fake_data['containers']])
|
||||||
|
self.dw.dc.wait = mock.MagicMock(return_value={'StatusCode': 0})
|
||||||
|
self.dw.dc.logs = mock.MagicMock(
|
||||||
|
side_effect=['fake stdout', 'fake stderr'])
|
||||||
|
self.dw.start_container()
|
||||||
|
self.assertTrue(self.dw.changed)
|
||||||
|
name = self.fake_data['params'].get('name')
|
||||||
|
self.dw.dc.wait.assert_called_once_with(name)
|
||||||
|
self.dw.dc.logs.assert_has_calls([
|
||||||
|
mock.call(name, stdout=True, stderr=False),
|
||||||
|
mock.call(name, stdout=False, stderr=True)])
|
||||||
|
self.dw.dc.stop.assert_called_once_with(name, timeout=10)
|
||||||
|
self.dw.dc.remove_container.assert_called_once_with(
|
||||||
|
container=name, force=True)
|
||||||
|
expected = {'rc': 0, 'stdout': 'fake stdout', 'stderr': 'fake stderr'}
|
||||||
|
self.assertEqual(expected, self.dw.result)
|
||||||
|
|
||||||
def test_stop_container(self):
|
def test_stop_container(self):
|
||||||
self.dw = get_DockerWorker({'name': 'my_container',
|
self.dw = get_DockerWorker({'name': 'my_container',
|
||||||
'action': 'stop_container'})
|
'action': 'stop_container'})
|
||||||
|
Loading…
Reference in New Issue
Block a user