Merge "Fix latency accuracy and dumping latencies to file"
[samplevnf.git] / VNFs / DPPD-PROX / helper-scripts / openstackrapid / createrapid.py
1 #!/usr/bin/python
2
3 ##
4 ## Copyright (c) 2010-2017 Intel Corporation
5 ##
6 ## Licensed under the Apache License, Version 2.0 (the "License");
7 ## you may not use this file except in compliance with the License.
8 ## You may obtain a copy of the License at
9 ##
10 ##     http://www.apache.org/licenses/LICENSE-2.0
11 ##
12 ## Unless required by applicable law or agreed to in writing, software
13 ## distributed under the License is distributed on an "AS IS" BASIS,
14 ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 ## See the License for the specific language governing permissions and
16 ## limitations under the License.
17 ##
18
19 from __future__ import print_function
20
21 import os
22 import stat
23 import sys
24 import time
25 import subprocess
26 import getopt
27 import re
28 import logging
29 from logging.handlers import RotatingFileHandler
30 from logging import handlers
31 from prox_ctrl import prox_ctrl
32 import ConfigParser
33
34 version="18.2.3"
35 stack = "rapid" #Default string for stack
36 yaml = "rapid.yaml" #Default string for yaml file
37 key = "prox" # This is also the default in the yaml file....
38 flavor = "prox_flavor" # This is also the default in the yaml file....
39 image = "rapidVM" # This is also the default in the yaml file....
40 image_file = "rapidVM.qcow2"
41 dataplane_network = "dataplane-network" # This is also the default in the yaml file....
42 subnet = "dpdk-subnet" #subnet for dataplane
43 subnet_cidr="10.10.10.0/24" # cidr for dataplane
44 internal_network="admin_internal_net"
45 floating_network="admin_floating_net"
46 loglevel="DEBUG" # sets log level for writing to file
47 runtime=10 # time in seconds for 1 test run
48
49 def usage():
50         print("usage: createrapid [--version] [-v]")
51         print("                   [--stack STACK_NAME]")
52         print("                   [--yaml YAML_FILE]")
53         print("                   [--key KEY_NAME]")
54         print("                   [--flavor FLAVOR_NAME]")
55         print("                   [--image IMAGE_NAME]")
56         print("                   [--image_file IMAGE_FILE]")
57         print("                   [--dataplane_network DP_NETWORK]")
58         print("                   [--subnet DP_SUBNET]")
59         print("                   [--subnet_cidr SUBNET_CIDR]")
60         print("                   [--internal_network ADMIN_NETWORK]")
61         print("                   [--floating_network ADMIN_NETWORK]")
62         print("                   [--log DEBUG|INFO|WARNING|ERROR|CRITICAL")
63         print("                   [-h] [--help]")
64         print("")
65         print("Command-line interface to createrapid")
66         print("")
67         print("optional arguments:")
68         print("  -v,  --version                 Show program's version number and exit")
69         print("  --stack STACK_NAME             Specify a name for the heat stack. Default is %s."%stack)
70         print("  --yaml YAML_FILE               Specify the yaml file to be used. Default is %s."%yaml)
71         print("  --key KEY_NAME                 Specify the key to be used. Default is %s."%key)
72         print("  --flavor FLAVOR_NAME           Specify the flavor to be used. Default is %s."%flavor)
73         print("  --image IMAGE_NAME             Specify the image to be used. Default is %s."%image)
74         print("  --image_file IMAGE_FILE        Specify the image qcow2 file to be used. Default is %s."%image_file)
75         print("  --dataplane_network NETWORK    Specify the network name to be used for the dataplane. Default is %s."%dataplane_network)
76         print("  --subnet DP_SUBNET             Specify the subnet name to be used for the dataplane. Default is %s."%subnet)
77         print("  --subnet_cidr SUBNET_CIDR      Specify the subnet CIDR to be used for the dataplane. Default is %s."%subnet_cidr)
78         print("  --internal_network NETWORK     Specify the network name to be used for the control plane. Default is %s."%internal_network)
79         print("  --floating_network NETWORK     Specify the external floating ip network name. Default is %s. NO if no floating ip used."%floating_network)
80         print("  --log                          Specify logging level for log file output, screen output level is hard coded")
81         print("  -h, --help                     Show help message and exit.")
82         print("")
83         print("To delete the rapid stack, type the following command")
84         print("   openstack stack delete --yes --wait %s"%stack)
85         print("Note that %s is the default stack name. Replace with STACK_NAME if needed"%stack)
86
87 try:
88         opts, args = getopt.getopt(sys.argv[1:], "vh", ["version","help", "yaml=","stack=","key=","flavor=","image=","image_file=","dataplane_network=","subnet=","subnet_cidr=","internal_network=","floating_network=","log="])
89 except getopt.GetoptError as err:
90         print("===========================================")
91         print(str(err))
92         print("===========================================")
93         usage()
94         sys.exit(2)
95 if args:
96         usage()
97         sys.exit(2)
98 for opt, arg in opts:
99         if opt in ("-h", "--help"):
100                 usage()
101                 sys.exit()
102         if opt in ("-v", "--version"):
103                 print("Rapid Automated Performance Indication for Dataplane "+version)
104                 sys.exit()
105         if opt in ("--stack"):
106                 stack = arg
107                 print ("Using '"+stack+"' as name for the stack")
108         elif opt in ("--yaml"):
109                 yaml = arg
110                 print ("Using stack: "+yaml)
111         elif opt in ("--key"):
112                 key = arg
113                 print ("Using key: "+key)
114         elif opt in ("--flavor"):
115                 flavor = arg
116                 print ("Using flavor: "+flavor)
117         elif opt in ("--image"):
118                 image = arg
119                 print ("Using image: "+image)
120         elif opt in ("--image_file"):
121                 image_file = arg
122                 print ("Using qcow2 file: "+image_file)
123         elif opt in ("--dataplane_network"):
124                 dataplane_network = arg
125                 print ("Using dataplane network: "+ dataplane_network)
126         elif opt in ("--subnet"):
127                 subnet = arg
128                 print ("Using dataplane subnet: "+ subnet)
129         elif opt in ("--subnet_cidr"):
130                 subnet_cidr = arg
131                 print ("Using dataplane subnet: "+ subnet_cidr)
132         elif opt in ("--internal_network"):
133                 internal_network = arg
134                 print ("Using control plane network: "+ internal_network)
135         elif opt in ("--floating_network"):
136                 floating_network = arg
137                 print ("Using floating ip network: "+ floating_network)
138         elif opt in ("--log"):
139                 loglevel = arg
140                 print ("Log level: "+ loglevel)
141
142
143 # create formatters
144 screen_formatter = logging.Formatter("%(message)s")
145 file_formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
146
147 # get a top-level logger,
148 # set its log level,
149 # BUT PREVENT IT from propagating messages to the root logger
150 #
151 log = logging.getLogger()
152 numeric_level = getattr(logging, loglevel.upper(), None)
153 if not isinstance(numeric_level, int):
154     raise ValueError('Invalid log level: %s' % loglevel)
155 log.setLevel(numeric_level)
156 log.propagate = 0
157
158 # create a console handler
159 # and set its log level to the command-line option 
160
161 console_handler = logging.StreamHandler(sys.stdout)
162 console_handler.setLevel(logging.INFO)
163 console_handler.setFormatter(screen_formatter)
164
165 # create a file handler
166 # and set its log level to DEBUG
167 #
168 log_file = 'CREATE' +stack +'.log'
169 file_handler = logging.handlers.RotatingFileHandler(log_file, backupCount=10)
170 #file_handler = log.handlers.TimedRotatingFileHandler(log_file, 'D', 1, 5)
171 file_handler.setLevel(numeric_level)
172 file_handler.setFormatter(file_formatter)
173
174 # add handlers to the logger
175 #
176 log.addHandler(file_handler)
177 log.addHandler(console_handler)
178
179 # Check if log exists and should therefore be rolled
180 needRoll = os.path.isfile(log_file)
181
182
183 # This is a stale log, so roll it
184 if needRoll:    
185     # Add timestamp
186     log.debug('\n---------\nLog closed on %s.\n---------\n' % time.asctime())
187
188     # Roll over on application start
189     log.handlers[0].doRollover()
190
191 # Add timestamp
192 log.debug('\n---------\nLog started on %s.\n---------\n' % time.asctime())
193
194 log.debug("createrapid.py version: "+version)
195 # Checking if the control network already exists, if not, stop the script
196 log.debug("Checking control plane network: "+internal_network)
197 cmd = 'openstack network show '+internal_network
198 log.debug (cmd)
199 cmd = cmd + ' |grep "status " | tr -s " " | cut -d" " -f 4'
200 NetworkExist = subprocess.check_output(cmd , shell=True).strip()
201 if NetworkExist == 'ACTIVE':
202         log.info("Control plane network ("+internal_network+")  already active")
203 else:
204         log.exception("Control plane network " + internal_network + " not existing")
205         raise Exception("Control plane network " + internal_network + " not existing")
206
207 # Checking if the floating ip network already exists, if not, stop the script
208 if floating_network <>'NO':
209         log.debug("Checking floating ip network: "+floating_network)
210         cmd = 'openstack network show '+floating_network
211         log.debug (cmd)
212         cmd = cmd + ' |grep "status " | tr -s " " | cut -d" " -f 4'
213         NetworkExist = subprocess.check_output(cmd , shell=True).strip()
214         if NetworkExist == 'ACTIVE':
215                 log.info("Floating ip network ("+floating_network+")  already active")
216         else:
217                 log.exception("Floating ip network " + floating_network + " not existing")
218                 raise Exception("Floating ip network " + floating_network + " not existing")
219
220 # Checking if the image already exists, if not create it
221 log.debug("Checking image: "+image)
222 cmd = 'openstack image show '+image
223 log.debug(cmd)
224 cmd = cmd +' |grep "status " | tr -s " " | cut -d" " -f 4'
225 ImageExist = subprocess.check_output(cmd , shell=True).strip()
226 if ImageExist == 'active':
227         log.info("Image ("+image+") already available")
228 else:
229         log.info('Creating image ...')
230         cmd = 'openstack image create --disk-format qcow2 --container-format bare --public --file ./'+image_file+ ' ' +image
231         log.debug(cmd)
232         cmd = cmd + ' |grep "status " | tr -s " " | cut -d" " -f 4'
233         ImageExist = subprocess.check_output(cmd , shell=True).strip()
234         if ImageExist == 'active':
235                 log.info('Image created and active')
236                 cmd = 'openstack image set --property hw_vif_multiqueue_enabled="true" ' +image
237 #               subprocess.check_call(cmd , shell=True)
238         else :
239                 log.exception("Failed to create image")
240                 raise Exception("Failed to create image")
241
242 # Checking if the key already exists, if not create it
243 log.debug("Checking key: "+key)
244 cmd = 'openstack keypair show '+key
245 log.debug (cmd)
246 cmd = cmd + ' |grep "name " | tr -s " " | cut -d" " -f 4'
247 KeyExist = subprocess.check_output(cmd , shell=True).strip()
248 if KeyExist == key:
249         log.info("Key ("+key+") already installed")
250 else:
251         log.info('Creating key ...')
252         cmd = 'openstack keypair create '+ key + '>' +key+'.pem'
253         log.debug(cmd)
254         subprocess.check_call(cmd , shell=True)
255         cmd = 'chmod 600 ' +key+'.pem'
256         subprocess.check_call(cmd , shell=True)
257         cmd = 'openstack keypair show '+key
258         log.debug(cmd)
259         cmd = cmd + ' |grep "name " | tr -s " " | cut -d" " -f 4'
260         KeyExist = subprocess.check_output(cmd , shell=True).strip()
261         if KeyExist == key:
262                 log.info("Key created")
263         else :
264                 log.exception("Failed to create key: " + key)
265                 raise Exception("Failed to create key: " + key)
266
267 # Checking if the flavor already exists, if not create it
268 log.debug("Checking flavor: "+flavor)
269 cmd = 'openstack flavor show '+flavor
270 log.debug (cmd)
271 cmd = cmd + ' |grep "name " | tr -s " " | cut -d" " -f 4'
272 FlavorExist = subprocess.check_output(cmd , shell=True).strip()
273 if FlavorExist == flavor:
274         log.info("Flavor ("+flavor+") already installed")
275 else:
276         log.info('Creating flavor ...')
277         cmd = 'openstack flavor create '+flavor+' --ram 8192 --disk 20 --vcpus 4'
278         log.debug(cmd)
279         cmd = cmd + ' |grep "name " | tr -s " " | cut -d" " -f 4'
280         FlavorExist = subprocess.check_output(cmd , shell=True).strip()
281         if FlavorExist == flavor:
282                 cmd = 'openstack flavor set '+ flavor +' --property hw:mem_page_size="large" --property hw:cpu_policy="dedicated" --property hw:cpu_threads_policy="isolate"'
283                 log.debug(cmd)
284                 subprocess.check_call(cmd , shell=True)
285                 log.info("Flavor created")
286         else :
287                 log.exception("Failed to create flavor: " + flavor)
288                 raise Exception("Failed to create flavor: " + flavor)
289
290 # Checking if the dataplane network already exists, if not create it
291 log.debug("Checking dataplane network: "+dataplane_network)
292 cmd = 'openstack network show '+dataplane_network
293 log.debug (cmd)
294 cmd = cmd + ' |grep "status " | tr -s " " | cut -d" " -f 4'
295 NetworkExist = subprocess.check_output(cmd , shell=True).strip()
296 if NetworkExist == 'ACTIVE':
297         log.info("Dataplane network ("+dataplane_network+") already active")
298 else:
299         log.info('Creating dataplane network ...')
300         cmd = 'openstack network create '+dataplane_network
301         log.debug(cmd)
302         cmd = cmd + ' |grep "status " | tr -s " " | cut -d" " -f 4'
303         NetworkExist = subprocess.check_output(cmd , shell=True).strip()
304         if NetworkExist == 'ACTIVE':
305                 log.info("Dataplane network created")
306         else :
307                 log.exception("Failed to create dataplane network: " + dataplane_network)
308                 raise Exception("Failed to create dataplane network: " + dataplane_network)
309
310 # Checking if the dataplane subnet already exists, if not create it
311 log.debug("Checking subnet: "+subnet)
312 cmd = 'openstack subnet show '+ subnet
313 log.debug (cmd)
314 cmd = cmd +' |grep "name " | tr -s " " | cut -d"|" -f 3'
315 SubnetExist = subprocess.check_output(cmd , shell=True).strip()
316 if SubnetExist == subnet:
317         log.info("Subnet (" +subnet+ ") already exists")
318 else:
319         log.info('Creating subnet ...')
320         cmd = 'openstack subnet create --network ' + dataplane_network + ' --subnet-range ' + subnet_cidr +' --gateway none ' + subnet
321         log.debug(cmd)
322         cmd = cmd + ' |grep "name " | tr -s " " | cut -d"|" -f 3'
323         SubnetExist = subprocess.check_output(cmd , shell=True).strip()
324         if SubnetExist == subnet:
325                 log.info("Subnet created")
326         else :
327                 log.exception("Failed to create subnet: " + subnet)
328                 raise Exception("Failed to create subnet: " + subnet)
329
330 # Checking if the stack already exists, if not create it
331 log.debug("Checking Stack: "+stack)
332 cmd = 'openstack stack show '+stack
333 log.debug (cmd)
334 cmd = cmd+' |grep "stack_status " | tr -s " " | cut -d"|" -f 3'
335 StackRunning = subprocess.check_output(cmd , shell=True).strip()
336 if StackRunning == '':
337         log.info('Creating Stack ...')
338         cmd = 'openstack stack create -t '+ yaml +  ' --parameter flavor="'+flavor  +'" --parameter key="'+ key + '" --parameter image="'+image  + '" --parameter dataplane_network="'+dataplane_network+ '" --parameter internal_network="'+internal_network+'" --parameter floating_network="'+floating_network+'" --wait '+stack 
339         log.debug(cmd)
340         cmd = cmd + ' |grep "stack_status " | tr -s " " | cut -d"|" -f 3'
341         StackRunning = subprocess.check_output(cmd , shell=True).strip()
342 if StackRunning != 'CREATE_COMPLETE':
343         log.exception("Failed to create stack")
344         raise Exception("Failed to create stack")
345
346 # Obtaining IP & MAC addresses for the VMs created in the stack
347 log.info("Stack ("+stack+") running")
348 cmd='openstack stack show -f yaml -c outputs ' + stack
349 log.debug(cmd)
350 output = subprocess.check_output(cmd , shell=True).strip()
351 matchObj = re.search('.*total_number_of_VMs.*?([0-9])', output, re.DOTALL)
352 total_number_of_VMs = matchObj.group(1)
353 vmDPIP =[]
354 vmAdminIP =[]
355 vmDPmac =[]
356 config = ConfigParser.RawConfigParser()
357 for vm in range(1, int(total_number_of_VMs)+1):
358         searchString = '.*vm%d_dataplane_ip.*?([0-9]*\.[0-9]*\.[0-9]*\.[0-9]*)' % vm
359         matchObj = re.search(searchString, output, re.DOTALL)
360         vmDPIP.append(matchObj.group(1))
361         if floating_network <> 'NO':
362                 searchString = '.*vm%d_public_ip.*?([0-9]*\.[0-9]*\.[0-9]*\.[0-9]*)' % vm
363                 matchObj = re.search(searchString, output, re.DOTALL)
364                 vmAdminIP.append(matchObj.group(1))
365         else:
366                 searchString = '.*vm%d_private_ip.*?([0-9]*\.[0-9]*\.[0-9]*\.[0-9]*)' % vm
367                 matchObj = re.search(searchString, output, re.DOTALL)
368                 vmAdminIP.append(matchObj.group(1))
369         searchString = '.*vm%d_dataplane_mac.*?([a-fA-F0-9:]{17})' % vm
370         matchObj = re.search(searchString, output, re.DOTALL)
371         vmDPmac.append(matchObj.group(1))
372         log.info('VM%d: (admin IP: %s), (dataplane IP: %s), (dataplane MAC: %s)' % (vm,vmAdminIP[-1],vmDPIP[-1],vmDPmac[-1]))
373         config.add_section('VM%d'%vm)
374         config.set('VM%d'%vm, 'admin_ip', vmAdminIP[-1])
375         config.set('VM%d'%vm, 'dp_ip', vmDPIP[-1])
376         config.set('VM%d'%vm, 'dp_mac', vmDPmac[-1])
377 config.add_section('OpenStack')
378 config.set('OpenStack', 'stack', stack)
379 config.set('OpenStack', 'yaml', yaml)
380 config.set('OpenStack', 'key', key)
381 config.set('OpenStack', 'flavor', flavor)
382 config.set('OpenStack', 'image', image)
383 config.set('OpenStack', 'image_file', image_file)
384 config.set('OpenStack', 'dataplane_network', dataplane_network)
385 config.set('OpenStack', 'subnet', subnet)
386 config.set('OpenStack', 'subnet_cidr', subnet_cidr)
387 config.set('OpenStack', 'internal_network', internal_network)
388 config.set('OpenStack', 'floating_network', floating_network)
389 config.add_section('rapid')
390 config.set('rapid', 'loglevel', loglevel)
391 config.set('rapid', 'version', version)
392 config.set('rapid', 'total_number_of_VMs', total_number_of_VMs)
393 config.set('DEFAULT', 'admin_ip', 'none')
394 # Writing the environment file
395 with open(stack+'.env', 'wb') as envfile:
396     config.write(envfile)
397