From 2b9ad531576ea233eec76e5a490d7061d2abcd07 Mon Sep 17 00:00:00 2001 From: Volodymyr Rozhanskyy Date: Tue, 6 Sep 2016 12:46:59 +0300 Subject: [PATCH] basic manila verification Change-Id: Ib5b2cd0fe2af525503966deaf404b55cee7d9fe2 --- plugin_test/helpers/manila_service_verify.py | 127 ++++++++++++++ plugin_test/helpers/openstack.py | 137 ++++++++++++++++ plugin_test/helpers/os_manila_actions.py | 164 +++++++++++++++++++ 3 files changed, 428 insertions(+) create mode 100644 plugin_test/helpers/manila_service_verify.py create mode 100644 plugin_test/helpers/openstack.py create mode 100644 plugin_test/helpers/os_manila_actions.py diff --git a/plugin_test/helpers/manila_service_verify.py b/plugin_test/helpers/manila_service_verify.py new file mode 100644 index 0000000..bd56163 --- /dev/null +++ b/plugin_test/helpers/manila_service_verify.py @@ -0,0 +1,127 @@ +# Copyright 2014 Mirantis, Inc. +# +# 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. + +from fuelweb_test.helpers import os_actions +from fuelweb_test import logger +from fuelweb_test import logwrap +from fuelweb_test.settings import SERVTEST_PASSWORD +from fuelweb_test.settings import SERVTEST_TENANT +from fuelweb_test.settings import SERVTEST_USERNAME + +from helpers import openstack +from helpers import os_manila_actions +from proboscis import asserts + + +@logwrap +class TestPluginCheck(object): + """Test suite for GCS plugin check.""" + + def __init__(self, obj): + """Create Test client for run tests. + + :param obj: Test case object + """ + + self.obj = obj + cluster_id = self.obj.fuel_web.get_last_created_cluster() + ip = self.obj.fuel_web.get_public_vip(cluster_id) + self.os_conn = os_actions.OpenStackActions( + ip, SERVTEST_USERNAME, SERVTEST_PASSWORD, SERVTEST_TENANT) + + self.manila_conn = os_manila_actions.ManilaActions( + ip, SERVTEST_USERNAME, SERVTEST_PASSWORD, SERVTEST_TENANT) + + def verify_manila_functionality(self): + """This method do basic functionality check : + + * creates share-type, share network, share, access_rule ; + * start instance using configuration from server-conf.yaml; + * mount share verify R/W to mounted share; + """ + + # create default share type + # cli:manila type-create default_share_type True + logger.info('#'*10 + "Create manila default share type" + '#'*10) + share_type = self.manila_conn.create_share_type( + type_name='default_share_type') + asserts.assert_equal(share_type.name, 'default_share_type', + message="Failed to create default share type") + + # get internal id of admin_internal_net network and subnet id + # neutron net-list | grep 'admin_internal_net' + network = self.os_conn.get_network('admin_internal_net') + logger.debug('admin_internal_net id is :{}'.format(network)) + + # create share network (share network = internal_admin_network) + logger.info('#' * 10 + "Create manila share network" + '#' * 10) + s_net = self.manila_conn.create_share_network( + net_id=network.get('id'), subnet_id=network.get('subnets')) + asserts.assert_equal(s_net.name, 'Test Share network', + message="Failed to create manila share network") + + share_network_id = s_net.id + logger.info('#' * 10 + "Manila share network ID :{0}".format(s_net.id)) + + # create share and wait until it will becomes available + logger.info('#' * 10 + "Create manila share" + '#' * 10) + test_share = self.manila_conn.create_basic_share( + share_name='test_share', network=share_network_id) + asserts.assert_equal(test_share.name, 'test_share', + message="Failed to create manila share") + self.manila_conn.wait_for_share_status( + share_name='test_share', status='available') + logger.info('#'*10 + "Share created and become available") + + logger.info('#'*10 + "add access rule allow any ip for created share") + access = self.manila_conn.add_acc_rule( + share_id=test_share, rule='0.0.0.0/0') + + asserts.assert_equal(access.type, 'ip', + message="Failed to assign ACL for manila share") + + logger.info("Create and configure instance to verify share") + test_instance = openstack.create_instance(self.os_conn) + openstack.verify_instance_state(self.os_conn, 'test_share_server') + + logger.info('#'*10 + "Assign floating ip for server") + fl_ip = openstack.create_and_assign_floating_ips( + self.os_conn, test_instance) + logger.info("IP: {0} user: {1} pass:{1}".format(fl_ip, 'manila')) + + logger.info('#' * 10 + "Connect via ssh to server") + ssh_client = openstack.get_ssh_connection(fl_ip) + + msg = 'New instance started floating ip is: {0}'.format(fl_ip) + logger.info(msg) + + # create mounting point + mounting_point = '/mnt/share1' + cmd = "sudo mkdir {0}".format(mounting_point) + openstack.execute(ssh_client, cmd) + + # mounting point + cmd2 = "sudo mount -t nfs {1} {0}".format(mounting_point, + test_share.export_location) + openstack.execute(ssh_client, cmd2) + + cmd3 = "echo Share is created > {0}/file.txt ".format(mounting_point) + openstack.execute(ssh_client, cmd3) + + cmd3 = "cat /mnt/share1/file.txt ".format(mounting_point) + output = openstack.execute(ssh_client, cmd3) + asserts.assert_true( + 'Share is created' in output['stdout'], + "R/W access for {0} verified".format(test_share.export_location)) + logger.info('Network share mounted and work as expected') diff --git a/plugin_test/helpers/openstack.py b/plugin_test/helpers/openstack.py new file mode 100644 index 0000000..0782d01 --- /dev/null +++ b/plugin_test/helpers/openstack.py @@ -0,0 +1,137 @@ +"""Copyright 2016 Mirantis, Inc. + +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 +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. +""" + +from devops.error import TimeoutError +from devops.helpers.helpers import icmp_ping +from devops.helpers.helpers import wait +from fuelweb_test import logger +import paramiko +from proboscis.asserts import assert_true +import socket + +# timeouts +BOOT_TIMEOUT = 300 + + +def create_instance(os_conn, + server_name='test_share_server', + network='admin_internal_net', + image='manila-service-image', + flavor='manila-service-flavor', + ): + """Create instances with nova """ + + # load server configuration from yaml + net = os_conn.get_network(network) + + for fl in os_conn.nova.flavors.list(): + if fl.name == flavor: + flavor_id = fl.id + + for im in os_conn.glance.images.list(): + if im.name == image: + image_id = im.id + + sec_group = os_conn.create_sec_group_for_ssh() + # create instance + server = os_conn.create_server( + name=server_name, + security_groups=[sec_group], + flavor_id=flavor_id, + net_id=net['id'], + availability_zone='nova', + timeout=200, + image=image_id + ) + return server + + +def verify_instance_state(os_conn, inst_name, expected_state='ACTIVE'): + """Verify that current state of each instance/s is expected. + + :param os_conn: type object, openstack + :param inst_name: type string, name of created instance + :param expected_state: type string, expected state of instance + """ + instances = os_conn.nova.servers.list() + for instance in instances: + if instance.name == inst_name: + try: + wait( + lambda: + os_conn.get_instance_detail(instance).status == + expected_state, timeout=BOOT_TIMEOUT) + except TimeoutError: + current_state = os_conn.get_instance_detail(instance).status + assert_true( + current_state == expected_state, + "Timeout is reached.Current state of Vm {0} is {1}".format( + instance.name, current_state) + ) + return instance + + +def create_and_assign_floating_ips(os_conn, instance): + """Create Vms on available hypervisors. + + :param os_conn: type object, openstack + :param instance: type string, name of instance + """ + ip = os_conn.assign_floating_ip(instance).ip + wait(lambda: icmp_ping(ip), timeout=60 * 5, interval=5) + return ip + + +def get_ssh_connection(ip, username='manila', user_password='manila', + timeout=30, + port=22): + """Get ssh to host. + + :param ip: string, host ip to connect to + :param username: string, a username to use for authentication + :param user_password: string, a password to use for authentication + :param timeout: timeout (in seconds) for the TCP connection + :param port: host port to connect to + """ + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + wait(lambda: sock.connect_ex((ip, port)) == 0, timeout=60 * 5, interval=5) + logger.info('#' * 10 + "ssh is avaliable on server") + ssh = paramiko.SSHClient() + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + ssh.connect( + ip, port=port, + username=username, + password=user_password, + timeout=timeout + ) + return ssh + + +def execute(ssh_client, command): + """Execute command on remote host. + + :param ssh_client: SSHClient to instance + :param command: type string, command to execute + """ + channel = ssh_client.get_transport().open_session() + channel.exec_command(command) + result = {'stdout': [], + 'stderr': [], + 'exit_code': 0 + } + result['exit_code'] = channel.recv_exit_status() + result['stdout'] = channel.recv(1024) + result['stderr'] = channel.recv_stderr(1024) + return result diff --git a/plugin_test/helpers/os_manila_actions.py b/plugin_test/helpers/os_manila_actions.py new file mode 100644 index 0000000..d86fdd7 --- /dev/null +++ b/plugin_test/helpers/os_manila_actions.py @@ -0,0 +1,164 @@ +# Copyright 2014 Mirantis, Inc. +# +# 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. + +from devops.helpers.helpers import wait +from fuelweb_test.helpers import common +from fuelweb_test.settings import DISABLE_SSL +from fuelweb_test.settings import PATH_TO_CERT +from fuelweb_test.settings import VERIFY_SSL +from keystoneauth1.session import Session as KeystoneSession +from keystoneclient.auth.identity import v2 +from manilaclient.v2 import client + + +class ManilaActions(common.Common): + """Manila client class to operate with Manila API""" + + def __make_auth_url(self, controller_ip): + if DISABLE_SSL: + auth_url = 'http://{0}:5000/v2.0'.format(controller_ip) + path_to_cert = None + return auth_url, path_to_cert + else: + auth_url = 'https://{0}:5000/v2.0'.format(controller_ip) + path_to_cert = PATH_TO_CERT + return auth_url, path_to_cert + + def __init__(self, controller_ip, user='admin', passwd='admin', + tenant='admin'): + """Create API client for manila service""" + super(ManilaActions, self).__init__(controller_ip, + user, passwd, + tenant) + + auth_url, cert_path = self.__make_auth_url(controller_ip) + auth = v2.Password(auth_url=auth_url, username=user, + password=passwd, tenant_name=tenant) + + if not DISABLE_SSL: + if VERIFY_SSL: + self.__keystone_ses = KeystoneSession( + auth=auth, ca_cert=cert_path) + else: + self.__keystone_ses = KeystoneSession( + auth=auth, verify=False) + else: + self.__keystone_ses = KeystoneSession( + auth=auth) + + def create_share_network(self, + net_id=None, + subnet_id=None, + name='Test Share network', + description='For testing purpose' + ): + """Create share network""" + + if self.get_share_network(name) is None: + manila_client = client.Client('2', session=self.__keystone_ses) + share_network = manila_client.share_networks.create( + neutron_net_id=net_id, + neutron_subnet_id=subnet_id, + nova_net_id=None, + name=name, + description=description + ) + return share_network + else: + return self.get_share_network(name) + + def get_share_network(self, net_name): + """Get share network by name""" + + manila_client = client.Client('2', session=self.__keystone_ses) + for network in manila_client.share_networks.list(): + if network.name == net_name: + return network + + def get_share_type(self, name=None): + """Get a list of all share types""" + manila_client = client.Client('2', session=self.__keystone_ses) + if name is None: + for share_type in manila_client.share_types.list(): + return share_type + else: + for share_type in manila_client.share_types.list(): + if share_type.name == name: + return share_type + + def create_share_type(self, type_name='Test_share_type', + handle_serv=True, + snap_sup=True, + public_share=True): + + """Create share type""" + if self.get_share_type(type_name) is None: + manila_client = client.Client('2', session=self.__keystone_ses) + manila_client.share_types.create( + name=type_name, + spec_driver_handles_share_servers=handle_serv, + spec_snapshot_support=snap_sup, + is_public=public_share + ) + return self.get_share_type(type_name) + + def get_share(self, share_name): + """Return object share with specified name""" + manila_client = client.Client('2', session=self.__keystone_ses) + for share in manila_client.shares.list(): + if share.name == share_name: + return share + return None + + def create_basic_share(self, protocol='NFS', + size=1, + share_name='Default_test_share', + share_type='default_share_type', + network=None, + public_share=True): + + """Create share""" + + manila_client = client.Client('2', session=self.__keystone_ses) + share = manila_client.shares.create( + share_proto=protocol, + size=size, + name=share_name, + share_type=share_type, + share_network=network, + is_public=public_share + ) + return share + + def get_shares_list(self): + """Get a list of all shares.""" + manila_client = client.Client('2', session=self.__keystone_ses) + for share in manila_client.shares.list(): + return share.name + + def wait_for_share_status(self, share_name, status): + """Waits for a share to reach a given status.""" + + wait(lambda: self.get_share(share_name).status == status, + timeout=60 * 5, interval=5, + timeout_msg="Share didn't get status avaliable") + + def add_acc_rule(self, share_id, acc_type='ip', rule=None, acc_level='rw'): + """Add access rule for specific share""" + + manila_client = client.Client('2', session=self.__keystone_ses) + manila_client.shares.allow(share=share_id, access_type=acc_type, + access=rule, access_level=acc_level) + return manila_client.shares.access_list(share_id) +