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
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" #Hardcoded at this moment
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
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]")
65 print("Command-line interface to createrapid")
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."%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.")
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)
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("===========================================")
92 print("===========================================")
99 if opt in ("-h", "--help"):
102 if opt in ("-v", "--version"):
103 print("Rapid Automated Performance Indication for Dataplane "+version)
105 if opt in ("--stack"):
107 print ("Using '"+stack+"' as name for the stack")
108 elif opt in ("--yaml"):
110 print ("Using stack: "+yaml)
111 elif opt in ("--key"):
113 print ("Using key: "+key)
114 elif opt in ("--flavor"):
116 print ("Using flavor: "+flavor)
117 elif opt in ("--image"):
119 print ("Using image: "+image)
120 elif opt in ("--image_file"):
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"):
128 print ("Using dataplane subnet: "+ subnet)
129 elif opt in ("--subnet_cidr"):
131 print ("Using dataplane subnet: "+ subnet_cidr)
132 elif opt in ("--internal_network"):
133 internal_network = arg
134 print ("Using controle 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"):
140 print ("Log level: "+ loglevel)
144 screen_formatter = logging.Formatter("%(message)s")
145 file_formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
147 # get a top-level logger,
149 # BUT PREVENT IT from propagating messages to the root logger
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)
158 # create a console handler
159 # and set its log level to the command-line option
161 console_handler = logging.StreamHandler(sys.stdout)
162 console_handler.setLevel(logging.INFO)
163 console_handler.setFormatter(screen_formatter)
165 # create a file handler
166 # and set its log level to DEBUG
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)
174 # add handlers to the logger
176 log.addHandler(file_handler)
177 log.addHandler(console_handler)
179 # Check if log exists and should therefore be rolled
180 needRoll = os.path.isfile(log_file)
183 # This is a stale log, so roll it
186 log.debug('\n---------\nLog closed on %s.\n---------\n' % time.asctime())
188 # Roll over on application start
189 log.handlers[0].doRollover()
192 log.debug('\n---------\nLog started on %s.\n---------\n' % time.asctime())
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
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")
204 log.exception("Control plane network " + internal_network + " not existing")
205 raise Exception("Control plane network " + internal_network + " not existing")
207 # Checking if the floating ip network already exists, if not, stop the script
208 log.debug("Checking floating ip network: "+floating_network)
209 cmd = 'openstack network show '+floating_network
211 cmd = cmd + ' |grep "status " | tr -s " " | cut -d" " -f 4'
212 NetworkExist = subprocess.check_output(cmd , shell=True).strip()
213 if NetworkExist == 'ACTIVE':
214 log.info("Floating ip network ("+floating_network+") already active")
216 log.exception("Floating ip network " + floating_network + " not existing")
217 raise Exception("Floating ip network " + floating_network + " not existing")
219 # Checking if the image already exists, if not create it
220 log.debug("Checking image: "+image)
221 cmd = 'openstack image show '+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 ("+image+") already available")
228 log.info('Creating image ...')
229 cmd = 'openstack image create --disk-format qcow2 --container-format bare --public --file ./'+image_file+ ' ' +image
231 cmd = cmd + ' |grep "status " | tr -s " " | cut -d" " -f 4'
232 ImageExist = subprocess.check_output(cmd , shell=True).strip()
233 if ImageExist == 'active':
234 log.info('Image created and active')
235 cmd = 'openstack image set --property hw_vif_multiqueue_enabled="true" ' +image
236 # subprocess.check_call(cmd , shell=True)
238 log.exception("Failed to create image")
239 raise Exception("Failed to create image")
241 # Checking if the key already exists, if not create it
242 log.debug("Checking key: "+key)
243 cmd = 'openstack keypair show '+key
245 cmd = cmd + ' |grep "name " | tr -s " " | cut -d" " -f 4'
246 KeyExist = subprocess.check_output(cmd , shell=True).strip()
248 log.info("Key ("+key+") already installed")
250 log.info('Creating key ...')
251 cmd = 'openstack keypair create '+ key + '>' +key+'.pem'
253 subprocess.check_call(cmd , shell=True)
254 cmd = 'chmod 600 ' +key+'.pem'
255 subprocess.check_call(cmd , shell=True)
256 cmd = 'openstack keypair show '+key
258 cmd = cmd + ' |grep "name " | tr -s " " | cut -d" " -f 4'
259 KeyExist = subprocess.check_output(cmd , shell=True).strip()
261 log.info("Key created")
263 log.exception("Failed to create key: " + key)
264 raise Exception("Failed to create key: " + key)
266 # Checking if the flavor already exists, if not create it
267 log.debug("Checking flavor: "+flavor)
268 cmd = 'openstack flavor show '+flavor
270 cmd = cmd + ' |grep "name " | tr -s " " | cut -d" " -f 4'
271 FlavorExist = subprocess.check_output(cmd , shell=True).strip()
272 if FlavorExist == flavor:
273 log.info("Flavor ("+flavor+") already installed")
275 log.info('Creating flavor ...')
276 cmd = 'openstack flavor create '+flavor+' --ram 8192 --disk 20 --vcpus 4'
278 cmd = cmd + ' |grep "name " | tr -s " " | cut -d" " -f 4'
279 FlavorExist = subprocess.check_output(cmd , shell=True).strip()
280 if FlavorExist == flavor:
281 cmd = 'openstack flavor set '+ flavor +' --property hw:mem_page_size="large" --property hw:cpu_policy="dedicated" --property hw:cpu_threads_policy="isolate"'
283 subprocess.check_call(cmd , shell=True)
284 log.info("Flavor created")
286 log.exception("Failed to create flavor: " + flavor)
287 raise Exception("Failed to create flavor: " + flavor)
289 # Checking if the dataplane network already exists, if not create it
290 log.debug("Checking dataplane network: "+dataplane_network)
291 cmd = 'openstack network show '+dataplane_network
293 cmd = cmd + ' |grep "status " | tr -s " " | cut -d" " -f 4'
294 NetworkExist = subprocess.check_output(cmd , shell=True).strip()
295 if NetworkExist == 'ACTIVE':
296 log.info("Dataplane network ("+dataplane_network+") already active")
298 log.info('Creating dataplane network ...')
299 cmd = 'openstack network create '+dataplane_network
301 cmd = cmd + ' |grep "status " | tr -s " " | cut -d" " -f 4'
302 NetworkExist = subprocess.check_output(cmd , shell=True).strip()
303 if NetworkExist == 'ACTIVE':
304 log.info("Dataplane network created")
306 log.exception("Failed to create dataplane network: " + dataplane_network)
307 raise Exception("Failed to create dataplane network: " + dataplane_network)
309 # Checking if the dataplane subnet already exists, if not create it
310 log.debug("Checking subnet: "+subnet)
311 cmd = 'openstack subnet show '+ subnet
313 cmd = cmd +' |grep "name " | tr -s " " | cut -d"|" -f 3'
314 SubnetExist = subprocess.check_output(cmd , shell=True).strip()
315 if SubnetExist == subnet:
316 log.info("Subnet (" +subnet+ ") already exists")
318 log.info('Creating subnet ...')
319 cmd = 'openstack subnet create --network ' + dataplane_network + ' --subnet-range ' + subnet_cidr +' --gateway none ' + subnet
321 cmd = cmd + ' |grep "name " | tr -s " " | cut -d"|" -f 3'
322 SubnetExist = subprocess.check_output(cmd , shell=True).strip()
323 if SubnetExist == subnet:
324 log.info("Subnet created")
326 log.exception("Failed to create subnet: " + subnet)
327 raise Exception("Failed to create subnet: " + subnet)
329 # Checking if the stack already exists, if not create it
330 log.debug("Checking Stack: "+stack)
331 cmd = 'openstack stack show '+stack
333 cmd = cmd+' |grep "stack_status " | tr -s " " | cut -d"|" -f 3'
334 StackRunning = subprocess.check_output(cmd , shell=True).strip()
335 if StackRunning == '':
336 log.info('Creating Stack ...')
337 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 cmd = cmd + ' |grep "stack_status " | tr -s " " | cut -d"|" -f 3'
340 StackRunning = subprocess.check_output(cmd , shell=True).strip()
341 if StackRunning != 'CREATE_COMPLETE':
342 log.exception("Failed to create stack")
343 raise Exception("Failed to create stack")
345 # Obtaining IP & MAC addresses for the VMs created in the stack
346 log.info("Stack ("+stack+") running")
347 cmd='openstack stack show -f yaml -c outputs ' + stack
349 output = subprocess.check_output(cmd , shell=True).strip()
350 matchObj = re.search('.*total_number_of_VMs.*?([0-9])', output, re.DOTALL)
351 total_number_of_VMs = matchObj.group(1)
355 config = ConfigParser.RawConfigParser()
356 for vm in range(1, int(total_number_of_VMs)+1):
357 searchString = '.*vm%d_dataplane_ip.*?([0-9]*\.[0-9]*\.[0-9]*\.[0-9]*)' % vm
358 matchObj = re.search(searchString, output, re.DOTALL)
359 vmDPIP.append(matchObj.group(1))
360 searchString = '.*vm%d_public_ip.*?([0-9]*\.[0-9]*\.[0-9]*\.[0-9]*)' % vm
361 matchObj = re.search(searchString, output, re.DOTALL)
362 vmAdminIP.append(matchObj.group(1))
363 searchString = '.*vm%d_dataplane_mac.*?([a-fA-F0-9:]{17})' % vm
364 matchObj = re.search(searchString, output, re.DOTALL)
365 vmDPmac.append(matchObj.group(1))
366 log.info('VM%d: (admin IP: %s), (dataplane IP: %s), (dataplane MAC: %s)' % (vm,vmAdminIP[-1],vmDPIP[-1],vmDPmac[-1]))
367 config.add_section('VM%d'%vm)
368 config.set('VM%d'%vm, 'admin_ip', vmAdminIP[-1])
369 config.set('VM%d'%vm, 'dp_ip', vmDPIP[-1])
370 config.set('VM%d'%vm, 'dp_mac', vmDPmac[-1])
371 config.add_section('OpenStack')
372 config.set('OpenStack', 'stack', stack)
373 config.set('OpenStack', 'yaml', yaml)
374 config.set('OpenStack', 'key', key)
375 config.set('OpenStack', 'flavor', flavor)
376 config.set('OpenStack', 'image', image)
377 config.set('OpenStack', 'image_file', image_file)
378 config.set('OpenStack', 'dataplane_network', dataplane_network)
379 config.set('OpenStack', 'subnet', subnet)
380 config.set('OpenStack', 'subnet_cidr', subnet_cidr)
381 config.set('OpenStack', 'internal_network', internal_network)
382 config.set('OpenStack', 'floating_network', floating_network)
383 config.add_section('rapid')
384 config.set('rapid', 'loglevel', loglevel)
385 config.set('rapid', 'version', version)
386 config.set('rapid', 'total_number_of_VMs', total_number_of_VMs)
387 config.set('DEFAULT', 'admin_ip', 'none')
388 # Writing the environment file
389 with open(stack+'.env', 'wb') as envfile:
390 config.write(envfile)