Add support for kubernetes deployment in rapid scripts.
[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 import ConfigParser
32
33 version="19.11.21"
34 stack = "rapid" #Default string for stack. This is not an OpenStack Heat stack, just a group of VMs
35 vms = "rapid.vms" #Default string for vms file
36 key = "prox" # default name for key
37 image = "rapidVM" # default name for the image
38 image_file = "rapidVM.qcow2"
39 dataplane_network = "dataplane-network" # default name for the dataplane network
40 subnet = "dpdk-subnet" #subnet for dataplane
41 subnet_cidr="10.10.10.0/24" # cidr for dataplane
42 internal_network="admin_internal_net"
43 floating_network="admin_floating_net"
44 loglevel="DEBUG" # sets log level for writing to file
45
46 def usage():
47         print("usage: createrapid [--version] [-v]")
48         print("                   [--stack STACK_NAME]")
49         print("                   [--vms VMS_FILE]")
50         print("                   [--key KEY_NAME]")
51         print("                   [--image IMAGE_NAME]")
52         print("                   [--image_file IMAGE_FILE]")
53         print("                   [--dataplane_network DP_NETWORK]")
54         print("                   [--subnet DP_SUBNET]")
55         print("                   [--subnet_cidr SUBNET_CIDR]")
56         print("                   [--internal_network ADMIN_NETWORK]")
57         print("                   [--floating_network FLOATING_NETWORK]")
58         print("                   [--log DEBUG|INFO|WARNING|ERROR|CRITICAL]")
59         print("                   [-h] [--help]")
60         print("")
61         print("Command-line interface to createrapid")
62         print("")
63         print("optional arguments:")
64         print("  -v,  --version                 Show program's version number and exit")
65         print("  --stack STACK_NAME             Specify a name for the stack. Default is %s."%stack)
66         print("  --vms VMS_FILE                 Specify the vms file to be used. Default is %s."%vms)
67         print("  --key KEY_NAME                 Specify the key to be used. Default is %s."%key)
68         print("  --image IMAGE_NAME             Specify the image to be used. Default is %s."%image)
69         print("  --image_file IMAGE_FILE        Specify the image qcow2 file to be used. Default is %s."%image_file)
70         print("  --dataplane_network NETWORK    Specify the network name to be used for the dataplane. Default is %s."%dataplane_network)
71         print("  --subnet DP_SUBNET             Specify the subnet name to be used for the dataplane. Default is %s."%subnet)
72         print("  --subnet_cidr SUBNET_CIDR      Specify the subnet CIDR to be used for the dataplane. Default is %s."%subnet_cidr)
73         print("  --internal_network NETWORK     Specify the network name to be used for the control plane. Default is %s."%internal_network)
74         print("  --floating_network NETWORK     Specify the external floating ip network name. Default is %s. NO if no floating ip used."%floating_network)
75         print("  --log                          Specify logging level for log file output, screen output level is hard coded")
76         print("  -h, --help                     Show help message and exit.")
77         print("")
78
79 try:
80         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="])
81 except getopt.GetoptError as err:
82         print("===========================================")
83         print(str(err))
84         print("===========================================")
85         usage()
86         sys.exit(2)
87 if args:
88         usage()
89         sys.exit(2)
90 for opt, arg in opts:
91         if opt in ["-h", "--help"]:
92                 usage()
93                 sys.exit()
94         if opt in ["-v", "--version"]:
95                 print("Rapid Automated Performance Indication for Dataplane "+version)
96                 sys.exit()
97         if opt in ["--stack"]:
98                 stack = arg
99                 print ("Using '"+stack+"' as name for the stack")
100         elif opt in ["--vms"]:
101                 vms = arg
102                 print ("Using Virtual Machines Description: "+vms)
103         elif opt in ["--key"]:
104                 key = arg
105                 print ("Using key: "+key)
106         elif opt in ["--image"]:
107                 image = arg
108                 print ("Using image: "+image)
109         elif opt in ["--image_file"]:
110                 image_file = arg
111                 print ("Using qcow2 file: "+image_file)
112         elif opt in ["--dataplane_network"]:
113                 dataplane_network = arg
114                 print ("Using dataplane network: "+ dataplane_network)
115         elif opt in ["--subnet"]:
116                 subnet = arg
117                 print ("Using dataplane subnet: "+ subnet)
118         elif opt in ["--subnet_cidr"]:
119                 subnet_cidr = arg
120                 print ("Using dataplane subnet: "+ subnet_cidr)
121         elif opt in ["--internal_network"]:
122                 internal_network = arg
123                 print ("Using control plane network: "+ internal_network)
124         elif opt in ["--floating_network"]:
125                 floating_network = arg
126                 print ("Using floating ip network: "+ floating_network)
127         elif opt in ["--log"]:
128                 loglevel = arg
129                 print ("Log level: "+ loglevel)
130
131
132 # create formatters
133 screen_formatter = logging.Formatter("%(message)s")
134 file_formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
135
136 # get a top-level logger,
137 # set its log level,
138 # BUT PREVENT IT from propagating messages to the root logger
139 #
140 log = logging.getLogger()
141 numeric_level = getattr(logging, loglevel.upper(), None)
142 if not isinstance(numeric_level, int):
143         raise ValueError('Invalid log level: %s' % loglevel)
144 log.setLevel(numeric_level)
145 log.propagate = 0
146
147 # create a console handler
148 # and set its log level to the command-line option 
149
150 console_handler = logging.StreamHandler(sys.stdout)
151 console_handler.setLevel(logging.INFO)
152 console_handler.setFormatter(screen_formatter)
153
154 # create a file handler
155 # and set its log level to DEBUG
156 #
157 log_file = 'CREATE' +stack +'.log'
158 file_handler = logging.handlers.RotatingFileHandler(log_file, backupCount=10)
159 #file_handler = log.handlers.TimedRotatingFileHandler(log_file, 'D', 1, 5)
160 file_handler.setLevel(numeric_level)
161 file_handler.setFormatter(file_formatter)
162
163 # add handlers to the logger
164 #
165 log.addHandler(file_handler)
166 log.addHandler(console_handler)
167
168 # Check if log exists and should therefore be rolled
169 needRoll = os.path.isfile(log_file)
170
171
172 # This is a stale log, so roll it
173 if needRoll:    
174         # Add timestamp
175         log.debug('\n---------\nLog closed on %s.\n---------\n' % time.asctime())
176         # Roll over on application start
177         log.handlers[0].doRollover()
178
179 # Add timestamp
180 log.debug('\n---------\nLog started on %s.\n---------\n' % time.asctime())
181
182 log.debug("createrapid.py version: "+version)
183 # Checking if the control network already exists, if not, stop the script
184 log.debug("Checking control plane network: " + internal_network)
185 cmd = 'openstack network list -f value -c Name'
186 log.debug (cmd)
187 Networks = subprocess.check_output(cmd , shell=True).decode().strip()
188 if internal_network in Networks:
189         log.info("Control plane network (" + internal_network+")  already active")
190 else:
191         log.exception("Control plane network " + internal_network + " not existing")
192         raise Exception("Control plane network " + internal_network + " not existing")
193
194 # Checking if the floating ip network should be used. If yes, check if it exists and stop the script if it doesn't
195 if floating_network !='NO':
196         log.debug("Checking floating ip network: " + floating_network)
197         if floating_network in Networks:
198                 log.info("Floating ip network (" + floating_network + ")  already active")
199         else:
200                 log.exception("Floating ip network " + floating_network + " not existing")
201                 raise Exception("Floating ip network " + floating_network + " not existing")
202
203 # Checking if the dataplane network already exists, if not create it
204 log.debug("Checking dataplane network: " + dataplane_network)
205 if dataplane_network in Networks:
206         # 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...
207         log.info("Dataplane network (" + dataplane_network + ") already active")
208         subnet = "n/a: was already existing"
209         subnet_cidr = "n/a, was already existing"
210 else:
211         log.info('Creating dataplane network ...')
212         cmd = 'openstack network create '+dataplane_network+' -f value -c status'
213         log.debug(cmd)
214         NetworkExist = subprocess.check_output(cmd , shell=True).decode().strip()
215         if 'ACTIVE' in NetworkExist:
216                 log.info("Dataplane network created")
217                 # Checking if the dataplane subnet already exists, if not create it
218                 log.debug("Checking subnet: "+subnet)
219                 cmd = 'openstack subnet list -f value -c Name'
220                 log.debug (cmd)
221                 Subnets = subprocess.check_output(cmd , shell=True).decode().strip()
222                 if subnet in  Subnets:
223                         log.info("Subnet (" +subnet+ ") already exists")
224                         subnet = "n/a, was already existing"
225                         subnet_cidr = "n/a, was already existing"
226                 else:
227                         log.info('Creating subnet ...')
228                         cmd = 'openstack subnet create --network ' + dataplane_network + ' --subnet-range ' + subnet_cidr +' --gateway none ' + subnet+' -f value -c name'
229                         log.debug(cmd)
230                         Subnets = subprocess.check_output(cmd , shell=True).decode().strip()
231                         if subnet in Subnets:
232                                 log.info("Subnet created")
233                         else :
234                                 log.exception("Failed to create subnet: " + subnet)
235                                 raise Exception("Failed to create subnet: " + subnet)
236         else :
237                 log.exception("Failed to create dataplane network: " + dataplane_network)
238                 raise Exception("Failed to create dataplane network: " + dataplane_network)
239
240 # Checking if the image already exists, if not create it
241 log.debug("Checking image: " + image)
242 cmd = 'openstack image list -f value -c Name'
243 log.debug(cmd)
244 Images = subprocess.check_output(cmd , shell=True).decode().strip()
245 if image in Images:
246         log.info("Image (" + image + ") already available")
247         image_file="Don't know, was already existing"
248 else:
249         log.info('Creating image ...')
250         cmd = 'openstack image create  -f value -c status --disk-format qcow2 --container-format bare --public --file ./'+image_file+ ' ' +image
251         log.debug(cmd)
252         ImageExist = subprocess.check_output(cmd , shell=True).decode().strip()
253         if 'active' in ImageExist:
254                 log.info('Image created and active')
255 #               cmd = 'openstack image set --property hw_vif_multiqueue_enabled="true" ' +image
256 #               subprocess.check_call(cmd , shell=True)
257         else :
258                 log.exception("Failed to create image")
259                 raise Exception("Failed to create image")
260
261 # Checking if the key already exists, if not create it
262 log.debug("Checking key: "+key)
263 cmd = 'openstack keypair list -f value -c Name'
264 log.debug (cmd)
265 KeyExist = subprocess.check_output(cmd , shell=True).decode().strip()
266 if key in KeyExist:
267         log.info("Key (" + key + ") already installed")
268 else:
269         log.info('Creating key ...')
270         cmd = 'openstack keypair create ' + key + '>' + key + '.pem'
271         log.debug(cmd)
272         subprocess.check_call(cmd , shell=True)
273         cmd = 'chmod 600 ' + key + '.pem'
274         subprocess.check_call(cmd, shell=True)
275         cmd = 'openstack keypair list -f value -c Name'
276         log.debug(cmd)
277         KeyExist = subprocess.check_output(cmd , shell=True).decode().strip()
278         if key in KeyExist:
279                 log.info("Key created")
280         else :
281                 log.exception("Failed to create key: " + key)
282                 raise Exception("Failed to create key: " + key)
283
284 ServerToBeCreated=[]
285 ServerName=[]
286 config = ConfigParser.RawConfigParser()
287 vmconfig = ConfigParser.RawConfigParser()
288 vmname = os.path.dirname(os.path.realpath(__file__))+'/' + vms
289 #vmconfig.read_file(open(vmname))
290 vmconfig.readfp(open(vmname))
291 total_number_of_VMs = vmconfig.get('DEFAULT', 'total_number_of_vms')
292 cmd = 'openstack server list -f value -c Name'
293 log.debug (cmd)
294 Servers = subprocess.check_output(cmd , shell=True).decode().strip()
295 cmd = 'openstack flavor list -f value -c Name'
296 log.debug (cmd)
297 Flavors = subprocess.check_output(cmd , shell=True).decode().strip()
298 for vm in range(1, int(total_number_of_VMs)+1):
299         flavor_info = vmconfig.get('VM%d'%vm, 'flavor_info')
300         flavor_meta_data = vmconfig.get('VM%d'%vm, 'flavor_meta_data')
301         boot_info = vmconfig.get('VM%d'%vm, 'boot_info')
302         SRIOV_port = vmconfig.get('VM%d'%vm, 'SRIOV_port')
303         SRIOV_mgmt_port = vmconfig.get('VM%d'%vm, 'SRIOV_mgmt_port')
304         ServerName.append('%s-VM%d'%(stack,vm))
305         flavor_name = '%s-VM%d-flavor'%(stack,vm)
306         log.debug("Checking server: " + ServerName[-1])
307         if ServerName[-1] in Servers:
308                 log.info("Server (" + ServerName[-1] + ") already active")
309                 ServerToBeCreated.append("no")
310         else:
311                 ServerToBeCreated.append("yes")
312                 # Checking if the flavor already exists, if not create it
313                 log.debug("Checking flavor: " + flavor_name)
314                 if flavor_name in Flavors:
315                         log.info("Flavor (" + flavor_name+") already installed")
316                 else:
317                         log.info('Creating flavor ...')
318                         cmd = 'openstack flavor create %s %s -f value -c name'%(flavor_name,flavor_info)
319                         log.debug(cmd)
320                         NewFlavor = subprocess.check_output(cmd , shell=True).decode().strip()
321                         if flavor_name in NewFlavor:
322                                 cmd = 'openstack flavor set %s %s'%(flavor_name, flavor_meta_data)
323                                 log.debug(cmd)
324                                 subprocess.check_call(cmd , shell=True)
325                                 log.info("Flavor created")
326                         else :
327                                 log.exception("Failed to create flavor: " + flavor_name)
328                                 raise Exception("Failed to create flavor: " + flavor_name)
329                 if SRIOV_mgmt_port == 'NO':
330                         nic_info = '--nic net-id=%s'%(internal_network)
331                 else:
332                         nic_info = '--nic port-id=%s'%(SRIOV_mgmt_port)
333                 if SRIOV_port == 'NO':
334                         nic_info = nic_info + ' --nic net-id=%s'%(dataplane_network)
335                 else:
336                         for port in SRIOV_port.split(','):
337                                 nic_info = nic_info + ' --nic port-id=%s'%(port)
338                 if vm==int(total_number_of_VMs):
339                         # For the last server, we want to wait for the server creation to complete, so the next operations will succeeed (e.g. IP allocation)
340                         # 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
341                         # VMs still needed to be created. Or the previous server creations take much longer than the last one.
342                         # In that case, we might be too fast when we query for the IP & MAC addresses.
343                         wait = '--wait'
344                 else:
345                         wait = ''
346                 log.info("Creating server...")
347                 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])
348                 log.debug(cmd)
349                 output = subprocess.check_output(cmd , shell=True).decode().strip()
350 if floating_network != 'NO':
351         for vm in range(0, int(total_number_of_VMs)):
352                 if ServerToBeCreated[vm] =="yes":
353                         log.info('Creating & Associating floating IP for ('+ServerName[vm]+')...')
354                         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)
355                         log.debug(cmd)
356                         vmportIP = subprocess.check_output(cmd , shell=True).decode().strip()
357                         cmd = 'openstack port list -c ID -c "Fixed IP Addresses" | grep %s  | cut -d" " -f 2 ' %(vmportIP)
358                         log.debug(cmd)
359                         vmportID = subprocess.check_output(cmd , shell=True).decode().strip()
360                         cmd = 'openstack floating ip create --port %s %s'%(vmportID,floating_network)
361                         log.debug(cmd)
362                         output = subprocess.check_output(cmd , shell=True).decode().strip()
363
364 config.add_section('rapid')
365 config.set('rapid', 'loglevel', loglevel)
366 config.set('rapid', 'version', version)
367 config.set('rapid', 'total_number_of_machines', total_number_of_VMs)
368 for vm in range(1, int(total_number_of_VMs)+1):
369         cmd = 'openstack server show %s'%(ServerName[vm-1])
370         log.debug(cmd)
371         output = subprocess.check_output(cmd , shell=True).decode().strip()
372         searchString = '.*%s=([0-9]*\.[0-9]*\.[0-9]*\.[0-9]*)' %(dataplane_network)
373         matchObj = re.search(searchString, output, re.DOTALL)
374         vmDPIP = matchObj.group(1)
375         searchString = '.*%s=([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+),*\s*([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)*' %(internal_network)
376         matchObj = re.search(searchString, output, re.DOTALL)
377         vmAdminIP = matchObj.group(2)
378         if vmAdminIP == None:
379                 vmAdminIP = matchObj.group(1)
380         cmd = 'openstack port list |egrep  "\\b%s\\b" | tr -s " " | cut -d"|" -f 4'%(vmDPIP)
381         log.debug(cmd)
382         vmDPmac = subprocess.check_output(cmd , shell=True).decode().strip()
383         config.add_section('M%d'%vm)
384         config.set('M%d'%vm, 'name', ServerName[vm-1])
385         config.set('M%d'%vm, 'admin_ip', vmAdminIP)
386         config.set('M%d'%vm, 'dp_ip', vmDPIP)
387         config.set('M%d'%vm, 'dp_mac', vmDPmac)
388         log.info('%s: (admin IP: %s), (dataplane IP: %s), (dataplane MAC: %s)' % (ServerName[vm-1],vmAdminIP,vmDPIP,vmDPmac))
389
390 config.add_section('ssh')
391 config.set('ssh', 'key', key + '.pem')
392 config.set('ssh', 'user', 'centos')
393 config.add_section('Varia')
394 config.set('Varia', 'VIM', 'OpenStack')
395 config.set('Varia', 'stack', stack)
396 config.set('Varia', 'VMs', vms)
397 config.set('Varia', 'image', image)
398 config.set('Varia', 'image_file', image_file)
399 config.set('Varia', 'dataplane_network', dataplane_network)
400 config.set('Varia', 'subnet', subnet)
401 config.set('Varia', 'subnet_cidr', subnet_cidr)
402 config.set('Varia', 'internal_network', internal_network)
403 config.set('Varia', 'floating_network', floating_network)
404 # Writing the environment file
405 with open(stack+'.env', 'wb') as envfile:
406         config.write(envfile)