Multiple changes for June release
[samplevnf.git] / VNFs / DPPD-PROX / helper-scripts / rapid / 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="19.6.30"
35 stack = "rapid" #Default string for stack. This is not an OpenStack Heat stack, just a group of VMs
36 vms = "rapidVMs.vms" #Default string for vms file
37 key = "prox" # default name for key
38 image = "rapidVM" # default name for the image
39 image_file = "rapidVM.qcow2"
40 dataplane_network = "dataplane-network" # default name for the dataplane network
41 subnet = "dpdk-subnet" #subnet for dataplane
42 subnet_cidr="10.10.10.0/24" # cidr for dataplane
43 internal_network="admin_internal_net"
44 floating_network="admin_floating_net"
45 loglevel="DEBUG" # sets log level for writing to file
46
47 def usage():
48         print("usage: createrapid [--version] [-v]")
49         print("                   [--stack STACK_NAME]")
50         print("                   [--vms VMS_FILE]")
51         print("                   [--key KEY_NAME]")
52         print("                   [--image IMAGE_NAME]")
53         print("                   [--image_file IMAGE_FILE]")
54         print("                   [--dataplane_network DP_NETWORK]")
55         print("                   [--subnet DP_SUBNET]")
56         print("                   [--subnet_cidr SUBNET_CIDR]")
57         print("                   [--internal_network ADMIN_NETWORK]")
58         print("                   [--floating_network FLOATING_NETWORK]")
59         print("                   [--log DEBUG|INFO|WARNING|ERROR|CRITICAL]")
60         print("                   [-h] [--help]")
61         print("")
62         print("Command-line interface to createrapid")
63         print("")
64         print("optional arguments:")
65         print("  -v,  --version                 Show program's version number and exit")
66         print("  --stack STACK_NAME             Specify a name for the stack. Default is %s."%stack)
67         print("  --vms VMS_FILE                 Specify the vms file to be used. Default is %s."%vms)
68         print("  --key KEY_NAME                 Specify the key to be used. Default is %s."%key)
69         print("  --image IMAGE_NAME             Specify the image to be used. Default is %s."%image)
70         print("  --image_file IMAGE_FILE        Specify the image qcow2 file to be used. Default is %s."%image_file)
71         print("  --dataplane_network NETWORK    Specify the network name to be used for the dataplane. Default is %s."%dataplane_network)
72         print("  --subnet DP_SUBNET             Specify the subnet name to be used for the dataplane. Default is %s."%subnet)
73         print("  --subnet_cidr SUBNET_CIDR      Specify the subnet CIDR to be used for the dataplane. Default is %s."%subnet_cidr)
74         print("  --internal_network NETWORK     Specify the network name to be used for the control plane. Default is %s."%internal_network)
75         print("  --floating_network NETWORK     Specify the external floating ip network name. Default is %s. NO if no floating ip used."%floating_network)
76         print("  --log                          Specify logging level for log file output, screen output level is hard coded")
77         print("  -h, --help                     Show help message and exit.")
78         print("")
79
80 try:
81         opts, args = getopt.getopt(sys.argv[1:], "vh", ["version","help", "vms=","stack=","key=","image=","image_file=","dataplane_network=","subnet=","subnet_cidr=","internal_network=","floating_network=","log="])
82 except getopt.GetoptError as err:
83         print("===========================================")
84         print(str(err))
85         print("===========================================")
86         usage()
87         sys.exit(2)
88 if args:
89         usage()
90         sys.exit(2)
91 for opt, arg in opts:
92         if opt in ("-h", "--help"):
93                 usage()
94                 sys.exit()
95         if opt in ("-v", "--version"):
96                 print("Rapid Automated Performance Indication for Dataplane "+version)
97                 sys.exit()
98         if opt in ("--stack"):
99                 stack = arg
100                 print ("Using '"+stack+"' as name for the stack")
101         elif opt in ("--vms"):
102                 vms = arg
103                 print ("Using Virtual Machines Description: "+vms)
104         elif opt in ("--key"):
105                 key = arg
106                 print ("Using key: "+key)
107         elif opt in ("--image"):
108                 image = arg
109                 print ("Using image: "+image)
110         elif opt in ("--image_file"):
111                 image_file = arg
112                 print ("Using qcow2 file: "+image_file)
113         elif opt in ("--dataplane_network"):
114                 dataplane_network = arg
115                 print ("Using dataplane network: "+ dataplane_network)
116         elif opt in ("--subnet"):
117                 subnet = arg
118                 print ("Using dataplane subnet: "+ subnet)
119         elif opt in ("--subnet_cidr"):
120                 subnet_cidr = arg
121                 print ("Using dataplane subnet: "+ subnet_cidr)
122         elif opt in ("--internal_network"):
123                 internal_network = arg
124                 print ("Using control plane network: "+ internal_network)
125         elif opt in ("--floating_network"):
126                 floating_network = arg
127                 print ("Using floating ip network: "+ floating_network)
128         elif opt in ("--log"):
129                 loglevel = arg
130                 print ("Log level: "+ loglevel)
131
132
133 # create formatters
134 screen_formatter = logging.Formatter("%(message)s")
135 file_formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
136
137 # get a top-level logger,
138 # set its log level,
139 # BUT PREVENT IT from propagating messages to the root logger
140 #
141 log = logging.getLogger()
142 numeric_level = getattr(logging, loglevel.upper(), None)
143 if not isinstance(numeric_level, int):
144         raise ValueError('Invalid log level: %s' % loglevel)
145 log.setLevel(numeric_level)
146 log.propagate = 0
147
148 # create a console handler
149 # and set its log level to the command-line option 
150
151 console_handler = logging.StreamHandler(sys.stdout)
152 console_handler.setLevel(logging.INFO)
153 console_handler.setFormatter(screen_formatter)
154
155 # create a file handler
156 # and set its log level to DEBUG
157 #
158 log_file = 'CREATE' +stack +'.log'
159 file_handler = logging.handlers.RotatingFileHandler(log_file, backupCount=10)
160 #file_handler = log.handlers.TimedRotatingFileHandler(log_file, 'D', 1, 5)
161 file_handler.setLevel(numeric_level)
162 file_handler.setFormatter(file_formatter)
163
164 # add handlers to the logger
165 #
166 log.addHandler(file_handler)
167 log.addHandler(console_handler)
168
169 # Check if log exists and should therefore be rolled
170 needRoll = os.path.isfile(log_file)
171
172
173 # This is a stale log, so roll it
174 if needRoll:    
175         # Add timestamp
176         log.debug('\n---------\nLog closed on %s.\n---------\n' % time.asctime())
177         # Roll over on application start
178         log.handlers[0].doRollover()
179
180 # Add timestamp
181 log.debug('\n---------\nLog started on %s.\n---------\n' % time.asctime())
182
183 log.debug("createrapid.py version: "+version)
184 # Checking if the control network already exists, if not, stop the script
185 log.debug("Checking control plane network: " + internal_network)
186 cmd = 'openstack network list -f value -c Name'
187 log.debug (cmd)
188 Networks = subprocess.check_output(cmd , shell=True).decode().strip()
189 if internal_network in Networks:
190         log.info("Control plane network (" + internal_network+")  already active")
191 else:
192         log.exception("Control plane network " + internal_network + " not existing")
193         raise Exception("Control plane network " + internal_network + " not existing")
194
195 # Checking if the floating ip network should be used. If yes, check if it exists and stop the script if it doesn't
196 if floating_network !='NO':
197         log.debug("Checking floating ip network: " + floating_network)
198         if floating_network in Networks:
199                 log.info("Floating ip network (" + floating_network + ")  already active")
200         else:
201                 log.exception("Floating ip network " + floating_network + " not existing")
202                 raise Exception("Floating ip network " + floating_network + " not existing")
203
204 # Checking if the dataplane network already exists, if not create it
205 log.debug("Checking dataplane network: " + dataplane_network)
206 if dataplane_network in Networks:
207         log.info("Dataplane network (" + dataplane_network + ") already active")
208 else:
209         log.info('Creating dataplane network ...')
210         cmd = 'openstack network create '+dataplane_network+' -f value -c status'
211         log.debug(cmd)
212         NetworkExist = subprocess.check_output(cmd , shell=True).decode().strip()
213         if 'ACTIVE' in NetworkExist:
214                 log.info("Dataplane network created")
215                 # Checking if the dataplane subnet already exists, if not create it
216                 log.debug("Checking subnet: "+subnet)
217                 cmd = 'openstack subnet list -f value -c Name'
218                 log.debug (cmd)
219                 Subnets = subprocess.check_output(cmd , shell=True).decode().strip()
220                 if subnet in  Subnets:
221                         log.info("Subnet (" +subnet+ ") already exists")
222                 else:
223                         log.info('Creating subnet ...')
224                         cmd = 'openstack subnet create --network ' + dataplane_network + ' --subnet-range ' + subnet_cidr +' --gateway none ' + subnet+' -f value -c name'
225                         log.debug(cmd)
226                         Subnets = subprocess.check_output(cmd , shell=True).decode().strip()
227                         if subnet in Subnets:
228                                 log.info("Subnet created")
229                         else :
230                                 log.exception("Failed to create subnet: " + subnet)
231                                 raise Exception("Failed to create subnet: " + subnet)
232         else :
233                 log.exception("Failed to create dataplane network: " + dataplane_network)
234                 raise Exception("Failed to create dataplane network: " + dataplane_network)
235
236 # Checking if the image already exists, if not create it
237 log.debug("Checking image: " + image)
238 cmd = 'openstack image list -f value -c Name'
239 log.debug(cmd)
240 Images = subprocess.check_output(cmd , shell=True).decode().strip()
241 if image in Images:
242         log.info("Image (" + image + ") already available")
243 else:
244         log.info('Creating image ...')
245         cmd = 'openstack image create  -f value -c status --disk-format qcow2 --container-format bare --public --file ./'+image_file+ ' ' +image
246         log.debug(cmd)
247         ImageExist = subprocess.check_output(cmd , shell=True).decode().strip()
248         if 'active' in ImageExist:
249                 log.info('Image created and active')
250 #               cmd = 'openstack image set --property hw_vif_multiqueue_enabled="true" ' +image
251 #               subprocess.check_call(cmd , shell=True)
252         else :
253                 log.exception("Failed to create image")
254                 raise Exception("Failed to create image")
255
256 # Checking if the key already exists, if not create it
257 log.debug("Checking key: "+key)
258 cmd = 'openstack keypair list -f value -c Name'
259 log.debug (cmd)
260 KeyExist = subprocess.check_output(cmd , shell=True).decode().strip()
261 if key in KeyExist:
262         log.info("Key ("+key+") already installed")
263 else:
264         log.info('Creating key ...')
265         cmd = 'openstack keypair create '+ key + '>' +key+'.pem'
266         log.debug(cmd)
267         subprocess.check_call(cmd , shell=True)
268         cmd = 'chmod 600 ' +key+'.pem'
269         subprocess.check_call(cmd , shell=True)
270         cmd = 'openstack keypair list -f value -c Name'
271         log.debug(cmd)
272         KeyExist = subprocess.check_output(cmd , shell=True).decode().strip()
273         if key in KeyExist:
274                 log.info("Key created")
275         else :
276                 log.exception("Failed to create key: " + key)
277                 raise Exception("Failed to create key: " + key)
278
279 ServerToBeCreated=[]
280 ServerName=[]
281 config = ConfigParser.RawConfigParser()
282 vmconfig = ConfigParser.RawConfigParser()
283 vmconfig.read(vms)
284 total_number_of_VMs = vmconfig.get('DEFAULT', 'total_number_of_vms')
285 cmd = 'openstack server list -f value -c Name'
286 log.debug (cmd)
287 Servers = subprocess.check_output(cmd , shell=True).decode().strip()
288 cmd = 'openstack flavor list -f value -c Name'
289 log.debug (cmd)
290 Flavors = subprocess.check_output(cmd , shell=True).decode().strip()
291 for vm in range(1, int(total_number_of_VMs)+1):
292         flavor_info = vmconfig.get('VM%d'%vm, 'flavor_info')
293         flavor_meta_data = vmconfig.get('VM%d'%vm, 'flavor_meta_data')
294         boot_info = vmconfig.get('VM%d'%vm, 'boot_info')
295         SRIOV_port = vmconfig.get('VM%d'%vm, 'SRIOV_port')
296         SRIOV_mgmt_port = vmconfig.get('VM%d'%vm, 'SRIOV_mgmt_port')
297         ServerName.append('%s-VM%d'%(stack,vm))
298         flavor_name = '%s-VM%d-flavor'%(stack,vm)
299         log.debug("Checking server: " + ServerName[-1])
300         if ServerName[-1] in Servers:
301                 log.info("Server (" + ServerName[-1] + ") already active")
302                 ServerToBeCreated.append("no")
303         else:
304                 ServerToBeCreated.append("yes")
305                 # Checking if the flavor already exists, if not create it
306                 log.debug("Checking flavor: " + flavor_name)
307                 if flavor_name in Flavors:
308                         log.info("Flavor (" + flavor_name+") already installed")
309                 else:
310                         log.info('Creating flavor ...')
311                         cmd = 'openstack flavor create %s %s -f value -c name'%(flavor_name,flavor_info)
312                         log.debug(cmd)
313                         NewFlavor = subprocess.check_output(cmd , shell=True).decode().strip()
314                         if flavor_name in NewFlavor:
315                                 cmd = 'openstack flavor set %s %s'%(flavor_name, flavor_meta_data)
316                                 log.debug(cmd)
317                                 subprocess.check_call(cmd , shell=True)
318                                 log.info("Flavor created")
319                         else :
320                                 log.exception("Failed to create flavor: " + flavor_name)
321                                 raise Exception("Failed to create flavor: " + flavor_name)
322                 if SRIOV_mgmt_port == 'NO':
323                         nic_info = '--nic net-id=%s'%(internal_network)
324                 else:
325                         for port in SRIOV_mgmt_port.split(','):
326                                 nic_info = '--nic port-id=%s'%(port)
327                 if SRIOV_port == 'NO':
328                         nic_info = nic_info + ' --nic net-id=%s'%(dataplane_network)
329                 else:
330                         for port in SRIOV_port.split(','):
331                                 nic_info = nic_info + ' --nic port-id=%s'%(port)
332                 if vm==int(total_number_of_VMs):
333                         # For the last server, we want to wait for the server creation to complete, so the next operations will succeeed (e.g. IP allocation)
334                         # Note that this waiting is not bullet proof. Imagine, we loop through all the VMs, and the last VM was already running, while the previous
335                         # VMs still needed to be created. Or the previous server creations take much longer than the last one.
336                         # In that case, we might be too fast when we query for the IP & MAC addresses.
337                         wait = '--wait'
338                 else:
339                         wait = ''
340                 log.info("Creating server...")
341                 cmd = 'openstack server create --flavor %s --key-name %s --image %s %s %s %s %s'%(flavor_name,key,image,nic_info,boot_info,wait,ServerName[-1])
342                 log.debug(cmd)
343                 output = subprocess.check_output(cmd , shell=True).decode().strip()
344 if floating_network != 'NO':
345         for vm in range(0, int(total_number_of_VMs)):
346                 if ServerToBeCreated[vm] =="yes":
347                         log.info('Creating & Associating floating IP for ('+ServerName[vm]+')...')
348                         cmd = 'openstack server show %s -c addresses -f value |grep -Eo "%s=[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*" | cut -d"=" -f2'%(ServerName[vm],internal_network)
349                         log.debug(cmd)
350                         vmportIP = subprocess.check_output(cmd , shell=True).decode().strip()
351                         cmd = 'openstack port list -c ID -c "Fixed IP Addresses" | grep %s  | cut -d" " -f 2 ' %(vmportIP)
352                         log.debug(cmd)
353                         vmportID = subprocess.check_output(cmd , shell=True).decode().strip()
354                         cmd = 'openstack floating ip create --port %s %s'%(vmportID,floating_network)
355                         log.debug(cmd)
356                         output = subprocess.check_output(cmd , shell=True).decode().strip()
357
358 config.add_section('rapid')
359 config.set('rapid', 'loglevel', loglevel)
360 config.set('rapid', 'version', version)
361 config.set('rapid', 'total_number_of_machines', total_number_of_VMs)
362 for vm in range(1, int(total_number_of_VMs)+1):
363         cmd = 'openstack server show %s'%(ServerName[vm-1])
364         log.debug(cmd)
365         output = subprocess.check_output(cmd , shell=True).decode().strip()
366         searchString = '.*%s=([0-9]*\.[0-9]*\.[0-9]*\.[0-9]*)' %(dataplane_network)
367         matchObj = re.search(searchString, output, re.DOTALL)
368         vmDPIP = matchObj.group(1)
369         searchString = '.*%s=([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+),*\s*([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)*' %(internal_network)
370         matchObj = re.search(searchString, output, re.DOTALL)
371         vmAdminIP = matchObj.group(2)
372         if vmAdminIP == None:
373                 vmAdminIP = matchObj.group(1)
374         cmd = 'openstack port list |egrep  "\\b%s\\b" | tr -s " " | cut -d"|" -f 4'%(vmDPIP)
375         log.debug(cmd)
376         vmDPmac = subprocess.check_output(cmd , shell=True).decode().strip()
377         config.add_section('M%d'%vm)
378         config.set('M%d'%vm, 'name', ServerName[vm-1])
379         config.set('M%d'%vm, 'admin_ip', vmAdminIP)
380         config.set('M%d'%vm, 'dp_ip', vmDPIP)
381         config.set('M%d'%vm, 'dp_mac', vmDPmac)
382         log.info('%s: (admin IP: %s), (dataplane IP: %s), (dataplane MAC: %s)' % (ServerName[vm-1],vmAdminIP,vmDPIP,vmDPmac))
383
384 config.add_section('ssh')
385 config.set('ssh', 'key', key)
386 config.add_section('Varia')
387 config.set('Varia', 'VIM', 'OpenStack')
388 config.set('Varia', 'stack', stack)
389 config.set('Varia', 'VMs', vms)
390 config.set('Varia', 'image', image)
391 config.set('Varia', 'image_file', image_file)
392 config.set('Varia', 'dataplane_network', dataplane_network)
393 config.set('Varia', 'subnet', subnet)
394 config.set('Varia', 'subnet_cidr', subnet_cidr)
395 config.set('Varia', 'internal_network', internal_network)
396 config.set('Varia', 'floating_network', floating_network)
397 # Writing the environment file
398 with open(stack+'.env', 'wb') as envfile:
399         config.write(envfile)