vPing.py: improved, updated and working with Ubuntu Cloud image.
[functest.git] / testcases / vPing / CI / libraries / vPing.py
1 #!/usr/bin/python
2 #
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
6 #
7 #               http://www.apache.org/licenses/LICENSE-2.0
8 #
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.
12 #
13 # Note: this is script works only with Ubuntu image, not with Cirros image
14 #
15
16 import os
17 import pprint
18 import subprocess
19 import time
20 import argparse
21 import logging
22 import novaclient.v2.client as novaclient
23 #import novaclient.v1_1.client as novaclient
24 import cinderclient.v1.client as cinderclient
25 pp = pprint.PrettyPrinter(indent=4)
26
27 EXIT_CODE = -1
28
29 #tODO: this parameters should be taken from a conf file
30 PING_TIMEOUT = 200
31 NAME_VM_1 = "opnfv-vping-1"
32 NAME_VM_2 = "opnfv-vping-2"
33 GLANCE_IMAGE_NAME = "trusty-server-cloudimg-amd64-disk1.img"
34 NEUTRON_NET_NAME = "test"
35 FLAVOR = "m1.small"
36
37 parser = argparse.ArgumentParser()
38 parser.add_argument("-d", "--debug", help="Debug mode",  action="store_true")
39 args = parser.parse_args()
40
41 """ logging configuration """
42 logger = logging.getLogger('vPing')
43 logger.setLevel(logging.DEBUG)
44
45 ch = logging.StreamHandler()
46 if args.debug:
47     ch.setLevel(logging.DEBUG)
48 else:
49     ch.setLevel(logging.INFO)
50 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
51 ch.setFormatter(formatter)
52 logger.addHandler(ch)
53
54
55
56 def pMsg(value):
57     """pretty printing"""
58     pp.pprint(value)
59
60 def print_title(title):
61     """Print titles"""
62     print "\n"+"#"*40+"\n# "+title+"\n"+"#"*40+"\n"
63
64 def get_credentials(service):
65     """Returns a creds dictionary filled with the following keys:
66     * username
67     * password/api_key (depending on the service)
68     * tenant_name/project_id (depending on the service)
69     * auth_url
70     :param service: a string indicating the name of the service
71                     requesting the credentials.
72     """
73     #TODO: get credentials from the openrc file
74     creds = {}
75     # Unfortunately, each of the OpenStack client will request slightly
76     # different entries in their credentials dict.
77     if service.lower() in ("nova", "cinder"):
78         password = "api_key"
79         tenant = "project_id"
80     else:
81         password = "password"
82         tenant = "tenant_name"
83
84     # The most common way to pass these info to the script is to do it through
85     # environment variables.
86     creds.update({
87         "username": os.environ.get('OS_USERNAME', "admin"),                                                             # add your cloud username details
88         password: os.environ.get("OS_PASSWORD", 'admin'),                                                               # add password
89         "auth_url": os.environ.get("OS_AUTH_URL","http://192.168.20.71:5000/v2.0"),             # Auth URL
90         tenant: os.environ.get("OS_TENANT_NAME", "admin"),
91     })
92
93     return creds
94
95
96 def get_server(creds, servername):
97     nova = novaclient.Client(**creds)
98     return nova.servers.find(name=servername)
99
100
101 def waitVmActive(nova,vm):
102     # sleep and wait for VM status change
103     while get_status(nova,vm) != "ACTIVE":
104         time.sleep(3)
105         logger.debug("Status: %s" % vm.status)
106     logger.debug("Status: %s" % vm.status)
107
108 def get_status(nova,vm):
109     vm = nova.servers.get(vm.id)
110     return vm.status
111
112
113 def main():
114     creds = get_credentials("nova")
115     nova = novaclient.Client(**creds)
116     cinder = cinderclient.Client(**creds)
117
118     """
119     # print images and server resources
120     # print nova_images
121     print_title("images list")
122     pMsg(nova.images.list())
123     print_title("servers list")
124     pMsg(nova.servers.list())
125     """
126
127     images=nova.images.list()
128     image_found = False
129     for image in images:
130         if image.name == GLANCE_IMAGE_NAME:
131             logger.info("Glance image found '%s'" %image.name)
132             image_found = True
133     if not image_found:
134         logger.error("ERROR: Glance image %s not found." % GLANCE_IMAGE_NAME)
135         logger.info("Available images are: ")
136         pMsg(nova.images.list())
137         exit(-1)
138
139     servers=nova.servers.list()
140     for server in servers:
141         if server.name == NAME_VM_1 or server.name == NAME_VM_2:
142             logger.info("Instance %s found. Deleting..." %server.name)
143             server.delete()
144
145
146
147     # boot VM 1
148     # basic boot
149   # tune (e.g. flavor, images, network) to your specific openstack configuration here
150     m = NAME_VM_1
151     f = nova.flavors.find(name = FLAVOR)
152     i = nova.images.find(name = GLANCE_IMAGE_NAME)
153     n = nova.networks.find(label = NEUTRON_NET_NAME)
154     u = "#cloud-config\npassword: opnfv\nchpasswd: { expire: False }\nssh_pwauth: True"
155     #k = "demo-key"
156
157     # create VM
158     logger.info("Creating instance '%s'..." %m)
159     logger.debug("Configuration:\n name=%s \n flavor=%s \n image=%s \n network=%s \n userdata= \n%s" %(m,f,i,n,u))
160     vm1 = nova.servers.create(
161         name               = m,
162         flavor             = f,
163         image              = i,
164         nics               = [{"net-id": n.id}],
165         #key_name           = k,
166         userdata           = u,
167     )
168
169     #pMsg(vm1)
170
171
172     #wait until VM status is active
173     waitVmActive(nova,vm1)
174
175     #retrieve IP of first VM
176     logger.debug("Fetching IP...")
177     server = get_server(creds, m)
178     #pMsg(server.networks)
179     # theoretically there is only one IP address so we take the first element of the table
180     # Dangerous! To be improved!
181     test_ip = server.networks.get(NEUTRON_NET_NAME)[0]
182     logger.debug("Instance '%s' got %s" %(m,test_ip))
183     test_cmd = '/tmp/vping.sh %s'%test_ip
184
185
186     # boot VM 2
187     # we will boot then execute a ping script with cloud-init
188     # the long chain corresponds to the ping procedure converted with base 64
189   # tune (e.g. flavor, images, network) to your specific openstack configuration here
190     m = NAME_VM_2
191     f = nova.flavors.find(name = FLAVOR)
192     i = nova.images.find(name = GLANCE_IMAGE_NAME)
193     n = nova.networks.find(label = NEUTRON_NET_NAME)
194     # use base 64 format becaus bad surprises with sh script with cloud-init but script is just pinging
195     #k = "demo-key"
196     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
197     # create VM
198     logger.info("Creating instance '%s'..." %m)
199     logger.debug("Configuration:\n name=%s \n flavor=%s \n image=%s \n network=%s \n userdata= \n%s" %(m,f,i,n,u))
200     vm2 = nova.servers.create(
201         name               = m,
202         flavor             = f,
203         image              = i,
204         nics               = [{"net-id": n.id}],
205         #key_name           = k,
206         userdata           = u,
207         #security_groups    = s,
208         #config_drive       = v.id
209     )
210     # The injected script will shutdown the VM2 when the ping works
211     # The console-log method is more consistent but doesn't work yet
212
213     waitVmActive(nova,vm2)
214
215     logger.info("Waiting for ping, timeout is %d sec..." % PING_TIMEOUT)
216     sec = 0
217     while True:
218         status = get_status(nova, vm2)
219         #print status
220         if status == "SHUTOFF" :
221             EXIT_CODE = 0
222             logger.info("vPing SUCCESSFUL after %d sec" % sec)
223             break
224         if sec == PING_TIMEOUT:
225             logger.info("Timeout. vPing UNSUCCESSFUL.")
226             break
227         time.sleep(1)
228         sec+=1
229
230     """
231     # I leave this here until we fix the console-log output
232     sec = 0
233     console_log = vm2.get_console_output()
234     while not ("vPing" in console_log):
235         time.sleep(1)
236         console_log = vm2.get_console_output()
237         print "--"+console_log
238
239         # report if the test is failed
240         if "vPing" in console_log:
241             pMsg("vPing is OK")
242             break
243         else:
244             pMsg("no vPing detected....")
245         sec+=1
246         if sec == PING_TIMEOUT:
247             break
248     """
249
250     # delete both VMs
251     logger.debug("Deleting Instances...")
252     nova.servers.delete(vm1)
253     logger.debug("Instance %s terminated." % NAME_VM_1)
254     nova.servers.delete(vm2)
255     logger.debug("Instance %s terminated." % NAME_VM_2)
256
257
258     logger.debug("EXIT_CODE=%s" % EXIT_CODE)
259     exit(EXIT_CODE)
260
261
262 if __name__ == '__main__':
263     main()