Code refactor: spawn_vm.py 41/23541/2
authorwu.zhihui <wu.zhihui1@zte.com.cn>
Sat, 22 Oct 2016 09:02:33 +0000 (17:02 +0800)
committerwu.zhihui <wu.zhihui1@zte.com.cn>
Fri, 28 Oct 2016 06:09:08 +0000 (14:09 +0800)
1. update SampleHeat.yaml
2. No need to fetch private key file my_key.pem.
3. remove keypair value from spawn_vm_test.py
4. cleanup redundant code.

Change-Id: Id7ccdbae5b88c86ebff7518710b6c91ab4281c53
Signed-off-by: wu.zhihui <wu.zhihui1@zte.com.cn>
config/SampleHeat.yaml
func/spawn_vm.py
tests/spawn_vm_test.py

index ae9f566..a42cdb7 100644 (file)
@@ -1,36 +1,66 @@
-heat_template_version: 2014-10-16
-parameters:
+heat_template_version: 2015-04-30
+
+description: >
+  Used to run VMs for Qtip
 
-  private_net_name:
+parameters:
+  image:
     type: string
-    default: 'private_network'
-    
-  availability_zone:
+    description: Name of the image
+    default: QTIP_CentOS
+
+  external_net_name:
     type: string
-    description: The AvailZone.
-    default: compute1
-  
+    description: Name of the external network which management network will connect to
+    default: admin_floating_net
+
 resources:
+  flavor:
+    type: OS::Nova::Flavor
+    properties:
+      ram: 8192
+      vcpus: 8
+      disk: 80
 
-  private_network:
-     type: OS::Neutron::Net
-  private_subnet:
+  network:
+    type: OS::Neutron::Net
+    properties:
+      name: qtip_net
+
+  subnet:
     type: OS::Neutron::Subnet
     properties:
-      network_id:  { get_resource: private_network }
-      cidr: '10.10.17.0/24'
-      dns_nameservers: [ '8.8.8.8' ]
-      gateway_ip: '10.10.17.1'
-      allocation_pools: [ {"start":'10.10.17.2', "end": '10.10.17.200'} ]
-  router_1:
+      name: qtip_subnet
+      ip_version: 4
+      cidr: 192.168.0.0/24
+      network: { get_resource: network }
+      dns_nameservers: [8.8.8.8]
+
+  management_router:
     type: OS::Neutron::Router
     properties:
+      name: qtip_router
       external_gateway_info:
-        network: { get_param: public_network  }
-  router_interface:
+        network: { get_param: external_net_name }
+
+  management_router_interface:
     type: OS::Neutron::RouterInterface
     properties:
-      router_id: { get_resource: router_1 } 
-      subnet: { get_resource: private_subnet }
+      router: { get_resource: management_router }
+      subnet: { get_resource: subnet }
+
+  security_group:
+    type: OS::Neutron::SecurityGroup
+    properties:
+      name: qtip_security_group
+      rules:
+          - port_range_min: 22
+            port_range_max: 5201
+            protocol: tcp
+          - port_range_min: 22
+            port_range_max: 5201
+            protocol: udp
+          - protocol: icmp
+
 outputs:
   description: 'none'
index 3a16e02..0a24d7a 100644 (file)
 ##############################################################################\r
-# Copyright (c) 2015 Dell Inc  and others.\r
+# Copyright (c) 2016 Dell Inc, ZTE and others.\r
 #\r
 # All rights reserved. This program and the accompanying materials\r
 # are made available under the terms of the Apache License, Version 2.0\r
 # which accompanies this distribution, and is available at\r
 # http://www.apache.org/licenses/LICENSE-2.0\r
 ##############################################################################\r
-\r
 import os\r
 import sys\r
-from collections import defaultdict\r
-from func.env_setup import Env_setup\r
 import yaml\r
 import heatclient.client\r
 import keystoneclient\r
-from novaclient import client\r
 import time\r
+from func.env_setup import Env_setup\r
 from func.create_zones import AvailabilityZone\r
+from utils import logger_utils\r
+\r
+logger = logger_utils.QtipLogger('spawn_vm').get\r
 \r
 \r
 class SpawnVM(Env_setup):\r
-    vm_role_ip_dict = defaultdict(list)\r
-    installer = ''\r
 \r
     def __init__(self, vm_info):\r
-        print 'SpawnVM Class initiated'\r
-        print 'vm_info: %s' % vm_info\r
+        logger.info('vm_info: %s' % vm_info)\r
         vm_role_ip_dict = vm_info.copy()\r
-        print 'Generating Heat Template\n'\r
         self._keystone_client = None\r
         self._heat_client = None\r
         self._glance_client = None\r
         self._nova_client = None\r
-        self. _get_nova_client()\r
         self.azone = AvailabilityZone()\r
         # TODO: it should clean up aggregates and stack after test case finished.\r
         self.azone.clean_all_aggregates()\r
         self.azone.create_aggs(vm_info['availability_zone'])\r
-        installer = self.get_installer_type()\r
-        self.Heat_template1 = self.heat_template_vm(vm_info, installer)\r
-        self.create_stack(vm_role_ip_dict, self.Heat_template1)\r
+        self.heat_template = self.generate_heat_template(vm_info)\r
+        self.create_stack(vm_role_ip_dict)\r
 \r
     @staticmethod\r
-    def get_installer_type():\r
-        print 'Getting Installer Name'\r
-        return os.environ['INSTALLER_TYPE']\r
-\r
-    @staticmethod\r
-    def get_public_network(installer_detected):\r
+    def get_public_network():\r
 \r
         """\r
         TODO: GET THE NAMES OF THE PUBLIC NETWORKS for OTHER PROJECTS\r
         """\r
-        print 'Getting Public Network'\r
-        if installer_detected.lower() == 'fuel':\r
+        installer = os.environ['INSTALLER_TYPE']\r
+\r
+        if installer.lower() == 'fuel':\r
             return 'admin_floating_net'\r
-        if installer_detected.lower() == 'apex':\r
+        if installer.lower() == 'apex':\r
             return 'external'\r
-        if installer_detected.lower() == 'compass':\r
+        if installer.lower() == 'compass':\r
             return 'ext-net'\r
-        if installer_detected.lower() == 'joid':\r
+        if installer.lower() == 'joid':\r
             return 'ext-net'\r
 \r
-    def heat_template_vm(self, vm_params, installer):\r
-        Heat_Dic = {}\r
+    def generate_heat_template(self, vm_params):\r
+        logger.info('Generating Heat Template')\r
+        heat_dict = {}\r
         try:\r
             with open('./config/SampleHeat.yaml', 'r+') as H_temp:\r
-                Heat_Dic = yaml.safe_load(H_temp)\r
+                heat_dict = yaml.safe_load(H_temp)\r
         except yaml.YAMLError as exc:\r
             if hasattr(exc, 'problem_mark'):\r
                 mark = exc.problem_mark\r
-                print 'Error in qtip/config/SampleHeat.yaml at: (%s,%s)' % (mark.line + 1, mark.column + 1)\r
-                print 'EXITING PROGRAM. Correct File and restart'\r
+                logger.error(\r
+                    'Error in qtip/config/SampleHeat.yaml at: (%s,%s)' % (mark.line + 1,\r
+                                                                          mark.column + 1))\r
+                logger.error('EXITING PROGRAM. Correct File and restart')\r
                 sys.exit(1)\r
+\r
         fopen = open('./config/QtipKey.pub', 'r')\r
         fopenstr = fopen.read()\r
         fopenstr = fopenstr.rstrip()\r
         scriptcmd = '#!/bin/bash \n echo {0} >>  foo.txt \n echo {1} >> /root/.ssh/authorized_keys'.format(\r
             fopenstr, fopenstr)\r
 \r
-        netName = self.get_public_network(installer)\r
-        print netName\r
-        Heat_Dic['heat_template_version'] = '2014-10-16'\r
-        Heat_Dic['resources']['KeyPairSavePrivate'] = {\r
-            'type': 'OS::Nova::KeyPair',\r
-            'properties': {\r
-                    'save_private_key': 'true',\r
-                    'name': 'my_key'\r
-            }\r
-        }\r
-        Heat_Dic['parameters']['public_network'] = {\r
+        netName = self.get_public_network()\r
+        heat_dict['heat_template_version'] = '2015-04-30'\r
+\r
+        heat_dict['parameters']['public_network'] = {\r
             'type': 'string',\r
             'default': netName\r
         }\r
+\r
         for x in range(1, len(vm_params['availability_zone']) + 1):\r
             avail_zone = vm_params['availability_zone'][x - 1]\r
-            img = vm_params['OS_image'][x - 1]\r
-            flavor = vm_params['flavor'][x - 1]\r
 \r
-            Heat_Dic['parameters']['availability_zone_' + str(x)] = \\r
+            heat_dict['parameters']['availability_zone_' + str(x)] = \\r
                 {'description': 'Availability Zone of the instance',\r
                  'default': avail_zone,\r
                  'type': 'string'}\r
 \r
-            Heat_Dic['resources']['public_port_' + str(x)] = \\r
+            heat_dict['resources']['public_port_' + str(x)] = \\r
                 {'type': 'OS::Neutron::Port',\r
-                 'properties': {'network': {'get_resource': 'private_network'},\r
-                                'security_groups': [{'get_resource': 'demo1_security_Group'}],\r
-                                'fixed_ips': [{'subnet_id':\r
-                                               {'get_resource': 'private_subnet'}}]}}\r
+                 'properties': {'network': {'get_resource': 'network'},\r
+                                'security_groups': [{'get_resource': 'security_group'}],\r
+                                'fixed_ips': [{'subnet_id': {'get_resource': 'subnet'}}]}}\r
 \r
-            Heat_Dic['resources']['floating_ip_' + str(x)] = {\r
+            heat_dict['resources']['floating_ip_' + str(x)] = {\r
                 'type': 'OS::Neutron::FloatingIP',\r
-                'properties': {\r
-                    'floating_network': {'get_param': 'public_network'}}}\r
+                'properties': {'floating_network': {'get_param': 'external_net_name'}}}\r
 \r
-            Heat_Dic['resources']['floating_ip_assoc_' + str(x)] = {\r
+            heat_dict['resources']['floating_ip_assoc_' + str(x)] = {\r
                 'type': 'OS::Neutron::FloatingIPAssociation',\r
                 'properties': {\r
                     'floatingip_id': {'get_resource': 'floating_ip_' + str(x)},\r
                     'port_id': {'get_resource': 'public_port_' + str(x)}}}\r
 \r
-            Heat_Dic['resources']['my_instance_' + str(x)] = \\r
+            heat_dict['resources']['my_instance_' + str(x)] = \\r
                 {'type': 'OS::Nova::Server',\r
-                 'properties': {'image': img,\r
+                 'properties': {'image': {'get_param': 'image'},\r
                                 'networks':\r
                                     [{'port': {'get_resource': 'public_port_' + str(x)}}],\r
-                                'flavor': flavor,\r
+                                'flavor': {'get_resource': 'flavor'},\r
                                 'availability_zone': avail_zone,\r
+                                'security_groups': [{'get_resource': 'security_group'}],\r
                                 'name': 'instance' + str(x),\r
-                                'key_name': {'get_resource': 'KeyPairSavePrivate'},\r
                                 'user_data_format': 'RAW',\r
                                 'user_data': scriptcmd}}\r
 \r
-            Heat_Dic['resources']['demo1_security_Group'] = {\r
-                'type': 'OS::Neutron::SecurityGroup',\r
-                'properties': {\r
-                    'name': 'demo1_security_Group',\r
-                    'rules': [{\r
-                        'protocol': 'tcp',\r
-                        'port_range_min': 22,\r
-                        'port_range_max': 5201},\r
-                        {'protocol': 'udp',\r
-                         'port_range_min': 22,\r
-                         'port_range_max': 5201},\r
-                        {'protocol': 'icmp'}]}}\r
-\r
-            Heat_Dic['outputs']['instance_PIP_' + str(x)] = {\r
+            heat_dict['outputs']['instance_PIP_' + str(x)] = {\r
                 'description': 'IP address of the instance',\r
                 'value': {'get_attr': ['my_instance_' + str(x), 'first_address']}}\r
-            Heat_Dic['outputs']['instance_ip_' + str(x)] = {\r
+\r
+            heat_dict['outputs']['instance_ip_' + str(x)] = {\r
                 'description': 'IP address of the instance',\r
                 'value': {'get_attr': ['floating_ip_' + str(x), 'floating_ip_address']}}\r
 \r
-            Heat_Dic['outputs']['availability_instance_' + str(x)] = {\r
+            heat_dict['outputs']['availability_instance_' + str(x)] = {\r
                 'description': 'Availability Zone of the Instance',\r
                 'value': {'get_param': 'availability_zone_' + str(x)}}\r
 \r
-        Heat_Dic['outputs']['KeyPair_PublicKey'] = {\r
-            'description': 'Private Key',\r
-            'value': {'get_attr': ['KeyPairSavePrivate', 'private_key']}\r
-        }\r
-        del Heat_Dic['outputs']['description']\r
-        print Heat_Dic\r
-        return Heat_Dic\r
+        del heat_dict['outputs']['description']\r
+        logger.info(heat_dict)\r
+\r
+        return heat_dict\r
 \r
     def _get_keystone_client(self):\r
         """returns a keystone client instance"""\r
@@ -176,12 +145,6 @@ class SpawnVM(Env_setup):
                 tenant_name=os.environ.get('OS_TENANT_NAME'))\r
         return self._keystone_client\r
 \r
-    def _get_nova_client(self):\r
-        if self._nova_client is None:\r
-            keystone = self._get_keystone_client()\r
-            self._nova_client = client.Client('2', token=keystone.auth_token)\r
-        return self._nova_client\r
-\r
     def _get_heat_client(self):\r
         """returns a heat client instance"""\r
         if self._heat_client is None:\r
@@ -192,45 +155,29 @@ class SpawnVM(Env_setup):
                 '1', endpoint=heat_endpoint, token=keystone.auth_token)\r
         return self._heat_client\r
 \r
-    def create_stack(self, vm_role_ip_dict, heat_template):\r
-\r
-        global sshkey\r
+    def create_stack(self, vm_role_ip_dict):\r
         stackname = 'QTIP'\r
         heat = self._get_heat_client()\r
 \r
-        for checks in range(3):\r
-            print "Try to delete heats %s" % checks\r
-            for prev_stacks in heat.stacks.list():\r
-                if prev_stacks.stack_name == 'QTIP':\r
-                    print 'QTIP Stacks exists.\nDeleting Existing Stack'\r
-                    heat.stacks.delete('QTIP')\r
-                    time.sleep(10)\r
-        print '\nStack Creating Started\n'\r
+        self.delete_stack(stackname)\r
 \r
-        try:\r
-            heat.stacks.create(stack_name=stackname, template=heat_template)\r
-        except Exception:\r
-            print 'Create Failed :( '\r
-\r
-        cluster_detail = heat.stacks.get(stackname)\r
-        while cluster_detail.status != 'COMPLETE':\r
-            if cluster_detail.status == 'IN_PROGRESS':\r
-                print 'Stack Creation in Progress'\r
-            cluster_detail = heat.stacks.get(stackname)\r
-            time.sleep(10)\r
-        print 'Stack Created'\r
-        print 'Getting Public IP(s)'\r
-        zone = []\r
-        s = 0\r
-        for vm in range(len(vm_role_ip_dict['OS_image'])):\r
+        logger.info('Start to create stack %s' % stackname)\r
+        heat.stacks.create(stack_name=stackname, template=self.heat_template)\r
+\r
+        stack_status = "IN_PROGRESS"\r
+        while stack_status != 'COMPLETE':\r
+            if stack_status == 'IN_PROGRESS':\r
+                logger.debug('Create in Progress')\r
+            if stack_status == 'CREATE_FAILED':\r
+                raise RuntimeError("Stack %s created failed!" % stackname)\r
+            stack_status = heat.stacks.get(stackname).status\r
+            time.sleep(15)\r
+        logger.info('Stack %s Created Complete!' % stackname)\r
 \r
-            for I in cluster_detail.outputs:\r
-                availabilityKey = 'availability_instance_' + str(vm + 1)\r
+        stack_outputs = heat.stacks.get(stackname).outputs\r
 \r
-                if I['output_key'] == availabilityKey:\r
-                    zone.insert(s, str(I['output_value']))\r
-                    s = s + 1\r
-            for i in cluster_detail.outputs:\r
+        for vm in range(len(vm_role_ip_dict['OS_image'])):\r
+            for i in stack_outputs:\r
                 instanceKey = "instance_ip_" + str(vm + 1)\r
                 privateIPkey = 'instance_PIP_' + str(vm + 1)\r
                 if i['output_key'] == instanceKey:\r
@@ -240,10 +187,20 @@ class SpawnVM(Env_setup):
 \r
                 if i['output_key'] == privateIPkey:\r
                     Env_setup.ip_pw_dict[vm_role_ip_dict['role'][vm]] = str(i['output_value'])\r
-                if i['output_key'] == 'KeyPair_PublicKey':\r
-                    sshkey = str(i['output_value'])\r
 \r
-        with open('./config/my_key.pem', 'w') as fopen:\r
-            fopen.write(sshkey)\r
-        fopen.close()\r
-        print Env_setup.ip_pw_list\r
+        logger.info('Getting Public IP(s): %s' % Env_setup.ip_pw_list)\r
+\r
+    def delete_stack(self, stack_name):\r
+        heat = self._get_heat_client()\r
+\r
+        stacks = heat.stacks.list()\r
+        exists = map(lambda x: x.stack_name, stacks)\r
+        if stack_name in exists:\r
+            logger.info("Delete stack %s" % stack_name)\r
+            heat.stacks.delete(stack_name)\r
+            while stack_name in exists:\r
+                time.sleep(10)\r
+                stacks = heat.stacks.list()\r
+                exists = map(lambda x: x.stack_name, stacks)\r
+                logger.debug("exists_stacks: %s" % exists)\r
+        logger.info("%s doesn't exist" % stack_name)\r
index 7890abd..fca7dd0 100644 (file)
@@ -17,9 +17,7 @@ class StackMock(MagicMock):
                {'output_key': 'instance_ip_1',
                 "output_value": "172.10.0.154"},
                {"output_key": "instance_PIP_1",
-                "output_value": "10.10.17.5"},
-               {'output_key': 'KeyPair_PublicKey',
-                "output_value": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpwIBAAKCAQEAqCiHcrLBXtxG0LhnKndU7VIVpYxORmv0d4tvujkWOkYuagiW\nU/MTRk0zhRvFQDVPEs0Jrj/BIecqm6fjjT6dZ/H7JLYGaqJitRkoupKgBsMSIqUz\nrR0ekOlfXZ6N+Ud8k6s+qjc7BO4b1ezz78jHisC5o0GCkUV0ECx64Re1fO+oKs1c\nfL9aaexahJUYN3J48pazQz+imc2x/G9nuqHX3cqEszmxnT4jwv//In1GjHy2AyXw\n1oA5F6wZoQCSrXc2BditU+1tlVhEkPFt5JgiHUpY8T8mYbroT7JH6xjcGSKUN+HG\nN8PXNUTD1VAQfwHpkfsGMfDyzjytCXsoTEOqnwIDAQABAoIBAAEL/4vfQQTuKiKy\ngzHofEbd8/SL4xDdKzBzVca7BEBon3FZjFYJdV1CrcduXNQBgPSFAkJrczBa2BEQ\nAoKmmSREhWO9Hl0blbG67l36+7QPEtXUYXX6cG5Ghal3izq6DzR8JG+62Es3kETM\nrNgZT+S1PnKdvcpZvFc9b6ZnF2InuTbrmNVBZKrhdWOJ5tCwRGKKUl6BHoJH3yu0\nT5hUW277e1LYHx+hZtoZ98ToC+LGe6/M8a8y6VLYpcQlX2AtVXeGDalomunF+p3f\nuY6din6s4lq1gSJz03PTpUbwiuhYCTe8Xkseu74Y+XYYJXPHopFju0Ewd6p0Db9Q\nJzzxCoECggCBAM2ox9zyrDc/Vlc0bb9SciFGUd/nEJF89+UHy98bAkpo22zNZIDg\nfacSgkg/6faZD+KrOU0I5W7m2B5t6w2fNHHik6NYGSLQ1JhgbXELGV7X/qECDL02\nctPaf+8o+dYoZja2LdJNASq2nmEmPI3LSHhzAt4dWY4W+geXiHt4iWVHAoIAgQDR\nUdN09xv4U+stWqNcSfgjtx6boEUE8Ky7pyj+LrZKG0L61Jy9cSDP0x0rCtkW9vVR\n6RjidWM/DHQ5cl6aq+7pPy20/OqtqttFYT4R+C3AoAnRSaNzPD9a80C2gjv7WEz0\nPPFstWkI1gsN71KKRx7e6NIa9CNn5x9iE+SGfjgb6QKCAIBXylzG7LCnRNpOj4rp\nyP//RE1fDvv7nyUTF6jnrFfl+6zvXR4yBaKd10DWJrJxGhW15PGo+Ms39EL9el6E\nihmRI+9yIwFX411dToxpXRuPaRTBFmbpvnx2Ayfpp8w+pzA62rnktApzeVFSl0fy\nH3zoLfBjcJPyG8zPwNf6HRJJsQKCAIAE2S5asTaWo+r4m/bYtmXm/eDZnfa7TI/T\nsOWELbTPNp5wjOgsgyhNaAhu7MtmesXn5cxLwohP94vhoMKMNptMD8iRPqJ471Iw\n4zW62NLGeW6AyIHes3CMPMIs+AtHoR33MkotSG5sY/jRk8+HoGoYo6/qK+l+CJ5z\neR579wR5sQKCAIAvPWq+bvcPTDKUU1Fe/Y/GyWoUA+uSqmCdORBkK38lALFGphxj\nfDz9dXskimqW+A9hOPOS8dm8YcVvi/TLXVE5Vsx9VkOg6z6AZBQpgNXGfOgpju4W\nbjER7bQaASatuWQyCxbA9oNlAUdSeOhGTxeFLkLj7hNMd6tLjfd8w7A/hA==\n-----END RSA PRIVATE KEY-----\n"}]
+                "output_value": "10.10.17.5"}]
 
 
 class HeatMock(MagicMock):
@@ -44,16 +42,15 @@ class TestClass:
     ])
     @mock.patch('func.spawn_vm.Env_setup')
     @mock.patch('func.spawn_vm.AvailabilityZone')
-    @mock.patch('func.spawn_vm.client', autospec=True)
     @mock.patch('func.spawn_vm.keystoneclient.v2_0', autospec=True)
     @mock.patch('func.spawn_vm.heatclient.client', autospec=True)
     def test_create_zones_success(self, mock_heat, mock_keystone,
-                                  mock_nova_client, mock_zone,
-                                  mock_setup, test_input, expected):
-        mock_nova_client.Client.return_value = Mock()
+                                  mock_zone, mock_setup, test_input, expected):
+        open('./config/QtipKey.pub', 'a').close()
         mock_heat.Client.return_value = Mock(stacks=HeatMock())
         k = mock.patch.dict(os.environ, {'INSTALLER_TYPE': 'fuel'})
         k.start()
         SpawnVM(test_input)
         k.stop()
+        os.remove('./config/QtipKey.pub')
         mock_setup.ip_pw_list.append.assert_called_with(expected[0])