Merge changes from topic 'june_release'
[samplevnf.git] / VNFs / DPPD-PROX / helper-scripts / rapid / createrapid.py
1 #!/usr/bin/python
2
3 ##
4 ## Copyright (c) 2010-2019 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         # If the dataplane already exists, we are assuming that this network is already created before with the proper configuration, hence we do not check if the subnet is created etc...
208         log.info("Dataplane network (" + dataplane_network + ") already active")
209 else:
210         log.info('Creating dataplane network ...')
211         cmd = 'openstack network create '+dataplane_network+' -f value -c status'
212         log.debug(cmd)
213         NetworkExist = subprocess.check_output(cmd , shell=True).decode().strip()
214         if 'ACTIVE' in NetworkExist:
215                 log.info("Dataplane network created")
216                 # Checking if the dataplane subnet already exists, if not create it
217                 log.debug("Checking subnet: "+subnet)
218                 cmd = 'openstack subnet list -f value -c Name'
219                 log.debug (cmd)
220                 Subnets = subprocess.check_output(cmd , shell=True).decode().strip()
221                 if subnet in  Subnets:
222                         log.info("Subnet (" +subnet+ ") already exists")
223                 else:
224                         log.info('Creating subnet ...')
225                         cmd = 'openstack subnet create --network ' + dataplane_network + ' --subnet-range ' + subnet_cidr +' --gateway none ' + subnet+' -f value -c name'
226                         log.debug(cmd)
227                         Subnets = subprocess.check_output(cmd , shell=True).decode().strip()
228                         if subnet in Subnets:
229                                 log.info("Subnet created")
230                         else :
231                                 log.exception("Failed to create subnet: " + subnet)
232                                 raise Exception("Failed to create subnet: " + subnet)
233         else :
234                 log.exception("Failed to create dataplane network: " + dataplane_network)
235                 raise Exception("Failed to create dataplane network: " + dataplane_network)
236
237 # Checking if the image already exists, if not create it
238 log.debug("Checking image: " + image)
239 cmd = 'openstack image list -f value -c Name'
240 log.debug(cmd)
241 Images = subprocess.check_output(cmd , shell=True).decode().strip()
242 if image in Images:
243         log.info("Image (" + image + ") already available")
244 else:
245         log.info('Creating image ...')
246         cmd = 'openstack image create  -f value -c status --disk-format qcow2 --container-format bare --public --file ./'+image_file+ ' ' +image
247         log.debug(cmd)
248         ImageExist = subprocess.check_output(cmd , shell=True).decode().strip()
249         if 'active' in ImageExist:
250                 log.info('Image created and active')
251 #               cmd = 'openstack image set --property hw_vif_multiqueue_enabled="true" ' +image
252 #               subprocess.check_call(cmd , shell=True)
253         else :
254                 log.exception("Failed to create image")
255                 raise Exception("Failed to create image")
256
257 # Checking if the key already exists, if not create it
258 log.debug("Checking key: "+key)
259 cmd = 'openstack keypair list -f value -c Name'
260 log.debug (cmd)
261 KeyExist = subprocess.check_output(cmd , shell=True).decode().strip()
262 if key in KeyExist:
263         log.info("Key ("+key+") already installed")
264 else:
265         log.info('Creating key ...')
266         cmd = 'openstack keypair create '+ key + '>' +key+'.pem'
267         log.debug(cmd)
268         subprocess.check_call(cmd , shell=True)
269         cmd = 'chmod 600 ' +key+'.pem'
270         subprocess.check_call(cmd , shell=True)
271         cmd = 'openstack keypair list -f value -c Name'
272         log.debug(cmd)
273         KeyExist = subprocess.check_output(cmd , shell=True).decode().strip()
274         if key in KeyExist:
275                 log.info("Key created")
276         else :
277                 log.exception("Failed to create key: " + key)
278                 raise Exception("Failed to create key: " + key)
279
280 ServerToBeCreated=[]
281 ServerName=[]
282 config = ConfigParser.RawConfigParser()
283 vmconfig = ConfigParser.RawConfigParser()
284 vmname = os.path.dirname(os.path.realpath(__file__))+'/' + vms
285 #vmconfig.read_file(open(vmname))
286 vmconfig.readfp(open(vmname))
287 total_number_of_VMs = vmconfig.get('DEFAULT', 'total_number_of_vms')
288 cmd = 'openstack server list -f value -c Name'
289 log.debug (cmd)
290 Servers = subprocess.check_output(cmd , shell=True).decode().strip()
291 cmd = 'openstack flavor list -f value -c Name'
292 log.debug (cmd)
293 Flavors = subprocess.check_output(cmd , shell=True).decode().strip()
294 for vm in range(1, int(total_number_of_VMs)+1):
295         flavor_info = vmconfig.get('VM%d'%vm, 'flavor_info')
296         flavor_meta_data = vmconfig.get('VM%d'%vm, 'flavor_meta_data')
297         boot_info = vmconfig.get('VM%d'%vm, 'boot_info')
298         SRIOV_port = vmconfig.get('VM%d'%vm, 'SRIOV_port')
299         SRIOV_mgmt_port = vmconfig.get('VM%d'%vm, 'SRIOV_mgmt_port')
300         ServerName.append('%s-VM%d'%(stack,vm))
301         flavor_name = '%s-VM%d-flavor'%(stack,vm)
302         log.debug("Checking server: " + ServerName[-1])
303         if ServerName[-1] in Servers:
304                 log.info("Server (" + ServerName[-1] + ") already active")
305                 ServerToBeCreated.append("no")
306         else:
307                 ServerToBeCreated.append("yes")
308                 # Checking if the flavor already exists, if not create it
309                 log.debug("Checking flavor: " + flavor_name)
310                 if flavor_name in Flavors:
311                         log.info("Flavor (" + flavor_name+") already installed")
312                 else:
313                         log.info('Creating flavor ...')
314                         cmd = 'openstack flavor create %s %s -f value -c name'%(flavor_name,flavor_info)
315                         log.debug(cmd)
316                         NewFlavor = subprocess.check_output(cmd , shell=True).decode().strip()
317                         if flavor_name in NewFlavor:
318                                 cmd = 'openstack flavor set %s %s'%(flavor_name, flavor_meta_data)
319                                 log.debug(cmd)
320                                 subprocess.check_call(cmd , shell=True)
321                                 log.info("Flavor created")
322                         else :
323                                 log.exception("Failed to create flavor: " + flavor_name)
324                                 raise Exception("Failed to create flavor: " + flavor_name)
325                 if SRIOV_mgmt_port == 'NO':
326                         nic_info = '--nic net-id=%s'%(internal_network)
327                 else:
328                         nic_info = '--nic port-id=%s'%(SRIOV_mgmt_port)
329                 if SRIOV_port == 'NO':
330                         nic_info = nic_info + ' --nic net-id=%s'%(dataplane_network)
331                 else:
332                         for port in SRIOV_port.split(','):
333                                 nic_info = nic_info + ' --nic port-id=%s'%(port)
334                 if vm==int(total_number_of_VMs):
335                         # For the last server, we want to wait for the server creation to complete, so the next operations will succeeed (e.g. IP allocation)
336                         # 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
337                         # VMs still needed to be created. Or the previous server creations take much longer than the last one.
338                         # In that case, we might be too fast when we query for the IP & MAC addresses.
339                         wait = '--wait'
340                 else:
341                         wait = ''
342                 log.info("Creating server...")
343                 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])
344                 log.debug(cmd)
345                 output = subprocess.check_output(cmd , shell=True).decode().strip()
346 if floating_network != 'NO':
347         for vm in range(0, int(total_number_of_VMs)):
348                 if ServerToBeCreated[vm] =="yes":
349                         log.info('Creating & Associating floating IP for ('+ServerName[vm]+')...')
350                         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)
351                         log.debug(cmd)
352                         vmportIP = subprocess.check_output(cmd , shell=True).decode().strip()
353                         cmd = 'openstack port list -c ID -c "Fixed IP Addresses" | grep %s  | cut -d" " -f 2 ' %(vmportIP)
354                         log.debug(cmd)
355                         vmportID = subprocess.check_output(cmd , shell=True).decode().strip()
356                         cmd = 'openstack floating ip create --port %s %s'%(vmportID,floating_network)
357                         log.debug(cmd)
358                         output = subprocess.check_output(cmd , shell=True).decode().strip()
359
360 config.add_section('rapid')
361 config.set('rapid', 'loglevel', loglevel)
362 config.set('rapid', 'version', version)
363 config.set('rapid', 'total_number_of_machines', total_number_of_VMs)
364 for vm in range(1, int(total_number_of_VMs)+1):
365         cmd = 'openstack server show %s'%(ServerName[vm-1])
366         log.debug(cmd)
367         output = subprocess.check_output(cmd , shell=True).decode().strip()
368         searchString = '.*%s=([0-9]*\.[0-9]*\.[0-9]*\.[0-9]*)' %(dataplane_network)
369         matchObj = re.search(searchString, output, re.DOTALL)
370         vmDPIP = matchObj.group(1)
371         searchString = '.*%s=([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+),*\s*([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)*' %(internal_network)
372         matchObj = re.search(searchString, output, re.DOTALL)
373         vmAdminIP = matchObj.group(2)
374         if vmAdminIP == None:
375                 vmAdminIP = matchObj.group(1)
376         cmd = 'openstack port list |egrep  "\\b%s\\b" | tr -s " " | cut -d"|" -f 4'%(vmDPIP)
377         log.debug(cmd)
378         vmDPmac = subprocess.check_output(cmd , shell=True).decode().strip()
379         config.add_section('M%d'%vm)
380         config.set('M%d'%vm, 'name', ServerName[vm-1])
381         config.set('M%d'%vm, 'admin_ip', vmAdminIP)
382         config.set('M%d'%vm, 'dp_ip', vmDPIP)
383         config.set('M%d'%vm, 'dp_mac', vmDPmac)
384         log.info('%s: (admin IP: %s), (dataplane IP: %s), (dataplane MAC: %s)' % (ServerName[vm-1],vmAdminIP,vmDPIP,vmDPmac))
385
386 config.add_section('ssh')
387 config.set('ssh', 'key', key)
388 config.add_section('Varia')
389 config.set('Varia', 'VIM', 'OpenStack')
390 config.set('Varia', 'stack', stack)
391 config.set('Varia', 'VMs', vms)
392 config.set('Varia', 'image', image)
393 config.set('Varia', 'image_file', image_file)
394 config.set('Varia', 'dataplane_network', dataplane_network)
395 config.set('Varia', 'subnet', subnet)
396 config.set('Varia', 'subnet_cidr', subnet_cidr)
397 config.set('Varia', 'internal_network', internal_network)
398 config.set('Varia', 'floating_network', floating_network)
399 # Writing the environment file
400 with open(stack+'.env', 'wb') as envfile:
401         config.write(envfile)