3 # Copyright (c) 2015 All rights reserved. This program and the accompanying materials
4 # are made available under the terms of the Apache License, Version 2.0
5 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # This script boots the VM1 and allocates IP address from Nova
10 # Later, the VM2 boots then execute cloud-init to ping VM1.
11 # After successful ping, both the VMs are deleted.
13 # Note: this is script works only with Ubuntu image, not with Cirros image
16 import os, time, subprocess, logging, argparse, yaml
18 import novaclient.v2.client as novaclient
19 import neutronclient.client as neutronclient
20 #import novaclient.v1_1.client as novaclient
21 import cinderclient.v1.client as cinderclient
22 pp = pprint.PrettyPrinter(indent=4)
25 HOME = os.environ['HOME']+"/"
26 with open(HOME+'.functest/functest.yaml') as f:
27 functest_yaml = yaml.safe_load(f)
30 PING_TIMEOUT = functest_yaml.get("vping").get("ping_timeout")
31 NAME_VM_1 = functest_yaml.get("vping").get("vm_name_1")
32 NAME_VM_2 = functest_yaml.get("vping").get("vm_name_2")
33 GLANCE_IMAGE_NAME = functest_yaml.get("general").get("openstack").get("image_name")
34 NEUTRON_PRIVATE_NET_NAME = functest_yaml.get("general").get("openstack").get("neutron_private_net_name")
35 FLAVOR = functest_yaml.get("vping").get("vm_flavor")
38 parser = argparse.ArgumentParser()
39 parser.add_argument("-d", "--debug", help="Debug mode", action="store_true")
40 args = parser.parse_args()
42 """ logging configuration """
43 logger = logging.getLogger('vPing')
44 logger.setLevel(logging.DEBUG)
46 ch = logging.StreamHandler()
48 ch.setLevel(logging.DEBUG)
50 ch.setLevel(logging.INFO)
51 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
52 ch.setFormatter(formatter)
61 def print_title(title):
63 print "\n"+"#"*40+"\n# "+title+"\n"+"#"*40+"\n"
65 def get_credentials(service):
66 """Returns a creds dictionary filled with the following keys:
68 * password/api_key (depending on the service)
69 * tenant_name/project_id (depending on the service)
71 :param service: a string indicating the name of the service
72 requesting the credentials.
74 #TODO: get credentials from the openrc file
76 # Unfortunately, each of the OpenStack client will request slightly
77 # different entries in their credentials dict.
78 if service.lower() in ("nova", "cinder"):
83 tenant = "tenant_name"
85 # The most common way to pass these info to the script is to do it through
86 # environment variables.
88 "username": os.environ.get('OS_USERNAME', "admin"), # add your cloud username details
89 password: os.environ.get("OS_PASSWORD", 'admin'), # add password
90 "auth_url": os.environ.get("OS_AUTH_URL","http://192.168.20.71:5000/v2.0"), # Auth URL
91 tenant: os.environ.get("OS_TENANT_NAME", "admin"),
97 def get_server(creds, servername):
98 nova = novaclient.Client(**creds)
99 return nova.servers.find(name=servername)
102 def waitVmActive(nova,vm):
103 # sleep and wait for VM status change
104 while get_status(nova,vm) != "ACTIVE":
106 logger.debug("Status: %s" % vm.status)
107 logger.debug("Status: %s" % vm.status)
109 def get_status(nova,vm):
110 vm = nova.servers.get(vm.id)
115 creds = get_credentials("nova")
116 nova = novaclient.Client(**creds)
117 cinder = cinderclient.Client(**creds)
120 # print images and server resources
122 print_title("images list")
123 pMsg(nova.images.list())
124 print_title("servers list")
125 pMsg(nova.servers.list())
127 # Check if the given image is created
128 images=nova.images.list()
131 if image.name == GLANCE_IMAGE_NAME:
132 logger.info("Glance image found '%s'" %image.name)
135 logger.error("ERROR: Glance image %s not found." % GLANCE_IMAGE_NAME)
136 logger.info("Available images are: ")
137 pMsg(nova.images.list())
140 # Check if the given neutron network is created
141 networks=nova.networks.list()
142 network_found = False
144 if net.human_id == NEUTRON_NET_NAME:
145 logger.info("Network found '%s'" %net.human_id)
147 if not network_found:
148 logger.error("Neutron network %s not found." % NEUTRON_NET_NAME)
149 logger.info("Available networks are: ")
150 pMsg(nova.networks.list())
153 servers=nova.servers.list()
154 for server in servers:
155 if server.name == NAME_VM_1 or server.name == NAME_VM_2:
156 logger.info("Instance %s found. Deleting..." %server.name)
163 # tune (e.g. flavor, images, network) to your specific openstack configuration here
165 f = nova.flavors.find(name = FLAVOR)
166 i = nova.images.find(name = GLANCE_IMAGE_NAME)
167 n = nova.networks.find(label = NEUTRON_NET_NAME)
168 u = "#cloud-config\npassword: opnfv\nchpasswd: { expire: False }\nssh_pwauth: True"
172 logger.info("Creating instance '%s'..." %m)
173 logger.debug("Configuration:\n name=%s \n flavor=%s \n image=%s \n network=%s \n userdata= \n%s" %(m,f,i,n,u))
174 vm1 = nova.servers.create(
178 nics = [{"net-id": n.id}],
186 #wait until VM status is active
187 waitVmActive(nova,vm1)
189 #retrieve IP of first VM
190 logger.debug("Fetching IP...")
191 server = get_server(creds, m)
192 #pMsg(server.networks)
193 # theoretically there is only one IP address so we take the first element of the table
194 # Dangerous! To be improved!
195 test_ip = server.networks.get(NEUTRON_NET_NAME)[0]
196 logger.debug("Instance '%s' got %s" %(m,test_ip))
197 test_cmd = '/tmp/vping.sh %s'%test_ip
201 # we will boot then execute a ping script with cloud-init
202 # the long chain corresponds to the ping procedure converted with base 64
203 # tune (e.g. flavor, images, network) to your specific openstack configuration here
205 f = nova.flavors.find(name = FLAVOR)
206 i = nova.images.find(name = GLANCE_IMAGE_NAME)
207 n = nova.networks.find(label = NEUTRON_NET_NAME)
208 # use base 64 format becaus bad surprises with sh script with cloud-init but script is just pinging
210 u = "#cloud-config\npassword: opnfv\nchpasswd: { expire: False }\nssh_pwauth: True\nwrite_files:\n- encoding: b64\n path: /tmp/vping.sh\n permissions: '0777'\n owner: root:root\n content: IyEvYmluL2Jhc2gKCndoaWxlIHRydWU7IGRvCiBwaW5nIC1jIDEgJDEgMj4mMSA+L2Rldi9udWxsCiBSRVM9JD8KIGlmIFsgIlokUkVTIiA9ICJaMCIgXSA7IHRoZW4KICBlY2hvICJ2UGluZyBPSyIKICBzbGVlcCAxMAogIHN1ZG8gc2h1dGRvd24gLWggbm93CiAgYnJlYWsKIGVsc2UKICBlY2hvICJ2UGluZyBLTyIKIGZpCiBzbGVlcCAxCmRvbmUK\nruncmd:\n - [ sh, -c, %s]"%test_cmd
212 logger.info("Creating instance '%s'..." %m)
213 logger.debug("Configuration:\n name=%s \n flavor=%s \n image=%s \n network=%s \n userdata= \n%s" %(m,f,i,n,u))
214 vm2 = nova.servers.create(
218 nics = [{"net-id": n.id}],
221 #security_groups = s,
224 # The injected script will shutdown the VM2 when the ping works
225 # The console-log method is more consistent but doesn't work yet
227 waitVmActive(nova,vm2)
229 logger.info("Waiting for ping, timeout is %d sec..." % PING_TIMEOUT)
232 status = get_status(nova, vm2)
234 if status == "SHUTOFF" :
236 logger.info("vPing SUCCESSFUL after %d sec" % sec)
238 if sec == PING_TIMEOUT:
239 logger.info("Timeout. vPing UNSUCCESSFUL.")
245 # I leave this here until we fix the console-log output
247 console_log = vm2.get_console_output()
248 while not ("vPing" in console_log):
250 console_log = vm2.get_console_output()
251 print "--"+console_log
253 # report if the test is failed
254 if "vPing" in console_log:
258 pMsg("no vPing detected....")
260 if sec == PING_TIMEOUT:
265 logger.debug("Deleting Instances...")
266 nova.servers.delete(vm1)
267 logger.debug("Instance %s terminated." % NAME_VM_1)
268 nova.servers.delete(vm2)
269 logger.debug("Instance %s terminated." % NAME_VM_2)
272 logger.debug("EXIT_CODE=%s" % EXIT_CODE)
276 if __name__ == '__main__':