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.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
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]")
62 print("Command-line interface to createrapid")
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.")
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("===========================================")
85 print("===========================================")
92 if opt in ("-h", "--help"):
95 if opt in ("-v", "--version"):
96 print("Rapid Automated Performance Indication for Dataplane "+version)
98 if opt in ("--stack"):
100 print ("Using '"+stack+"' as name for the stack")
101 elif opt in ("--vms"):
103 print ("Using Virtual Machines Description: "+vms)
104 elif opt in ("--key"):
106 print ("Using key: "+key)
107 elif opt in ("--image"):
109 print ("Using image: "+image)
110 elif opt in ("--image_file"):
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"):
118 print ("Using dataplane subnet: "+ subnet)
119 elif opt in ("--subnet_cidr"):
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"):
130 print ("Log level: "+ loglevel)
134 screen_formatter = logging.Formatter("%(message)s")
135 file_formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
137 # get a top-level logger,
139 # BUT PREVENT IT from propagating messages to the root logger
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)
148 # create a console handler
149 # and set its log level to the command-line option
151 console_handler = logging.StreamHandler(sys.stdout)
152 console_handler.setLevel(logging.INFO)
153 console_handler.setFormatter(screen_formatter)
155 # create a file handler
156 # and set its log level to DEBUG
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)
164 # add handlers to the logger
166 log.addHandler(file_handler)
167 log.addHandler(console_handler)
169 # Check if log exists and should therefore be rolled
170 needRoll = os.path.isfile(log_file)
173 # This is a stale log, so roll it
176 log.debug('\n---------\nLog closed on %s.\n---------\n' % time.asctime())
177 # Roll over on application start
178 log.handlers[0].doRollover()
181 log.debug('\n---------\nLog started on %s.\n---------\n' % time.asctime())
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'
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")
192 log.exception("Control plane network " + internal_network + " not existing")
193 raise Exception("Control plane network " + internal_network + " not existing")
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")
201 log.exception("Floating ip network " + floating_network + " not existing")
202 raise Exception("Floating ip network " + floating_network + " not existing")
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")
209 log.info('Creating dataplane network ...')
210 cmd = 'openstack network create '+dataplane_network+' -f value -c status'
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'
219 Subnets = subprocess.check_output(cmd , shell=True).decode().strip()
220 if subnet in Subnets:
221 log.info("Subnet (" +subnet+ ") already exists")
223 log.info('Creating subnet ...')
224 cmd = 'openstack subnet create --network ' + dataplane_network + ' --subnet-range ' + subnet_cidr +' --gateway none ' + subnet+' -f value -c name'
226 Subnets = subprocess.check_output(cmd , shell=True).decode().strip()
227 if subnet in Subnets:
228 log.info("Subnet created")
230 log.exception("Failed to create subnet: " + subnet)
231 raise Exception("Failed to create subnet: " + subnet)
233 log.exception("Failed to create dataplane network: " + dataplane_network)
234 raise Exception("Failed to create dataplane network: " + dataplane_network)
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'
240 Images = subprocess.check_output(cmd , shell=True).decode().strip()
242 log.info("Image (" + image + ") already available")
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
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)
253 log.exception("Failed to create image")
254 raise Exception("Failed to create image")
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'
260 KeyExist = subprocess.check_output(cmd , shell=True).decode().strip()
262 log.info("Key ("+key+") already installed")
264 log.info('Creating key ...')
265 cmd = 'openstack keypair create '+ key + '>' +key+'.pem'
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'
272 KeyExist = subprocess.check_output(cmd , shell=True).decode().strip()
274 log.info("Key created")
276 log.exception("Failed to create key: " + key)
277 raise Exception("Failed to create key: " + key)
281 config = ConfigParser.RawConfigParser()
282 vmconfig = ConfigParser.RawConfigParser()
284 total_number_of_VMs = vmconfig.get('DEFAULT', 'total_number_of_vms')
285 cmd = 'openstack server list -f value -c Name'
287 Servers = subprocess.check_output(cmd , shell=True).decode().strip()
288 cmd = 'openstack flavor list -f value -c Name'
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")
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")
310 log.info('Creating flavor ...')
311 cmd = 'openstack flavor create %s %s -f value -c name'%(flavor_name,flavor_info)
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)
317 subprocess.check_call(cmd , shell=True)
318 log.info("Flavor created")
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)
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)
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.
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])
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)
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)
353 vmportID = subprocess.check_output(cmd , shell=True).decode().strip()
354 cmd = 'openstack floating ip create --port %s %s'%(vmportID,floating_network)
356 output = subprocess.check_output(cmd , shell=True).decode().strip()
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])
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)
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))
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)