4 ## Copyright (c) 2010-2017 Intel Corporation
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
10 ## http://www.apache.org/licenses/LICENSE-2.0
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.
19 from __future__ import print_function
29 from logging.handlers import RotatingFileHandler
30 from logging import handlers
31 from prox_ctrl import prox_ctrl
35 stack = "rapid" #Default string for stack. This is not an OpenStack Heat stack, just a group of VMs
36 vms = "rapidVMs" #Default string for vms file
37 key = "prox" # default name for kay
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 runtime=10 # time in seconds for 1 test run
49 print("usage: createrapid [--version] [-v]")
50 print(" [--stack STACK_NAME]")
51 print(" [--vms VMS_FILE]")
52 print(" [--key KEY_NAME]")
53 print(" [--image IMAGE_NAME]")
54 print(" [--image_file IMAGE_FILE]")
55 print(" [--dataplane_network DP_NETWORK]")
56 print(" [--subnet DP_SUBNET]")
57 print(" [--subnet_cidr SUBNET_CIDR]")
58 print(" [--internal_network ADMIN_NETWORK]")
59 print(" [--floating_network ADMIN_NETWORK]")
60 print(" [--log DEBUG|INFO|WARNING|ERROR|CRITICAL]")
61 print(" [-h] [--help]")
63 print("Command-line interface to createrapid")
65 print("optional arguments:")
66 print(" -v, --version Show program's version number and exit")
67 print(" --stack STACK_NAME Specify a name for the stack. Default is %s."%stack)
68 print(" --vms VMS_FILE Specify the vms file to be used. Default is %s.vms."%vms)
69 print(" --key KEY_NAME Specify the key to be used. Default is %s."%key)
70 print(" --image IMAGE_NAME Specify the image to be used. Default is %s."%image)
71 print(" --image_file IMAGE_FILE Specify the image qcow2 file to be used. Default is %s."%image_file)
72 print(" --dataplane_network NETWORK Specify the network name to be used for the dataplane. Default is %s."%dataplane_network)
73 print(" --subnet DP_SUBNET Specify the subnet name to be used for the dataplane. Default is %s."%subnet)
74 print(" --subnet_cidr SUBNET_CIDR Specify the subnet CIDR to be used for the dataplane. Default is %s."%subnet_cidr)
75 print(" --internal_network NETWORK Specify the network name to be used for the control plane. Default is %s."%internal_network)
76 print(" --floating_network NETWORK Specify the external floating ip network name. Default is %s. NO if no floating ip used."%floating_network)
77 print(" --log Specify logging level for log file output, screen output level is hard coded")
78 print(" -h, --help Show help message and exit.")
82 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="])
83 except getopt.GetoptError as err:
84 print("===========================================")
86 print("===========================================")
93 if opt in ("-h", "--help"):
96 if opt in ("-v", "--version"):
97 print("Rapid Automated Performance Indication for Dataplane "+version)
99 if opt in ("--stack"):
101 print ("Using '"+stack+"' as name for the stack")
102 elif opt in ("--vms"):
104 print ("Using Virtual Machines Description: "+vms)
105 elif opt in ("--key"):
107 print ("Using key: "+key)
108 elif opt in ("--image"):
110 print ("Using image: "+image)
111 elif opt in ("--image_file"):
113 print ("Using qcow2 file: "+image_file)
114 elif opt in ("--dataplane_network"):
115 dataplane_network = arg
116 print ("Using dataplane network: "+ dataplane_network)
117 elif opt in ("--subnet"):
119 print ("Using dataplane subnet: "+ subnet)
120 elif opt in ("--subnet_cidr"):
122 print ("Using dataplane subnet: "+ subnet_cidr)
123 elif opt in ("--internal_network"):
124 internal_network = arg
125 print ("Using control plane network: "+ internal_network)
126 elif opt in ("--floating_network"):
127 floating_network = arg
128 print ("Using floating ip network: "+ floating_network)
129 elif opt in ("--log"):
131 print ("Log level: "+ loglevel)
135 screen_formatter = logging.Formatter("%(message)s")
136 file_formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
138 # get a top-level logger,
140 # BUT PREVENT IT from propagating messages to the root logger
142 log = logging.getLogger()
143 numeric_level = getattr(logging, loglevel.upper(), None)
144 if not isinstance(numeric_level, int):
145 raise ValueError('Invalid log level: %s' % loglevel)
146 log.setLevel(numeric_level)
149 # create a console handler
150 # and set its log level to the command-line option
152 console_handler = logging.StreamHandler(sys.stdout)
153 console_handler.setLevel(logging.INFO)
154 console_handler.setFormatter(screen_formatter)
156 # create a file handler
157 # and set its log level to DEBUG
159 log_file = 'CREATE' +stack +'.log'
160 file_handler = logging.handlers.RotatingFileHandler(log_file, backupCount=10)
161 #file_handler = log.handlers.TimedRotatingFileHandler(log_file, 'D', 1, 5)
162 file_handler.setLevel(numeric_level)
163 file_handler.setFormatter(file_formatter)
165 # add handlers to the logger
167 log.addHandler(file_handler)
168 log.addHandler(console_handler)
170 # Check if log exists and should therefore be rolled
171 needRoll = os.path.isfile(log_file)
174 # This is a stale log, so roll it
177 log.debug('\n---------\nLog closed on %s.\n---------\n' % time.asctime())
179 # Roll over on application start
180 log.handlers[0].doRollover()
183 log.debug('\n---------\nLog started on %s.\n---------\n' % time.asctime())
185 log.debug("createrapid.py version: "+version)
186 # Checking if the control network already exists, if not, stop the script
187 log.debug("Checking control plane network: "+internal_network)
188 cmd = 'openstack network show '+internal_network
190 cmd = cmd + ' |grep "status " | tr -s " " | cut -d" " -f 4'
191 NetworkExist = subprocess.check_output(cmd , shell=True).strip()
192 if NetworkExist == 'ACTIVE':
193 log.info("Control plane network ("+internal_network+") already active")
195 log.exception("Control plane network " + internal_network + " not existing")
196 raise Exception("Control plane network " + internal_network + " not existing")
198 # Checking if the floating ip network already exists, if not, stop the script
199 if floating_network <>'NO':
200 log.debug("Checking floating ip network: "+floating_network)
201 cmd = 'openstack network show '+floating_network
203 cmd = cmd + ' |grep "status " | tr -s " " | cut -d" " -f 4'
204 NetworkExist = subprocess.check_output(cmd , shell=True).strip()
205 if NetworkExist == 'ACTIVE':
206 log.info("Floating ip network ("+floating_network+") already active")
208 log.exception("Floating ip network " + floating_network + " not existing")
209 raise Exception("Floating ip network " + floating_network + " not existing")
211 # Checking if the image already exists, if not create it
212 log.debug("Checking image: "+image)
213 cmd = 'openstack image show '+image
215 cmd = cmd +' |grep "status " | tr -s " " | cut -d" " -f 4'
216 ImageExist = subprocess.check_output(cmd , shell=True).strip()
217 if ImageExist == 'active':
218 log.info("Image ("+image+") already available")
220 log.info('Creating image ...')
221 cmd = 'openstack image create --disk-format qcow2 --container-format bare --public --file ./'+image_file+ ' ' +image
223 cmd = cmd + ' |grep "status " | tr -s " " | cut -d" " -f 4'
224 ImageExist = subprocess.check_output(cmd , shell=True).strip()
225 if ImageExist == 'active':
226 log.info('Image created and active')
227 cmd = 'openstack image set --property hw_vif_multiqueue_enabled="true" ' +image
228 # subprocess.check_call(cmd , shell=True)
230 log.exception("Failed to create image")
231 raise Exception("Failed to create image")
233 # Checking if the key already exists, if not create it
234 log.debug("Checking key: "+key)
235 cmd = 'openstack keypair show '+key
237 cmd = cmd + ' |grep "name " | tr -s " " | cut -d" " -f 4'
238 KeyExist = subprocess.check_output(cmd , shell=True).strip()
240 log.info("Key ("+key+") already installed")
242 log.info('Creating key ...')
243 cmd = 'openstack keypair create '+ key + '>' +key+'.pem'
245 subprocess.check_call(cmd , shell=True)
246 cmd = 'chmod 600 ' +key+'.pem'
247 subprocess.check_call(cmd , shell=True)
248 cmd = 'openstack keypair show '+key
250 cmd = cmd + ' |grep "name " | tr -s " " | cut -d" " -f 4'
251 KeyExist = subprocess.check_output(cmd , shell=True).strip()
253 log.info("Key created")
255 log.exception("Failed to create key: " + key)
256 raise Exception("Failed to create key: " + key)
259 # Checking if the dataplane network already exists, if not create it
260 log.debug("Checking dataplane network: "+dataplane_network)
261 cmd = 'openstack network show '+dataplane_network
263 cmd = cmd + ' |grep "status " | tr -s " " | cut -d" " -f 4'
264 NetworkExist = subprocess.check_output(cmd , shell=True).strip()
265 if NetworkExist == 'ACTIVE':
266 log.info("Dataplane network ("+dataplane_network+") already active")
268 log.info('Creating dataplane network ...')
269 cmd = 'openstack network create '+dataplane_network
271 cmd = cmd + ' |grep "status " | tr -s " " | cut -d" " -f 4'
272 NetworkExist = subprocess.check_output(cmd , shell=True).strip()
273 if NetworkExist == 'ACTIVE':
274 log.info("Dataplane network created")
276 log.exception("Failed to create dataplane network: " + dataplane_network)
277 raise Exception("Failed to create dataplane network: " + dataplane_network)
279 # Checking if the dataplane subnet already exists, if not create it
280 log.debug("Checking subnet: "+subnet)
281 cmd = 'openstack subnet show '+ subnet
283 cmd = cmd +' |grep "name " | tr -s " " | cut -d"|" -f 3'
284 SubnetExist = subprocess.check_output(cmd , shell=True).strip()
285 if SubnetExist == subnet:
286 log.info("Subnet (" +subnet+ ") already exists")
288 log.info('Creating subnet ...')
289 cmd = 'openstack subnet create --network ' + dataplane_network + ' --subnet-range ' + subnet_cidr +' --gateway none ' + subnet
291 cmd = cmd + ' |grep "name " | tr -s " " | cut -d"|" -f 3'
292 SubnetExist = subprocess.check_output(cmd , shell=True).strip()
293 if SubnetExist == subnet:
294 log.info("Subnet created")
296 log.exception("Failed to create subnet: " + subnet)
297 raise Exception("Failed to create subnet: " + subnet)
301 config = ConfigParser.RawConfigParser()
302 vmconfig = ConfigParser.RawConfigParser()
303 vmconfig.read(vms+'.vms')
304 total_number_of_VMs = vmconfig.get('DEFAULT', 'total_number_of_vms')
305 for vm in range(1, int(total_number_of_VMs)+1):
306 flavor_info = vmconfig.get('VM%d'%vm, 'flavor_info')
307 flavor_meta_data = vmconfig.get('VM%d'%vm, 'flavor_meta_data')
308 boot_info = vmconfig.get('VM%d'%vm, 'boot_info')
309 SRIOV_port = vmconfig.get('VM%d'%vm, 'SRIOV_port')
310 ServerName.append('%s-VM%d'%(stack,vm))
311 flavor_name = '%s-VM%d-flavor'%(stack,vm)
312 log.debug("Checking server: "+ServerName[-1])
313 cmd = 'openstack server show '+ServerName[-1]
315 cmd = cmd + ' |grep "\sname\s" | tr -s " " | cut -d" " -f 4'
316 ServerExist = subprocess.check_output(cmd , shell=True).strip()
317 if ServerExist == ServerName[-1]:
318 log.info("Server ("+ServerName[-1]+") already active")
319 ServerToBeCreated.append("no")
321 ServerToBeCreated.append("yes")
322 # Checking if the flavor already exists, if not create it
323 log.debug("Checking flavor: "+flavor_name)
324 cmd = 'openstack flavor show '+flavor_name
326 cmd = cmd + ' |grep "\sname\s" | tr -s " " | cut -d" " -f 4'
327 FlavorExist = subprocess.check_output(cmd , shell=True).strip()
328 if FlavorExist == flavor_name:
329 log.info("Flavor ("+flavor_name+") already installed")
331 log.info('Creating flavor ...')
332 cmd = 'openstack flavor create %s %s'%(flavor_name,flavor_info)
334 cmd = cmd + ' |grep "\sname\s" | tr -s " " | cut -d" " -f 4'
335 FlavorExist = subprocess.check_output(cmd , shell=True).strip()
336 if FlavorExist == flavor_name:
337 cmd = 'openstack flavor set %s %s'%(flavor_name, flavor_meta_data)
339 subprocess.check_call(cmd , shell=True)
340 log.info("Flavor created")
342 log.exception("Failed to create flavor: " + flavor_name)
343 raise Exception("Failed to create flavor: " + flavor_name)
344 if SRIOV_port == 'NO':
345 nic_info = '--nic net-id=%s --nic net-id=%s'%(internal_network,dataplane_network)
347 nic_info = '--nic net-id=%s'%(internal_network)
348 for port in SRIOV_port.split(','):
349 nic_info = nic_info + ' --nic port-id=%s'%(port)
350 if vm==int(total_number_of_VMs):
351 # For the last server, we want to wait for the server creation to complete, so the next operations will succeeed (e.g. IP allocation)
352 # 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
353 # VMs still needed to be created. Or the previous server creations take much longer than the last one.
354 # In that case, we might be to fast when we query for the IP & MAC addresses.
358 log.info("Creating server...")
359 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])
361 cmd = cmd + ' |grep "\sname\s" | tr -s " " | cut -d" " -f 4'
362 ServerExist = subprocess.check_output(cmd , shell=True).strip()
363 if floating_network <> 'NO':
364 for vm in range(0, int(total_number_of_VMs)):
365 if ServerToBeCreated[vm] =="yes":
366 log.info('Creating floating IP ...')
367 cmd = 'openstack floating ip create ' + floating_network
369 cmd = cmd + ' |grep "floating_ip_address " | tr -s " " | cut -d"|" -f 3'
370 vmAdminIP = subprocess.check_output(cmd , shell=True).strip()
371 log.info('Associating floating IP ...')
372 cmd = 'openstack server add floating ip %s %s'%(ServerName[vm],vmAdminIP)
374 output = subprocess.check_output(cmd , shell=True).strip()
376 for vm in range(1, int(total_number_of_VMs)+1):
377 cmd = 'openstack server show %s'%(ServerName[vm-1])
379 output = subprocess.check_output(cmd , shell=True).strip()
380 searchString = '.*%s.*?([0-9]*\.[0-9]*\.[0-9]*\.[0-9]*)' %(dataplane_network)
381 matchObj = re.search(searchString, output, re.DOTALL)
382 vmDPIP = matchObj.group(1)
383 searchString = '.*%s=([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+),*\s*([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)*' %(internal_network)
384 matchObj = re.search(searchString, output, re.DOTALL)
385 vmAdminIP = matchObj.group(2)
386 if vmAdminIP == None:
387 vmAdminIP = matchObj.group(1)
388 cmd = 'openstack port list |egrep "\\b%s\\b" | tr -s " " | cut -d"|" -f 4'%(vmDPIP)
390 vmDPmac = subprocess.check_output(cmd , shell=True).strip()
391 config.add_section('M%d'%vm)
392 config.set('M%d'%vm, 'name', ServerName[vm-1])
393 config.set('M%d'%vm, 'admin_ip', vmAdminIP)
394 config.set('M%d'%vm, 'dp_ip', vmDPIP)
395 config.set('M%d'%vm, 'dp_mac', vmDPmac)
396 log.info('%s: (admin IP: %s), (dataplane IP: %s), (dataplane MAC: %s)' % (ServerName[vm-1],vmAdminIP,vmDPIP,vmDPmac))
398 config.add_section('OpenStack')
399 config.set('OpenStack', 'stack', stack)
400 config.set('OpenStack', 'VMs', vms)
401 config.set('OpenStack', 'key', key)
402 config.set('OpenStack', 'image', image)
403 config.set('OpenStack', 'image_file', image_file)
404 config.set('OpenStack', 'dataplane_network', dataplane_network)
405 config.set('OpenStack', 'subnet', subnet)
406 config.set('OpenStack', 'subnet_cidr', subnet_cidr)
407 config.set('OpenStack', 'internal_network', internal_network)
408 config.set('OpenStack', 'floating_network', floating_network)
409 config.add_section('rapid')
410 config.set('rapid', 'loglevel', loglevel)
411 config.set('rapid', 'version', version)
412 config.set('rapid', 'total_number_of_machines', total_number_of_VMs)
413 config.set('DEFAULT', 'admin_ip', 'none')
414 # Writing the environment file
415 with open(stack+'.env', 'wb') as envfile:
416 config.write(envfile)