blob: 18cf0879ef5a9e2b4f426aacc29c44444b650413 [file] [log] [blame]
Jeremy Mordkoff6f07e6f2016-09-07 18:56:51 -04001#!/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"""
23This is a skeletal python tool that invokes the rwcal plugin
24to perform cloud operations.
25"""
26
27import argparse
28import os
29import socket
30import sys
31import logging
32
33from gi import require_version
34require_version('RwCal', '1.0')
35
36from gi.repository import GObject, Peas, GLib, GIRepository
37from gi.repository import RwCal, RwTypes
38
39def 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
173def resource_subcommand(rwcloud, cmdargs):
174 """Process the resources subcommand"""
175
176 if cmdargs.which == 'list':
177 resource_list_subcommand(rwcloud, cmdargs)
178
179def vm_list_subcommand(rwcloud, cmdargs):
180 status, vminfo = rwcloud.get_vm_list()
181 for vm in vminfo.vminfo_list:
182 print(vm)
183
184def vm_show_subcommand(rwcloud, cmdargs):
185 status, vm = rwcloud.get_vm(cmdargs.id)
186 print(vm)
187
188def vm_create_subcommand(cmdargs):
189 pass
190
191def vm_destroy_subcommand(cmdargs):
192 pass
193
194def vm_reboot_subcommand(cmdargs):
195 pass
196
197def vm_start_subcommand(cmdargs):
198 pass
199
200def 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
216def flavor_list_subcommand(rwcloud, cmdargs):
217 status, flavorinfo = rwcloud.get_flavor_list()
218 for flavor in flavorinfo.flavorinfo_list:
219 print(flavor)
220
221def flavor_show_subcommand(rwcloud, cmdargs):
222 status, flavor = rwcloud.get_flavor(cmdargs.id)
223 print(flavor)
224
225def 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
234def 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
418if __name__ == "__main__":
419 main()
420