Example #1
0
class OktawaveCliContext(object):
    p = None
    api = None
    ocs = None
    config = None

    def init_output(self, output=sys.stdout):
        self.p = Printer(output)

    def init_api(self, api_username, api_password, debug=False):
        self.api = OktawaveApi(
            username=api_username, password=api_password,
            debug=debug)
        try:
            self.api.logon(only_common=False)
        except OktawaveLoginError:
            print "ERROR: Couldn't login to Oktawave."
            sys.exit(1)

    def init_ocs(self, ocs_username, ocs_password):
        self.ocs = OCSConnection(username=ocs_username, password=ocs_password)

    def print_table(self, head, results, mapper_func):
        items = map(mapper_func, results)
        if items:
            self.p.print_table([head] + items)
            return True
        return False
Example #2
0
 def __init__(self, args, debug=False, output=sys.stdout):
     self.p = Printer(output)
     self.api = OktawaveApi(username=args.username,
                            password=args.password,
                            debug=debug)
     self.ocs = OCSConnection(username=args.ocs_username,
                              password=args.ocs_password)
     self.args = args
     try:
         self.api._logon(only_common=False)
     except OktawaveLoginError:
         print "ERROR: Couldn't login to Oktawave."
         sys.exit(1)
Example #3
0
 def init_api(self, api_username, api_password, debug=False):
     self.api = OktawaveApi(
         username=api_username, password=api_password,
         debug=debug)
     try:
         self.api.logon(only_common=False)
     except OktawaveLoginError:
         print "ERROR: Couldn't login to Oktawave."
         sys.exit(1)
Example #4
0
 def __init__(self, args, debug=False, output=sys.stdout):
     self.p = Printer(output)
     self.api = OktawaveApi(
         username=args.username, password=args.password,
         debug=debug)
     self.ocs = OCSConnection(
         username=args.ocs_username, password=args.ocs_password)
     self.args = args
     try:
         self.api._logon(only_common=False)
     except OktawaveLoginError:
         print "ERROR: Couldn't login to Oktawave."
         sys.exit(1)
Example #5
0
class OktawaveCli(object):

    def __init__(self, args, debug=False, output=sys.stdout):
        self.p = Printer(output)
        self.api = OktawaveApi(
            username=args.username, password=args.password,
            debug=debug)
        self.ocs = OCSConnection(
            username=args.ocs_username, password=args.ocs_password)
        self.args = args
        try:
            self.api._logon(only_common=False)
        except OktawaveLoginError:
            print "ERROR: Couldn't login to Oktawave."
            sys.exit(1)

    def _print_table(self, head, results, mapper_func):
        items = map(mapper_func, results)
        if items:
            self.p.print_table([head] + items)
            return True
        return False

    def Account_Settings(self, args):
        res = self.api.Account_Settings()
        tab = [
            ['Key', 'Value'],
            ['Time zone', res['time_zone']],
            ['Currency', res['currency']],
            ['Date format', res['date_format']],
            ['Availability zone', res['availability_zone']],
            ['24h clock', 'Yes' if res['24h_clock'] else 'No']
        ]
        self.p._print("Account settings:")
        self.p.print_table(tab)

    def Account_RunningJobs(self, args):
        ops = self.api.Account_RunningJobs()
        def fmt(op):
            return [
                op['id'],
                op['creation_date'],
                op['creation_user_name'],
                op['type'],
                '%(object_type)s: %(object_name)s' % op,
                '%(progress_percent)d%%' % op,
                op['status']
            ]
        if not self._print_table(
            ['Operation ID', 'Started at', 'Started by', 'Operation type', 'Object', 'Progress', 'Status'],
            ops, fmt):
            print "No running operations"

    def Account_Users(self, args):
        """Print users in client account."""
        users = self.api.Account_Users()
        def fmt(user):
            return [
                self.api.client_id,
                user['email'],
                user['name']
            ]

        self._print_table(
            ['Client ID', 'E-mail', 'Name'],
            users, fmt)

    def OCI_Test(self, args):
        self.api.OCI_Test()

    def OCI_TemplateCategories(self, args):
        """Lists available template categories"""
        cats = self.api.OCI_TemplateCategories()
        def fmt(cat):
            tc_id = cat['id']
            if cat['parent_id'] is not None:
                tc_id = '  ' + str(tc_id)
            return [tc_id, cat['name'], cat['description']]

        self._print_table(
            ['Template category ID', 'Name', 'Description'],
            cats, fmt)

    def OCI_Templates(self, args, name_filter=''):
        """Lists templates in a category"""
        templates = self.api.OCI_Templates(args.id, name_filter)
        if templates:
            res = dict((k, [v]) for k, v in templates.items())
            self.p.print_hash_table(res, ['Template ID', 'Template name'])
        else:
            print "No templates in this category.\n"

    def OCI_TemplateInfo(self, args):
        """Shows more detailed info about a particular template"""
        ti = self.api.OCI_TemplateInfo(args.id)

        def _hdd_label(hdd):
            if hdd['is_primary']:
                return '%(name)s (%(capacity_gb)d GB, Primary)' % hdd
            else:
                return '%(name)s (%(capacity_gb)d GB)' % hdd

        tab = [['Key', 'Value']]
        tab.extend([
            ['Template ID', ti['template_id']],
            ['VM class', '%s (class ID: %s)' % (ti['vm_class_name'], ti['vm_class_id'])],
            ['Name', ti['label']],
            ['Template name', ti['template_name']],
            ['System category', ti['system_category_name']],
            ['Template category', ti['template_category']],
            ['Software', ti['software']],
            ['Ethernet controllers', ti['eth_count']],
            ['Connection', ti['connection_type']],
            ['Disk drives', ', '.join(_hdd_label(hdd) for hdd in ti['disks'])],
            ['Description', ti['description']],
        ])
        self.p.print_table(tab)

    def OCI_List(self, args):
        """Lists client's virtual machines"""
        vms = self.api.OCI_List()
        def fmt(vm):
            return [vm['id'], vm['name'], vm['status']]

        self._print_table(
            ['Virtual machine ID', 'Name', 'Status'], vms, fmt)

    def OCI_ListDetails(self, args):
        """Lists client's virtual machines"""
        vms = self.api.OCI_ListDetails()
        def fmt(vm):
            return [vm['id'], vm['name'], vm['status'], vm['class_name'],
                    '%d/%d MHz' % (vm['cpu_usage_mhz'], vm['cpu_mhz']),
                    '%d/%d MB' % (vm['memory_usage_mb'], vm['memory_mb'])]

        self._print_table(
            ['Virtual machine ID', 'Name', 'Status', 'Class', 'CPU', 'Memory'], vms, fmt)

    def OCI_Restart(self, args):
        """Restarts given VM"""
        self.api.OCI_Restart(args.id)

    def OCI_TurnOff(self, args):
        """Turns given VM off"""
        self.api.OCI_TurnOff(args.id)

    def OCI_TurnOn(self, args):
        """Turns given virtual machine on"""
        self.api.OCI_TurnOn(args.id)

    def OCI_Delete(self, args):
        """Deletes given virtual machine"""
        self.api.OCI_Delete(args.id)

    def OCI_Logs(self, args):
        """Shows virtual machine logs"""
        logs = self.api.OCI_Logs(args.id)
        def fmt(op):
            return [
                op['time'],
                op['type'],
                op['user_name'],
                op['status'],
                ' '.join(op['parameters'])
            ]

        self._print_table(
            ['Time', 'Operation type', 'User', 'Status', 'Parameters'],
            logs, fmt)

    def OCI_Settings(self, args):
        """Shows basic VM settings (IP addresses, OS, names, autoscaling etc.)"""
        settings = self.api.OCI_Settings(args.id)

        base_tab = [['Key', 'Value']]
        base_tab.extend([
            ['Autoscaling', settings['autoscaling']],
            ['Connection', settings['connection_type']],
            ['CPU (MHz)', settings['cpu_mhz']],
            ['CPU usage (MHz)', settings['cpu_usage_mhz']],
            ['Creation date', settings['creation_date']],
            ['Created by', settings['creation_user_name']],
            ['IOPS usage', settings['iops_usage']],
            ['Last changed', settings['last_change_date']],
            ['Payment type', settings['payment_type']],
            ['RAM (MB)', settings['memory_mb']],
            ['RAM usage (MB)', settings['memory_usage_mb']],
            ['Status', settings['status']],
            ['Name', settings['name']],
            ['Class', settings['vm_class_name']]
        ])
        self.p._print('Basic VM settings and statistics')
        self.p.print_table(base_tab)

        def fmt_disk(disk):
            return [
                disk['name'],
                disk['capacity_gb'],
                disk['creation_date'],
                disk['creation_user_name'],
                'Yes' if disk['is_primary'] else 'No'
            ]
        self.p._print("Hard disks")
        self._print_table(
            ['Name', 'Capacity (GB)', 'Created at', 'Created by', 'Primary'],
            settings['disks'], fmt_disk)

        def fmt_ip(ip):
            return [
                ip['ipv4'] + '/' + ip['netmask'],
                ip['ipv6'],
                ip['creation_date'],
                ip['dhcp_branch'],
                ip['gateway'],
                ip['status'],
                ip['last_change_date'],
                ip['macaddr']
            ]
        self.p._print("IP addresses")
        self._print_table([
            'IPv4 address',
            'IPv6 address',
            'Created at',
            'DHCP branch',
            'Gateway',
            'Status',
            'Last changed',
            'MAC address'
            ], settings['ips'], fmt_ip)

        if settings['vlans']:
            self.p._print("Private vlans")
            def fmt_vlan(vlan):
                return [
                    vlan['ipv4'],
                    vlan['creation_date'],
                    vlan['macaddr'],
                ]

            self._print_table(
                ['IPv4 address', 'Created at', 'MAC address'],
                settings['vlans'], fmt_vlan)

    def OCI_Create(self, args, forced_type='Machine', db_type=None):
        """Creates a new instance from template"""
        forced_type = getattr(TemplateType, forced_type)
        if not args.oci_class:
            args.oci_class = None
        try:
            self.api.OCI_Create(args.name, args.template, args.oci_class, forced_type, db_type)
        except OktawaveOCIClassNotFound:
            print "OCI class not found"

    def OCI_ChangeClass(self, args):
        """Changes running VM class"""
        self.api.OCI_ChangeClass(args.id, args.oci_class)

    def OCI_Clone(self, args):
        """Clones a VM"""
        clonetype = getattr(CloneType, args.clonetype)
        self.api.OCI_Clone(args.id, args.name, clonetype)

    def _ocs_split_params(self, args):
        container = args.container
        path = args.path
        if path is None:
            container, _slash, path = container.partition('/')
            if path == '':
                path = None
        return container, path

    def OCS_ListContainers(self, args):
        """Lists containers"""
        headers, containers = self.ocs.get_account()
        self.p.print_hash_table(
            dict((o['name'], [o['count'], o['bytes']]) for o in containers),
            ['Container name', 'Objects count', 'Size in bytes']
        )

    def OCS_Get(self, args):
        """Gets an object or file"""
        container, path = self._ocs_split_params(args)
        if path is None:
            self.p.print_swift_container(self.ocs.get_container(container))
        else:
            self.p.print_swift_file(
                self.ocs.get_object(container, path))

    def OCS_List(self, args):
        """Lists content of a directory or container"""
        container, path = self._ocs_split_params(args)
        obj = self.ocs.get_container(
            container)  # TODO: perhaps we can optimize it not to download the whole container when not necessary
        self.p.list_swift_objects(obj, path, cname=container)

    def OCS_CreateContainer(self, args):
        """Creates a new container"""
        container, path = self._ocs_split_params(args)
        self.ocs.put_container(name)
        print "OK"

    def OCS_CreateDirectory(self, args):
        """Creates a new directory within a container"""
        container, path = self._ocs_split_params(args)
        self.ocs.put_object(
            container, path, None, content_type='application/directory')
        print "OK"

    def OCS_Put(self, args):
        """Uploads a file to the server"""
        container, path = self._ocs_split_params(args)
        fh = open(local_path, 'r')
        self.ocs.put_object(container, path, fh)
        print "OK"

    def OCS_Delete(self, args):
        """Deletes an object from a container"""
        container, path = self._ocs_split_params(args)
        self.ocs.delete_object(container, path)
        print "OK"

    def OCS_DeleteContainer(self, args):
        """Deletes a whole container"""
        container, path = self._ocs_split_params(args)
        self.ocs.delete_container(container)
        print "OK"

    def OVS_List(self, args):
        """Lists disks"""
        disks = self.api.OVS_List()
        def fmt(disk):
            return [
                disk['id'],
                disk['name'],
                disk['tier'],
                '%d GB' % disk['capacity_gb'],
                '%d GB' % disk['used_gb'],
                'Yes' if disk['is_shared'] else 'No',
                ', '.join('%(id)d (%(name)s)' % vm for vm in disk['vms']) if disk['vms'] else 'None'
            ]

        self._print_table(
            ['ID', 'Name', 'Tier', 'Capacity', 'Used', 'Shared', 'VMs'],
            disks, fmt)

    def OVS_Delete(self, args):
        """Deletes a disk"""
        try:
            self.api.OVS_Delete(args.id)
        except OktawaveOVSDeleteError:
            print "ERROR: Disk cannot be deleted (is it mapped to any OCI instances?)."
        else:
            print "OK"

    def OVS_Create(self, args):
        """Adds a disk"""
        self.api.OVS_Create(args.name, args.capacity, args.tier, (args.disktype=='shared'))
        print "OK"

    def OVS_Map(self, args):
        """Maps a disk into an instance"""
        try:
            self.api.OVS_Map(args.disk_id, args.oci_id)
        except OktawaveOVSMappedError:
            print "ERROR: Disk is already mapped to this instance"
            return 1
        except OktawaveOVSMapError:
            print "ERROR: Disk cannot be mapped."
        else:
            print "OK"

    def OVS_Unmap(self, args):
        """Unmaps a disk from an instance"""
        try:
            self.api.OVS_Unmap(args.disk_id, args.oci_id)
        except OktawaveOVSUnmappedError:
            print "ERROR: Disk is not mapped to this instance"
            return 1
        except OktawaveOVSUnmapError:
            print "ERROR: Disk cannot be unmapped."
        else:
            print "OK"

    def OVS_ChangeTier(self, args):
        """Changes OVS tier"""
        self.api.OVS_ChangeTier(args.disk_id, args.tier)
        print "OK"

    def OVS_Extend(self, args):
        """Resizes OVS volume"""
        try:
            self.api.OVS_Extend(args.disk_id, args.size)
        except OktawaveOVSMappedError:
            print "ERROR: Disk is mapped to an instance"
            return 1
        except OktawaveOVSTooSmallError:
            print "ERROR: Requested size smaller than current size"
            return 1
        else:
            print "OK"

    def ORDB_List(self, args):
        """Lists databases"""
        dbs = self.api.ORDB_List()
        def fmt(db):
            return [
                db['id'],
                db['name'],
                db['type'],
                db['size'],
                db['available_space']
            ]
        self._print_table(
            ['Virtual machine ID', 'Name', 'Type', 'Size', 'Available space'],
            dbs, fmt)

    def ORDB_TurnOn(self, args):
        """Turns a database on"""
        self.api.ORDB_TurnOn(args.id)

    def ORDB_TurnOff(self, args):
        """Turns a database off"""
        self.api.ORDB_TurnOff(args.id)

    def ORDB_Restart(self, args):
        """Restarts a database"""
        self.api.ORDB_Restart(args.id)

    def ORDB_Clone(self, args):
        """Clones a database VM"""
        self.OCI_Clone(args)

    def ORDB_Delete(self, args):
        """Deletes a database or VM"""
        self.api.ORDB_Delete(args.id, args.db_name)

    def ORDB_Logs(self, args):
        """Shows database VM logs"""
        self.OCI_Logs()

    def ORDB_LogicalDatabases(self, args):
        """Shows logical databases"""
        dbs = self.api.ORDB_LogicalDatabases(args.id)
        def fmt(db):
            return [
                db['id'],
                db['name'],
                db['type'],
                db['encoding'],
                'Yes' if db['is_running'] else 'No',
                db['QPS'],
                db['Size']
            ]
        self._print_table(
            ['Virtual machine ID', 'Name', 'Type', 'Encoding', 'Running', 'QPS', 'Size'],
            dbs, fmt)

    def ORDB_Settings(self, args):
        """Shows database VM settings"""
        self.OCI_Settings(args)

    def ORDB_Create(self, args):
        """Creates a database VM"""
        try:
            self.api.ORDB_Create(args.name, args.template, args.oci_class)
        except OktawaveORDBInvalidTemplateError:
            print "ERROR: Selected template is not a database template"
            return 1

    def ORDB_GlobalSettings(self, args):
        """Shows global database engine settings"""
        settings = self.api.ORDB_GlobalSettings(args.id)
        def fmt(item):
            return [item['name'], item['value']]
        self._print_table(['Name', 'Value'], settings, fmt)

    def ORDB_Templates(self, args):
        """Lists database VM templates"""
        print "\nCategory: MySQL"
        args.id = OktawaveConstants['MYSQL_TEMPLATE_CATEGORY']
        self.OCI_Templates(args, 'ORDB')
        print "Category: PostgreSQL"
        args.id = OktawaveConstants['POSTGRESQL_TEMPLATE_CATEGORY']
        self.OCI_Templates(args, 'ORDB')

    def ORDB_TemplateInfo(self, args):
        """Shows information about a template"""
        self.OCI_TemplateInfo(args, category_id=OktawaveConstants['DB_VM_CATEGORY'])

    def ORDB_CreateLogicalDatabase(self, args):
        """Creates a new logical database within an instance"""
        self.api.ORDB_CreateLogicalDatabase(args.id, args.name, args.encoding)
        print "OK"

    def ORDB_BackupLogicalDatabase(self, args):
        """Creates a backup of logical database"""
        self.api.ORDB_BackupLogicalDatabase(args.id, args.name)
        print "OK"

    def ORDB_MoveLogicalDatabase(self, args):
        """Moves a logical database"""
        self.api.ORDB_MoveLogicalDatabase(args.id_from, args.id_to, args.name)
        print "OK"

    def ORDB_Backups(self, args):
        """Lists logical database backups"""
        backups = self.api.ORDB_Backups()
        def fmt(b):
            return [b['file_name'], b['type'], b['path']]

        self._print_table(
            ['File name', 'Database type', 'Full path'],
            backups, fmt)

    def ORDB_RestoreLogicalDatabase(self, args):
        """Restores a database from backup"""
        self.api.ORDB_RestoreLogicalDatabase(args.id, args.name, args.backup_file)
        print "OK"
Example #6
0
class OktawaveCli(object):
    def __init__(self, args, debug=False, output=sys.stdout):
        self.p = Printer(output)
        self.api = OktawaveApi(username=args.username,
                               password=args.password,
                               debug=debug)
        self.ocs = OCSConnection(username=args.ocs_username,
                                 password=args.ocs_password)
        self.args = args
        try:
            self.api._logon(only_common=False)
        except OktawaveLoginError:
            print "ERROR: Couldn't login to Oktawave."
            sys.exit(1)

    def _print_table(self, head, results, mapper_func):
        items = map(mapper_func, results)
        if items:
            self.p.print_table([head] + items)
            return True
        return False

    def _name_to_id(self, name_or_id):
        if isinstance(name_or_id, int):
            return name_or_id
        return name_or_id.as_int(self.api)

    def Account_Settings(self, args):
        res = self.api.Account_Settings()
        tab = [['Key', 'Value'], ['Time zone', res['time_zone']],
               ['Currency', res['currency']],
               ['Date format', res['date_format']],
               ['Availability zone', res['availability_zone']],
               ['24h clock', 'Yes' if res['24h_clock'] else 'No']]
        self.p._print("Account settings:")
        self.p.print_table(tab)

    def Account_RunningJobs(self, args):
        ops = self.api.Account_RunningJobs()

        def fmt(op):
            return [
                op['id'], op['creation_date'], op['creation_user_name'],
                op['type'],
                '%(object_type)s: %(object_name)s' % op,
                '%(progress_percent)d%%' % op, op['status']
            ]

        if not self._print_table([
                'Operation ID', 'Started at', 'Started by', 'Operation type',
                'Object', 'Progress', 'Status'
        ], ops, fmt):
            print "No running operations"

    def Account_Users(self, args):
        """Print users in client account."""
        users = self.api.Account_Users()

        def fmt(user):
            return [self.api.client_id, user['email'], user['name']]

        self._print_table(['Client ID', 'E-mail', 'Name'], users, fmt)

    def Template_Show(self, args):
        """Shows more detailed info about a particular template"""
        ti = self.api.Template_Show(args.id)

        def _hdd_label(hdd):
            if hdd['is_primary']:
                return '%(name)s (%(capacity_gb)d GB, Primary)' % hdd
            else:
                return '%(name)s (%(capacity_gb)d GB)' % hdd

        tab = [['Key', 'Value']]
        tab.extend([
            ['Template ID', ti['template_id']],
            [
                'VM class',
                '%s (class ID: %s)' % (ti['vm_class_name'], ti['vm_class_id'])
            ],
            ['Name', ti['label']],
            ['Template name', ti['template_name']],
            ['System category', ti['system_category_name']],
            ['Template category', ti['template_category']],
            ['Software', ', '.join(str(s) for s in ti['software'])],
            ['Ethernet controllers', ti['eth_count']],
            ['Connection', ti['connection_type']],
            ['Disk drives', ', '.join(_hdd_label(hdd) for hdd in ti['disks'])],
            ['Description', ti['description']],
        ])
        self.p.print_table(tab)

    def _print_templates(self, templates):
        if templates:
            tab = [['ID', 'Name', 'Category', 'System category']]
            tab.extend(
                [[t['id'], t['name'], t['category'], t['system_category']]
                 for t in templates])
            self.p.print_table(tab)
        else:
            print "No templates found.\n"

    def Template_List(self, args, name_filter=''):
        """Lists templates of a particular category"""
        templates = []
        if args.category:
            templates = self.api.Template_List(args.category, name_filter)
        else:
            templates = []
            for origin in TemplateOrigin.names:
                templates.extend(
                    self.api.Template_List(origin, name_filter) or [])
        self._print_templates(templates)

    def OCI_List(self, args):
        """Lists client's virtual machines"""
        vms = self.api.OCI_List()

        def fmt(vm):
            return [vm['id'], vm['name'], vm['status']]

        self._print_table(['Virtual machine ID', 'Name', 'Status'], vms, fmt)

    def OCI_ListDetails(self, args):
        """Lists client's virtual machines"""
        vms = self.api.OCI_ListDetails()

        def fmt(vm):
            return [
                vm['id'], vm['name'], vm['status'], vm['class_name'],
                '%d/%d MHz' % (vm['cpu_usage_mhz'], vm['cpu_mhz']),
                '%d/%d MB' % (vm['memory_usage_mb'], vm['memory_mb'])
            ]

        self._print_table(
            ['Virtual machine ID', 'Name', 'Status', 'Class', 'CPU', 'Memory'],
            vms, fmt)

    def OCI_Restart(self, args):
        """Restarts given VM"""
        oci_id = self._name_to_id(args.id)
        self.api.OCI_Restart(oci_id)

    def OCI_TurnOff(self, args):
        """Turns given VM off"""
        oci_id = self._name_to_id(args.id)
        self.api.OCI_TurnOff(oci_id)

    def OCI_TurnOn(self, args):
        """Turns given virtual machine on"""
        oci_id = self._name_to_id(args.id)
        self.api.OCI_TurnOn(oci_id)

    def OCI_Delete(self, args):
        """Deletes given virtual machine"""
        oci_id = self._name_to_id(args.id)
        self.api.OCI_Delete(oci_id)

    def OCI_Logs(self, args):
        """Shows virtual machine logs"""
        oci_id = self._name_to_id(args.id)
        logs = self.api.OCI_Logs(oci_id)

        def fmt(op):
            return [
                op['time'], op['type'], op['user_name'], op['status'],
                ' '.join(op['parameters'])
            ]

        self._print_table(
            ['Time', 'Operation type', 'User', 'Status', 'Parameters'], logs,
            fmt)

    def OCI_Settings(self, args):
        """Shows basic VM settings (IP addresses, OS, names, autoscaling etc.)"""
        oci_id = self._name_to_id(args.id)
        settings = self.api.OCI_Settings(oci_id)

        base_tab = [['Key', 'Value']]
        base_tab.extend([['Autoscaling', settings['autoscaling']],
                         ['Connection', settings['connection_type']],
                         ['CPU (MHz)', settings['cpu_mhz']],
                         ['CPU usage (MHz)', settings['cpu_usage_mhz']],
                         ['Creation date', settings['creation_date']],
                         ['Created by', settings['creation_user_name']],
                         ['IOPS usage', settings['iops_usage']],
                         ['Last changed', settings['last_change_date']],
                         ['Payment type', settings['payment_type']],
                         ['RAM (MB)', settings['memory_mb']],
                         ['RAM usage (MB)', settings['memory_usage_mb']],
                         ['Status', settings['status']],
                         ['Name', settings['name']],
                         ['Class', settings['vm_class_name']]])
        self.p._print('Basic VM settings and statistics')
        self.p.print_table(base_tab)

        def fmt_disk(disk):
            return [
                disk['id'], disk['name'], disk['capacity_gb'],
                disk['creation_date'], disk['creation_user_name'],
                'Yes' if disk['is_primary'] else 'No',
                'Yes' if disk['is_shared'] else 'No'
            ]

        self.p._print("Hard disks")
        self._print_table([
            'ID', 'Name', 'Capacity (GB)', 'Created at', 'Created by',
            'Primary', 'Shared'
        ], settings['disks'], fmt_disk)

        def fmt_ip(ip):
            return [
                ip['ipv4'] + '/' + ip['netmask'], ip['ipv6'],
                ip['creation_date'], ip['dhcp_branch'], ip['gateway'],
                ip['status'], ip['last_change_date'], ip['macaddr']
            ]

        self.p._print("IP addresses")
        self._print_table([
            'IPv4 address', 'IPv6 address', 'Created at', 'DHCP branch',
            'Gateway', 'Status', 'Last changed', 'MAC address'
        ], settings['ips'], fmt_ip)

        if settings['vlans']:
            self.p._print("Private vlans")

            def fmt_vlan(vlan):
                return [
                    vlan['ipv4'],
                    vlan['creation_date'],
                    vlan['macaddr'],
                ]

            self._print_table(['IPv4 address', 'Created at', 'MAC address'],
                              settings['vlans'], fmt_vlan)

    def OCI_Create(self, args, forced_type='Machine', db_type=None):
        """Creates a new instance from template"""
        forced_type = getattr(TemplateType, forced_type)
        if not args.oci_class:
            args.oci_class = None
        try:
            self.api.OCI_Create(args.name, args.template, args.oci_class,
                                forced_type, db_type, args.subregion)
        except OktawaveOCIClassNotFound:
            print "OCI class not found"

    def OCI_ChangeClass(self, args):
        """Changes running VM class"""
        oci_id = self._name_to_id(args.id)
        self.api.OCI_ChangeClass(oci_id, args.oci_class)

    def OCI_Clone(self, args):
        """Clones a VM"""
        oci_id = self._name_to_id(args.id)
        clonetype = getattr(CloneType, args.clonetype)
        self.api.OCI_Clone(oci_id, args.name, clonetype)

    def _oci_ip(self, oci_id):
        settings = self.api.OCI_Settings(oci_id)
        return settings['ips'][0]['ipv4']

    def OCI_ping(self, args):
        oci_id = self._name_to_id(args.id)
        ip = self._oci_ip(oci_id)
        os.execvp('ping', ('ping', ip) + tuple(args.exec_args))

    def OCI_ssh(self, args):
        oci_id = self._name_to_id(args.id)
        ip = self._oci_ip(oci_id)
        print 'Default OCI password: %s' % self.api.OCI_DefaultPassword(oci_id)
        remote = '%s@%s' % (args.user, ip)
        os.execvp('ssh', ('ssh', remote) + tuple(args.exec_args))

    def OCI_ssh_copy_id(self, args):
        oci_id = self._name_to_id(args.id)
        ip = self._oci_ip(oci_id)
        print 'Default OCI password: %s' % self.api.OCI_DefaultPassword(oci_id)
        remote = '%s@%s' % (args.user, ip)
        os.execvp('ssh-copy-id',
                  ('ssh-copy-id', remote) + tuple(args.exec_args))

    def _ocs_split_params(self, args):
        container = args.container
        path = args.path
        if path is None:
            container, _slash, path = container.partition('/')
            if path == '':
                path = None
        return container, path

    @classmethod
    def _swift_object_type(cls, data):
        if data['content_type'] == 'application/directory':
            return 'directory'
        if data['content_type'] == 'application/object':
            return 'object'
        return data['content_type']

    def _list_swift_objects(self, container, cname, path=None):
        if path is None:
            path = ''
        elif not path.endswith('/'):
            path += '/'
        container = container[1]

        if path:
            for d in container:
                if d['content_type'] == 'application/directory' and d[
                        'name'] + '/' == path:
                    print 'Directory content:'
                    break
            else:
                print "No such container/directory!"
                return
        else:
            print 'Container content:'

        def fmt_file(swift_obj):
            return [
                cname + '/' + swift_obj['name'],
                self._swift_object_type(swift_obj),
                swift_obj['bytes'],
                swift_obj['last_modified'],
            ]

        self._print_table(
            ['Full path', 'Type', 'Size in bytes', 'Last modified'],
            sorted([o for o in container if o['name'].startswith(path)],
                   key=lambda row: row['name']), fmt_file)

    def _print_swift_file(self, data):
        headers, content = data
        ctype = headers['content-type']

        if ctype == 'application/directory':
            print '<DIRECTORY>'
        elif ctype == 'application/object':
            attrs = dict((key[len('x-object-meta-'):], headers[key])
                         for key in headers
                         if key.startswith('x-object-meta-'))
            self.p.print_table(
                [['Key', 'Value']] +
                [[key, attrs[key]]
                 for key in sorted(attrs.keys(), key=lambda x: x.lower())])
        else:
            print content

    def OCS_ListContainers(self, args):
        """Lists containers"""
        headers, containers = self.ocs.get_account()
        self.p.print_hash_table(
            dict((o['name'], [o['count'], o['bytes']]) for o in containers),
            ['Container name', 'Objects count', 'Size in bytes'])

    def OCS_Get(self, args):
        """Gets an object or file"""
        container, path = self._ocs_split_params(args)
        if path is None:
            headers, contents = self.ocs.get_container(container)
            self.p.print_hash_table(
                {
                    '1 Container name': [container],
                    '2 Objects count': [headers['x-container-object-count']],
                    '3 Size in bytes': [headers['x-container-bytes-used']],
                },
                order=True)
        else:
            self._print_swift_file(self.ocs.get_object(container, path))

    def OCS_List(self, args):
        """Lists content of a directory or container"""
        container, path = self._ocs_split_params(args)
        obj = self.ocs.get_container(
            container
        )  # TODO: perhaps we can optimize it not to download the whole container when not necessary
        self._list_swift_objects(obj, container, path)

    def OCS_CreateContainer(self, args):
        """Creates a new container"""
        self.ocs.put_container(args.name)
        print "OK"

    def OCS_CreateDirectory(self, args):
        """Creates a new directory within a container"""
        container, path = self._ocs_split_params(args)
        self.ocs.put_object(container,
                            path,
                            None,
                            content_type='application/directory')
        print "OK"

    def OCS_Put(self, args):
        """Uploads a file to the server"""
        container, path = self._ocs_split_params(args)
        fh = open(args.local_path, 'r')
        self.ocs.put_object(container, path, fh)
        print "OK"

    def OCS_Delete(self, args):
        """Deletes an object from a container"""
        container, path = self._ocs_split_params(args)
        self.ocs.delete_object(container, path)
        print "OK"

    def OCS_DeleteContainer(self, args):
        """Deletes a whole container"""
        container, path = self._ocs_split_params(args)
        self.ocs.delete_container(container)
        print "OK"

    def OVS_List(self, args):
        """Lists disks"""
        disks = self.api.OVS_List()

        def fmt_mapping(mapping):
            ovs_id = mapping['id']
            name = mapping['name']
            if mapping['primary']:
                tags = 'primary',
            else:
                tags = ()
            if mapping['vm_status'].status == PowerStatus.PowerOn:
                tags += 'powered on',
            if tags:
                tag = ': ' + ', '.join(tags)
            else:
                tag = ''
            return u'{0} ({1}{2})'.format(ovs_id, name, tag)

        def fmt(disk):
            return [
                disk['id'], disk['name'], disk['tier'],
                '%d GB' % disk['capacity_gb'],
                '%d GB' % disk['used_gb'],
                'Yes' if disk['is_shared'] else 'No',
                '\n'.join(fmt_mapping(vm)
                          for vm in disk['vms']) if disk['vms'] else ''
            ]

        self._print_table(
            ['ID', 'Name', 'Tier', 'Capacity', 'Used', 'Shared', 'VMs'], disks,
            fmt)

    def OVS_Delete(self, args):
        """Deletes a disk"""
        ovs_id = self._name_to_id(args.id)
        try:
            self.api.OVS_Delete(ovs_id)
        except OktawaveOVSDeleteError:
            print "ERROR: Disk cannot be deleted (is it mapped to any OCI instances?)."
        else:
            print "OK"

    def OVS_Create(self, args):
        """Adds a disk"""
        self.api.OVS_Create(args.name, args.capacity, args.tier,
                            (args.disktype == 'shared'), args.subregion)
        print "OK"

    def OVS_Map(self, args):
        """Maps a disk into an instance"""
        ovs_id = self._name_to_id(args.id)
        oci_id = self._name_to_id(args.oci_id)
        try:
            self.api.OVS_Map(ovs_id, oci_id)
        except OktawaveOVSMappedError:
            print "ERROR: Disk is already mapped to this instance"
            return 1
        except OktawaveOVSMapError:
            print "ERROR: Disk cannot be mapped."
        else:
            print "OK"

    def OVS_Unmap(self, args):
        """Unmaps a disk from an instance"""
        ovs_id = self._name_to_id(args.id)
        oci_id = self._name_to_id(args.oci_id)
        try:
            self.api.OVS_Unmap(ovs_id, oci_id)
        except OktawaveOVSUnmappedError:
            print "ERROR: Disk is not mapped to this instance"
            return 1
        except OktawaveOVSUnmapError:
            print "ERROR: Disk cannot be unmapped."
        else:
            print "OK"

    def OVS_ChangeTier(self, args):
        """Changes OVS tier"""
        ovs_id = self._name_to_id(args.id)
        self.api.OVS_ChangeTier(ovs_id, args.tier)
        print "OK"

    def OVS_Extend(self, args):
        """Resizes OVS volume"""
        ovs_id = self._name_to_id(args.id)
        try:
            self.api.OVS_Extend(ovs_id, args.size)
        except OktawaveOVSMappedError:
            print "ERROR: Disk is mapped to an instance"
            return 1
        except OktawaveOVSTooSmallError:
            print "ERROR: Requested size smaller than current size"
            return 1
        else:
            print "OK"

    def ORDB_List(self, args):
        """Lists databases"""
        dbs = self.api.ORDB_List()

        def fmt(db):
            return [
                db['id'], db['name'], db['type'], db['size'],
                db['available_space']
            ]

        self._print_table(
            ['Virtual machine ID', 'Name', 'Type', 'Size', 'Available space'],
            dbs, fmt)

    def ORDB_TurnOn(self, args):
        """Turns a database on"""
        oci_id = self._name_to_id(args.id)
        self.api.ORDB_TurnOn(oci_id)

    def ORDB_TurnOff(self, args):
        """Turns a database off"""
        oci_id = self._name_to_id(args.id)
        self.api.ORDB_TurnOff(oci_id)

    def ORDB_Restart(self, args):
        """Restarts a database"""
        oci_id = self._name_to_id(args.id)
        self.api.ORDB_Restart(oci_id)

    def ORDB_Clone(self, args):
        """Clones a database VM"""
        self.OCI_Clone(args)

    def ORDB_Delete(self, args):
        """Deletes a database or VM"""
        oci_id = self._name_to_id(args.id)
        self.api.ORDB_Delete(oci_id, args.db_name)

    def ORDB_Logs(self, args):
        """Shows database VM logs"""
        self.OCI_Logs(args)

    def ORDB_LogicalDatabases(self, args):
        """Shows logical databases"""
        oci_id = self._name_to_id(args.id)
        dbs = self.api.ORDB_LogicalDatabases(oci_id)

        def fmt(db):
            return [
                db['id'], db['name'], db['type'], db['encoding'],
                'Yes' if db['is_running'] else 'No', db['QPS'], db['Size']
            ]

        self._print_table([
            'Virtual machine ID', 'Name', 'Type', 'Encoding', 'Running', 'QPS',
            'Size'
        ], dbs, fmt)

    def ORDB_Settings(self, args):
        """Shows database VM settings"""
        self.OCI_Settings(args)

    def ORDB_Create(self, args):
        """Creates a database VM"""
        try:
            self.api.ORDB_Create(args.name,
                                 args.template,
                                 oci_class=args.oci_class,
                                 subregion=args.subregion)
        except OktawaveORDBInvalidTemplateError:
            print "ERROR: Selected template is not a database template"
            return 1

    def ORDB_GlobalSettings(self, args):
        """Shows global database engine settings"""
        oci_id = self._name_to_id(args.id)
        settings = self.api.ORDB_GlobalSettings(oci_id)

        def fmt(item):
            return [item['name'], item['value']]

        self._print_table(['Name', 'Value'], settings, fmt)

    def ORDB_Templates(self, args):
        """Lists database VM templates"""
        print "\nCategory: MySQL"
        self._print_templates(
            self.api.templates_in_category(
                OktawaveConstants['MYSQL_TEMPLATE_CATEGORY']))
        print "Category: PostgreSQL"
        self._print_templates(
            self.api.templates_in_category(
                OktawaveConstants['POSTGRESQL_TEMPLATE_CATEGORY']))

    def ORDB_TemplateInfo(self, args):
        """Shows information about a template"""
        self.Template_Show(args)

    def ORDB_CreateLogicalDatabase(self, args):
        """Creates a new logical database within an instance"""
        oci_id = self._name_to_id(args.id)
        self.api.ORDB_CreateLogicalDatabase(oci_id, args.name, args.encoding)
        print "OK"

    def ORDB_BackupLogicalDatabase(self, args):
        """Creates a backup of logical database"""
        oci_id = self._name_to_id(args.id)
        self.api.ORDB_BackupLogicalDatabase(oci_id, args.name)
        print "OK"

    def ORDB_MoveLogicalDatabase(self, args):
        """Moves a logical database"""
        oci_id_from = self._name_to_id(args.id_from)
        oci_id_to = self._name_to_id(args.id_to)
        self.api.ORDB_MoveLogicalDatabase(oci_id_from, oci_id_to, args.name)
        print "OK"

    def ORDB_Backups(self, args):
        """Lists logical database backups"""
        backups = self.api.ORDB_Backups()

        def fmt(b):
            return [b['file_name'], b['type'], b['path']]

        self._print_table(['File name', 'Database type', 'Full path'], backups,
                          fmt)

    def ORDB_RestoreLogicalDatabase(self, args):
        """Restores a database from backup"""
        oci_id = self._name_to_id(args.id)
        self.api.ORDB_RestoreLogicalDatabase(oci_id, args.name,
                                             args.backup_file)
        print "OK"

    def Container_List(self, args):
        """Lists client's containers"""
        containers = self.api.Container_List()

        def fmt(c):
            return [c['id'], c['name'], c['vms']]

        self._print_table(['Container ID', 'Name', 'VMs'], containers, fmt)

    def Container_Get(self, args):
        """Displays a container's information"""
        container_id = self._name_to_id(args.id)
        c = self.api.Container_Get(container_id)

        base_tab = [['Key', 'Value']]
        base_tab.extend([
            ['ID', c['id']],
            ['Name', c['name']],
            ['Autoscaling', c['autoscaling']],
            ['Healthcheck', 'Yes' if c['healthcheck'] else 'No'],
            ['Load balancer', 'Yes' if c['load_balancer'] else 'No'],
            ['Schedulers', c['schedulers']],
            ['Virtual machines', c['vms']],
        ])
        if c['load_balancer']:
            base_tab.extend([
                ['IP version', c['ip_version']],
                ['Load balancer algorithm', c['load_balancer_algorithm']],
                ['Proxy cache', 'Yes' if c['proxy_cache'] else 'No'],
                ['SSL enabled', 'Yes' if c['ssl'] else 'No'],
                [
                    'Service', c['service'] + ' (' + str(c['port']) +
                    ')' if c['service'] == 'Port' else c['service']
                ],
                ['Session type', c['session_type']],
            ])
            ipv4 = '\n'.join(ip['ipv4'] for ip in c['ips'])
            ipv6 = '\n'.join(ip['ipv6'] for ip in c['ips'])
            base_tab.append(['IPv4 addresses', ipv4])
            base_tab.append(['IPv6 addresses', ipv6])
        if c['master_service_id'] is not None:
            base_tab.extend([[
                'Master OCI (MySQL)', c['master_service_name'] + ' (' +
                str(c['master_service_id']) + ')'
            ]])
        if c['db_user'] is not None:
            base_tab.extend([['Database user', c['db_user']]])
        if c['db_password'] is not None:
            base_tab.extend([['Database password', c['db_password']]])
        self.p._print('\nBasic container settings')
        self.p.print_table(base_tab)

        oci_list = self.api.Container_OCIList(container_id)

        def fmt_oci(oci):
            return [oci['oci_id'], oci['oci_name'], oci['status']]

        self.p._print('\nAttached OCIs')
        self._print_table(['ID', 'Name', 'Status'], oci_list, fmt_oci)

    def Container_RemoveOCI(self, args):
        """Removes an OCI from a container"""
        container_id = self._name_to_id(args.id)
        oci_id = self._name_to_id(args.oci_id)
        self.api.Container_RemoveOCI(container_id, oci_id)
        print "OK"

    def Container_AddOCI(self, args):
        """Adds an OCI to a container"""
        container_id = self._name_to_id(args.id)
        oci_id = self._name_to_id(args.oci_id)
        self.api.Container_AddOCI(container_id, oci_id)
        print "OK"

    def Container_Delete(self, args):
        """Deletes a container"""
        container_id = self._name_to_id(args.id)
        self.api.Container_Delete(container_id)
        print "OK"

    def Container_Create(self, args):
        """Creates a new container"""
        self.api._d(args)
        container_id = self.api.Container_Create(
            args.name, args.load_balancer, args.service, args.port,
            args.proxy_cache, args.use_ssl, args.healthcheck,
            args.mysql_master_id, args.session_persistence,
            args.load_balancer_algorithm, args.ip_version, args.autoscaling)
        print "OK, new container ID: " + str(container_id) + "."

    def Container_Edit(self, args):
        """Modifies a container."""
        self.api._d(args)
        container_id = self._name_to_id(args.id)
        self.api.Container_Edit(container_id, args.name, args.load_balancer,
                                args.service, args.port, args.proxy_cache,
                                args.use_ssl, args.healthcheck,
                                args.mysql_master_id, args.session_persistence,
                                args.load_balancer_algorithm, args.ip_version,
                                args.autoscaling)
        print "OK"

    def OPN_List(self, args):
        """Lists client's private networks"""
        vlans = self.api.OPN_List()

        def fmt(c):
            return [c['id'], c['name'], c['address_pool'], c['payment_type']]

        self._print_table(['OPN ID', 'Name', 'Address pool', 'Payment type'],
                          vlans, fmt)

    def OPN_Get(self, args):
        """Displays an OPN"""
        opn_id = self._name_to_id(args.id)
        c = self.api.OPN_Get(opn_id)

        base_tab = [['Key', 'Value']]
        base_tab.extend([['ID', c['id']], ['Name', c['name']],
                         ['Address pool', c['address_pool']],
                         ['Payment type', c['payment_type']]])
        self.p._print('\nBasic OPN settings')
        self.p.print_table(base_tab)
        vm_tab = [['OCI ID', 'Name', 'MAC address', 'Private IP address']]
        vm_tab.extend([[
            vm['VirtualMachine']['VirtualMachineId'],
            vm['VirtualMachine']['VirtualMachineName'], vm['MacAddress'],
            vm['PrivateIpAddress']
        ] for vm in c['vms']])
        self.p._print('Virtual machines')
        self.p.print_table(vm_tab)

    def OPN_Create(self, args):
        """Creates a new OPN"""
        self.api.OPN_Create(args.name, args.address_pool)
        print "OK"

    def OPN_AddOCI(self, args):
        """Adds an OCI to an OPN"""
        opn_id = self._name_to_id(args.id)
        oci_id = self._name_to_id(args.oci_id)
        self.api.OPN_AddOCI(opn_id, oci_id, args.ip_address)
        print "OK"

    def OPN_RemoveOCI(self, args):
        """Removes an OCI from an OPN"""
        opn_id = self._name_to_id(args.id)
        oci_id = self._name_to_id(args.oci_id)
        self.api.OPN_RemoveOCI(opn_id, oci_id)
        print "OK"

    def OPN_Delete(self, args):
        """Deletes a private network."""
        opn_id = self._name_to_id(args.id)
        self.api.OPN_Delete(opn_id)
        print "OK"

    def OPN_Rename(self, args):
        """Changes an OPN's name"""
        opn_id = self._name_to_id(args.id)
        self.api.OPN_Rename(opn_id, args.name)
        print "OK"
Example #7
0
class OktawaveCli(object):
    def __init__(self, args, debug=False, output=sys.stdout):
        self.p = Printer(output)
        self.api = OktawaveApi(
            username=args.username, password=args.password,
            debug=debug)
        self.ocs = OCSConnection(
            username=args.ocs_username, password=args.ocs_password)
        self.args = args
        try:
            self.api._logon(only_common=False)
        except OktawaveLoginError:
            print "ERROR: Couldn't login to Oktawave."
            sys.exit(1)

    def _print_table(self, head, results, mapper_func):
        items = map(mapper_func, results)
        if items:
            self.p.print_table([head] + items)
            return True
        return False

    def _name_to_id(self, name_or_id):
        if isinstance(name_or_id, int):
            return name_or_id
        return name_or_id.as_int(self.api)

    def Account_Settings(self, args):
        res = self.api.Account_Settings()
        tab = [
            ['Key', 'Value'],
            ['Time zone', res['time_zone']],
            ['Currency', res['currency']],
            ['Date format', res['date_format']],
            ['Availability zone', res['availability_zone']],
            ['24h clock', 'Yes' if res['24h_clock'] else 'No']
        ]
        self.p._print("Account settings:")
        self.p.print_table(tab)

    def Account_RunningJobs(self, args):
        ops = self.api.Account_RunningJobs()

        def fmt(op):
            return [
                op['id'],
                op['creation_date'],
                op['creation_user_name'],
                op['type'],
                '%(object_type)s: %(object_name)s' % op,
                '%(progress_percent)d%%' % op,
                op['status']
            ]

        if not self._print_table(
                ['Operation ID', 'Started at', 'Started by', 'Operation type', 'Object', 'Progress', 'Status'],
                ops, fmt):
            print "No running operations"

    def Account_Users(self, args):
        """Print users in client account."""
        users = self.api.Account_Users()

        def fmt(user):
            return [
                self.api.client_id,
                user['email'],
                user['name']
            ]

        self._print_table(
            ['Client ID', 'E-mail', 'Name'],
            users, fmt)

    def Template_Show(self, args):
        """Shows more detailed info about a particular template"""
        ti = self.api.Template_Show(args.id)

        def _hdd_label(hdd):
            if hdd['is_primary']:
                return '%(name)s (%(capacity_gb)d GB, Primary)' % hdd
            else:
                return '%(name)s (%(capacity_gb)d GB)' % hdd

        tab = [['Key', 'Value']]
        tab.extend([
            ['Template ID', ti['template_id']],
            ['VM class', '%s (class ID: %s)' % (ti['vm_class_name'], ti['vm_class_id'])],
            ['Name', ti['label']],
            ['Template name', ti['template_name']],
            ['System category', ti['system_category_name']],
            ['Template category', ti['template_category']],
            ['Software', ', '.join(str(s) for s in ti['software'])],
            ['Ethernet controllers', ti['eth_count']],
            ['Connection', ti['connection_type']],
            ['Disk drives', ', '.join(_hdd_label(hdd) for hdd in ti['disks'])],
            ['Description', ti['description']],
        ])
        self.p.print_table(tab)

    def _print_templates(self, templates):
        if templates:
            tab = [['ID', 'Name', 'Category', 'System category']]
            tab.extend([
                [t['id'], t['name'], t['category'], t['system_category']]
            for t in templates])
            self.p.print_table(tab)
        else:
            print "No templates found.\n"

    def Template_List(self, args, name_filter=''):
        """Lists templates of a particular category"""
        templates = []
        if args.category:
            templates = self.api.Template_List(args.category, name_filter)
        else:
            templates = []
            for origin in TemplateOrigin.names:
                templates.extend(self.api.Template_List(origin, name_filter) or [])
        self._print_templates(templates)

    def OCI_List(self, args):
        """Lists client's virtual machines"""
        vms = self.api.OCI_List()

        def fmt(vm):
            return [vm['id'], vm['name'], vm['status']]

        self._print_table(
            ['Virtual machine ID', 'Name', 'Status'], vms, fmt)

    def OCI_ListDetails(self, args):
        """Lists client's virtual machines"""
        vms = self.api.OCI_ListDetails()

        def fmt(vm):
            return [vm['id'], vm['name'], vm['status'], vm['class_name'],
                    '%d/%d MHz' % (vm['cpu_usage_mhz'], vm['cpu_mhz']),
                    '%d/%d MB' % (vm['memory_usage_mb'], vm['memory_mb'])]

        self._print_table(
            ['Virtual machine ID', 'Name', 'Status', 'Class', 'CPU', 'Memory'], vms, fmt)

    def OCI_Restart(self, args):
        """Restarts given VM"""
        oci_id = self._name_to_id(args.id)
        self.api.OCI_Restart(oci_id)

    def OCI_TurnOff(self, args):
        """Turns given VM off"""
        oci_id = self._name_to_id(args.id)
        self.api.OCI_TurnOff(oci_id)

    def OCI_TurnOn(self, args):
        """Turns given virtual machine on"""
        oci_id = self._name_to_id(args.id)
        self.api.OCI_TurnOn(oci_id)

    def OCI_Delete(self, args):
        """Deletes given virtual machine"""
        oci_id = self._name_to_id(args.id)
        self.api.OCI_Delete(oci_id)

    def OCI_Logs(self, args):
        """Shows virtual machine logs"""
        oci_id = self._name_to_id(args.id)
        logs = self.api.OCI_Logs(oci_id)

        def fmt(op):
            return [
                op['time'],
                op['type'],
                op['user_name'],
                op['status'],
                ' '.join(op['parameters'])
            ]

        self._print_table(
            ['Time', 'Operation type', 'User', 'Status', 'Parameters'],
            logs, fmt)

    def OCI_Settings(self, args):
        """Shows basic VM settings (IP addresses, OS, names, autoscaling etc.)"""
        oci_id = self._name_to_id(args.id)
        settings = self.api.OCI_Settings(oci_id)

        base_tab = [['Key', 'Value']]
        base_tab.extend([
            ['Autoscaling', settings['autoscaling']],
            ['Connection', settings['connection_type']],
            ['CPU (MHz)', settings['cpu_mhz']],
            ['CPU usage (MHz)', settings['cpu_usage_mhz']],
            ['Creation date', settings['creation_date']],
            ['Created by', settings['creation_user_name']],
            ['IOPS usage', settings['iops_usage']],
            ['Last changed', settings['last_change_date']],
            ['Payment type', settings['payment_type']],
            ['RAM (MB)', settings['memory_mb']],
            ['RAM usage (MB)', settings['memory_usage_mb']],
            ['Status', settings['status']],
            ['Name', settings['name']],
            ['Class', settings['vm_class_name']]
        ])
        self.p._print('Basic VM settings and statistics')
        self.p.print_table(base_tab)

        def fmt_disk(disk):
            return [
                disk['id'],
                disk['name'],
                disk['capacity_gb'],
                disk['creation_date'],
                disk['creation_user_name'],
                'Yes' if disk['is_primary'] else 'No',
                'Yes' if disk['is_shared'] else 'No'
            ]

        self.p._print("Hard disks")
        self._print_table(
            ['ID', 'Name', 'Capacity (GB)', 'Created at', 'Created by', 'Primary', 'Shared'],
            settings['disks'], fmt_disk)

        def fmt_ip(ip):
            return [
                ip['ipv4'] + '/' + ip['netmask'],
                ip['ipv6'],
                ip['creation_date'],
                ip['dhcp_branch'],
                ip['gateway'],
                ip['status'],
                ip['last_change_date'],
                ip['macaddr']
            ]

        self.p._print("IP addresses")
        self._print_table([
                              'IPv4 address',
                              'IPv6 address',
                              'Created at',
                              'DHCP branch',
                              'Gateway',
                              'Status',
                              'Last changed',
                              'MAC address'
                          ], settings['ips'], fmt_ip)

        if settings['vlans']:
            self.p._print("Private vlans")

            def fmt_vlan(vlan):
                return [
                    vlan['ipv4'],
                    vlan['creation_date'],
                    vlan['macaddr'],
                ]

            self._print_table(
                ['IPv4 address', 'Created at', 'MAC address'],
                settings['vlans'], fmt_vlan)

    def OCI_Create(self, args, forced_type='Machine', db_type=None):
        """Creates a new instance from template"""
        forced_type = getattr(TemplateType, forced_type)
        if not args.oci_class:
            args.oci_class = None
        try:
            self.api.OCI_Create(args.name, args.template, args.oci_class, forced_type, db_type, args.subregion)
        except OktawaveOCIClassNotFound:
            print "OCI class not found"

    def OCI_ChangeClass(self, args):
        """Changes running VM class"""
        oci_id = self._name_to_id(args.id)
        self.api.OCI_ChangeClass(oci_id, args.oci_class)

    def OCI_Clone(self, args):
        """Clones a VM"""
        oci_id = self._name_to_id(args.id)
        clonetype = getattr(CloneType, args.clonetype)
        self.api.OCI_Clone(oci_id, args.name, clonetype)

    def _oci_ip(self, oci_id):
        settings = self.api.OCI_Settings(oci_id)
        return settings['ips'][0]['ipv4']

    def OCI_ping(self, args):
        oci_id = self._name_to_id(args.id)
        ip = self._oci_ip(oci_id)
        os.execvp('ping', ('ping', ip) + tuple(args.exec_args))

    def OCI_ssh(self, args):
        oci_id = self._name_to_id(args.id)
        ip = self._oci_ip(oci_id)
        print 'Default OCI password: %s' % self.api.OCI_DefaultPassword(oci_id)
        remote = '%s@%s' % (args.user, ip)
        os.execvp('ssh', ('ssh', remote) + tuple(args.exec_args))

    def OCI_ssh_copy_id(self, args):
        oci_id = self._name_to_id(args.id)
        ip = self._oci_ip(oci_id)
        print 'Default OCI password: %s' % self.api.OCI_DefaultPassword(oci_id)
        remote = '%s@%s' % (args.user, ip)
        os.execvp('ssh-copy-id', ('ssh-copy-id', remote) + tuple(args.exec_args))

    def _ocs_split_params(self, args):
        container = args.container
        path = args.path
        if path is None:
            container, _slash, path = container.partition('/')
            if path == '':
                path = None
        return container, path

    @classmethod
    def _swift_object_type(cls, data):
        if data['content_type'] == 'application/directory':
            return 'directory'
        if data['content_type'] == 'application/object':
            return 'object'
        return data['content_type']

    def _list_swift_objects(self, container, cname, path=None):
        if path is None:
            path = ''
        elif not path.endswith('/'):
            path += '/'
        container = container[1]

        if path:
            for d in container:
                if d['content_type'] == 'application/directory' and d['name'] + '/' == path:
                    print 'Directory content:'
                    break
            else:
                print "No such container/directory!"
                return
        else:
            print 'Container content:'

        def fmt_file(swift_obj):
            return [
                cname + '/' + swift_obj['name'],
                self._swift_object_type(swift_obj),
                swift_obj['bytes'],
                swift_obj['last_modified'],
            ]

        self._print_table(
            ['Full path', 'Type', 'Size in bytes', 'Last modified'],
            sorted([o for o in container if o['name'].startswith(path)], key=lambda row: row['name']),
            fmt_file)

    def _print_swift_file(self, data):
        headers, content = data
        ctype = headers['content-type']

        if ctype == 'application/directory':
            print '<DIRECTORY>'
        elif ctype == 'application/object':
            attrs = dict((key[len('x-object-meta-'):], headers[key])
                         for key in headers if key.startswith('x-object-meta-'))
            self.p.print_table([['Key', 'Value']] + [[
                key,
                attrs[key]
            ] for key in sorted(attrs.keys(), key=lambda x: x.lower())])
        else:
            print content

    def OCS_ListContainers(self, args):
        """Lists containers"""
        headers, containers = self.ocs.get_account()
        self.p.print_hash_table(
            dict((o['name'], [o['count'], o['bytes']]) for o in containers),
            ['Container name', 'Objects count', 'Size in bytes']
        )

    def OCS_Get(self, args):
        """Gets an object or file"""
        container, path = self._ocs_split_params(args)
        if path is None:
            headers, contents = self.ocs.get_container(container)
            self.p.print_hash_table(
                {
                    '1 Container name': [container],
                    '2 Objects count': [headers['x-container-object-count']],
                    '3 Size in bytes': [headers['x-container-bytes-used']],
                },
                order=True)
        else:
            self._print_swift_file(
                self.ocs.get_object(container, path))

    def OCS_List(self, args):
        """Lists content of a directory or container"""
        container, path = self._ocs_split_params(args)
        obj = self.ocs.get_container(
            container)  # TODO: perhaps we can optimize it not to download the whole container when not necessary
        self._list_swift_objects(obj, container, path)

    def OCS_CreateContainer(self, args):
        """Creates a new container"""
        self.ocs.put_container(args.name)
        print "OK"

    def OCS_CreateDirectory(self, args):
        """Creates a new directory within a container"""
        container, path = self._ocs_split_params(args)
        self.ocs.put_object(
            container, path, None, content_type='application/directory')
        print "OK"

    def OCS_Put(self, args):
        """Uploads a file to the server"""
        container, path = self._ocs_split_params(args)
        fh = open(args.local_path, 'r')
        self.ocs.put_object(container, path, fh)
        print "OK"

    def OCS_Delete(self, args):
        """Deletes an object from a container"""
        container, path = self._ocs_split_params(args)
        self.ocs.delete_object(container, path)
        print "OK"

    def OCS_DeleteContainer(self, args):
        """Deletes a whole container"""
        container, path = self._ocs_split_params(args)
        self.ocs.delete_container(container)
        print "OK"

    def OVS_List(self, args):
        """Lists disks"""
        disks = self.api.OVS_List()

        def fmt_mapping(mapping):
            ovs_id = mapping['id']
            name = mapping['name']
            if mapping['primary']:
                tags = 'primary',
            else:
                tags = ()
            if mapping['vm_status'].status == PowerStatus.PowerOn:
                tags += 'powered on',
            if tags:
                tag = ': ' + ', '.join(tags)
            else:
                tag = ''
            return u'{0} ({1}{2})'.format(ovs_id, name, tag)

        def fmt(disk):
            return [
                disk['id'],
                disk['name'],
                disk['tier'],
                '%d GB' % disk['capacity_gb'],
                '%d GB' % disk['used_gb'],
                'Yes' if disk['is_shared'] else 'No',
                '\n'.join(fmt_mapping(vm) for vm in disk['vms']) if disk['vms'] else ''
            ]

        self._print_table(
            ['ID', 'Name', 'Tier', 'Capacity', 'Used', 'Shared', 'VMs'],
            disks, fmt)

    def OVS_Delete(self, args):
        """Deletes a disk"""
        ovs_id = self._name_to_id(args.id)
        try:
            self.api.OVS_Delete(ovs_id)
        except OktawaveOVSDeleteError:
            print "ERROR: Disk cannot be deleted (is it mapped to any OCI instances?)."
        else:
            print "OK"

    def OVS_Create(self, args):
        """Adds a disk"""
        self.api.OVS_Create(args.name, args.capacity, args.tier, (args.disktype == 'shared'), args.subregion)
        print "OK"

    def OVS_Map(self, args):
        """Maps a disk into an instance"""
        ovs_id = self._name_to_id(args.id)
        oci_id = self._name_to_id(args.oci_id)
        try:
            self.api.OVS_Map(ovs_id, oci_id)
        except OktawaveOVSMappedError:
            print "ERROR: Disk is already mapped to this instance"
            return 1
        except OktawaveOVSMapError:
            print "ERROR: Disk cannot be mapped."
        else:
            print "OK"

    def OVS_Unmap(self, args):
        """Unmaps a disk from an instance"""
        ovs_id = self._name_to_id(args.id)
        oci_id = self._name_to_id(args.oci_id)
        try:
            self.api.OVS_Unmap(ovs_id, oci_id)
        except OktawaveOVSUnmappedError:
            print "ERROR: Disk is not mapped to this instance"
            return 1
        except OktawaveOVSUnmapError:
            print "ERROR: Disk cannot be unmapped."
        else:
            print "OK"

    def OVS_ChangeTier(self, args):
        """Changes OVS tier"""
        ovs_id = self._name_to_id(args.id)
        self.api.OVS_ChangeTier(ovs_id, args.tier)
        print "OK"

    def OVS_Extend(self, args):
        """Resizes OVS volume"""
        ovs_id = self._name_to_id(args.id)
        try:
            self.api.OVS_Extend(ovs_id, args.size)
        except OktawaveOVSMappedError:
            print "ERROR: Disk is mapped to an instance"
            return 1
        except OktawaveOVSTooSmallError:
            print "ERROR: Requested size smaller than current size"
            return 1
        else:
            print "OK"

    def ORDB_List(self, args):
        """Lists databases"""
        dbs = self.api.ORDB_List()

        def fmt(db):
            return [
                db['id'],
                db['name'],
                db['type'],
                db['size'],
                db['available_space']
            ]

        self._print_table(
            ['Virtual machine ID', 'Name', 'Type', 'Size', 'Available space'],
            dbs, fmt)

    def ORDB_TurnOn(self, args):
        """Turns a database on"""
        oci_id = self._name_to_id(args.id)
        self.api.ORDB_TurnOn(oci_id)

    def ORDB_TurnOff(self, args):
        """Turns a database off"""
        oci_id = self._name_to_id(args.id)
        self.api.ORDB_TurnOff(oci_id)

    def ORDB_Restart(self, args):
        """Restarts a database"""
        oci_id = self._name_to_id(args.id)
        self.api.ORDB_Restart(oci_id)

    def ORDB_Clone(self, args):
        """Clones a database VM"""
        self.OCI_Clone(args)

    def ORDB_Delete(self, args):
        """Deletes a database or VM"""
        oci_id = self._name_to_id(args.id)
        self.api.ORDB_Delete(oci_id, args.db_name)

    def ORDB_Logs(self, args):
        """Shows database VM logs"""
        self.OCI_Logs(args)

    def ORDB_LogicalDatabases(self, args):
        """Shows logical databases"""
        oci_id = self._name_to_id(args.id)
        dbs = self.api.ORDB_LogicalDatabases(oci_id)

        def fmt(db):
            return [
                db['id'],
                db['name'],
                db['type'],
                db['encoding'],
                'Yes' if db['is_running'] else 'No',
                db['QPS'],
                db['Size']
            ]

        self._print_table(
            ['Virtual machine ID', 'Name', 'Type', 'Encoding', 'Running', 'QPS', 'Size'],
            dbs, fmt)

    def ORDB_Settings(self, args):
        """Shows database VM settings"""
        self.OCI_Settings(args)

    def ORDB_Create(self, args):
        """Creates a database VM"""
        try:
            self.api.ORDB_Create(args.name, args.template, oci_class=args.oci_class, subregion=args.subregion)
        except OktawaveORDBInvalidTemplateError:
            print "ERROR: Selected template is not a database template"
            return 1

    def ORDB_GlobalSettings(self, args):
        """Shows global database engine settings"""
        oci_id = self._name_to_id(args.id)
        settings = self.api.ORDB_GlobalSettings(oci_id)

        def fmt(item):
            return [item['name'], item['value']]

        self._print_table(['Name', 'Value'], settings, fmt)

    def ORDB_Templates(self, args):
        """Lists database VM templates"""
        print "\nCategory: MySQL"
        self._print_templates(self.api.templates_in_category(OktawaveConstants['MYSQL_TEMPLATE_CATEGORY']))
        print "Category: PostgreSQL"
        self._print_templates(self.api.templates_in_category(OktawaveConstants['POSTGRESQL_TEMPLATE_CATEGORY']))

    def ORDB_TemplateInfo(self, args):
        """Shows information about a template"""
        self.Template_Show(args)

    def ORDB_CreateLogicalDatabase(self, args):
        """Creates a new logical database within an instance"""
        oci_id = self._name_to_id(args.id)
        self.api.ORDB_CreateLogicalDatabase(oci_id, args.name, args.encoding)
        print "OK"

    def ORDB_BackupLogicalDatabase(self, args):
        """Creates a backup of logical database"""
        oci_id = self._name_to_id(args.id)
        self.api.ORDB_BackupLogicalDatabase(oci_id, args.name)
        print "OK"

    def ORDB_MoveLogicalDatabase(self, args):
        """Moves a logical database"""
        oci_id_from = self._name_to_id(args.id_from)
        oci_id_to = self._name_to_id(args.id_to)
        self.api.ORDB_MoveLogicalDatabase(oci_id_from, oci_id_to, args.name)
        print "OK"

    def ORDB_Backups(self, args):
        """Lists logical database backups"""
        backups = self.api.ORDB_Backups()

        def fmt(b):
            return [b['file_name'], b['type'], b['path']]

        self._print_table(
            ['File name', 'Database type', 'Full path'],
            backups, fmt)

    def ORDB_RestoreLogicalDatabase(self, args):
        """Restores a database from backup"""
        oci_id = self._name_to_id(args.id)
        self.api.ORDB_RestoreLogicalDatabase(oci_id, args.name, args.backup_file)
        print "OK"

    def Container_List(self, args):
        """Lists client's containers"""
        containers = self.api.Container_List()

        def fmt(c):
            return [c['id'], c['name'], c['vms']]

        self._print_table(
            ['Container ID', 'Name', 'VMs'], containers, fmt)

    def Container_Get(self, args):
        """Displays a container's information"""
        container_id = self._name_to_id(args.id)
        c = self.api.Container_Get(container_id)

        base_tab = [['Key', 'Value']]
        base_tab.extend([
            ['ID', c['id']],
            ['Name', c['name']],
            ['Autoscaling', c['autoscaling']],
            ['Healthcheck', 'Yes' if c['healthcheck'] else 'No'],
            ['Load balancer', 'Yes' if c['load_balancer'] else 'No'],
            ['Schedulers', c['schedulers']],
            ['Virtual machines', c['vms']],
        ])
        if c['load_balancer']:
            base_tab.extend([
                ['IP version', c['ip_version']],
                ['Load balancer algorithm', c['load_balancer_algorithm']],
                ['Proxy cache', 'Yes' if c['proxy_cache'] else 'No'],
                ['SSL enabled', 'Yes' if c['ssl'] else 'No'],
                ['Service', c['service'] + ' (' + str(c['port']) + ')' if c['service'] == 'Port' else c['service']],
                ['Session type', c['session_type']],
            ])
            ipv4 = '\n'.join(ip['ipv4'] for ip in c['ips'])
            ipv6 = '\n'.join(ip['ipv6'] for ip in c['ips'])
            base_tab.append(['IPv4 addresses', ipv4])
            base_tab.append(['IPv6 addresses', ipv6])
        if c['master_service_id'] is not None:
            base_tab.extend(
                [['Master OCI (MySQL)', c['master_service_name'] + ' (' + str(c['master_service_id']) + ')']])
        if c['db_user'] is not None:
            base_tab.extend([['Database user', c['db_user']]])
        if c['db_password'] is not None:
            base_tab.extend([['Database password', c['db_password']]])
        self.p._print('\nBasic container settings')
        self.p.print_table(base_tab)

        oci_list = self.api.Container_OCIList(container_id)

        def fmt_oci(oci):
            return [oci['oci_id'], oci['oci_name'], oci['status']]

        self.p._print('\nAttached OCIs')
        self._print_table(
            ['ID', 'Name', 'Status'], oci_list, fmt_oci)

    def Container_RemoveOCI(self, args):
        """Removes an OCI from a container"""
        container_id = self._name_to_id(args.id)
        oci_id = self._name_to_id(args.oci_id)
        self.api.Container_RemoveOCI(container_id, oci_id)
        print "OK"

    def Container_AddOCI(self, args):
        """Adds an OCI to a container"""
        container_id = self._name_to_id(args.id)
        oci_id = self._name_to_id(args.oci_id)
        self.api.Container_AddOCI(container_id, oci_id)
        print "OK"

    def Container_Delete(self, args):
        """Deletes a container"""
        container_id = self._name_to_id(args.id)
        self.api.Container_Delete(container_id)
        print "OK"

    def Container_Create(self, args):
        """Creates a new container"""
        self.api._d(args)
        container_id = self.api.Container_Create(
            args.name, args.load_balancer, args.service, args.port, args.proxy_cache,
            args.use_ssl, args.healthcheck, args.mysql_master_id, args.session_persistence,
            args.load_balancer_algorithm, args.ip_version, args.autoscaling
        )
        print "OK, new container ID: " + str(container_id) + "."

    def Container_Edit(self, args):
        """Modifies a container."""
        self.api._d(args)
        container_id = self._name_to_id(args.id)
        self.api.Container_Edit(
            container_id, args.name, args.load_balancer, args.service, args.port, args.proxy_cache,
            args.use_ssl, args.healthcheck, args.mysql_master_id, args.session_persistence,
            args.load_balancer_algorithm, args.ip_version, args.autoscaling
        )
        print "OK"

    def OPN_List(self, args):
        """Lists client's private networks"""
        vlans = self.api.OPN_List()

        def fmt(c):
            return [c['id'], c['name'], c['address_pool'], c['payment_type']]

        self._print_table(
            ['OPN ID', 'Name', 'Address pool', 'Payment type'], vlans, fmt)

    def OPN_Get(self, args):
        """Displays an OPN"""
        opn_id = self._name_to_id(args.id)
        c = self.api.OPN_Get(opn_id)

        base_tab = [['Key', 'Value']]
        base_tab.extend([
            ['ID', c['id']],
            ['Name', c['name']],
            ['Address pool', c['address_pool']],
            ['Payment type', c['payment_type']]
        ])
        self.p._print('\nBasic OPN settings')
        self.p.print_table(base_tab)
        vm_tab = [['OCI ID', 'Name', 'MAC address', 'Private IP address']]
        vm_tab.extend([[
            vm['VirtualMachine']['VirtualMachineId'],
            vm['VirtualMachine']['VirtualMachineName'],
            vm['MacAddress'],
            vm['PrivateIpAddress']
        ] for vm in c['vms']])
        self.p._print('Virtual machines')
        self.p.print_table(vm_tab)

    def OPN_Create(self, args):
        """Creates a new OPN"""
        self.api.OPN_Create(args.name, args.address_pool)
        print "OK"

    def OPN_AddOCI(self, args):
        """Adds an OCI to an OPN"""
        opn_id = self._name_to_id(args.id)
        oci_id = self._name_to_id(args.oci_id)
        self.api.OPN_AddOCI(opn_id, oci_id, args.ip_address)
        print "OK"

    def OPN_RemoveOCI(self, args):
        """Removes an OCI from an OPN"""
        opn_id = self._name_to_id(args.id)
        oci_id = self._name_to_id(args.oci_id)
        self.api.OPN_RemoveOCI(opn_id, oci_id)
        print "OK"

    def OPN_Delete(self, args):
        """Deletes a private network."""
        opn_id = self._name_to_id(args.id)
        self.api.OPN_Delete(opn_id)
        print "OK"

    def OPN_Rename(self, args):
        """Changes an OPN's name"""
        opn_id = self._name_to_id(args.id)
        self.api.OPN_Rename(opn_id, args.name)
        print "OK"