RIFT OSM R1 Initial Submission
[osm/SO.git] / rwcal / src / rwvim.py
diff --git a/rwcal/src/rwvim.py b/rwcal/src/rwvim.py
new file mode 100755 (executable)
index 0000000..18cf087
--- /dev/null
@@ -0,0 +1,420 @@
+#!/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()
+