diff options
-rw-r--r-- | config/SampleHeat.yaml | 74 | ||||
-rw-r--r-- | docs/userguide/annex.rst | 2 | ||||
-rw-r--r-- | func/spawn_vm.py | 207 | ||||
-rw-r--r-- | tests/spawn_vm_test.py | 11 |
4 files changed, 139 insertions, 155 deletions
diff --git a/config/SampleHeat.yaml b/config/SampleHeat.yaml index ae9f5667..a42cdb79 100644 --- a/config/SampleHeat.yaml +++ b/config/SampleHeat.yaml @@ -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' diff --git a/docs/userguide/annex.rst b/docs/userguide/annex.rst index ce1775d6..e8bf5555 100644 --- a/docs/userguide/annex.rst +++ b/docs/userguide/annex.rst @@ -15,4 +15,4 @@ Annex Downloads ========= -- :download:`Sample configuration <../download/sample_config.yaml>`
\ No newline at end of file +- :download:`Sample configuration <../download/sample_config.yaml>` diff --git a/func/spawn_vm.py b/func/spawn_vm.py index 3a16e02d..0a24d7a4 100644 --- a/func/spawn_vm.py +++ b/func/spawn_vm.py @@ -1,169 +1,138 @@ ##############################################################################
-# Copyright (c) 2015 Dell Inc and others.
+# Copyright (c) 2016 Dell Inc, ZTE and others.
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Apache License, Version 2.0
# which accompanies this distribution, and is available at
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################
-
import os
import sys
-from collections import defaultdict
-from func.env_setup import Env_setup
import yaml
import heatclient.client
import keystoneclient
-from novaclient import client
import time
+from func.env_setup import Env_setup
from func.create_zones import AvailabilityZone
+from utils import logger_utils
+
+logger = logger_utils.QtipLogger('spawn_vm').get
class SpawnVM(Env_setup):
- vm_role_ip_dict = defaultdict(list)
- installer = ''
def __init__(self, vm_info):
- print 'SpawnVM Class initiated'
- print 'vm_info: %s' % vm_info
+ logger.info('vm_info: %s' % vm_info)
vm_role_ip_dict = vm_info.copy()
- print 'Generating Heat Template\n'
self._keystone_client = None
self._heat_client = None
self._glance_client = None
self._nova_client = None
- self. _get_nova_client()
self.azone = AvailabilityZone()
# TODO: it should clean up aggregates and stack after test case finished.
self.azone.clean_all_aggregates()
self.azone.create_aggs(vm_info['availability_zone'])
- installer = self.get_installer_type()
- self.Heat_template1 = self.heat_template_vm(vm_info, installer)
- self.create_stack(vm_role_ip_dict, self.Heat_template1)
+ self.heat_template = self.generate_heat_template(vm_info)
+ self.create_stack(vm_role_ip_dict)
@staticmethod
- def get_installer_type():
- print 'Getting Installer Name'
- return os.environ['INSTALLER_TYPE']
-
- @staticmethod
- def get_public_network(installer_detected):
+ def get_public_network():
"""
TODO: GET THE NAMES OF THE PUBLIC NETWORKS for OTHER PROJECTS
"""
- print 'Getting Public Network'
- if installer_detected.lower() == 'fuel':
+ installer = os.environ['INSTALLER_TYPE']
+
+ if installer.lower() == 'fuel':
return 'admin_floating_net'
- if installer_detected.lower() == 'apex':
+ if installer.lower() == 'apex':
return 'external'
- if installer_detected.lower() == 'compass':
+ if installer.lower() == 'compass':
return 'ext-net'
- if installer_detected.lower() == 'joid':
+ if installer.lower() == 'joid':
return 'ext-net'
- def heat_template_vm(self, vm_params, installer):
- Heat_Dic = {}
+ def generate_heat_template(self, vm_params):
+ logger.info('Generating Heat Template')
+ heat_dict = {}
try:
with open('./config/SampleHeat.yaml', 'r+') as H_temp:
- Heat_Dic = yaml.safe_load(H_temp)
+ heat_dict = yaml.safe_load(H_temp)
except yaml.YAMLError as exc:
if hasattr(exc, 'problem_mark'):
mark = exc.problem_mark
- print 'Error in qtip/config/SampleHeat.yaml at: (%s,%s)' % (mark.line + 1, mark.column + 1)
- print 'EXITING PROGRAM. Correct File and restart'
+ logger.error(
+ 'Error in qtip/config/SampleHeat.yaml at: (%s,%s)' % (mark.line + 1,
+ mark.column + 1))
+ logger.error('EXITING PROGRAM. Correct File and restart')
sys.exit(1)
+
fopen = open('./config/QtipKey.pub', 'r')
fopenstr = fopen.read()
fopenstr = fopenstr.rstrip()
scriptcmd = '#!/bin/bash \n echo {0} >> foo.txt \n echo {1} >> /root/.ssh/authorized_keys'.format(
fopenstr, fopenstr)
- netName = self.get_public_network(installer)
- print netName
- Heat_Dic['heat_template_version'] = '2014-10-16'
- Heat_Dic['resources']['KeyPairSavePrivate'] = {
- 'type': 'OS::Nova::KeyPair',
- 'properties': {
- 'save_private_key': 'true',
- 'name': 'my_key'
- }
- }
- Heat_Dic['parameters']['public_network'] = {
+ netName = self.get_public_network()
+ heat_dict['heat_template_version'] = '2015-04-30'
+
+ heat_dict['parameters']['public_network'] = {
'type': 'string',
'default': netName
}
+
for x in range(1, len(vm_params['availability_zone']) + 1):
avail_zone = vm_params['availability_zone'][x - 1]
- img = vm_params['OS_image'][x - 1]
- flavor = vm_params['flavor'][x - 1]
- Heat_Dic['parameters']['availability_zone_' + str(x)] = \
+ heat_dict['parameters']['availability_zone_' + str(x)] = \
{'description': 'Availability Zone of the instance',
'default': avail_zone,
'type': 'string'}
- Heat_Dic['resources']['public_port_' + str(x)] = \
+ heat_dict['resources']['public_port_' + str(x)] = \
{'type': 'OS::Neutron::Port',
- 'properties': {'network': {'get_resource': 'private_network'},
- 'security_groups': [{'get_resource': 'demo1_security_Group'}],
- 'fixed_ips': [{'subnet_id':
- {'get_resource': 'private_subnet'}}]}}
+ 'properties': {'network': {'get_resource': 'network'},
+ 'security_groups': [{'get_resource': 'security_group'}],
+ 'fixed_ips': [{'subnet_id': {'get_resource': 'subnet'}}]}}
- Heat_Dic['resources']['floating_ip_' + str(x)] = {
+ heat_dict['resources']['floating_ip_' + str(x)] = {
'type': 'OS::Neutron::FloatingIP',
- 'properties': {
- 'floating_network': {'get_param': 'public_network'}}}
+ 'properties': {'floating_network': {'get_param': 'external_net_name'}}}
- Heat_Dic['resources']['floating_ip_assoc_' + str(x)] = {
+ heat_dict['resources']['floating_ip_assoc_' + str(x)] = {
'type': 'OS::Neutron::FloatingIPAssociation',
'properties': {
'floatingip_id': {'get_resource': 'floating_ip_' + str(x)},
'port_id': {'get_resource': 'public_port_' + str(x)}}}
- Heat_Dic['resources']['my_instance_' + str(x)] = \
+ heat_dict['resources']['my_instance_' + str(x)] = \
{'type': 'OS::Nova::Server',
- 'properties': {'image': img,
+ 'properties': {'image': {'get_param': 'image'},
'networks':
[{'port': {'get_resource': 'public_port_' + str(x)}}],
- 'flavor': flavor,
+ 'flavor': {'get_resource': 'flavor'},
'availability_zone': avail_zone,
+ 'security_groups': [{'get_resource': 'security_group'}],
'name': 'instance' + str(x),
- 'key_name': {'get_resource': 'KeyPairSavePrivate'},
'user_data_format': 'RAW',
'user_data': scriptcmd}}
- Heat_Dic['resources']['demo1_security_Group'] = {
- 'type': 'OS::Neutron::SecurityGroup',
- 'properties': {
- 'name': 'demo1_security_Group',
- 'rules': [{
- 'protocol': 'tcp',
- 'port_range_min': 22,
- 'port_range_max': 5201},
- {'protocol': 'udp',
- 'port_range_min': 22,
- 'port_range_max': 5201},
- {'protocol': 'icmp'}]}}
-
- Heat_Dic['outputs']['instance_PIP_' + str(x)] = {
+ heat_dict['outputs']['instance_PIP_' + str(x)] = {
'description': 'IP address of the instance',
'value': {'get_attr': ['my_instance_' + str(x), 'first_address']}}
- Heat_Dic['outputs']['instance_ip_' + str(x)] = {
+
+ heat_dict['outputs']['instance_ip_' + str(x)] = {
'description': 'IP address of the instance',
'value': {'get_attr': ['floating_ip_' + str(x), 'floating_ip_address']}}
- Heat_Dic['outputs']['availability_instance_' + str(x)] = {
+ heat_dict['outputs']['availability_instance_' + str(x)] = {
'description': 'Availability Zone of the Instance',
'value': {'get_param': 'availability_zone_' + str(x)}}
- Heat_Dic['outputs']['KeyPair_PublicKey'] = {
- 'description': 'Private Key',
- 'value': {'get_attr': ['KeyPairSavePrivate', 'private_key']}
- }
- del Heat_Dic['outputs']['description']
- print Heat_Dic
- return Heat_Dic
+ del heat_dict['outputs']['description']
+ logger.info(heat_dict)
+
+ return heat_dict
def _get_keystone_client(self):
"""returns a keystone client instance"""
@@ -176,12 +145,6 @@ class SpawnVM(Env_setup): tenant_name=os.environ.get('OS_TENANT_NAME'))
return self._keystone_client
- def _get_nova_client(self):
- if self._nova_client is None:
- keystone = self._get_keystone_client()
- self._nova_client = client.Client('2', token=keystone.auth_token)
- return self._nova_client
-
def _get_heat_client(self):
"""returns a heat client instance"""
if self._heat_client is None:
@@ -192,45 +155,29 @@ class SpawnVM(Env_setup): '1', endpoint=heat_endpoint, token=keystone.auth_token)
return self._heat_client
- def create_stack(self, vm_role_ip_dict, heat_template):
-
- global sshkey
+ def create_stack(self, vm_role_ip_dict):
stackname = 'QTIP'
heat = self._get_heat_client()
- for checks in range(3):
- print "Try to delete heats %s" % checks
- for prev_stacks in heat.stacks.list():
- if prev_stacks.stack_name == 'QTIP':
- print 'QTIP Stacks exists.\nDeleting Existing Stack'
- heat.stacks.delete('QTIP')
- time.sleep(10)
- print '\nStack Creating Started\n'
+ self.delete_stack(stackname)
- try:
- heat.stacks.create(stack_name=stackname, template=heat_template)
- except Exception:
- print 'Create Failed :( '
-
- cluster_detail = heat.stacks.get(stackname)
- while cluster_detail.status != 'COMPLETE':
- if cluster_detail.status == 'IN_PROGRESS':
- print 'Stack Creation in Progress'
- cluster_detail = heat.stacks.get(stackname)
- time.sleep(10)
- print 'Stack Created'
- print 'Getting Public IP(s)'
- zone = []
- s = 0
- for vm in range(len(vm_role_ip_dict['OS_image'])):
+ logger.info('Start to create stack %s' % stackname)
+ heat.stacks.create(stack_name=stackname, template=self.heat_template)
+
+ stack_status = "IN_PROGRESS"
+ while stack_status != 'COMPLETE':
+ if stack_status == 'IN_PROGRESS':
+ logger.debug('Create in Progress')
+ if stack_status == 'CREATE_FAILED':
+ raise RuntimeError("Stack %s created failed!" % stackname)
+ stack_status = heat.stacks.get(stackname).status
+ time.sleep(15)
+ logger.info('Stack %s Created Complete!' % stackname)
- for I in cluster_detail.outputs:
- availabilityKey = 'availability_instance_' + str(vm + 1)
+ stack_outputs = heat.stacks.get(stackname).outputs
- if I['output_key'] == availabilityKey:
- zone.insert(s, str(I['output_value']))
- s = s + 1
- for i in cluster_detail.outputs:
+ for vm in range(len(vm_role_ip_dict['OS_image'])):
+ for i in stack_outputs:
instanceKey = "instance_ip_" + str(vm + 1)
privateIPkey = 'instance_PIP_' + str(vm + 1)
if i['output_key'] == instanceKey:
@@ -240,10 +187,20 @@ class SpawnVM(Env_setup): if i['output_key'] == privateIPkey:
Env_setup.ip_pw_dict[vm_role_ip_dict['role'][vm]] = str(i['output_value'])
- if i['output_key'] == 'KeyPair_PublicKey':
- sshkey = str(i['output_value'])
- with open('./config/my_key.pem', 'w') as fopen:
- fopen.write(sshkey)
- fopen.close()
- print Env_setup.ip_pw_list
+ logger.info('Getting Public IP(s): %s' % Env_setup.ip_pw_list)
+
+ def delete_stack(self, stack_name):
+ heat = self._get_heat_client()
+
+ stacks = heat.stacks.list()
+ exists = map(lambda x: x.stack_name, stacks)
+ if stack_name in exists:
+ logger.info("Delete stack %s" % stack_name)
+ heat.stacks.delete(stack_name)
+ while stack_name in exists:
+ time.sleep(10)
+ stacks = heat.stacks.list()
+ exists = map(lambda x: x.stack_name, stacks)
+ logger.debug("exists_stacks: %s" % exists)
+ logger.info("%s doesn't exist" % stack_name)
diff --git a/tests/spawn_vm_test.py b/tests/spawn_vm_test.py index 7890abd1..fca7dd00 100644 --- a/tests/spawn_vm_test.py +++ b/tests/spawn_vm_test.py @@ -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]) |