# Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # 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 os import time from oslo_utils import uuidutils from tempest.lib.cli import base from tempest.lib.cli import output_parser from tempest.lib import exceptions as tempest_lib_exc class OpenStackClientTestBase(base.ClientTestBase): """Command line client base functions.""" def setUp(self): super(OpenStackClientTestBase, self).setUp() self.parser = output_parser def _get_clients(self): cli_dir = os.environ.get( 'OS_SENLINCLIENT_EXEC_DIR', os.path.join(os.path.abspath('.'), '.tox/functional/bin')) return base.CLIClient( username=os.environ.get('OS_USERNAME'), password=os.environ.get('OS_PASSWORD'), tenant_name=os.environ.get('OS_PROJECT_NAME', os.environ.get('OS_TENANT_NAME')), uri=os.environ.get('OS_AUTH_URL'), cli_dir=cli_dir) def openstack(self, *args, **kwargs): return self.clients.openstack(*args, **kwargs) def show_to_dict(self, output): obj = {} items = self.parser.listing(output) for item in items: obj[item['Field']] = str(item['Value']) return dict((self._key_name(k), v) for k, v in obj.items()) def _key_name(self, key): return key.lower().replace(' ', '_') def name_generate(self): """Generate randomized name for some entity.""" name = uuidutils.generate_uuid()[:8] return name def _get_profile_path(self, profile_name): return os.path.join(os.path.dirname(os.path.realpath(__file__)), 'profiles/%s' % profile_name) def _get_policy_path(self, policy_name): return os.path.join(os.path.dirname(os.path.realpath(__file__)), 'policies/%s' % policy_name) def wait_for_status(self, name, status, check_type, timeout=60, poll_interval=5): """Wait until name reaches given status. :param name: node or cluster name :param status: expected status of node or cluster :param timeout: timeout in seconds :param poll_interval: poll interval in seconds """ if check_type == 'node': cmd = ('cluster node show %s' % name) elif check_type == 'cluster': cmd = ('cluster show %s' % name) time.sleep(poll_interval) start_time = time.time() while time.time() - start_time < timeout: check_status = self.openstack(cmd) result = self.show_to_dict(check_status) if result['status'] == status: break time.sleep(poll_interval) else: message = ("%s %s did not reach status %s after %d s" % (check_type, name, status, timeout)) raise tempest_lib_exc.TimeoutException(message) def wait_for_delete(self, name, check_type, timeout=60, poll_interval=5): """Wait until delete finish""" if check_type == 'node': cmd = ('cluster node show %s' % name) if check_type == 'cluster': cmd = ('cluster show %s' % name) time.sleep(poll_interval) start_time = time.time() while time.time() - start_time < timeout: try: self.openstack(cmd) except tempest_lib_exc.CommandFailed as ex: if "No Node found" or "No Cluster found" in ex.stderr: break time.sleep(poll_interval) else: message = ("failed in deleting %s %s after %d seconds" % (check_type, name, timeout)) raise tempest_lib_exc.TimeoutException(message) def policy_create(self, name, policy='deletion_policy.yaml'): pf = self._get_policy_path(policy) cmd = ('cluster policy create --spec-file %s %s' % (pf, name)) policy_raw = self.openstack(cmd) result = self.show_to_dict(policy_raw) return result def policy_delete(self, name_or_id): cmd = ('cluster policy delete %s --force' % name_or_id) self.openstack(cmd) def profile_create(self, name, profile='cirros_basic.yaml'): pf = self._get_profile_path(profile) cmd = ('cluster profile create --spec-file %s %s' % (pf, name)) profile_raw = self.openstack(cmd) result = self.show_to_dict(profile_raw) return result def profile_delete(self, name_or_id): cmd = ('cluster profile delete %s --force' % name_or_id) self.openstack(cmd) def node_create(self, profile, name): cmd = ('cluster node create --profile %s %s' % (profile, name)) node_raw = self.openstack(cmd) result = self.show_to_dict(node_raw) self.wait_for_status(name, 'ACTIVE', 'node', 120) return result def node_delete(self, name_or_id): cmd = ('cluster node delete %s --force' % name_or_id) self.openstack(cmd) self.wait_for_delete(name_or_id, 'node', 120) def cluster_create(self, profile, name, desired_capacity=0): cmd = ('cluster create --profile %s --desired-capacity %d %s' % (profile, desired_capacity, name)) cluster_raw = self.openstack(cmd) result = self.show_to_dict(cluster_raw) self.wait_for_status(name, 'ACTIVE', 'cluster', 120) return result def cluster_delete(self, name_or_id): cmd = ('cluster delete %s --force' % name_or_id) self.openstack(cmd) self.wait_for_delete(name_or_id, 'cluster', 120) def receiver_create(self, name, cluster, action='CLUSTER_SCALE_OUT', rt='webhook'): cmd = ('cluster receiver create --cluster %s --action %s --type %s ' '%s' % (cluster, action, rt, name)) receiver_raw = self.openstack(cmd) result = self.show_to_dict(receiver_raw) return result def receiver_delete(self, name_or_id): cmd = ('cluster receiver delete %s --force' % name_or_id) self.openstack(cmd)