Define validation_resources function for ssh validation

This patch implements changes needed to setup validation resources
for verifying ssh access to VM.

Partially implements: blueprint ssh-auth-strategy

Change-Id: I61d7e12ee842165006a2e0c5f74b8c513c3e57b2
diff --git a/tempest/api/compute/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py
index ee756f4..443357f 100644
--- a/tempest/api/compute/servers/test_create_server.py
+++ b/tempest/api/compute/servers/test_create_server.py
@@ -43,6 +43,7 @@
 
     @classmethod
     def resource_setup(cls):
+        cls.set_validation_resources()
         super(ServersTestJSON, cls).resource_setup()
         cls.meta = {'hello': 'world'}
         cls.accessIPv4 = '1.1.1.1'
diff --git a/tempest/common/validation_resources.py b/tempest/common/validation_resources.py
new file mode 100644
index 0000000..d370ebc
--- /dev/null
+++ b/tempest/common/validation_resources.py
@@ -0,0 +1,113 @@
+# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
+#    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 oslo_log import log as logging
+
+from tempest import config
+from tempest_lib.common.utils import data_utils
+from tempest_lib import exceptions as lib_exc
+
+CONF = config.CONF
+LOG = logging.getLogger(__name__)
+
+
+def create_ssh_security_group(os, add_rule=False):
+    security_group_client = os.security_groups_client
+    sg_name = data_utils.rand_name('securitygroup-')
+    sg_description = data_utils.rand_name('description-')
+    security_group = \
+        security_group_client.create_security_group(sg_name, sg_description)
+    if add_rule:
+        security_group_client.create_security_group_rule(security_group['id'],
+                                                         'tcp', 22, 22)
+        security_group_client.create_security_group_rule(security_group['id'],
+                                                         'icmp', -1, -1)
+    LOG.debug("SSH Validation resource security group with tcp and icmp "
+              "rules %s created"
+              % sg_name)
+    return security_group
+
+
+def create_validation_resources(os, validation_resources=None):
+    # Create and Return the validation resources required to validate a VM
+    validation_data = {}
+    if validation_resources:
+        if validation_resources['keypair']:
+            keypair_name = data_utils.rand_name('keypair')
+            validation_data['keypair'] = \
+                os.keypairs_client.create_keypair(keypair_name)
+            LOG.debug("Validation resource key %s created" % keypair_name)
+        add_rule = False
+        if validation_resources['security_group']:
+            if validation_resources['security_group_rules']:
+                add_rule = True
+            validation_data['security_group'] = \
+                create_ssh_security_group(os, add_rule)
+        if validation_resources['floating_ip']:
+            floating_client = os.floating_ips_client
+            validation_data['floating_ip'] = \
+                floating_client.create_floating_ip()
+    return validation_data
+
+
+def clear_validation_resources(os, validation_data=None):
+    # Cleanup the vm validation resources
+    has_exception = None
+    if validation_data:
+        if 'keypair' in validation_data:
+            keypair_client = os.keypairs_client
+            keypair_name = validation_data['keypair']['name']
+            try:
+                keypair_client.delete_keypair(keypair_name)
+            except lib_exc.NotFound:
+                LOG.warn("Keypair %s is not found when attempting to delete"
+                         % keypair_name)
+            except Exception as exc:
+                LOG.exception('Exception raised while deleting key %s'
+                              % keypair_name)
+                if not has_exception:
+                    has_exception = exc
+        if 'security_group' in validation_data:
+            security_group_client = os.security_groups_client
+            sec_id = validation_data['security_group']['id']
+            try:
+                security_group_client.delete_security_group(sec_id)
+                security_group_client.wait_for_resource_deletion(sec_id)
+            except lib_exc.NotFound:
+                LOG.warn("Security group %s is not found when attempting to "
+                         " delete" % sec_id)
+            except lib_exc.Conflict as exc:
+                LOG.exception('Conflict while deleting security '
+                              'group %s VM might not be deleted ' % sec_id)
+                if not has_exception:
+                    has_exception = exc
+            except Exception as exc:
+                LOG.exception('Exception raised while deleting security '
+                              'group %s ' % sec_id)
+                if not has_exception:
+                    has_exception = exc
+        if 'floating_ip' in validation_data:
+            floating_client = os.floating_ips_client
+            fip_id = validation_data['floating_ip']['id']
+            try:
+                floating_client.delete_floating_ip(fip_id)
+            except lib_exc.NotFound:
+                LOG.warn('Floating ip %s not found while attempting to delete'
+                         % fip_id)
+            except Exception as exc:
+                LOG.exception('Exception raised while deleting ip %s '
+                              % fip_id)
+                if not has_exception:
+                    has_exception = exc
+    if has_exception:
+        raise has_exception
diff --git a/tempest/test.py b/tempest/test.py
index ae77284..2d5e94a 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -34,6 +34,7 @@
 from tempest.common import credentials
 from tempest.common import fixed_network
 import tempest.common.generator.valid_generator as valid
+import tempest.common.validation_resources as vresources
 from tempest import config
 from tempest import exceptions
 
@@ -231,6 +232,8 @@
     # NOTE(andreaf) credentials holds a list of the credentials to be allocated
     # at class setup time. Credential types can be 'primary', 'alt' or 'admin'
     credentials = []
+    # Resources required to validate a server using ssh
+    validation_resources = {}
     network_resources = {}
 
     # NOTE(sdague): log_format is defined inline here instead of using the oslo
@@ -360,7 +363,12 @@
     def resource_setup(cls):
         """Class level resource setup for test cases.
         """
-        pass
+        if hasattr(cls, "os"):
+            cls.validation_resources = vresources.create_validation_resources(
+                cls.os, cls.validation_resources)
+        else:
+            LOG.warn("Client manager not found, validation resources not"
+                     " created")
 
     @classmethod
     def resource_cleanup(cls):
@@ -368,7 +376,14 @@
         Resource cleanup must be able to handle the case of partially setup
         resources, in case a failure during `resource_setup` should happen.
         """
-        pass
+        if cls.validation_resources:
+            if hasattr(cls, "os"):
+                vresources.clear_validation_resources(cls.os,
+                                                      cls.validation_resources)
+                cls.validation_resources = {}
+            else:
+                LOG.warn("Client manager not found, validation resources not"
+                         " deleted")
 
     def setUp(self):
         super(BaseTestCase, self).setUp()
@@ -434,6 +449,43 @@
             cls.isolated_creds.clear_isolated_creds()
 
     @classmethod
+    def set_validation_resources(cls, keypair=None, floating_ip=None,
+                                 security_group=None,
+                                 security_group_rules=None):
+        """Specify which ssh server validation resources should be created.
+        Each of the argument must be set to either None, True or False, with
+        None - use default from config (security groups and security group
+               rules get created when set to None)
+        False - Do not create the validation resource
+        True - create the validation resource
+
+        @param keypair
+        @param security_group
+        @param security_group_rules
+        @param floating_ip
+        """
+        if keypair is None:
+            if CONF.validation.auth_method.lower() == "keypair":
+                keypair = True
+            else:
+                keypair = False
+        if floating_ip is None:
+            if CONF.validation.connect_method.lower() == "floating":
+                floating_ip = True
+            else:
+                floating_ip = False
+        if security_group is None:
+            security_group = True
+        if security_group_rules is None:
+            security_group_rules = True
+        if not cls.validation_resources:
+            cls.validation_resources = {
+                'keypair': keypair,
+                'security_group': security_group,
+                'security_group_rules': security_group_rules,
+                'floating_ip': floating_ip}
+
+    @classmethod
     def set_network_resources(cls, network=False, router=False, subnet=False,
                               dhcp=False):
         """Specify which network resources should be created