Fix ordering of elements for Openstack block device mapping
[osm/SO.git] / rwcal / src / rwvim.py
1 #!/usr/bin/python3
2
3 #
4 # Copyright 2016 RIFT.IO Inc
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 # Author(s): Anil Gunturu
19 # Creation Date: 07/24/2014
20 #
21
22 """
23 This is a skeletal python tool that invokes the rwcal plugin
24 to perform cloud operations.
25 """
26
27 import argparse
28 import os
29 import socket
30 import sys
31 import logging
32
33 from gi import require_version
34 require_version('RwCal', '1.0')
35
36 from gi.repository import GObject, Peas, GLib, GIRepository
37 from gi.repository import RwCal, RwTypes
38
39 def resource_list_subcommand(rwcloud, cmdargs):
40 status, flavorinfo = rwcloud.get_flavor_list()
41 status, vminfo = rwcloud.get_vm_list()
42 if vminfo is None:
43 return
44
45 hosts = {}
46
47 # no yaml module installed for Python3, hack for now
48 if cmdargs.hostinfo_file_name:
49 with open(cmdargs.hostinfo_file_name, 'r') as f:
50 lines = f.readlines()
51
52 host = None
53 for l in lines:
54 l = l.strip()
55
56 if l == 'hosts:':
57 continue
58
59 if l == '-':
60 if host:
61 hosts[host['name']] = host
62 #hosts.append(host)
63 host = {}
64 continue
65
66 k,v = l.split(':')
67 host[k.strip()] = v.strip()
68
69 # Collect the unique Top of Rack (TOR) swithes
70 tors = set(hosts[vm.host_name]['tor'].lower() for vm in vminfo.vminfo_list)
71
72 print("resources:")
73 for vm in vminfo.vminfo_list:
74 _, __, host_ip_list = socket.gethostbyaddr(vm.host_name)
75
76 print(" -")
77 print(" name: {}".format(vm.vm_name))
78 print(" osid: {}".format(vm.vm_id))
79 print(" host_name: {}".format(vm.host_name))
80 print(" host_ip: {}".format(host_ip_list[0]))
81 controller, scratch = cmdargs.auth_url[7:].split(':')
82 print(" controller: {}".format(controller))
83 print(" tor: {}".format(hosts[vm.host_name]['tor']))
84 print(" image_name: {}".format(vm.image_name))
85 print(" flavor_name: {}".format(vm.flavor_name))
86 print(" availability_zone: {}".format(vm.availability_zone))
87 print(" private_ip_list: {}".format(
88 sorted(v.ip_address for v in vm.private_ip_list)
89 ))
90 # select the 10.0 network for management ip
91 for p in vm.private_ip_list:
92 if p.ip_address.startswith('10.0.'):
93 print(" ip_address: {}".format(p.ip_address))
94 break;
95
96 print(" public_ip_list: {}".format(
97 [v.ip_address for v in vm.public_ip_list]
98 ))
99 for flavor in flavorinfo.flavorinfo_list:
100 if flavor.name == vm.flavor_name:
101 print(" vcpu: {}".format(flavor.vcpus))
102 print(" ram: {}".format(flavor.memory))
103 print(" disk: {}".format(flavor.disk))
104 print(" host_aggregate_list: {}".format(
105 [a.name for a in flavor.host_aggregate_list]
106 ))
107 print(" pci_passthrough_device_list: {}".format(
108 [(d.alias,d.count) for d in flavor.pci_passthrough_device_list]
109 ))
110 # Number of openflow switches this resource connects to are the
111 # number of TOR switches for the pool for demos
112 print(" num_openflow_switches: {}".format(len(tors)))
113 # The number of legacy switches are 0 for demos
114 print(" num_legacy_switches: 0")
115 print(" epa_attributes:")
116
117 # HACK: rw_wag* VMs trusted_execution is always TRUE
118 if vm.vm_name.startswith('rw_wag'):
119 trusted_execution = 'TRUE'
120 else:
121 trusted_execution = str(flavor.trusted_host_only).upper()
122 print(" trusted_execution: {}".format(trusted_execution))
123 print(" ddio: {}".format(hosts[vm.host_name]['ddio']))
124 print(" cat: {}".format(hosts[vm.host_name]['cat']))
125 print(" ovs_acceleration: {}".format(hosts[vm.host_name]['ovs_acceleration']))
126 print(" mem_page_size: {}".format(flavor.mem_page_size))
127 if flavor.cpu_threads:
128 print(" cpu_threads: {}".format(flavor.cpu_threads))
129 print(" cpu_pinning_policy: {}".format(flavor.cpu_policy))
130 # print(" numa_policy: {{ node_cnt: {} }}".format(flavor.numa_node_cnt))
131 print(" numa_node_cnt: {}".format(flavor.numa_node_cnt))
132
133 # if any of the PCI passthrough devices are Coleto Creek
134 # set qat to accel
135 qat=False
136 passthrough=False
137 rrc=False
138 for d in flavor.pci_passthrough_device_list:
139 if 'COLETO' in d.alias:
140 qat=True
141 break
142 elif '10G' in d.alias:
143 passthrough=True
144 elif '100G' in d.alias:
145 passthrough=True
146 rrc=True
147 # NOTE: The following can break if SRIOV is used
148 # But for the demos 1,2,3 SRIOV is not used
149 # This is updated logic to set the nic to default to Niantic
150 # if 100G is not in the devise list.
151 if rrc:
152 print(" nic: RRC")
153 else:
154 print(" nic: NIANTIC")
155
156 if passthrough or hosts[vm.host_name]['ovs_acceleration'].upper() != 'DISABLED':
157 print(" dpdk_accelerated: TRUE")
158 else:
159 print(" dpdk_accelerated: FALSE")
160
161 if passthrough:
162 print(" pci_passthrough: TRUE")
163 else:
164 print(" pci_passthrough: FALSE")
165
166 if qat:
167 print(" quick_assist_policy: MANDATORY")
168 else:
169 print(" quick_assist_policy: NOACCEL")
170
171 break
172
173 def resource_subcommand(rwcloud, cmdargs):
174 """Process the resources subcommand"""
175
176 if cmdargs.which == 'list':
177 resource_list_subcommand(rwcloud, cmdargs)
178
179 def vm_list_subcommand(rwcloud, cmdargs):
180 status, vminfo = rwcloud.get_vm_list()
181 for vm in vminfo.vminfo_list:
182 print(vm)
183
184 def vm_show_subcommand(rwcloud, cmdargs):
185 status, vm = rwcloud.get_vm(cmdargs.id)
186 print(vm)
187
188 def vm_create_subcommand(cmdargs):
189 pass
190
191 def vm_destroy_subcommand(cmdargs):
192 pass
193
194 def vm_reboot_subcommand(cmdargs):
195 pass
196
197 def vm_start_subcommand(cmdargs):
198 pass
199
200 def vm_subcommand(rwcloud, cmdargs):
201 """Process the vm subcommand"""
202
203 if cmdargs.which == 'list':
204 vm_list_subcommand(rwcloud, cmdargs)
205 elif cmdargs.which == 'show':
206 vm_show_subcommand(rwcloud, cmdargs)
207 elif cmdargs.which == 'create':
208 vm_create_subcommand(cmdargs)
209 elif cmdargs.which == 'reboot':
210 vm_reboot_subcommand(cmdargs)
211 elif cmdargs.which == 'start':
212 vm_start_subcommand(cmdargs)
213 elif cmdargs.which == 'destroy':
214 vm_destroy_subcommand(cmdargs)
215
216 def flavor_list_subcommand(rwcloud, cmdargs):
217 status, flavorinfo = rwcloud.get_flavor_list()
218 for flavor in flavorinfo.flavorinfo_list:
219 print(flavor)
220
221 def flavor_show_subcommand(rwcloud, cmdargs):
222 status, flavor = rwcloud.get_flavor(cmdargs.id)
223 print(flavor)
224
225 def flavor_subcommand(rwcloud, cmdargs):
226 """Process the flavor subcommand"""
227
228 if cmdargs.which == 'list':
229 flavor_list_subcommand(rwcloud, cmdargs)
230 elif cmdargs.which == 'show':
231 flavor_show_subcommand(rwcloud, cmdargs)
232
233
234 def main(args=sys.argv[1:]):
235 logging.basicConfig(format='RWCAL %(message)s')
236
237 ##
238 # Command line argument specification
239 ##
240 desc="""This tool is used to manage the VMs"""
241 parser = argparse.ArgumentParser(description=desc)
242 subparsers = parser.add_subparsers()
243
244 # ipaddr = socket.gethostbyname(socket.getfqdn())
245 # default_auth_url = 'http://%s:35357/v2.0/tokens' % ipaddr
246 default_auth_url = "http://10.64.1.31:35357/v2.0/tokens"
247
248 parser.add_argument('-t', '--provider-type', dest='provider_type',
249 type=str, default='OPENSTACK',
250 help='Cloud provider type (default: %(default)s)')
251 parser.add_argument('-u', '--user-name', dest='user',
252 type=str, default='demo',
253 help='User name (default: %(default)s)')
254 parser.add_argument('-p', '--password', dest='passwd',
255 type=str, default='mypasswd',
256 help='Password (default: %(default)s)')
257 parser.add_argument('-n', '--tenant-name', dest='tenant',
258 type=str, default='demo',
259 help='User name (default: %(default)s)')
260 parser.add_argument('-a', '--auth-url', dest='auth_url',
261 type=str, default=default_auth_url,
262 help='Password (default: %(default)s)')
263
264 ##
265 # Subparser for Resources
266 ##
267 resource_parser = subparsers.add_parser('resource')
268 resource_subparsers = resource_parser.add_subparsers()
269
270 # List resource subparser
271 resource_list_parser = resource_subparsers.add_parser('list')
272 resource_list_parser.set_defaults(which='list')
273 resource_list_parser.add_argument('-f', '--hostinfo-file-name',
274 dest='hostinfo_file_name',
275 required=True,
276 type=str,
277 help='name of the static yaml file containing host information')
278
279 resource_parser.set_defaults(func=resource_subcommand)
280
281 ##
282 # Subparser for Flavor
283 ##
284 flavor_parser = subparsers.add_parser('flavor')
285 flavor_subparsers = flavor_parser.add_subparsers()
286
287 # List flavor subparser
288 flavor_list_parser = flavor_subparsers.add_parser('list')
289 flavor_list_parser.set_defaults(which='list')
290
291 # Show flavor subparser
292 flavor_show_parser = flavor_subparsers.add_parser('show')
293 flavor_show_parser.add_argument('id', type=str)
294 flavor_show_parser.set_defaults(which='show')
295
296 flavor_parser.set_defaults(func=flavor_subcommand)
297
298 ##
299 # Subparser for VM
300 ##
301 vm_parser = subparsers.add_parser('vm')
302 vm_subparsers = vm_parser.add_subparsers()
303
304 # Create VM subparser
305 vm_create_parser = vm_subparsers.add_parser('create')
306 vm_create_parser.add_argument('-c', '--count',
307 type=int, default=1,
308 help='The number of VMs to launch '
309 '(default: %(default)d)')
310 vm_create_parser.add_argument('-i', '--image',
311 default='rwopenstack_vm',
312 help='Specify the image for the VM')
313 vm_create_parser.add_argument('-n', '--name',
314 help='Specify the name of the VM')
315 vm_create_parser.add_argument('-f', '--flavor',
316 help='Specify the flavor for the VM')
317 vm_create_parser.add_argument('-R', '--reserve', dest='reserve_new_vms',
318 action='store_true', help='reserve any newly created VMs')
319 vm_create_parser.add_argument('-s', '--single', dest='wait_after_create',
320 action='store_true',
321 help='wait for each VM to start before creating the next')
322
323 vm_create_parser.set_defaults(which='create')
324
325 # Reboot VM subparser
326 vm_reboot_parser = vm_subparsers.add_parser('reboot')
327 group = vm_reboot_parser.add_mutually_exclusive_group()
328 group.add_argument('-n', '--vm-name', dest='vm_name',
329 type=str,
330 help='Specify the name of the VM')
331 group.add_argument('-a', '--reboot-all',
332 dest='reboot_all', action='store_true',
333 help='Reboot all VMs')
334 vm_reboot_parser.add_argument('-s', '--sleep',
335 dest='sleep_time',
336 type=int, default=4,
337 help='time in seconds to sleep between reboots')
338 vm_reboot_parser.set_defaults(which='reboot')
339
340 # Destroy VM subparser
341 vm_destroy_parser = vm_subparsers.add_parser('destroy')
342 group = vm_destroy_parser.add_mutually_exclusive_group()
343 group.add_argument('-n', '--vm-name', dest='vm_name',
344 type=str,
345 help='Specify the name of the VM (accepts regular expressions)')
346 group.add_argument('-a', '--destroy-all',
347 dest='destroy_all', action='store_true',
348 help='Delete all VMs')
349 group.add_argument('-w', '--wait',
350 dest='wait', action='store_true',
351 help='destroy all and wait until all VMs have exited')
352 vm_destroy_parser.set_defaults(which='destroy')
353
354 # List VM subparser
355 vm_list_parser = vm_subparsers.add_parser('list')
356 vm_list_parser.set_defaults(which='list')
357 vm_list_parser.add_argument('-i', '--ips_only', dest='ipsonly',
358 action='store_true',
359 help='only list IP addresses')
360
361 # Show vm subparser
362 vm_show_parser = vm_subparsers.add_parser('show')
363 vm_show_parser.add_argument('id', type=str)
364 vm_show_parser.set_defaults(which='show')
365 vm_parser.set_defaults(func=vm_subcommand)
366
367 cmdargs = parser.parse_args(args)
368
369 # Open the peas engine
370 engine = Peas.Engine.get_default()
371
372 # Load our plugin proxy into the g_irepository namespace
373 default = GIRepository.Repository.get_default()
374 GIRepository.Repository.require(default, "RwCal", "1.0", 0)
375
376 # Enable python language loader
377 engine.enable_loader("python3");
378
379 # Set the search path for peas engine,
380 # rift-shell sets the PLUGINDIR and GI_TYPELIB_PATH
381 paths = set([])
382 paths = paths.union(os.environ['PLUGINDIR'].split(":"))
383 for path in paths:
384 engine.add_search_path(path, path)
385
386 # Load the rwcal python plugin and create the extension.
387 info = engine.get_plugin_info("rwcal-plugin")
388 if info is None:
389 print("Error loading rwcal-python plugin")
390 sys.exit(1)
391 engine.load_plugin(info)
392 rwcloud = engine.create_extension(info, RwCal.Cloud, None)
393
394 # For now cloud credentials are hard coded
395 if cmdargs.provider_type == 'OPENSTACK':
396 provider_type = RwCal.CloudType.OPENSTACK_AUTH_URL
397 elif cmdargs.provider_type == 'EC2_US_EAST':
398 provider_type = RwCal.CloudType.EC2_US_EAST
399 elif cmdargs.provider_type == 'VSPHERE':
400 provider_type = RwCal.CloudType.VSPHERE
401 else:
402 sys.exit("Cloud provider %s is NOT supported yet" % cmdargs.provider_type)
403
404
405 if not 'RIFT_SHELL' in os.environ:
406 sys.stderr.write("This tool should be run from inside a rift-shell")
407
408 status = rwcloud.init(provider_type,
409 cmdargs.user,
410 cmdargs.passwd,
411 cmdargs.auth_url,
412 cmdargs.tenant);
413
414 assert status == RwTypes.RwStatus.SUCCESS
415
416 cmdargs.func(rwcloud, cmdargs)
417
418 if __name__ == "__main__":
419 main()
420