summaryrefslogtreecommitdiffstats
path: root/apex/tests
diff options
context:
space:
mode:
Diffstat (limited to 'apex/tests')
-rw-r--r--apex/tests/config/98faaca.diff331
-rw-r--r--apex/tests/test_apex_build_utils.py21
-rw-r--r--apex/tests/test_apex_common_builder.py69
-rw-r--r--apex/tests/test_apex_common_utils.py48
-rw-r--r--apex/tests/test_apex_deploy.py70
-rw-r--r--apex/tests/test_apex_overcloud_builder.py65
-rw-r--r--apex/tests/test_apex_overcloud_deploy.py159
-rw-r--r--apex/tests/test_apex_undercloud.py29
8 files changed, 763 insertions, 29 deletions
diff --git a/apex/tests/config/98faaca.diff b/apex/tests/config/98faaca.diff
new file mode 100644
index 0000000..68a66fb
--- /dev/null
+++ b/apex/tests/config/98faaca.diff
@@ -0,0 +1,331 @@
+From 98faacad44e39a456d9fe1a1d21f5a65e8de4fc1 Mon Sep 17 00:00:00 2001
+From: Janki Chhatbar <jchhatba@redhat.com>
+Date: Tue, 23 Jan 2018 22:43:49 +0530
+Subject: [PATCH] Minor update steps for ODL
+
+Updating OpenStack (within release) means updating ODL from v1 to v1.1.
+This is done by "openstack overcloud update" which collects
+update_tasks. ODL needs 2 different steps to achieve this
+minor update. These are called Level1 and Level2. L1 is
+simple - stop ODL, update, start. This is taken care by paunch
+and no separate implementation is needed. L2 has extra steps
+which are implemented in update_tasks and post_update_tasks.
+
+Updating ODL within the same major release (1->1.1) consists of either
+L1 or L2 steps. These steps are decided from ODLUpdateLevel parameter
+specified in environments/services-docker/update-odl.yaml.
+
+Upgrading ODL to the next major release (1.1->2) requires
+only the L2 steps. These are implemented as upgrade_tasks and
+post_upgrade_tasks in https://review.openstack.org/489201.
+
+Steps involved in level 2 update are
+ 1. Block OVS instances to connect to ODL
+ 2. Set ODL upgrade flag to True
+ 3. Start ODL
+ 4. Start Neutron re-sync and wait for it to finish
+ 5. Delete OVS groups and ports
+ 6. Stop OVS
+ 7. Unblock OVS ports
+ 8. Start OVS
+ 9. Unset ODL upgrade flag
+
+These steps are exactly same as upgrade_tasks.
+The logic implemented is:
+follow upgrade_tasks; when update_level == 2
+
+Change-Id: Ie532800663dd24313a7350b5583a5080ddb796e7
+---
+
+diff --git a/common/deploy-steps.j2 b/common/deploy-steps.j2
+index 595e16c..c4fb05f 100644
+--- a/common/deploy-steps.j2
++++ b/common/deploy-steps.j2
+@@ -23,6 +23,7 @@
+ {% set post_upgrade_steps_max = 4 -%}
+ {% set fast_forward_upgrade_steps_max = 9 -%}
+ {% set fast_forward_upgrade_prep_steps_max = 3 -%}
++{% set post_update_steps_max = 4 -%}
+
+ heat_template_version: queens
+
+@@ -590,3 +591,15 @@
+ - include_tasks: {{role.name}}/fast_forward_upgrade_tasks.yaml
+ when: role_name == '{{role.name}}' and ansible_hostname == {{role.name}}[0]
+ {%- endfor %}
++ post_update_steps_tasks: |
++{%- for role in roles %}
++ - include: {{role.name}}/post_update_tasks.yaml
++ when: role_name == '{{role.name}}'
++{%- endfor %}
++ post_update_steps_playbook: |
++ - hosts: overcloud
++ tasks:
++ - include: post_update_steps_tasks.yaml
++ with_sequence: start=0 end={{post_update_steps_max-1}}
++ loop_control:
++ loop_var: step
+diff --git a/common/services.yaml b/common/services.yaml
+index 2a62c1b..c197b05 100644
+--- a/common/services.yaml
++++ b/common/services.yaml
+@@ -283,6 +283,16 @@
+ expression: coalesce($.data, []).where($ != null).select($.get('update_tasks')).where($ != null).flatten().distinct()
+ data: {get_attr: [ServiceChain, role_data]}
+
++ PostUpdateTasks:
++ type: OS::Heat::Value
++ properties:
++ type: comma_delimited_list
++ value:
++ yaql:
++ # Note we use distinct() here to filter any identical tasks, e.g yum update for all services
++ expression: coalesce($.data, []).where($ != null).select($.get('post_update_tasks')).where($ != null).flatten().distinct()
++ data: {get_attr: [ServiceChain, role_data]}
++
+ UpgradeBatchTasks:
+ type: OS::Heat::Value
+ properties:
+@@ -349,6 +359,7 @@
+ upgrade_tasks: {get_attr: [UpgradeTasks, value]}
+ post_upgrade_tasks: {get_attr: [PostUpgradeTasks, value]}
+ update_tasks: {get_attr: [UpdateTasks, value]}
++ post_update_tasks: {get_attr: [PostUpdateTasks, value]}
+ upgrade_batch_tasks: {get_attr: [UpgradeBatchTasks, value]}
+ service_metadata_settings: {get_attr: [ServiceServerMetadataHook, metadata]}
+
+diff --git a/docker/services/opendaylight-api.yaml b/docker/services/opendaylight-api.yaml
+index 6175db9..3cafe53 100644
+--- a/docker/services/opendaylight-api.yaml
++++ b/docker/services/opendaylight-api.yaml
+@@ -44,6 +44,14 @@
+ type: string
+ description: Specifies the default CA cert to use if TLS is used for
+ services in the internal network.
++ ODLUpdateLevel:
++ default: 1
++ description: Specify the level of update
++ type: number
++ constraints:
++ - allowed_values:
++ - 1
++ - 2
+
+ conditions:
+
+@@ -167,23 +175,25 @@
+ - opendaylight_enabled.rc == 0
+ service: name=opendaylight state=stopped enabled=no
+ # Containarised deployment upgrade steps
+- - name: remove journal and snapshots
+- when: step|int == 0
+- file:
+- path: /var/lib/opendaylight/{{item}}
+- state: absent
+- with_items:
+- - snapshots
+- - journal
+- - name: Set ODL upgrade flag to True
+- copy:
+- dest: /var/lib/opendaylight/etc/opendaylight/datastore/initial/config/genius-mdsalutil-config.xml
+- content: |
+- <config xmlns="urn:opendaylight:params:xml:ns:yang:mdsalutil">
+- <upgradeInProgress>true</upgradeInProgress>
+- </config>
+- when: step|int == 1
+- post_upgrade_tasks:
++ - name: ODL container L2 update and upgrade tasks
++ block: &odl_container_upgrade_tasks
++ - name: remove journal and snapshots
++ when: step|int == 0
++ file:
++ path: /var/lib/opendaylight/{{item}}
++ state: absent
++ with_items:
++ - snapshots
++ - journal
++ - name: Set ODL upgrade flag to True
++ copy:
++ dest: /var/lib/opendaylight/etc/opendaylight/datastore/initial/config/genius-mdsalutil-config.xml
++ content: |
++ <config xmlns="urn:opendaylight:params:xml:ns:yang:mdsalutil">
++ <upgradeInProgress>true</upgradeInProgress>
++ </config>
++ when: step|int == 1
++ post_upgrade_tasks: &odl_container_post_upgrade_tasks
+ - name: Unset upgrade flag in ODL
+ shell:
+ str_replace:
+@@ -192,7 +202,20 @@
+ -H "Content-Type: application/json" \
+ $ODL_URI/restconf/config/genius-mdsalutil:config'
+ params:
+- $ODL_USERNAME: {get_param: [OpenDaylightBase, OpenDaylightUsername]}
+- $ODL_PASSWORD: {get_param: [OpenDaylightBase, OpenDaylightPassword]}
++ $ODL_USERNAME: {get_attr: [OpenDaylightBase, role_data, config_settings, 'opendaylight::username']}
++ $ODL_PASSWORD: {get_attr: [OpenDaylightBase, role_data, config_settings, 'opendaylight::password']}
+ $ODL_URI: {get_param: [EndpointMap, OpenDaylightInternal, uri]}
+ when: step|int == 0
++ update_tasks:
++ - name: Get ODL update level
++ block: &get_odl_update_level
++ - name: store update level to update_level variable
++ set_fact:
++ odl_update_level: {get_param: ODLUpdateLevel}
++ - name: Run L2 update tasks that are similar to upgrade_tasks when update level is 2
++ block: *odl_container_upgrade_tasks
++ when: odl_update_level == 2
++ post_update_tasks:
++ - block: *get_odl_update_level
++ - block: *odl_container_post_upgrade_tasks
++ when: odl_update_level == 2
+\ No newline at end of file
+diff --git a/environments/services-docker/update-odl.yaml b/environments/services-docker/update-odl.yaml
+new file mode 100644
+index 0000000..87d74ef
+--- /dev/null
++++ b/environments/services-docker/update-odl.yaml
+@@ -0,0 +1,11 @@
++# This file describes parameters needed for ODL update.
++# This file is to be used along with other env files during
++# level 2 minor update.
++# Level 2 update involves yang changes in ODL within same ODL release and
++# hence needs DB wipe and resync.
++# Level 1 is simple update - stop ODL, pull new image, start ODL
++# This file is not be used during level1 update or major upgrade.
++# In case doubt, please reach out to ODL developers on #tripleo IRC channel
++
++parameter_defaults:
++ ODLUpdateLevel: 2
+\ No newline at end of file
+diff --git a/puppet/services/opendaylight-ovs.yaml b/puppet/services/opendaylight-ovs.yaml
+index 3390645..958e1bb 100644
+--- a/puppet/services/opendaylight-ovs.yaml
++++ b/puppet/services/opendaylight-ovs.yaml
+@@ -104,6 +104,14 @@
+ type: string
+ description: Specifies the default CA cert to use if TLS is used for
+ services in the internal network.
++ ODLUpdateLevel:
++ default: 1
++ description: Specify the level of update
++ type: number
++ constraints:
++ - allowed_values:
++ - 1
++ - 2
+
+ parameter_groups:
+ - label: deprecated
+@@ -230,14 +238,16 @@
+ - openvswitch_enabled.rc == 0
+ service: name=openvswitch state=stopped
+ # Container upgrade steps.
+- - name: Block connections to ODL. #This rule will be inserted at the top.
+- iptables: chain=OUTPUT action=insert protocol=tcp destination_port={{ item }} jump=DROP
+- when: step|int == 0
+- with_items:
+- - 6640
+- - 6653
+- - 6633
+- post_upgrade_tasks:
++ - name: ODL container L2 update and upgrade tasks
++ block: &odl_container_upgrade_tasks
++ - name: Block connections to ODL. #This rule will be inserted at the top.
++ iptables: chain=OUTPUT action=insert protocol=tcp destination_port={{ item }} jump=DROP
++ when: step|int == 0
++ with_items:
++ - 6640
++ - 6653
++ - 6633
++ post_upgrade_tasks: &odl_container_post_upgrade_tasks
+ - name: Check service openvswitch is running
+ command: systemctl is-active --quiet openvswitch
+ tags: common
+@@ -260,6 +270,20 @@
+ - name: start openvswitch service
+ when: step|int == 3
+ service : name=openvswitch state=started
++ update_tasks:
++ - name: Get ODL update level
++ block: &get_odl_update_level
++ - name: store update level to update_level variable
++ set_fact:
++ odl_update_level: {get_param: ODLUpdateLevel}
++ - name: Run L2 update tasks that are similar to upgrade_tasks when update level is 2
++ block: *odl_container_upgrade_tasks
++ when: odl_update_level == 2
++ post_update_tasks:
++ - block: *get_odl_update_level
++ - block: *odl_container_post_upgrade_tasks
++ when: odl_update_level == 2
++
+ metadata_settings:
+ if:
+ - internal_tls_enabled
+@@ -267,4 +291,4 @@
+ - service: ovs
+ network: {get_param: [ServiceNetMap, OpendaylightApiNetwork]}
+ type: node
+- - null
++ - null
+\ No newline at end of file
+diff --git a/releasenotes/notes/odl_upgrade-f5540d242b9a6b52.yaml b/releasenotes/notes/odl_upgrade-f5540d242b9a6b52.yaml
+index 45703d0..e2943de 100644
+--- a/releasenotes/notes/odl_upgrade-f5540d242b9a6b52.yaml
++++ b/releasenotes/notes/odl_upgrade-f5540d242b9a6b52.yaml
+@@ -1,6 +1,6 @@
+ ---
+
+-features:
++upgrade:
+ - Add ODL upgradability
+ Steps of upgrade are as follows
+ 1. Block OVS instances to connect to ODL done in upgrade_tasks
+diff --git a/releasenotes/notes/update_odl-cb997ce5c136ebb7.yaml b/releasenotes/notes/update_odl-cb997ce5c136ebb7.yaml
+new file mode 100644
+index 0000000..1bcf8ed
+--- /dev/null
++++ b/releasenotes/notes/update_odl-cb997ce5c136ebb7.yaml
+@@ -0,0 +1,19 @@
++---
++features:
++ - Minor update ODL steps are added. ODL minor update (within same ODL
++ release) can have 2 different workflow. These are called level 1 and
++ level2. Level 1 is simple - stop, update and start ODL. Level 2 is
++ complex and involved yang model changes. This requires wiping of
++ DB and resync to repopulate the data.
++ Steps involved in level 2 update are
++ 1. Block OVS instances to connect to ODL
++ 2. Set ODL upgrade flag to True
++ 3. Start ODL
++ 4. Start Neutron re-sync and wait for it to finish
++ 5. Delete OVS groups and ports
++ 6. Stop OVS
++ 7. Unblock OVS ports
++ 8. Start OVS
++ 9. Unset ODL upgrade flag
++ To achieve L2 update, use "-e environments/services-docker/
++ update-odl.yaml" along with other env files to the update command.
+\ No newline at end of file
+diff --git a/tools/yaml-validate.py b/tools/yaml-validate.py
+index 59473f5..9ab6a87 100755
+--- a/tools/yaml-validate.py
++++ b/tools/yaml-validate.py
+@@ -46,11 +46,11 @@
+ OPTIONAL_DOCKER_SECTIONS = ['docker_puppet_tasks', 'upgrade_tasks',
+ 'fast_forward_upgrade_tasks',
+ 'post_upgrade_tasks', 'update_tasks',
+- 'service_config_settings', 'host_prep_tasks',
+- 'metadata_settings', 'kolla_config',
+- 'global_config_settings', 'logging_source',
+- 'logging_groups', 'external_deploy_tasks',
+- 'external_post_deploy_tasks',
++ 'post_update_tasks', 'service_config_settings',
++ 'host_prep_tasks', 'metadata_settings',
++ 'kolla_config', 'global_config_settings',
++ 'logging_source', 'logging_groups',
++ 'external_deploy_tasks', 'external_post_deploy_tasks',
+ 'docker_config_scripts', 'step_config']
+ REQUIRED_DOCKER_PUPPET_CONFIG_SECTIONS = ['config_volume', 'step_config',
+ 'config_image']
diff --git a/apex/tests/test_apex_build_utils.py b/apex/tests/test_apex_build_utils.py
index d9d542d..f18103c 100644
--- a/apex/tests/test_apex_build_utils.py
+++ b/apex/tests/test_apex_build_utils.py
@@ -9,17 +9,20 @@
import argparse
import git
+import os
+import unittest
from mock import patch
from apex import build_utils
+from apex.tests import constants as con
from nose.tools import (
assert_is_instance,
assert_raises)
-class TestBuildUtils(object):
+class TestBuildUtils(unittest.TestCase):
@classmethod
def setup_class(cls):
"""This method is run once for each class before any tests are run"""
@@ -165,3 +168,19 @@ class TestBuildUtils(object):
def test_main_debug(self, mock_get_parser):
with patch.object(build_utils.sys, 'argv', self.sys_argv_debug):
build_utils.main()
+
+ def test_strip_patch_sections(self):
+ with open(os.path.join(con.TEST_DUMMY_CONFIG, '98faaca.diff')) as fh:
+ dummy_patch = fh.read()
+ tmp_patch = build_utils.strip_patch_sections(dummy_patch)
+ self.assertNotRegex(tmp_patch, 'releasenotes')
+ self.assertNotRegex(tmp_patch, 'Minor update ODL steps')
+ self.assertNotRegex(tmp_patch, 'Steps of upgrade are as follows')
+ self.assertNotRegex(tmp_patch, 'Steps invlolved in level 2 update')
+
+ def test_strip_no_patch_sections(self):
+ with open(os.path.join(con.TEST_DUMMY_CONFIG, '98faaca.diff')) as fh:
+ dummy_patch = fh.read()
+ tmp_patch = build_utils.strip_patch_sections(dummy_patch,
+ sections=[])
+ self.assertEqual(dummy_patch, tmp_patch)
diff --git a/apex/tests/test_apex_common_builder.py b/apex/tests/test_apex_common_builder.py
index c32f72c..d501746 100644
--- a/apex/tests/test_apex_common_builder.py
+++ b/apex/tests/test_apex_common_builder.py
@@ -10,11 +10,20 @@
import unittest
from apex.builders import common_builder as c_builder
+from apex.builders import exceptions
from apex.common import constants as con
from mock import patch
from mock import mock_open
from mock import MagicMock
+DOCKER_YAML = {
+ 'resource_registry': {
+ 'OS::TripleO::Services::NovaApi': '../docker/services/nova-api.yaml',
+ 'OS::TripleO::Services::NovaConductor':
+ '../docker/services/nova-conductor.yaml'
+ }
+}
+
class TestCommonBuilder(unittest.TestCase):
@classmethod
@@ -68,6 +77,54 @@ class TestCommonBuilder(unittest.TestCase):
mock_customize.assert_called_once_with(test_virt_ops, 'dummy.qcow2')
@patch('builtins.open', mock_open())
+ @patch('apex.build_utils.get_patch')
+ @patch('apex.virtual.utils.virt_customize')
+ def test_add_upstream_patches_docker_puppet(
+ self, mock_customize, mock_get_patch):
+ change_id = 'I301370fbf47a71291614dd60e4c64adc7b5ebb42'
+ patches = [{
+ 'change-id': change_id,
+ 'project': 'openstack/puppet-tripleo'
+ }]
+ project_path = '/etc/puppet/modules/tripleo'
+ patch_file = "{}.patch".format(change_id)
+ patch_file_path = "/dummytmp/{}".format(patch_file)
+ test_virt_ops = [
+ {con.VIRT_INSTALL: 'patch'},
+ {con.VIRT_UPLOAD: "{}:{}".format(patch_file_path,
+ project_path)},
+ {con.VIRT_RUN_CMD: "cd {} && patch -p1 < {}".format(
+ project_path, patch_file)}]
+ mock_get_patch.return_value = 'some random diff'
+ c_builder.add_upstream_patches(patches, 'dummy.qcow2', '/dummytmp/',
+ uc_ip='192.0.2.1',
+ docker_tag='latest')
+ mock_customize.assert_called_once_with(test_virt_ops, 'dummy.qcow2')
+
+ @patch('builtins.open', mock_open())
+ @patch('apex.builders.common_builder.project_to_docker_image')
+ @patch('apex.builders.overcloud_builder.build_dockerfile')
+ @patch('apex.build_utils.get_patch')
+ @patch('apex.virtual.utils.virt_customize')
+ def test_add_upstream_patches_docker_python(
+ self, mock_customize, mock_get_patch, mock_build_docker_file,
+ mock_project2docker):
+ mock_project2docker.return_value = ['NovaApi']
+ change_id = 'I301370fbf47a71291614dd60e4c64adc7b5ebb42'
+ patches = [{
+ 'change-id': change_id,
+ 'project': 'openstack/nova'
+ }]
+ mock_get_patch.return_value = 'some random diff'
+ services = c_builder.add_upstream_patches(patches, 'dummy.qcow2',
+ '/dummytmp/',
+ uc_ip='192.0.2.1',
+ docker_tag='latest')
+ assert mock_customize.not_called
+ assert mock_build_docker_file.called
+ self.assertSetEqual(services, {'NovaApi'})
+
+ @patch('builtins.open', mock_open())
@patch('apex.virtual.utils.virt_customize')
def test_add_repo(self, mock_customize):
c_builder.add_repo('fake/url', 'dummyrepo', 'dummy.qcow2',
@@ -85,3 +142,15 @@ class TestCommonBuilder(unittest.TestCase):
self.assertEqual(c_builder.create_git_archive('fake/url', 'dummyrepo',
'/dummytmp/'),
'/dummytmp/dummyrepo.tar')
+
+ def test_project_to_docker_image(self):
+ found_services = c_builder.project_to_docker_image(project='nova')
+ assert 'nova-api' in found_services
+
+ @patch('apex.common.utils.open_webpage')
+ def test_project_to_docker_image_bad_web_content(
+ self, mock_open_web):
+ mock_open_web.return_value = b'{"blah": "blah"}'
+ self.assertRaises(exceptions.ApexCommonBuilderException,
+ c_builder.project_to_docker_image,
+ 'nova')
diff --git a/apex/tests/test_apex_common_utils.py b/apex/tests/test_apex_common_utils.py
index 6f2a947..0e4041c 100644
--- a/apex/tests/test_apex_common_utils.py
+++ b/apex/tests/test_apex_common_utils.py
@@ -12,12 +12,14 @@ import os
import shutil
import urllib.error
+from apex.common import exceptions
from apex.common import utils
from apex.settings.network_settings import NetworkSettings
from apex.tests.constants import (
TEST_CONFIG_DIR,
TEST_PLAYBOOK_DIR)
+from mock import patch, mock_open
from nose.tools import (
assert_equal,
assert_is_instance,
@@ -25,6 +27,7 @@ from nose.tools import (
assert_raises)
NET_SETS = os.path.join(TEST_CONFIG_DIR, 'network', 'network_settings.yaml')
+a_mock_open = mock_open(read_data=None)
class TestCommonUtils:
@@ -100,3 +103,48 @@ class TestCommonUtils:
url, ['dummy_test.tar'])
assert os.path.isfile('/tmp/fetch_test/test.txt')
shutil.rmtree('/tmp/fetch_test')
+
+ def test_nofetch_upstream_and_unpack(self):
+ test_file = 'overcloud-full.tar.md5'
+ url = 'https://images.rdoproject.org/master/delorean/' \
+ 'current-tripleo/stable/'
+ os.makedirs('/tmp/fetch_test', exist_ok=True)
+ target = "/tmp/fetch_test/{}".format(test_file)
+ open(target, 'w').close()
+ target_mtime = os.path.getmtime(target)
+ utils.fetch_upstream_and_unpack('/tmp/fetch_test',
+ url, [test_file], fetch=False)
+ post_target_mtime = os.path.getmtime(target)
+ shutil.rmtree('/tmp/fetch_test')
+ assert_equal(target_mtime, post_target_mtime)
+
+ def test_nofetch_upstream_and_unpack_no_target(self):
+ test_file = 'overcloud-full.tar.md5'
+ url = 'https://images.rdoproject.org/master/delorean/' \
+ 'current-tripleo/stable/'
+ utils.fetch_upstream_and_unpack('/tmp/fetch_test',
+ url, [test_file])
+ assert os.path.isfile("/tmp/fetch_test/{}".format(test_file))
+ shutil.rmtree('/tmp/fetch_test')
+
+ def test_open_webpage(self):
+ output = utils.open_webpage('http://opnfv.org')
+ assert output is not None
+
+ def test_open_invalid_webpage(self):
+ assert_raises(urllib.request.URLError, utils.open_webpage,
+ 'http://inv4lIdweb-page.com')
+
+ @patch('builtins.open', a_mock_open)
+ @patch('yaml.safe_dump')
+ @patch('yaml.safe_load')
+ def test_edit_tht_env(self, mock_yaml_load, mock_yaml_dump):
+ settings = {'SomeParameter': 'some_value'}
+ mock_yaml_load.return_value = {
+ 'parameter_defaults': {'SomeParameter': 'dummy'}
+ }
+ utils.edit_tht_env('/dummy-environment.yaml', 'parameter_defaults',
+ settings)
+ new_data = {'parameter_defaults': settings}
+ mock_yaml_dump.assert_called_once_with(new_data, a_mock_open(),
+ default_flow_style=False)
diff --git a/apex/tests/test_apex_deploy.py b/apex/tests/test_apex_deploy.py
index 403b709..6c2a185 100644
--- a/apex/tests/test_apex_deploy.py
+++ b/apex/tests/test_apex_deploy.py
@@ -143,7 +143,8 @@ class TestDeploy(unittest.TestCase):
'sfc': False,
'vpn': False,
'yardstick': 'test',
- 'os_version': DEFAULT_OS_VERSION}}
+ 'os_version': DEFAULT_OS_VERSION,
+ 'containers': False}}
args = mock_parser.return_value.parse_args.return_value
args.virtual = False
args.quickstart = False
@@ -216,7 +217,8 @@ class TestDeploy(unittest.TestCase):
'sfc': False,
'vpn': False,
'yardstick': 'test',
- 'os_version': DEFAULT_OS_VERSION}}
+ 'os_version': DEFAULT_OS_VERSION,
+ 'containers': False}}
args = mock_parser.return_value.parse_args.return_value
args.virtual = True
args.quickstart = False
@@ -236,3 +238,67 @@ class TestDeploy(unittest.TestCase):
args.virt_compute_ram = 16
args.virt_default_ram = 10
main()
+
+ @patch('apex.deploy.c_builder')
+ @patch('apex.deploy.uc_builder')
+ @patch('apex.deploy.oc_builder')
+ @patch('apex.deploy.network_data.create_network_data')
+ @patch('apex.deploy.shutil')
+ @patch('apex.deploy.oc_deploy')
+ @patch('apex.deploy.uc_lib')
+ @patch('apex.deploy.build_vms')
+ @patch('apex.deploy.Inventory')
+ @patch('apex.deploy.virt_utils')
+ @patch('apex.deploy.oc_cfg')
+ @patch('apex.deploy.parsers')
+ @patch('apex.deploy.utils')
+ @patch('apex.deploy.NetworkEnvironment')
+ @patch('apex.deploy.NetworkSettings')
+ @patch('apex.deploy.DeploySettings')
+ @patch('apex.deploy.os')
+ @patch('apex.deploy.json')
+ @patch('apex.deploy.jumphost')
+ @patch('apex.deploy.validate_cross_settings')
+ @patch('apex.deploy.validate_deploy_args')
+ @patch('apex.deploy.create_deploy_parser')
+ @patch('builtins.open', a_mock_open, create=True)
+ def test_main_virt_containers_upstream(
+ self, mock_parser, mock_val_args, mock_cross_sets, mock_jumphost,
+ mock_json, mock_os, mock_deploy_sets, mock_net_sets, mock_net_env,
+ mock_utils, mock_parsers, mock_oc_cfg, mock_virt_utils,
+ mock_inv, mock_build_vms, mock_uc_lib, mock_oc_deploy,
+ mock_shutil, mock_network_data, mock_oc_builder,
+ mock_uc_builder, mock_c_builder):
+
+ ds_opts_dict = {'global_params': MagicMock(),
+ 'deploy_options': {'gluon': False,
+ 'congress': False,
+ 'sdn_controller': 'opendaylight',
+ 'dataplane': 'ovs',
+ 'sfc': False,
+ 'vpn': False,
+ 'yardstick': 'test',
+ 'os_version': DEFAULT_OS_VERSION,
+ 'containers': True}}
+ args = mock_parser.return_value.parse_args.return_value
+ args.virtual = True
+ args.quickstart = False
+ args.debug = True
+ args.virt_default_ram = 10
+ args.ha_enabled = True
+ args.virt_compute_nodes = 1
+ args.virt_compute_ram = None
+ args.virt_default_ram = 12
+ args.upstream = True
+ net_sets = mock_net_sets.return_value
+ net_sets.enabled_network_list = ['admin']
+ deploy_sets = mock_deploy_sets.return_value
+ deploy_sets.__getitem__.side_effect = ds_opts_dict.__getitem__
+ deploy_sets.__contains__.side_effect = ds_opts_dict.__contains__
+ main()
+ args.virt_compute_ram = 16
+ args.virt_default_ram = 10
+ main()
+ mock_oc_deploy.prep_image.assert_called
+ # TODO(trozet) add assertions here with arguments for functions in
+ # deploy main
diff --git a/apex/tests/test_apex_overcloud_builder.py b/apex/tests/test_apex_overcloud_builder.py
index e9a6e6c..46b5f87 100644
--- a/apex/tests/test_apex_overcloud_builder.py
+++ b/apex/tests/test_apex_overcloud_builder.py
@@ -11,7 +11,9 @@ import unittest
from apex.builders import overcloud_builder as oc_builder
from apex.common import constants as con
-from mock import patch
+from mock import patch, mock_open
+
+a_mock_open = mock_open(read_data=None)
class TestOvercloudBuilder(unittest.TestCase):
@@ -37,14 +39,69 @@ class TestOvercloudBuilder(unittest.TestCase):
mock_git_archive.return_value = '/dummytmp/puppet-opendaylight.tar'
archive = '/dummytmp/puppet-opendaylight.tar'
test_virt_ops = [
- {con.VIRT_INSTALL: 'opendaylight'},
{con.VIRT_UPLOAD: "{}:/etc/puppet/modules/".format(archive)},
{con.VIRT_RUN_CMD: 'rm -rf /etc/puppet/modules/opendaylight'},
{con.VIRT_RUN_CMD: "cd /etc/puppet/modules/ && tar xvf "
- "puppet-opendaylight.tar"}
+ "puppet-opendaylight.tar"},
+ {con.VIRT_INSTALL: 'opendaylight'}
]
oc_builder.inject_opendaylight(con.DEFAULT_ODL_VERSION, 'dummy.qcow2',
- '/dummytmp/')
+ '/dummytmp/', uc_ip='192.0.2.2',
+ os_version=con.DEFAULT_OS_VERSION)
+ assert mock_git_archive.called
+ assert mock_add_repo.called
+ mock_customize.assert_called_once_with(test_virt_ops, 'dummy.qcow2')
+
+ @patch('apex.builders.overcloud_builder.build_dockerfile')
+ @patch('apex.builders.common_builder.create_git_archive')
+ @patch('apex.builders.common_builder.add_repo')
+ @patch('apex.virtual.utils.virt_customize')
+ def test_inject_opendaylight_docker(self, mock_customize, mock_add_repo,
+ mock_git_archive, mock_build_docker):
+ mock_git_archive.return_value = '/dummytmp/puppet-opendaylight.tar'
+ archive = '/dummytmp/puppet-opendaylight.tar'
+ test_virt_ops = [
+ {con.VIRT_UPLOAD: "{}:/etc/puppet/modules/".format(archive)},
+ {con.VIRT_RUN_CMD: 'rm -rf /etc/puppet/modules/opendaylight'},
+ {con.VIRT_RUN_CMD: "cd /etc/puppet/modules/ && tar xvf "
+ "puppet-opendaylight.tar"},
+ ]
+ oc_builder.inject_opendaylight('oxygen', 'dummy.qcow2',
+ '/dummytmp/', uc_ip='192.0.2.2',
+ os_version=con.DEFAULT_OS_VERSION,
+ docker_tag='latest')
+ odl_url = "https://nexus.opendaylight.org/content/repositories" \
+ "/opendaylight-oxygen-epel-7-x86_64-devel/"
+ docker_cmds = [
+ "RUN yum remove opendaylight -y",
+ "RUN echo $'[opendaylight]\\n\\",
+ "baseurl={}\\n\\".format(odl_url),
+ "gpgcheck=0\\n\\",
+ "enabled=1' > /etc/yum.repos.d/opendaylight.repo",
+ "RUN yum -y install opendaylight"
+ ]
+ src_img_uri = "192.0.2.1:8787/nova-api/centos-binary-master:latest"
assert mock_git_archive.called
assert mock_add_repo.called
+ assert mock_build_docker.called_once_with(
+ 'opendaylight', '/dummytmp', docker_cmds, src_img_uri
+ )
mock_customize.assert_called_once_with(test_virt_ops, 'dummy.qcow2')
+
+ @patch('builtins.open', a_mock_open)
+ @patch('os.makedirs')
+ @patch('os.path.isfile')
+ @patch('os.path.isdir')
+ def test_build_dockerfile(self, mock_isdir, mock_isfile, mock_makedirs):
+ src_img_uri = "192.0.2.1:8787/nova-api/centos-binary-master:latest"
+ oc_builder.build_dockerfile('nova-api', '/tmpdummy/', ['RUN dummy'],
+ src_img_uri)
+ a_mock_open.assert_called_with(
+ '/tmpdummy/containers/nova-api/Dockerfile', 'a+')
+ a_mock_open().write.assert_called_once_with('RUN dummy')
+
+ @patch('tarfile.open')
+ @patch('os.path.isdir')
+ def test_archive_docker_patches(self, mock_isdir, mock_tarfile):
+ oc_builder.archive_docker_patches('/tmpdummy/')
+ assert mock_tarfile.assert_called
diff --git a/apex/tests/test_apex_overcloud_deploy.py b/apex/tests/test_apex_overcloud_deploy.py
index b5b1b75..54f95bb 100644
--- a/apex/tests/test_apex_overcloud_deploy.py
+++ b/apex/tests/test_apex_overcloud_deploy.py
@@ -29,6 +29,7 @@ from apex.overcloud.deploy import prep_sriov_env
from apex.overcloud.deploy import external_network_cmds
from apex.overcloud.deploy import create_congress_cmds
from apex.overcloud.deploy import SDN_FILE_MAP
+from apex.overcloud.deploy import get_docker_sdn_file
from nose.tools import (
assert_regexp_matches,
@@ -88,14 +89,17 @@ class TestOvercloudDeploy(unittest.TestCase):
def test_create_deploy_cmd(self, mock_sdn_list, mock_prep_storage,
mock_prep_sriov):
mock_sdn_list.return_value = []
- ds = {'deploy_options': MagicMock(),
+ ds = {'deploy_options':
+ {'ha_enabled': True,
+ 'congress': True,
+ 'tacker': True,
+ 'containers': False,
+ 'barometer': True,
+ 'ceph': False,
+ 'sriov': False
+ },
'global_params': MagicMock()}
- ds['global_params'].__getitem__.side_effect = \
- lambda i: True if i == 'ha_enabled' else MagicMock()
- ds['deploy_options'].__getitem__.side_effect = \
- lambda i: True if i == 'congress' else MagicMock()
- ds['deploy_options'].__contains__.side_effect = \
- lambda i: True if i == 'congress' else MagicMock()
+
ns = {'ntp': ['ntp']}
inv = MagicMock()
inv.get_node_counts.return_value = (3, 2)
@@ -111,6 +115,44 @@ class TestOvercloudDeploy(unittest.TestCase):
@patch('apex.overcloud.deploy.prep_sriov_env')
@patch('apex.overcloud.deploy.prep_storage_env')
+ @patch('builtins.open', mock_open())
+ def test_create_deploy_cmd_containers_sdn(self, mock_prep_storage,
+ mock_prep_sriov):
+ ds = {'deploy_options':
+ {'ha_enabled': True,
+ 'congress': False,
+ 'tacker': False,
+ 'containers': True,
+ 'barometer': False,
+ 'ceph': True,
+ 'sdn_controller': 'opendaylight',
+ 'sriov': False
+ },
+ 'global_params': MagicMock()}
+
+ ns = {'ntp': ['ntp']}
+ inv = MagicMock()
+ inv.get_node_counts.return_value = (3, 2)
+ virt = True
+ result_cmd = create_deploy_cmd(ds, ns, inv, '/tmp', virt)
+ assert_in('--ntp-server ntp', result_cmd)
+ assert_not_in('enable_tacker.yaml', result_cmd)
+ assert_not_in('enable_congress.yaml', result_cmd)
+ assert_not_in('enable_barometer.yaml', result_cmd)
+ assert_in('virtual-environment.yaml', result_cmd)
+ assert_in('--control-scale 3', result_cmd)
+ assert_in('--compute-scale 2', result_cmd)
+ assert_in('docker-images.yaml', result_cmd)
+ assert_in('sdn-images.yaml', result_cmd)
+ assert_in('/usr/share/openstack-tripleo-heat-templates/environments'
+ '/docker.yaml', result_cmd)
+ assert_in('/usr/share/openstack-tripleo-heat-templates/environments/'
+ 'storage-environment.yaml', result_cmd)
+ assert_in('/usr/share/openstack-tripleo-heat-templates/environments'
+ '/services-docker/neutron-opendaylight.yaml', result_cmd)
+
+ @patch('apex.overcloud.deploy.prep_sriov_env')
+ @patch('apex.overcloud.deploy.prep_storage_env')
@patch('apex.overcloud.deploy.build_sdn_env_list')
@patch('builtins.open', mock_open())
def test_create_deploy_cmd_no_ha_bm(self, mock_sdn_list,
@@ -155,7 +197,8 @@ class TestOvercloudDeploy(unittest.TestCase):
def test_prep_image(self, mock_os_path, mock_shutil, mock_virt_utils):
ds_opts = {'dataplane': 'fdio',
'sdn_controller': 'opendaylight',
- 'odl_version': 'master'}
+ 'odl_version': 'master',
+ 'sriov': False}
ds = {'deploy_options': MagicMock(),
'global_params': MagicMock()}
ds['deploy_options'].__getitem__.side_effect = \
@@ -200,6 +243,35 @@ class TestOvercloudDeploy(unittest.TestCase):
prep_image(ds, ns, 'undercloud.qcow2', '/tmp', root_pw='test')
mock_virt_utils.virt_customize.assert_called()
+ @patch('apex.overcloud.deploy.c_builder')
+ @patch('apex.overcloud.deploy.oc_builder')
+ @patch('apex.overcloud.deploy.virt_utils')
+ @patch('apex.overcloud.deploy.shutil')
+ @patch('apex.overcloud.deploy.os.path')
+ @patch('builtins.open', mock_open())
+ def test_prep_image_sdn_odl_upstream_containers_patches(
+ self, mock_os_path, mock_shutil, mock_virt_utils,
+ mock_oc_builder, mock_c_builder):
+ ds_opts = {'dataplane': 'ovs',
+ 'sdn_controller': 'opendaylight',
+ 'odl_version': con.DEFAULT_ODL_VERSION,
+ 'odl_vpp_netvirt': True}
+ ds = {'deploy_options': MagicMock(),
+ 'global_params': MagicMock()}
+ ds['deploy_options'].__getitem__.side_effect = \
+ lambda i: ds_opts.get(i, MagicMock())
+ ds['deploy_options'].__contains__.side_effect = \
+ lambda i: True if i in ds_opts else MagicMock()
+ ns = MagicMock()
+ mock_c_builder.add_upstream_patches.return_value = ['nova-api']
+ patches = ['dummy_nova_patch']
+ rv = prep_image(ds, ns, 'undercloud.qcow2', '/tmp', root_pw='test',
+ docker_tag='latest', patches=patches, upstream=True)
+ mock_oc_builder.inject_opendaylight.assert_called
+ mock_virt_utils.virt_customize.assert_called()
+ mock_c_builder.add_upstream_patches.assert_called
+ self.assertListEqual(sorted(rv), ['nova-api', 'opendaylight'])
+
@patch('apex.overcloud.deploy.virt_utils')
@patch('apex.overcloud.deploy.shutil')
@patch('apex.overcloud.deploy.os.path')
@@ -380,19 +452,60 @@ class TestOvercloudDeploy(unittest.TestCase):
mock_ceph_key):
mock_fileinput.input.return_value = \
['CephClusterFSID', 'CephMonKey', 'CephAdminKey', 'random_key']
- ds = {'deploy_options': MagicMock()}
- ds['deploy_options'].__getitem__.side_effect = \
- lambda i: '/dev/sdx' if i == 'ceph_device' else MagicMock()
- ds['deploy_options'].__contains__.side_effect = \
- lambda i: True if i == 'ceph_device' else MagicMock()
- prep_storage_env(ds, '/tmp')
+ ds = {'deploy_options': {
+ 'ceph_device': '/dev/sdx',
+ 'containers': False
+ }}
+ ns = {}
+ prep_storage_env(ds, ns, virtual=False, tmp_dir='/tmp')
+
+ @patch('apex.overcloud.deploy.utils.edit_tht_env')
+ @patch('apex.overcloud.deploy.generate_ceph_key')
+ @patch('apex.overcloud.deploy.fileinput')
+ @patch('apex.overcloud.deploy.os.path.isfile')
+ @patch('builtins.open', mock_open())
+ def test_prep_storage_env_containers(self, mock_isfile, mock_fileinput,
+ mock_ceph_key, mock_edit_tht):
+ mock_fileinput.input.return_value = \
+ ['CephClusterFSID', 'CephMonKey', 'CephAdminKey', 'random_key']
+ ds = {'deploy_options': {
+ 'ceph_device': '/dev/sdx',
+ 'containers': True,
+ 'os_version': 'master'
+ }, 'global_params': {'ha_enabled': False}}
+ ns = {'networks': {con.ADMIN_NETWORK: {'installer_vm':
+ {'ip': '192.0.2.1'}}}
+ }
+ prep_storage_env(ds, ns, virtual=True, tmp_dir='/tmp')
+ ceph_params = {
+ 'DockerCephDaemonImage':
+ '192.0.2.1:8787/ceph/daemon:tag-build-master-luminous-centos'
+ '-7',
+ 'CephPoolDefaultSize': 1,
+ 'CephAnsibleExtraConfig': {
+ 'centos_package_dependencies': [],
+ 'ceph_osd_docker_memory_limit': '1g',
+ 'ceph_mds_docker_memory_limit': '1g'
+ },
+ 'CephPoolDefaultPgNum': 32,
+ 'CephAnsibleDisksConfig': {
+ 'devices': ['/dev/sdx'],
+ 'journal_size': 512,
+ 'osd_scenario': 'collocated'
+ }
+ }
+ mock_edit_tht.assert_called_with('/tmp/storage-environment.yaml',
+ 'parameter_defaults',
+ ceph_params)
@patch('apex.overcloud.deploy.os.path.isfile')
@patch('builtins.open', mock_open())
def test_prep_storage_env_raises(self, mock_isfile):
mock_isfile.return_value = False
ds = {'deploy_options': MagicMock()}
- assert_raises(ApexDeployException, prep_storage_env, ds, '/tmp')
+ ns = {}
+ assert_raises(ApexDeployException, prep_storage_env, ds,
+ ns, virtual=False, tmp_dir='/tmp')
@patch('apex.overcloud.deploy.generate_ceph_key')
@patch('apex.overcloud.deploy.fileinput')
@@ -487,3 +600,19 @@ class TestOvercloudDeploy(unittest.TestCase):
def test_create_congress_cmds_raises(self, mock_parsers):
mock_parsers.return_value.__getitem__.side_effect = KeyError()
assert_raises(KeyError, create_congress_cmds, 'overcloud_file')
+
+ def test_get_docker_sdn_file(self):
+ ds_opts = {'ha_enabled': True,
+ 'congress': True,
+ 'tacker': True,
+ 'containers': False,
+ 'barometer': True,
+ 'ceph': False,
+ 'sdn_controller': 'opendaylight'
+ }
+ output = get_docker_sdn_file(ds_opts)
+ self.assertEqual(output,
+ ('/usr/share/openstack-tripleo-heat-templates'
+ '/environments/services-docker/neutron-opendaylight'
+ '.yaml')
+ )
diff --git a/apex/tests/test_apex_undercloud.py b/apex/tests/test_apex_undercloud.py
index 0df785f..9e2752a 100644
--- a/apex/tests/test_apex_undercloud.py
+++ b/apex/tests/test_apex_undercloud.py
@@ -7,6 +7,7 @@
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################
+import ipaddress
import libvirt
import os
import subprocess
@@ -187,13 +188,27 @@ class TestUndercloud(unittest.TestCase):
@patch.object(Undercloud, '_get_vm', return_value=None)
@patch.object(Undercloud, 'create')
def test_generate_config(self, mock_get_vm, mock_create):
- ns_net = MagicMock()
- ns_net.__getitem__.side_effect = \
- lambda i: '1234/24' if i is 'cidr' else MagicMock()
- ns = {'apex': MagicMock(),
- 'dns-domain': 'dns',
- 'networks': {'admin': ns_net,
- 'external': [ns_net]}}
+ ns = MagicMock()
+ ns.enabled_network_list = ['admin', 'external']
+ ns_dict = {
+ 'apex': MagicMock(),
+ 'dns-domain': 'dns',
+ 'networks': {'admin':
+ {'cidr': ipaddress.ip_network('192.0.2.0/24'),
+ 'installer_vm': {'ip': '192.0.2.1',
+ 'vlan': 'native'},
+ 'dhcp_range': ['192.0.2.15', '192.0.2.30']
+ },
+ 'external':
+ [{'enabled': True,
+ 'cidr': ipaddress.ip_network('192.168.0.0/24'),
+ 'installer_vm': {'ip': '192.168.0.1',
+ 'vlan': 'native'}
+ }]
+ }
+ }
+ ns.__getitem__.side_effect = ns_dict.__getitem__
+ ns.__contains__.side_effect = ns_dict.__contains__
ds = {'global_params': {}}
Undercloud('img_path', 'tplt_path').generate_config(ns, ds)