Addition of IPv6 icpm, udp and tcp to Neutron Security Group
[yardstick.git] / yardstick / orchestrator / heat.py
index fd6c4f6..57847bf 100644 (file)
@@ -21,7 +21,7 @@ import logging
 import socket
 import time
 
-import heatclient
+import heatclient.client
 import pkg_resources
 
 from oslo_utils import encodeutils
@@ -89,14 +89,14 @@ class HeatStack(HeatObject):
         if self.uuid is None:
             return
 
-        log.info("Deleting stack '%s', uuid:%s", self.name, self.uuid)
+        log.info("Deleting stack '%s' START, uuid:%s", self.name, self.uuid)
         heat = self.heat_client
         template = heat.stacks.get(self.uuid)
         start_time = time.time()
         template.delete()
 
         for status in iter(self.status, u'DELETE_COMPLETE'):
-            log.debug("stack state %s", status)
+            log.debug("Deleting stack state: %s", status)
             if status == u'DELETE_FAILED':
                 raise RuntimeError(
                     heat.stacks.get(self.uuid).stack_status_reason)
@@ -104,7 +104,7 @@ class HeatStack(HeatObject):
             time.sleep(2)
 
         end_time = time.time()
-        log.info("Deleted stack '%s' in %d secs", self.name,
+        log.info("Deleting stack '%s' DONE in %d secs", self.name,
                  end_time - start_time)
         self.uuid = None
 
@@ -230,27 +230,68 @@ name (i.e. %s).\
             'value': {'get_resource': name}
         }
 
+    def add_volume(self, name, size=10):
+        """add to the template a volume description"""
+        log.debug("adding Cinder::Volume '%s' size '%d' ", name, size)
+
+        self.resources[name] = {
+            'type': 'OS::Cinder::Volume',
+            'properties': {'name': name,
+                           'size': size}
+        }
+
+        self._template['outputs'][name] = {
+            'description': 'Volume %s ID' % name,
+            'value': {'get_resource': name}
+        }
+
+    def add_volume_attachment(self, server_name, volume_name, mountpoint=None):
+        """add to the template an association of volume to instance"""
+        log.debug("adding Cinder::VolumeAttachment server '%s' volume '%s' ", server_name,
+                  volume_name)
+
+        name = "%s-%s" % (server_name, volume_name)
+
+        volume_id = op_utils.get_volume_id(volume_name)
+        if not volume_id:
+            volume_id = {'get_resource': volume_name}
+        self.resources[name] = {
+            'type': 'OS::Cinder::VolumeAttachment',
+            'properties': {'instance_uuid': {'get_resource': server_name},
+                           'volume_id': volume_id}
+        }
+
+        if mountpoint:
+            self.resources[name]['properties']['mountpoint'] = mountpoint
+
     def add_network(self, name, physical_network='physnet1', provider=None,
-                    segmentation_id=None):
+                    segmentation_id=None, port_security_enabled=None, network_type=None):
         """add to the template a Neutron Net"""
         log.debug("adding Neutron::Net '%s'", name)
         if provider is None:
             self.resources[name] = {
                 'type': 'OS::Neutron::Net',
-                'properties': {'name': name}
+                'properties': {
+                    'name': name,
+                }
             }
         else:
             self.resources[name] = {
                 'type': 'OS::Neutron::ProviderNet',
                 'properties': {
                     'name': name,
-                    'network_type': 'vlan',
-                    'physical_network': physical_network
-                }
+                    'network_type': 'flat' if network_type is None else network_type,
+                    'physical_network': physical_network,
+                },
             }
             if segmentation_id:
-                seg_id_dit = {'segmentation_id': segmentation_id}
-                self.resources[name]["properties"].update(seg_id_dit)
+                self.resources[name]['properties']['segmentation_id'] = segmentation_id
+                if network_type is None:
+                    self.resources[name]['properties']['network_type'] = 'vlan'
+        # if port security is not defined then don't add to template:
+        # some deployments don't have port security plugin installed
+        if port_security_enabled is not None:
+            self.resources[name]['properties']['port_security_enabled'] = port_security_enabled
 
     def add_server_group(self, name, policies):     # pragma: no cover
         """add to the template a ServerGroup"""
@@ -262,8 +303,9 @@ name (i.e. %s).\
                            'policies': policies}
         }
 
-    def add_subnet(self, name, network, cidr):
-        """add to the template a Neutron Subnet"""
+    def add_subnet(self, name, network, cidr, enable_dhcp='true', gateway_ip=None):
+        """add to the template a Neutron Subnet
+        """
         log.debug("adding Neutron::Subnet '%s' in network '%s', cidr '%s'",
                   name, network, cidr)
         self.resources[name] = {
@@ -272,9 +314,14 @@ name (i.e. %s).\
             'properties': {
                 'name': name,
                 'cidr': cidr,
-                'network_id': {'get_resource': network}
+                'network_id': {'get_resource': network},
+                'enable_dhcp': enable_dhcp,
             }
         }
+        if gateway_ip == 'null':
+            self.resources[name]['properties']['gateway_ip'] = None
+        elif gateway_ip is not None:
+            self.resources[name]['properties']['gateway_ip'] = gateway_ip
 
         self._template['outputs'][name] = {
             'description': 'subnet %s ID' % name,
@@ -316,16 +363,18 @@ name (i.e. %s).\
             }
         }
 
-    def add_port(self, name, network_name, subnet_name, sec_group_id=None,
-                 provider=None):
-        """add to the template a named Neutron Port"""
-        log.debug("adding Neutron::Port '%s', network:'%s', subnet:'%s', "
-                  "secgroup:%s", name, network_name, subnet_name, sec_group_id)
+    def add_port(self, name, network_name, subnet_name, vnic_type, sec_group_id=None,
+                 provider=None, allowed_address_pairs=None):
+        """add to the template a named Neutron Port
+        """
+        log.debug("adding Neutron::Port '%s', network:'%s', subnet:'%s', vnic_type:'%s', "
+                  "secgroup:%s", name, network_name, subnet_name, vnic_type, sec_group_id)
         self.resources[name] = {
             'type': 'OS::Neutron::Port',
             'depends_on': [subnet_name],
             'properties': {
                 'name': name,
+                'binding:vnic_type': vnic_type,
                 'fixed_ips': [{'subnet': {'get_resource': subnet_name}}],
                 'network_id': {'get_resource': network_name},
                 'replacement_policy': 'AUTO',
@@ -341,6 +390,10 @@ name (i.e. %s).\
             self.resources[name]['properties']['security_groups'] = \
                 [sec_group_id]
 
+        if allowed_address_pairs:
+            self.resources[name]['properties'][
+                'allowed_address_pairs'] = allowed_address_pairs
+
         self._template['outputs'][name] = {
             'description': 'Address for interface %s' % name,
             'value': {'get_attr': [name, 'fixed_ips', 0, 'ip_address']}
@@ -444,7 +497,7 @@ name (i.e. %s).\
             'type': 'OS::Neutron::SecurityGroup',
             'properties': {
                 'name': name,
-                'description': "Group allowing icmp and upd/tcp on all ports",
+                'description': "Group allowing IPv4 and IPv6 for icmp and upd/tcp on all ports",
                 'rules': [
                     {'remote_ip_prefix': '0.0.0.0/0',
                      'protocol': 'tcp',
@@ -455,7 +508,20 @@ name (i.e. %s).\
                      'port_range_min': '1',
                      'port_range_max': '65535'},
                     {'remote_ip_prefix': '0.0.0.0/0',
-                     'protocol': 'icmp'}
+                     'protocol': 'icmp'},
+                    {'remote_ip_prefix': '::/0',
+                     'ethertype': 'IPv6',
+                     'protocol': 'tcp',
+                     'port_range_min': '1',
+                     'port_range_max': '65535'},
+                    {'remote_ip_prefix': '::/0',
+                     'ethertype': 'IPv6',
+                     'protocol': 'udp',
+                     'port_range_min': '1',
+                     'port_range_max': '65535'},
+                    {'remote_ip_prefix': '::/0',
+                     'ethertype': 'IPv6',
+                     'protocol': 'ipv6-icmp'}
                 ]
             }
         }
@@ -534,6 +600,7 @@ name (i.e. %s).\
         }
 
     HEAT_WAIT_LOOP_INTERVAL = 2
+    HEAT_CREATE_COMPLETE_STATUS = u'CREATE_COMPLETE'
 
     def create(self, block=True, timeout=3600):
         """
@@ -545,7 +612,7 @@ name (i.e. %s).\
         :param: timeout: timeout in seconds for Heat create, default 3600s
         :type timeout: int
         """
-        log.info("Creating stack '%s'", self.name)
+        log.info("Creating stack '%s' START", self.name)
 
         # create stack early to support cleanup, e.g. ctrl-c while waiting
         stack = HeatStack(self.name)
@@ -558,14 +625,18 @@ name (i.e. %s).\
 
         if not block:
             self.outputs = stack.outputs = {}
+            end_time = time.time()
+            log.info("Creating stack '%s' DONE in %d secs",
+                     self.name, end_time - start_time)
             return stack
 
         time_limit = start_time + timeout
-        for status in iter(self.status, u'CREATE_COMPLETE'):
-            log.debug("stack state %s", status)
+        for status in iter(self.status, self.HEAT_CREATE_COMPLETE_STATUS):
+            log.debug("Creating stack state: %s", status)
             if status == u'CREATE_FAILED':
-                raise RuntimeError(
-                    heat_client.stacks.get(self.uuid).stack_status_reason)
+                stack_status_reason = heat_client.stacks.get(self.uuid).stack_status_reason
+                heat_client.stacks.delete(self.uuid)
+                raise RuntimeError(stack_status_reason)
             if time.time() > time_limit:
                 raise RuntimeError("Heat stack create timeout")
 
@@ -573,7 +644,7 @@ name (i.e. %s).\
 
         end_time = time.time()
         outputs = heat_client.stacks.get(self.uuid).outputs
-        log.info("Created stack '%s' in %d secs",
+        log.info("Creating stack '%s' DONE in %d secs",
                  self.name, end_time - start_time)
 
         # keep outputs as unicode