Workflows to load validations
This commit adds workflow to list available validations and validation groups. Change-Id: I85fb6c1939e711887b2ee91c9cefa41a3da681a3
This commit is contained in:
parent
81514076c8
commit
ceecdadbf4
@ -72,3 +72,5 @@ mistral.actions =
|
||||
tripleo.reset_parameters = tripleo_common.actions.parameters:ResetParametersAction
|
||||
tripleo.deploy = tripleo_common.actions.deployment:DeployStackAction
|
||||
tripleo.validations.get_pubkey = tripleo_common.actions.validations:GetPubkeyAction
|
||||
tripleo.validations.list_validations = tripleo_common.actions.validations:ListValidationsAction
|
||||
tripleo.validations.list_groups = tripleo_common.actions.validations:ListGroupsAction
|
||||
|
@ -53,3 +53,26 @@ class GetPubkeyAction(base.TripleOAction):
|
||||
mc.environments.create(**workflow_env)
|
||||
|
||||
return public_key
|
||||
|
||||
|
||||
class ListValidationsAction(base.TripleOAction):
|
||||
"""Return a set of TripleO validations"""
|
||||
def __init__(self, groups=None):
|
||||
super(ListValidationsAction, self).__init__()
|
||||
self.groups = groups
|
||||
|
||||
def run(self):
|
||||
return utils.load_validations(groups=self.groups)
|
||||
|
||||
|
||||
class ListGroupsAction(base.TripleOAction):
|
||||
"""Return a set of TripleO validation groups"""
|
||||
def __init__(self):
|
||||
super(ListGroupsAction, self).__init__()
|
||||
|
||||
def run(self):
|
||||
validations = utils.load_validations()
|
||||
return {
|
||||
group for validation in validations
|
||||
for group in validation['groups']
|
||||
}
|
||||
|
@ -32,6 +32,10 @@ DEFAULT_CONTAINER_NAME = 'overcloud'
|
||||
#: The path to the tripleo heat templates installed on the undercloud
|
||||
DEFAULT_TEMPLATES_PATH = '/usr/share/openstack-tripleo-heat-templates/'
|
||||
|
||||
# The path to the tripleo validations installed on the undercloud
|
||||
DEFAULT_VALIDATIONS_PATH = \
|
||||
'/usr/share/openstack-tripleo-validations/validations/'
|
||||
|
||||
# TRIPLEO_META_USAGE_KEY is inserted into metadata for containers created in
|
||||
# Swift via SwiftPlanStorageBackend to identify them from other containers
|
||||
TRIPLEO_META_USAGE_KEY = 'x-container-meta-usage-tripleo'
|
||||
|
@ -17,6 +17,7 @@ import mock
|
||||
|
||||
from tripleo_common.actions import validations
|
||||
from tripleo_common.tests import base
|
||||
from tripleo_common.tests.utils import test_validations
|
||||
|
||||
|
||||
class GetPubkeyActionTest(base.TestCase):
|
||||
@ -55,3 +56,35 @@ class GetPubkeyActionTest(base.TestCase):
|
||||
mock_mkdtemp.assert_called_once()
|
||||
mock_create_keypair.assert_called_once_with('/tmp_path/id_rsa')
|
||||
mock_rmtree.asser_called_once_with('/tmp_path')
|
||||
|
||||
|
||||
class ListValidationsActionTest(base.TestCase):
|
||||
|
||||
@mock.patch('tripleo_common.utils.validations.load_validations')
|
||||
def test_run_default(self, mock_load_validations):
|
||||
mock_load_validations.return_value = 'list of validations'
|
||||
action = validations.ListValidationsAction()
|
||||
self.assertEqual('list of validations', action.run())
|
||||
mock_load_validations.assert_called_once_with(groups=None)
|
||||
|
||||
@mock.patch('tripleo_common.utils.validations.load_validations')
|
||||
def test_run_groups(self, mock_load_validations):
|
||||
mock_load_validations.return_value = 'list of validations'
|
||||
action = validations.ListValidationsAction(groups=['group1',
|
||||
'group2'])
|
||||
self.assertEqual('list of validations', action.run())
|
||||
mock_load_validations.assert_called_once_with(groups=['group1',
|
||||
'group2'])
|
||||
|
||||
|
||||
class ListGroupsActionTest(base.TestCase):
|
||||
|
||||
@mock.patch('tripleo_common.utils.validations.load_validations')
|
||||
def test_run(self, mock_load_validations):
|
||||
mock_load_validations.return_value = [
|
||||
test_validations.VALIDATION_GROUPS_1_2_PARSED,
|
||||
test_validations.VALIDATION_GROUP_1_PARSED,
|
||||
test_validations.VALIDATION_WITH_METADATA_PARSED]
|
||||
action = validations.ListGroupsAction()
|
||||
self.assertEqual(set(['group1', 'group2']), action.run())
|
||||
mock_load_validations.assert_called_once_with()
|
||||
|
@ -14,12 +14,78 @@
|
||||
# limitations under the License.
|
||||
|
||||
import mock
|
||||
import yaml
|
||||
|
||||
from tripleo_common.tests import base
|
||||
from tripleo_common.utils import validations
|
||||
|
||||
|
||||
class ValidationsTest(base.TestCase):
|
||||
VALIDATION_GROUP_1 = """---
|
||||
- hosts: overcloud
|
||||
vars:
|
||||
metadata:
|
||||
name: First validation
|
||||
description: A validation belonging to group1
|
||||
groups:
|
||||
- group1
|
||||
tasks:
|
||||
- name: Ping the nodes
|
||||
ping:
|
||||
"""
|
||||
|
||||
VALIDATION_WITH_METADATA = """---
|
||||
- hosts: undercloud
|
||||
vars:
|
||||
metadata:
|
||||
name: Validation with metadata
|
||||
description: A validation with extra metadata
|
||||
foo: a foo metadata
|
||||
bar: 42
|
||||
tasks:
|
||||
- name: Do something useful
|
||||
watch_tv:
|
||||
"""
|
||||
|
||||
VALIDATION_GROUPS_1_2 = """---
|
||||
- hosts: undercloud
|
||||
vars:
|
||||
metadata:
|
||||
name: Validation from many groups
|
||||
description: A validation belonging to groups 1 and 2
|
||||
groups:
|
||||
- group1
|
||||
- group2
|
||||
tasks:
|
||||
- name: Do something useful
|
||||
watch_tv:
|
||||
"""
|
||||
|
||||
VALIDATION_GROUP_1_PARSED = {
|
||||
'description': 'A validation belonging to group1',
|
||||
'groups': ['group1'],
|
||||
'id': 'VALIDATION_GROUP_1',
|
||||
'metadata': {},
|
||||
'name': 'First validation',
|
||||
}
|
||||
|
||||
VALIDATION_WITH_METADATA_PARSED = {
|
||||
'description': 'A validation with extra metadata',
|
||||
'groups': [],
|
||||
'id': 'VALIDATION_WITH_METADATA',
|
||||
'metadata': {'foo': 'a foo metadata', 'bar': 42},
|
||||
'name': 'Validation with metadata',
|
||||
}
|
||||
|
||||
VALIDATION_GROUPS_1_2_PARSED = {
|
||||
'description': 'A validation belonging to groups 1 and 2',
|
||||
'groups': ['group1', 'group2'],
|
||||
'id': 'VALIDATION_GROUPS_1_2',
|
||||
'metadata': {},
|
||||
'name': 'Validation from many groups',
|
||||
}
|
||||
|
||||
|
||||
class ValidationsKeyTest(base.TestCase):
|
||||
|
||||
@mock.patch("oslo_concurrency.processutils.execute")
|
||||
def test_create_ssh_keypair(self, mock_execute):
|
||||
@ -27,3 +93,63 @@ class ValidationsTest(base.TestCase):
|
||||
mock_execute.assert_called_once_with(
|
||||
'/usr/bin/ssh-keygen', '-t', 'rsa', '-N', '',
|
||||
'-f', '/path/to/key', '-C', 'tripleo-validations')
|
||||
|
||||
|
||||
class LoadValidationsTest(base.TestCase):
|
||||
|
||||
def test_get_validation_metadata(self):
|
||||
validation = yaml.safe_load(VALIDATION_GROUP_1)
|
||||
value = validations.get_validation_metadata(validation, 'name')
|
||||
self.assertEqual('First validation', value)
|
||||
|
||||
@mock.patch('tripleo_common.utils.validations.DEFAULT_METADATA')
|
||||
def test_get_validation_metadata_default_value(self, mock_metadata):
|
||||
mock_metadata.get.return_value = 'default_value'
|
||||
value = validations.get_validation_metadata({}, 'missing')
|
||||
self.assertEqual('default_value', value)
|
||||
|
||||
def test_get_remaining_metadata(self):
|
||||
validation = yaml.safe_load(VALIDATION_WITH_METADATA)
|
||||
value = validations.get_remaining_metadata(validation)
|
||||
expected = {
|
||||
'foo': 'a foo metadata',
|
||||
'bar': 42
|
||||
}
|
||||
self.assertEqual(expected, value)
|
||||
|
||||
def test_get_remaining_metadata_no_extra(self):
|
||||
validation = yaml.safe_load(VALIDATION_GROUP_1)
|
||||
value = validations.get_remaining_metadata(validation)
|
||||
self.assertEqual({}, value)
|
||||
|
||||
@mock.patch('glob.glob')
|
||||
def test_load_validations_no_group(self, mock_glob):
|
||||
mock_glob.return_value = ['VALIDATION_GROUP_1',
|
||||
'VALIDATION_WITH_METADATA']
|
||||
mock_open_context = mock.mock_open()
|
||||
mock_open_context().read.side_effect = [VALIDATION_GROUP_1,
|
||||
VALIDATION_WITH_METADATA]
|
||||
|
||||
with mock.patch('tripleo_common.utils.validations.open',
|
||||
mock_open_context):
|
||||
my_validations = validations.load_validations()
|
||||
|
||||
expected = [VALIDATION_GROUP_1_PARSED, VALIDATION_WITH_METADATA_PARSED]
|
||||
self.assertEqual(expected, my_validations)
|
||||
|
||||
@mock.patch('glob.glob')
|
||||
def test_load_validations_group(self, mock_glob):
|
||||
mock_glob.return_value = ['VALIDATION_GROUPS_1_2',
|
||||
'VALIDATION_GROUP_1',
|
||||
'VALIDATION_WITH_METADATA']
|
||||
mock_open_context = mock.mock_open()
|
||||
mock_open_context().read.side_effect = [VALIDATION_GROUPS_1_2,
|
||||
VALIDATION_GROUP_1,
|
||||
VALIDATION_WITH_METADATA]
|
||||
|
||||
with mock.patch('tripleo_common.utils.validations.open',
|
||||
mock_open_context):
|
||||
my_validations = validations.load_validations(groups=['group1'])
|
||||
|
||||
expected = [VALIDATION_GROUPS_1_2_PARSED, VALIDATION_GROUP_1_PARSED]
|
||||
self.assertEqual(expected, my_validations)
|
||||
|
@ -12,12 +12,64 @@
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import glob
|
||||
import logging
|
||||
import os
|
||||
import yaml
|
||||
|
||||
from oslo_concurrency import processutils
|
||||
|
||||
from tripleo_common import constants
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
DEFAULT_METADATA = {
|
||||
'name': 'Unnamed',
|
||||
'description': 'No description',
|
||||
'stage': 'No stage',
|
||||
'groups': [],
|
||||
}
|
||||
|
||||
|
||||
def get_validation_metadata(validation, key):
|
||||
try:
|
||||
return validation[0]['vars']['metadata'][key]
|
||||
except KeyError:
|
||||
return DEFAULT_METADATA.get(key)
|
||||
except TypeError:
|
||||
LOG.exception("Failed to get validation metadata.")
|
||||
|
||||
|
||||
def load_validations(groups=None):
|
||||
'''Loads all validations.'''
|
||||
paths = glob.glob('{}/*.yaml'.format(constants.DEFAULT_VALIDATIONS_PATH))
|
||||
results = []
|
||||
for validation_path in sorted(paths):
|
||||
with open(validation_path) as f:
|
||||
validation = yaml.safe_load(f.read())
|
||||
validation_groups = get_validation_metadata(validation, 'groups') \
|
||||
or []
|
||||
if not groups or \
|
||||
set.intersection(set(groups), set(validation_groups)):
|
||||
results.append({
|
||||
'id': os.path.splitext(
|
||||
os.path.basename(validation_path))[0],
|
||||
'name': get_validation_metadata(validation, 'name'),
|
||||
'groups': get_validation_metadata(validation, 'groups'),
|
||||
'description': get_validation_metadata(validation,
|
||||
'description'),
|
||||
'metadata': get_remaining_metadata(validation)
|
||||
})
|
||||
return results
|
||||
|
||||
|
||||
def get_remaining_metadata(validation):
|
||||
try:
|
||||
return {k: v for k, v in validation[0]['vars']['metadata'].items()
|
||||
if k not in ['name', 'description', 'groups']}
|
||||
except KeyError:
|
||||
return dict()
|
||||
|
||||
|
||||
def create_ssh_keypair(key_path):
|
||||
"""Create SSH keypair"""
|
||||
|
@ -5,6 +5,20 @@ description: TripleO Validations Workflows v1
|
||||
|
||||
workflows:
|
||||
|
||||
list:
|
||||
type: direct
|
||||
input:
|
||||
- group_names: []
|
||||
tasks:
|
||||
find_validations:
|
||||
action: tripleo.validations.list_validations groups=<% $.group_names %>
|
||||
|
||||
list_groups:
|
||||
type: direct
|
||||
tasks:
|
||||
find_groups:
|
||||
action: tripleo.validations.list_groups
|
||||
|
||||
copy_ssh_key:
|
||||
type: direct
|
||||
input:
|
||||
|
Loading…
x
Reference in New Issue
Block a user