4 ## Copyright (c) 2010-2019 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 # 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")
210 log.info('Creating dataplane network ...')
211 cmd = 'openstack network create '+dataplane_network+' -f value -c status'
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'
220 Subnets = subprocess.check_output(cmd , shell=True).decode().strip()
221 if subnet in Subnets:
222 log.info("Subnet (" +subnet+ ") already exists")
224 log.info('Creating subnet ...')
225 cmd = 'openstack subnet create --network ' + dataplane_network + ' --subnet-range ' + subnet_cidr +' --gateway none ' + subnet+' -f value -c name'
227 Subnets = subprocess.check_output(cmd , shell=True).decode().strip()
228 if subnet in Subnets:
229 log.info("Subnet created")
231 log.exception("Failed to create subnet: " + subnet)
232 raise Exception("Failed to create subnet: " + subnet)
234 log.exception("Failed to create dataplane network: " + dataplane_network)
235 raise Exception("Failed to create dataplane network: " + dataplane_network)
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'
241 Images = subprocess.check_output(cmd , shell=True).decode().strip()
243 log.info("Image (" + image + ") already available")
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
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)
254 log.exception("Failed to create image")
255 raise Exception("Failed to create image")
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'
261 KeyExist = subprocess.check_output(cmd , shell=True).decode().strip()
263 log.info("Key ("+key+") already installed")
265 log.info('Creating key ...')
266 cmd = 'openstack keypair create '+ key + '>' +key+'.pem'
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'
273 KeyExist = subprocess.check_output(cmd , shell=True).decode().strip()
275 log.info("Key created")
277 log.exception("Failed to create key: " + key)
278 raise Exception("Failed to create key: " + key)
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'
290 Servers = subprocess.check_output(cmd , shell=True).decode().strip()
291 cmd = 'openstack flavor list -f value -c Name'
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")
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")
313 log.info('Creating flavor ...')
314 cmd = 'openstack flavor create %s %s -f value -c name'%(flavor_name,flavor_info)
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)
320 subprocess.check_call(cmd , shell=True)
321 log.info("Flavor created")
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)
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)
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.
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])
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)
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)
355 vmportID = subprocess.check_output(cmd , shell=True).decode().strip()
356 cmd = 'openstack floating ip create --port %s %s'%(vmportID,floating_network)
358 output = subprocess.check_output(cmd , shell=True).decode().strip()
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])
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)
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))
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)