| #!/usr/bin/python3 |
| |
| # |
| # Copyright 2016 RIFT.IO Inc |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # |
| # Author(s): Anil Gunturu |
| # Creation Date: 07/24/2014 |
| # |
| |
| """ |
| This is a skeletal python tool that invokes the rwcal plugin |
| to perform cloud operations. |
| """ |
| |
| import argparse |
| import os |
| import socket |
| import sys |
| import logging |
| |
| from gi import require_version |
| require_version('RwCal', '1.0') |
| |
| from gi.repository import GObject, Peas, GLib, GIRepository |
| from gi.repository import RwCal, RwTypes |
| |
| def resource_list_subcommand(rwcloud, cmdargs): |
| status, flavorinfo = rwcloud.get_flavor_list() |
| status, vminfo = rwcloud.get_vm_list() |
| if vminfo is None: |
| return |
| |
| hosts = {} |
| |
| # no yaml module installed for Python3, hack for now |
| if cmdargs.hostinfo_file_name: |
| with open(cmdargs.hostinfo_file_name, 'r') as f: |
| lines = f.readlines() |
| |
| host = None |
| for l in lines: |
| l = l.strip() |
| |
| if l == 'hosts:': |
| continue |
| |
| if l == '-': |
| if host: |
| hosts[host['name']] = host |
| #hosts.append(host) |
| host = {} |
| continue |
| |
| k,v = l.split(':') |
| host[k.strip()] = v.strip() |
| |
| # Collect the unique Top of Rack (TOR) swithes |
| tors = set(hosts[vm.host_name]['tor'].lower() for vm in vminfo.vminfo_list) |
| |
| print("resources:") |
| for vm in vminfo.vminfo_list: |
| _, __, host_ip_list = socket.gethostbyaddr(vm.host_name) |
| |
| print(" -") |
| print(" name: {}".format(vm.vm_name)) |
| print(" osid: {}".format(vm.vm_id)) |
| print(" host_name: {}".format(vm.host_name)) |
| print(" host_ip: {}".format(host_ip_list[0])) |
| controller, scratch = cmdargs.auth_url[7:].split(':') |
| print(" controller: {}".format(controller)) |
| print(" tor: {}".format(hosts[vm.host_name]['tor'])) |
| print(" image_name: {}".format(vm.image_name)) |
| print(" flavor_name: {}".format(vm.flavor_name)) |
| print(" availability_zone: {}".format(vm.availability_zone)) |
| print(" private_ip_list: {}".format( |
| sorted(v.ip_address for v in vm.private_ip_list) |
| )) |
| # select the 10.0 network for management ip |
| for p in vm.private_ip_list: |
| if p.ip_address.startswith('10.0.'): |
| print(" ip_address: {}".format(p.ip_address)) |
| break; |
| |
| print(" public_ip_list: {}".format( |
| [v.ip_address for v in vm.public_ip_list] |
| )) |
| for flavor in flavorinfo.flavorinfo_list: |
| if flavor.name == vm.flavor_name: |
| print(" vcpu: {}".format(flavor.vcpus)) |
| print(" ram: {}".format(flavor.memory)) |
| print(" disk: {}".format(flavor.disk)) |
| print(" host_aggregate_list: {}".format( |
| [a.name for a in flavor.host_aggregate_list] |
| )) |
| print(" pci_passthrough_device_list: {}".format( |
| [(d.alias,d.count) for d in flavor.pci_passthrough_device_list] |
| )) |
| # Number of openflow switches this resource connects to are the |
| # number of TOR switches for the pool for demos |
| print(" num_openflow_switches: {}".format(len(tors))) |
| # The number of legacy switches are 0 for demos |
| print(" num_legacy_switches: 0") |
| print(" epa_attributes:") |
| |
| # HACK: rw_wag* VMs trusted_execution is always TRUE |
| if vm.vm_name.startswith('rw_wag'): |
| trusted_execution = 'TRUE' |
| else: |
| trusted_execution = str(flavor.trusted_host_only).upper() |
| print(" trusted_execution: {}".format(trusted_execution)) |
| print(" ddio: {}".format(hosts[vm.host_name]['ddio'])) |
| print(" cat: {}".format(hosts[vm.host_name]['cat'])) |
| print(" ovs_acceleration: {}".format(hosts[vm.host_name]['ovs_acceleration'])) |
| print(" mem_page_size: {}".format(flavor.mem_page_size)) |
| if flavor.cpu_threads: |
| print(" cpu_threads: {}".format(flavor.cpu_threads)) |
| print(" cpu_pinning_policy: {}".format(flavor.cpu_policy)) |
| # print(" numa_policy: {{ node_cnt: {} }}".format(flavor.numa_node_cnt)) |
| print(" numa_node_cnt: {}".format(flavor.numa_node_cnt)) |
| |
| # if any of the PCI passthrough devices are Coleto Creek |
| # set qat to accel |
| qat=False |
| passthrough=False |
| rrc=False |
| for d in flavor.pci_passthrough_device_list: |
| if 'COLETO' in d.alias: |
| qat=True |
| break |
| elif '10G' in d.alias: |
| passthrough=True |
| elif '100G' in d.alias: |
| passthrough=True |
| rrc=True |
| # NOTE: The following can break if SRIOV is used |
| # But for the demos 1,2,3 SRIOV is not used |
| # This is updated logic to set the nic to default to Niantic |
| # if 100G is not in the devise list. |
| if rrc: |
| print(" nic: RRC") |
| else: |
| print(" nic: NIANTIC") |
| |
| if passthrough or hosts[vm.host_name]['ovs_acceleration'].upper() != 'DISABLED': |
| print(" dpdk_accelerated: TRUE") |
| else: |
| print(" dpdk_accelerated: FALSE") |
| |
| if passthrough: |
| print(" pci_passthrough: TRUE") |
| else: |
| print(" pci_passthrough: FALSE") |
| |
| if qat: |
| print(" quick_assist_policy: MANDATORY") |
| else: |
| print(" quick_assist_policy: NOACCEL") |
| |
| break |
| |
| def resource_subcommand(rwcloud, cmdargs): |
| """Process the resources subcommand""" |
| |
| if cmdargs.which == 'list': |
| resource_list_subcommand(rwcloud, cmdargs) |
| |
| def vm_list_subcommand(rwcloud, cmdargs): |
| status, vminfo = rwcloud.get_vm_list() |
| for vm in vminfo.vminfo_list: |
| print(vm) |
| |
| def vm_show_subcommand(rwcloud, cmdargs): |
| status, vm = rwcloud.get_vm(cmdargs.id) |
| print(vm) |
| |
| def vm_create_subcommand(cmdargs): |
| pass |
| |
| def vm_destroy_subcommand(cmdargs): |
| pass |
| |
| def vm_reboot_subcommand(cmdargs): |
| pass |
| |
| def vm_start_subcommand(cmdargs): |
| pass |
| |
| def vm_subcommand(rwcloud, cmdargs): |
| """Process the vm subcommand""" |
| |
| if cmdargs.which == 'list': |
| vm_list_subcommand(rwcloud, cmdargs) |
| elif cmdargs.which == 'show': |
| vm_show_subcommand(rwcloud, cmdargs) |
| elif cmdargs.which == 'create': |
| vm_create_subcommand(cmdargs) |
| elif cmdargs.which == 'reboot': |
| vm_reboot_subcommand(cmdargs) |
| elif cmdargs.which == 'start': |
| vm_start_subcommand(cmdargs) |
| elif cmdargs.which == 'destroy': |
| vm_destroy_subcommand(cmdargs) |
| |
| def flavor_list_subcommand(rwcloud, cmdargs): |
| status, flavorinfo = rwcloud.get_flavor_list() |
| for flavor in flavorinfo.flavorinfo_list: |
| print(flavor) |
| |
| def flavor_show_subcommand(rwcloud, cmdargs): |
| status, flavor = rwcloud.get_flavor(cmdargs.id) |
| print(flavor) |
| |
| def flavor_subcommand(rwcloud, cmdargs): |
| """Process the flavor subcommand""" |
| |
| if cmdargs.which == 'list': |
| flavor_list_subcommand(rwcloud, cmdargs) |
| elif cmdargs.which == 'show': |
| flavor_show_subcommand(rwcloud, cmdargs) |
| |
| |
| def main(args=sys.argv[1:]): |
| logging.basicConfig(format='RWCAL %(message)s') |
| |
| ## |
| # Command line argument specification |
| ## |
| desc="""This tool is used to manage the VMs""" |
| parser = argparse.ArgumentParser(description=desc) |
| subparsers = parser.add_subparsers() |
| |
| # ipaddr = socket.gethostbyname(socket.getfqdn()) |
| # default_auth_url = 'http://%s:35357/v2.0/tokens' % ipaddr |
| default_auth_url = "http://10.64.1.31:35357/v2.0/tokens" |
| |
| parser.add_argument('-t', '--provider-type', dest='provider_type', |
| type=str, default='OPENSTACK', |
| help='Cloud provider type (default: %(default)s)') |
| parser.add_argument('-u', '--user-name', dest='user', |
| type=str, default='demo', |
| help='User name (default: %(default)s)') |
| parser.add_argument('-p', '--password', dest='passwd', |
| type=str, default='mypasswd', |
| help='Password (default: %(default)s)') |
| parser.add_argument('-n', '--tenant-name', dest='tenant', |
| type=str, default='demo', |
| help='User name (default: %(default)s)') |
| parser.add_argument('-a', '--auth-url', dest='auth_url', |
| type=str, default=default_auth_url, |
| help='Password (default: %(default)s)') |
| |
| ## |
| # Subparser for Resources |
| ## |
| resource_parser = subparsers.add_parser('resource') |
| resource_subparsers = resource_parser.add_subparsers() |
| |
| # List resource subparser |
| resource_list_parser = resource_subparsers.add_parser('list') |
| resource_list_parser.set_defaults(which='list') |
| resource_list_parser.add_argument('-f', '--hostinfo-file-name', |
| dest='hostinfo_file_name', |
| required=True, |
| type=str, |
| help='name of the static yaml file containing host information') |
| |
| resource_parser.set_defaults(func=resource_subcommand) |
| |
| ## |
| # Subparser for Flavor |
| ## |
| flavor_parser = subparsers.add_parser('flavor') |
| flavor_subparsers = flavor_parser.add_subparsers() |
| |
| # List flavor subparser |
| flavor_list_parser = flavor_subparsers.add_parser('list') |
| flavor_list_parser.set_defaults(which='list') |
| |
| # Show flavor subparser |
| flavor_show_parser = flavor_subparsers.add_parser('show') |
| flavor_show_parser.add_argument('id', type=str) |
| flavor_show_parser.set_defaults(which='show') |
| |
| flavor_parser.set_defaults(func=flavor_subcommand) |
| |
| ## |
| # Subparser for VM |
| ## |
| vm_parser = subparsers.add_parser('vm') |
| vm_subparsers = vm_parser.add_subparsers() |
| |
| # Create VM subparser |
| vm_create_parser = vm_subparsers.add_parser('create') |
| vm_create_parser.add_argument('-c', '--count', |
| type=int, default=1, |
| help='The number of VMs to launch ' |
| '(default: %(default)d)') |
| vm_create_parser.add_argument('-i', '--image', |
| default='rwopenstack_vm', |
| help='Specify the image for the VM') |
| vm_create_parser.add_argument('-n', '--name', |
| help='Specify the name of the VM') |
| vm_create_parser.add_argument('-f', '--flavor', |
| help='Specify the flavor for the VM') |
| vm_create_parser.add_argument('-R', '--reserve', dest='reserve_new_vms', |
| action='store_true', help='reserve any newly created VMs') |
| vm_create_parser.add_argument('-s', '--single', dest='wait_after_create', |
| action='store_true', |
| help='wait for each VM to start before creating the next') |
| |
| vm_create_parser.set_defaults(which='create') |
| |
| # Reboot VM subparser |
| vm_reboot_parser = vm_subparsers.add_parser('reboot') |
| group = vm_reboot_parser.add_mutually_exclusive_group() |
| group.add_argument('-n', '--vm-name', dest='vm_name', |
| type=str, |
| help='Specify the name of the VM') |
| group.add_argument('-a', '--reboot-all', |
| dest='reboot_all', action='store_true', |
| help='Reboot all VMs') |
| vm_reboot_parser.add_argument('-s', '--sleep', |
| dest='sleep_time', |
| type=int, default=4, |
| help='time in seconds to sleep between reboots') |
| vm_reboot_parser.set_defaults(which='reboot') |
| |
| # Destroy VM subparser |
| vm_destroy_parser = vm_subparsers.add_parser('destroy') |
| group = vm_destroy_parser.add_mutually_exclusive_group() |
| group.add_argument('-n', '--vm-name', dest='vm_name', |
| type=str, |
| help='Specify the name of the VM (accepts regular expressions)') |
| group.add_argument('-a', '--destroy-all', |
| dest='destroy_all', action='store_true', |
| help='Delete all VMs') |
| group.add_argument('-w', '--wait', |
| dest='wait', action='store_true', |
| help='destroy all and wait until all VMs have exited') |
| vm_destroy_parser.set_defaults(which='destroy') |
| |
| # List VM subparser |
| vm_list_parser = vm_subparsers.add_parser('list') |
| vm_list_parser.set_defaults(which='list') |
| vm_list_parser.add_argument('-i', '--ips_only', dest='ipsonly', |
| action='store_true', |
| help='only list IP addresses') |
| |
| # Show vm subparser |
| vm_show_parser = vm_subparsers.add_parser('show') |
| vm_show_parser.add_argument('id', type=str) |
| vm_show_parser.set_defaults(which='show') |
| vm_parser.set_defaults(func=vm_subcommand) |
| |
| cmdargs = parser.parse_args(args) |
| |
| # Open the peas engine |
| engine = Peas.Engine.get_default() |
| |
| # Load our plugin proxy into the g_irepository namespace |
| default = GIRepository.Repository.get_default() |
| GIRepository.Repository.require(default, "RwCal", "1.0", 0) |
| |
| # Enable python language loader |
| engine.enable_loader("python3"); |
| |
| # Set the search path for peas engine, |
| # rift-shell sets the PLUGINDIR and GI_TYPELIB_PATH |
| paths = set([]) |
| paths = paths.union(os.environ['PLUGINDIR'].split(":")) |
| for path in paths: |
| engine.add_search_path(path, path) |
| |
| # Load the rwcal python plugin and create the extension. |
| info = engine.get_plugin_info("rwcal-plugin") |
| if info is None: |
| print("Error loading rwcal-python plugin") |
| sys.exit(1) |
| engine.load_plugin(info) |
| rwcloud = engine.create_extension(info, RwCal.Cloud, None) |
| |
| # For now cloud credentials are hard coded |
| if cmdargs.provider_type == 'OPENSTACK': |
| provider_type = RwCal.CloudType.OPENSTACK_AUTH_URL |
| elif cmdargs.provider_type == 'EC2_US_EAST': |
| provider_type = RwCal.CloudType.EC2_US_EAST |
| elif cmdargs.provider_type == 'VSPHERE': |
| provider_type = RwCal.CloudType.VSPHERE |
| else: |
| sys.exit("Cloud provider %s is NOT supported yet" % cmdargs.provider_type) |
| |
| |
| if not 'RIFT_SHELL' in os.environ: |
| sys.stderr.write("This tool should be run from inside a rift-shell") |
| |
| status = rwcloud.init(provider_type, |
| cmdargs.user, |
| cmdargs.passwd, |
| cmdargs.auth_url, |
| cmdargs.tenant); |
| |
| assert status == RwTypes.RwStatus.SUCCESS |
| |
| cmdargs.func(rwcloud, cmdargs) |
| |
| if __name__ == "__main__": |
| main() |
| |