Example #1
0
 def _init_clients(self):
     """Convenience method to initialize ClientsService client"""
     if hasattr(self, 'clients'):
         return
     self.clients = ApiClient(jsonapi_clients, self.username, self.password,
                              self.debug)
     self._d(self.clients)
    def get_certificates(master, client=None):
        """Returns all the agent certificates for a Master

        :param master: The master in question
        :param client: The ApiClient to use
        :type master: ppaas.Master
        :type client: ppaas.ApiClient

        :Example:

        >>> ppaas.Master.get_masters()
        [<Puppet Master 0e85b81f-5a29-4e2b-a46c-e024049acb07>]
        >>> master = _[0]
        >>> ppaas.Certificate.get_certificates(master)
        [<Agent Certificate machine.maurice.fr@0e85b81f-5a29-4e2b-a46c-e024049acb07>]

        .. note:: You will probably never use this method neither and use the one
                  shipped with the Master class I guess.
        """
        if not client:
            client = ApiClient()
        result, status = client.get('/masters/%s/certs' % master.uuid)
        certificates = []
        for certificate in result['certs']:
            certificates.append(Certificate(master, certificate['hostname']))
        return certificates
    def __init__(self, name, cached_data):
        """Creates a new object representing an *existing* deploy key

        :param name: The name of the deploy key you want to load
        :type name: str
        :param cached_data: Cached data to instantiate the master
        :type cached_data: dict

        :Example:

        >>> ppaas.DeployKey('thomas')
        <Deploy Key thomas>
        >>> ppaas.DeployKey('thomas').fingerprint
        u'52:35:1c:6c:12:57:5f:64:48:3b:ef:89:4c:c5:08:f9'
        >>> ppaas.DeployKey('Idontexist').fingerprint
        Traceback (most recent call last):
          File "<stdin>", line 1, in <module>
          File "ppaas/deploy_key.py", line 36, in __init__
            self.cached_data, _ = self.client.get('/deploy-keys/%s' % (self.name))
          File "ppaas/client.py", line 72, in get
            return self.call('GET', self.endpoint + url, params=params)
          File "ppaas/client.py", line 112, in call
            raise ResourceNotFoundError(result)
        ppaas.client.ResourceNotFoundError: {u'message': u'The requested resource could not be found.'}

        .. seealso:: get_deploy_keys(), create_deploy_key()
        """
        self.client = ApiClient()
        self.name = name
        self.reload_data(cached_data)
Example #4
0
    def __init__(self, master, hostname, cached_data=None):
        """Creates a new object representing an *existing* agent certificate

        :param master: The Master the wanted certificate is attached to
        :type master: ppaas.Master
        :param hostname: The hostname of the agent
        :type hostname: str
        :param cached_data: Cached data to instantiate the master
        :type cached_data: dict

        :Example:
        >>> ppaas.Master.get_masters()
        [<Puppet Master 0e85b81f-5a29-4e2b-a46c-e024049acb07>]
        >>> master = _[0]
        >>> ppaas.Certificate(master, 'machine.maurice.fr')
        <Agent Certificate machine.maurice.fr@0e85b81f-5a29-4e2b-a46c-e024049acb07>

        .. note:: You will probably never call this directly and instead use the
                  ppaas.Master.certificate() method instead
        .. seealso:: get_certificates(), ppaas.Master.certificate()
        """
        self.client = ApiClient()
        self.hostname = hostname
        self.master = master
        self.reload_data(cached_data)
Example #5
0
 def _init_common(self):
     """Convenience method to initialize CommonService client"""
     if hasattr(self, 'common'):
         return
     self.common = ApiClient(jsonapi_common, self.username, self.password,
                             self.debug)
     self._d(self.common)
Example #6
0
    def get_certificates(master, client=None):
        """Returns all the agent certificates for a Master

        :param master: The master in question
        :param client: The ApiClient to use
        :type master: ppaas.Master
        :type client: ppaas.ApiClient

        :Example:

        >>> ppaas.Master.get_masters()
        [<Puppet Master 0e85b81f-5a29-4e2b-a46c-e024049acb07>]
        >>> master = _[0]
        >>> ppaas.Certificate.get_certificates(master)
        [<Agent Certificate machine.maurice.fr@0e85b81f-5a29-4e2b-a46c-e024049acb07>]

        .. note:: You will probably never use this method neither and use the one
                  shipped with the Master class I guess.
        """
        if not client:
            client = ApiClient()
        result, status = client.get('/masters/%s/certs' % master.uuid)
        certificates = []
        for certificate in result['certs']:
            certificates.append(Certificate(master, certificate['hostname']))
        return certificates
Example #7
0
    def create_master(name,
                      source,
                      deploy_key,
                      vars={},
                      nb=1,
                      type=None,
                      hierarchy=[],
                      hieras=[],
                      client=None):
        """ Creates a Pupper master

        :param name: Name of the puppet master
        :type name: str
        :param source: Source git repository of the puppet master
        :type source: str
        :param deploy_key: Deploy key to link with your puppet master
        :type deploy_key: ppaas.DeployKey
        :param nb: Number of servers for the master
        :type nb: int
        :param type: Kind of server to use
        :type type: str
        :param hierarchy: Array of hierarchies
        :type hierarchy: list
        :param hieras: Array of hiera backend
        :type hieras: list
        :param client: A client object you want to pass, if empty a new one will be created
        :type client: ppaas.ApiClient

        :return: The newly created puppet master
        :rtype: Master

        :Example:
        >>> ppaas.Master.create_master("master1", "[email protected]:puppet/puppet.git", "github")
        <Puppet Master 0e85b81f-5a29-4e2b-a46c-e024049acb07>
        >>> master.name
        'master1'

        """
        payload = {
            "name": name,
            "source": source,
            "deploy_key": deploy_key,
            "nb": nb,
            "hierarchy": hierarchy,
            "hieras": hieras,
            "vars": vars
        }
        if type:
            payload["type"] = type

        if not client:
            client = ApiClient()

        result, _ = client.post("/masters", data=payload)
        return Master(result["id"], result)
Example #8
0
def run():
    try:
        client = ApiClient('YOUR_CLIENT_ID', 'YOUR_CLIENT_SECRET')
        result = client.get(
            'v2/astrology/kundli/advanced', {
                'ayanamsa': 1,
                'coordinates': '23.1765,75.7885',
                'datetime': '2020-10-19T12:31:14+00:00',
            })
        print json.dumps(result, indent=4)
    except ValidationError as e:
        for msg in e.getValidationMessages():
            print(msg['detail'])
    except AuthenticationError as e:
        print(e.message)
Example #9
0
 def _init_clients(self):
     """Convenience method to initialize ClientsService client"""
     if hasattr(self, 'clients'):
         return
     self.clients = ApiClient(
         jsonapi_clients, self.username, self.password, self.debug)
     self._d(self.clients)
Example #10
0
 def _init_common(self):
     """Convenience method to initialize CommonService client"""
     if hasattr(self, 'common'):
         return
     self.common = ApiClient(
         jsonapi_common, self.username, self.password, self.debug)
     self._d(self.common)
    def __init__(self, master, hostname, cached_data=None):
        """Creates a new object representing an *existing* agent certificate

        :param master: The Master the wanted certificate is attached to
        :type master: ppaas.Master
        :param hostname: The hostname of the agent
        :type hostname: str
        :param cached_data: Cached data to instantiate the master
        :type cached_data: dict

        :Example:
        >>> ppaas.Master.get_masters()
        [<Puppet Master 0e85b81f-5a29-4e2b-a46c-e024049acb07>]
        >>> master = _[0]
        >>> ppaas.Certificate(master, 'machine.maurice.fr')
        <Agent Certificate machine.maurice.fr@0e85b81f-5a29-4e2b-a46c-e024049acb07>

        .. note:: You will probably never call this directly and instead use the
                  ppaas.Master.certificate() method instead
        .. seealso:: get_certificates(), ppaas.Master.certificate()
        """
        self.client = ApiClient()
        self.hostname = hostname
        self.master = master
        self.reload_data(cached_data)
Example #12
0
    def __init__(self, uuid):
        """Creates a new object representing an *existing* puppet master

        :param uuid: UUID of the master
        :type uuid: str

        :Example:
        >>> ppaas.Master('0e85b81f-5a29-4e2b-a46c-e024049acb07')
        <Puppet Master 0e85b81f-5a29-4e2b-a46c-e024049acb07>
        >>> master.name
        'thomas'

        .. seealso:: get_masters()
        """
        self.client = ApiClient()
        self.uuid = uuid
        self.cached_data, _ = self.client.get('/masters/%s' % self.uuid)
    def create_deploy_key(name, client=None):
        """Creates a new deployment key with a given name.

        :param name: Name of the new key
        :type name: str

        :return: The newly created key
        :rtype: DeployKey

        :Example:

        >>> ppaas.DeployKey.create_deploy_key('fookey')
        <Deploy Key fookey>
        """
        if not client:
            client = ApiClient()
        result, status = client.post('/deploy-keys', data={'name': name})
        return DeployKey(name, result)
Example #14
0
def run():
    try:
        client = ApiClient('a995b0ff-2269-45bf-a96e-07233c2aa03c',
                           'iqxjWqVzDUObnVTMgVdUGKVPhdFhE6qCRIF6oG8u')
        result = client.get(
            'v2/astrology/planet-position', {
                'ayanamsa': 1,
                'coordinates': '23.1765,75.7885',
                'datetime': '1975-04-25T14:10:00+00:00',
                'chart_type': 'lagna',
                'chart_style': 'north-indian'
            })
        # print json.dumps(result, indent=4)
        print(result)
    except ValidationError as e:
        for msg in e.getValidationMessages():
            print(msg['detail'])
    except AuthenticationError as e:
        print(e.message)
Example #15
0
    def __init__(self, uuid, cached_data=None):
        """Creates a new object representing an *existing* puppet master

        :param uuid: UUID of the master
        :type uuid: str
        :param cached_data: Cached data to instantiate the master
        :type cached_data: dict


        :Example:
        >>> ppaas.Master('0e85b81f-5a29-4e2b-a46c-e024049acb07')
        <Puppet Master 0e85b81f-5a29-4e2b-a46c-e024049acb07>
        >>> master.name
        'thomas'

        .. seealso:: get_masters()
        """
        self.client = ApiClient()
        self.uuid = uuid
        self.reload_data(cached_data)
    def get_deploy_keys(client=None):
        """Retrieves all your deployment keys.

        :param client: A client object you want to pass, if empty a new one will be created
        :type client: ApiClient

        :return: The list of your deployment keys
        :rtype: List of DeployKey objects

        :Example:

        >>> ppaas.DeployKey.get_deploy_keys()
        [<Deploy Key github>, <Deploy Key thomas>]
        """
        if not client:
            client = ApiClient()
        result, status = client.get('/deploy-keys')
        keys = []
        for key in result['deploy_keys']:
            keys.append(DeployKey(key['name'], key))
        return keys
    def get_masters(client=None):
        """Retrieves all your puppet masters

        :param client: A client object you want to pass, if empty a new one will be created
        :type client: ppaas.ApiClient

        :return: The list of your puppet masters
        :rtype: List of Master objects

        :Example:

        >>> ppaas.Master.get_masters()
        [<Puppet Master 0e85b81f-5a29-4e2b-a46c-e024049acb07>]
        """
        if not client:
            client = ApiClient()
        result, status = client.get('/masters')
        masters = []
        for master in result['masters']:
            masters.append(Master(master['id'], master))
        return masters
Example #18
0
    def get_masters(client=None):
        """Retrieves all your puppet masters

        :param client: A client object you want to pass, if empty a new one will be created
        :type client: ppaas.ApiClient

        :return: The list of your puppet masters
        :rtype: List of Master objects

        :Example:

        >>> ppaas.Master.get_deploy_keys()
        [<Puppet Master 0e85b81f-5a29-4e2b-a46c-e024049acb07>]
        """
        if not client:
            client = ApiClient()
        result, status = client.get('/masters')
        masters = []
        for master in result['masters']:
            masters.append(Master(master['id']))
        return masters
    def create_master(name, source, deploy_key, vars={}, nb=1, type=None, hierarchy=[], hieras=[], client=None):
        """ Creates a Pupper master

        :param name: Name of the puppet master
        :type name: str
        :param source: Source git repository of the puppet master
        :type source: str
        :param deploy_key: Deploy key to link with your puppet master
        :type deploy_key: ppaas.DeployKey
        :param nb: Number of servers for the master
        :type nb: int
        :param type: Kind of server to use
        :type type: str
        :param hierarchy: Array of hierarchies
        :type hierarchy: list
        :param hieras: Array of hiera backend
        :type hieras: list
        :param client: A client object you want to pass, if empty a new one will be created
        :type client: ppaas.ApiClient

        :return: The newly created puppet master
        :rtype: Master

        :Example:
        >>> ppaas.Master.create_master("master1", "[email protected]:puppet/puppet.git", "github")
        <Puppet Master 0e85b81f-5a29-4e2b-a46c-e024049acb07>
        >>> master.name
        'master1'

        """
        payload = {"name": name, "source": source, "deploy_key": deploy_key, "nb": nb,
                "hierarchy": hierarchy, "hieras": hieras, "vars": vars}
        if type:
            payload["type"] = type

        if not client:
            client = ApiClient()

        result, _ = client.post("/masters", data=payload)
        return Master(result["id"], result)
Example #20
0
    def __init__(self, merlin_url: str, use_google_oauth: bool = True):
        self._merlin_url = merlin_url
        config = Configuration()
        config.host = self._merlin_url + "/v1"

        self._api_client = ApiClient(config)
        if use_google_oauth:
            credentials, project = google.auth.default(scopes=OAUTH_SCOPES)
            autorized_http = AuthorizedHttp(credentials, urllib3.PoolManager())
            self._api_client.rest_client.pool_manager = autorized_http

        self._project_api = ProjectApi(self._api_client)
        self._model_api = ModelsApi(self._api_client)
        self._version_api = VersionApi(self._api_client)
        self._endpoint_api = EndpointApi(self._api_client)
        self._env_api = EnvironmentApi(self._api_client)
    def __init__(self, uuid):
        """Creates a new object representing an *existing* puppet master

        :param uuid: UUID of the master
        :type uuid: str

        :Example:
        >>> ppaas.Master('0e85b81f-5a29-4e2b-a46c-e024049acb07')
        <Puppet Master 0e85b81f-5a29-4e2b-a46c-e024049acb07>
        >>> master.name
        'thomas'

        .. seealso:: get_masters()
        """
        self.client = ApiClient()
        self.uuid = uuid
        self.cached_data, _ = self.client.get('/masters/%s' % self.uuid)
    def __init__(self, uuid, cached_data=None):
        """Creates a new object representing an *existing* puppet master

        :param uuid: UUID of the master
        :type uuid: str
        :param cached_data: Cached data to instantiate the master
        :type cached_data: dict


        :Example:
        >>> ppaas.Master('0e85b81f-5a29-4e2b-a46c-e024049acb07')
        <Puppet Master 0e85b81f-5a29-4e2b-a46c-e024049acb07>
        >>> master.name
        'thomas'

        .. seealso:: get_masters()
        """
        self.client = ApiClient()
        self.uuid = uuid
        self.reload_data(cached_data)
Example #23
0
    def get_master(name, client=None):
        """Gets a master by name, because who the hell can remember uuids ?

        :param name: Name of the Puppet Master you want to retrieve
        :param client: A client object you want to pass, if empty a new one will be created
        :type name: str
        :type client: ppaas.ApiClient

        :return: A Master object, or None if no matching master was found
        :rtype: ppaas.Master, or None

        :Example:

        >>> ppaas.Master.get_master('thomas')
        <Puppet Master 0e85b81f-5a29-4e2b-a46c-e024049acb07>
        """
        if not client:
            client = ApiClient()
        masters = Master.get_masters(client)
        for master in masters:
            if master.cached_data['name'] == name:
                return master
        return None
Example #24
0
from configuration import *
from client import ApiClient
from common import Logger
from traffic import TrafficPointDownloader

# Configuración y dependencias
configuration: Configuration = Configuration.load_from_file(
    'configuration.development.json')

#Cliente de la API
api_client: ApiClient = ApiClient(configuration.api)

#Logger
logger: Logger = Logger()

traffic: TrafficPointDownloader = TrafficPointDownloader()
Example #25
0
class OktawaveApi(object):
    def __init__(self, username, password, debug=False):
        """Initialize the API instance

        Arguments:
        - username (string) - Oktawave account username
        - password (string) - Oktawave account password
        - debug (bool) - enable debug output?
        """
        self.username = username
        self.password = password
        self.debug = debug
        self.client_id = None
        self.client_object = None
        self.common = None
        self.clients = None

    # HELPER METHODS ###
    # methods starting with "_" will not be autodispatched to client commands
    # ###

    def _d(self, what):
        if self.debug:
            print what

    def _init_common(self):
        """Convenience method to initialize CommonService client"""
        if self.common is not None:
            return
        self.common = ApiClient(jsonapi_common, self.username, self.password, self.debug)
        self._d(self.common)

    def _init_clients(self):
        """Convenience method to initialize ClientsService client"""
        if self.clients is not None:
            return
        self.clients = ApiClient(jsonapi_clients, self.username, self.password, self.debug)
        self._d(self.clients)

    def logon(self, only_common=False):
        """Initializes CommonService client and calls LogonUser method.

        Returns the User object, as returned by LogonUser.
        Also sets self.client_id for convenience.
        """
        self._init_common()
        if not only_common:
            self._init_clients()
        if self.client_object is not None:
            return self.client_object
        try:
            res = self.common.call(
                "LogonUser",
                user=self.username,
                password=self.password,
                ipAddress=_get_machine_ip(),
                userAgent="Oktawave CLI",
            )
        except AttributeError:
            raise OktawaveLoginError()
        self.client_id = res["User"]["Client"]["ClientId"]
        self.client_object = res["User"]
        return res

    def _simple_vm_method(self, method, vm_id):
        """Wraps around common simple virtual machine method call pattern"""
        self.logon()
        return self.clients.call(method, virtualMachineId=vm_id, clientId=self.client_id)

    def _find_disk(self, disk_id):
        """Finds a disk (OVS) by id"""
        dsp = {"ClientId": self.client_id}
        disks = [d for d in self.clients.call("GetDisks", searchParams=dsp)["_results"] if d["ClientHddId"] == disk_id]
        if len(disks) == 0:
            return None
        res = disks[0]
        if res["VirtualMachineHdds"] is None:
            res["VirtualMachineHdds"] = []
        return res

    def _dict_item(self, dict_id, key):
        items = self.common.call("GetDictionaryItems", dictionary=dict_id, clientId=self.client_id)
        for item in items:
            item = DictionaryItem(item)
            if item.name == key:
                return item

    def _oci_class(self, class_name):
        """Returns a dictionary item for OCI class with a given name"""
        return self._dict_item(DICT["OCI_CLASSES_DICT_ID"], class_name)

    def _ovs_tier(self, tier):
        """Returns ID of a given disk tier"""
        tier_name = "Tier " + str(tier)
        tier_obj = self._dict_item(DICT["OVS_TIERS_DICT_ID"], tier_name)
        if not tier_obj:
            raise OktawaveOVSTierNotFound()
        return tier_obj

    def _container_simple(self, container_id):
        """Fetches a container's information using GetContainersSimpleWithVM"""
        self.logon()
        cs = self.clients.call("GetContainersSimpleWithVM", clientId=self.client_id)
        for c in cs:
            self._d([c, container_id])
            if str(c["ContainerId"]) == str(container_id):
                return c
        raise OktawaveContainerNotFoundError()

    # API methods below ###

    # General / Account ###

    def Account_Settings(self):
        """Print basic settings of the client account

        args is an object containing at least the following fields:
        - username - Oktawave username
        - password - Oktawave client password
        Typically args will be the object returned from argparse.

        """
        self.logon(only_common=True)
        client = self.client_object
        # TODO: probably get more settings
        return {
            "time_zone": client["TimeZone"]["DisplayName"],
            "currency": DictionaryItem(client["Currency"]),
            "date_format": DictionaryItem(client["DateFormat"]),
            "availability_zone": DictionaryItem(
                self.common.call("GetDictionaryItemById", dictionaryItemId=client["AvailabilityZone"])
            ),
            "24h_clock": client["Is24HourClock"],
        }

    def Account_RunningJobs(self):
        self.logon()
        res = self.common.call("GetRunningOperations", clientId=self.client_id)
        if not res:
            return
        for op in res:
            yield {
                "id": op["AsynchronousOperationId"],
                "creation_date": op["CreationDate"],
                "creation_user_name": op["CreationUserFullName"],
                "type": RawDictionaryItem(op["OperationTypeId"], op["OperationTypeName"]),
                "object_type": RawDictionaryItem(op["ObjectTypeId"], op["ObjectTypeName"]),
                "object_name": op["ObjectName"],
                "progress_percent": op["Progress"],
                "status": RawDictionaryItem(op["StatusId"], op["StatusName"]),
            }

    def Account_Users(self):
        """Print users in client account."""
        self.logon()
        users = self.clients.call("GetClientUsers", clientId=self.client_id)
        self._d(users)
        for user in users:
            yield {"email": user["Email"], "name": user["FullName"]}

    # OCI (VMs) ###

    def OCI_TemplateCategories(self):
        """Lists available template categories"""
        self.logon()
        data = self.common.call("GetTemplateCategories", clientId=self.client_id)
        self._d(data)

        for tc in data:
            yield TemplateCategory(tc, None)
            if tc["CategoryChildren"] is not None:
                for tcc in tc["CategoryChildren"]:
                    yield TemplateCategory(tcc, tc["TemplateCategoryId"])

    def OCI_Templates(self, category_id, name_filter=""):
        """Lists templates in a category"""
        self.logon()
        data = self.common.call(
            "GetTemplatesByCategory", categoryId=category_id, categorySystemId=None, type=None, clientId=self.client_id
        )
        if data:
            return dict(
                (template["TemplateId"], template["TemplateName"])
                for template in data
                if name_filter in template["TemplateName"]
            )

    def OCI_TemplateInfo(self, template_id):
        """Shows more detailed info about a particular template"""
        self.logon()
        data = self.clients.call("GetTemplate", templateId=template_id, clientId=self.client_id)

        template_category = TemplateCategory(data["TemplateCategory"], None)
        software = [SoftwareItem(item["Software"]) for item in data["SoftwareList"]]

        return {
            "template_id": data["TemplateId"],
            "template_name": data["TemplateName"],
            "template_category": template_category.tree_path,
            "vm_class_id": data["VMClass"]["DictionaryItemId"],
            "vm_class_name": DictionaryItem(data["VMClass"]),
            "system_category_name": DictionaryItem(data["TemplateSystemCategory"]),
            "label": data["Name"],
            "software": software,
            "eth_count": data["EthernetControllersCount"],
            "connection_type": DictionaryItem(data["ConnectionType"]),
            "disks": [
                {"name": hdd["HddName"], "capacity_gb": hdd["CapacityGB"], "is_primary": hdd["IsPrimary"]}
                for hdd in data["DiskDrives"]
            ],
            "description": TemplateDescription(data["TemplateDescription"]),
        }

    def OCI_List(self):
        """Lists client's virtual machines' basic info"""
        self.logon()
        vms = self.clients.call("GetVirtualMachinesSimple", clientId=self.client_id)
        self._d(vms)
        for vm in vms:
            yield {
                "id": vm["VirtualMachineId"],
                "name": vm["VirtualMachineName"],
                "status": PowerStatus(vm["StatusDictId"]),
            }

    def OCI_ListDetails(self):
        """Lists client's virtual machines"""
        self.logon()
        sp = {"ClientId": self.client_id}
        vms = self.clients.call("GetVirtualMachines", searchParams=sp)
        self._d(vms)
        for vm in vms["_results"]:
            yield {
                "id": vm["VirtualMachineId"],
                "name": vm["VirtualMachineName"],
                "status": PowerStatus(vm["StatusDictId"]),
                "class_name": DictionaryItem(vm["VMClass"]),
                "cpu_mhz": vm["CpuMhz"],
                "cpu_usage_mhz": vm["CpuMhzUsage"],
                "memory_mb": vm["RamMB"],
                "memory_usage_mb": vm["RamMBUsage"],
            }

    def OCI_Restart(self, oci_id):
        """Restarts given VM"""
        self._simple_vm_method("RestartVirtualMachine", oci_id)

    def OCI_TurnOff(self, oci_id, force=False):
        """Turns given VM off"""
        if not force:
            try:
                self._simple_vm_method("ShutdownVirtualMachine", oci_id)
                return
            except OktawaveAPIError:
                # XXX: swallow only the "clean shutdown not supported" exception
                pass

        self._simple_vm_method("TurnoffVirtualMachine", oci_id)

    def OCI_TurnOn(self, oci_id):
        """Turns given virtual machine on"""
        self._simple_vm_method("TurnOnVirtualMachine", oci_id)

    def OCI_Delete(self, oci_id):
        """Deletes given virtual machine"""
        self._simple_vm_method("DeleteVirtualMachine", oci_id)

    def OCI_Logs(self, oci_id):
        """Shows virtual machine logs"""
        self.logon()
        sp = {"VirtualMachineId": oci_id, "PageSize": 100, "SortingDirection": 0}  # descending
        data = self.clients.call("GetVirtualMachineHistories", searchParams=sp, clientId=self.client_id)
        self._d(data)
        for op in data["_results"]:
            yield {
                "time": self.clients.parse_date(op["CreationDate"]),
                "type": DictionaryItem(op["OperationType"]),
                "user_name": op["CreationUser"]["FullName"],
                "status": DictionaryItem(op["Status"]),
                "parameters": [item["Value"] for item in op["Parameters"]],
            }

    def OCI_DefaultPassword(self, oci_id):
        logs = self.OCI_Logs(oci_id)
        for entry in logs:
            if entry["type"] == "Instance access details":
                try:
                    return entry["parameters"][0]
                except IndexError:
                    return  # no data yet

    def OCI_Settings(self, oci_id):
        """Shows basic VM settings (IP addresses, OS, names, autoscaling etc.)"""
        data = self._simple_vm_method("GetVirtualMachineById", oci_id)

        res = {
            "autoscaling": DictionaryItem(data["AutoScalingType"]),
            "connection_type": DictionaryItem(data["ConnectionType"]),
            "cpu_mhz": data["CpuMhz"],
            "cpu_usage_mhz": data["CpuMhzUsage"],
            "creation_date": self.clients.parse_date(data["CreationDate"]),
            "creation_user_name": data["CreationUserSimple"]["FullName"],
            "iops_usage": data["IopsUsage"],
            "last_change_date": self.clients.parse_date(data["LastChangeDate"]),
            "payment_type": DictionaryItem(data["PaymentType"]),
            "memory_mb": data["RamMB"],
            "memory_usage_mb": data["RamMBUsage"],
            "status": DictionaryItem(data["Status"]),
            "name": data["VirtualMachineName"],
            "vm_class_name": DictionaryItem(data["VMClass"]),
            "disks": [
                {
                    "id": disk["ClientHddId"],
                    "name": disk["ClientHdd"]["HddName"],
                    "capacity_gb": disk["ClientHdd"]["CapacityGB"],
                    "creation_date": self.clients.parse_date(disk["ClientHdd"]["CreationDate"]),
                    "creation_user_name": disk["ClientHdd"]["CreationUser"]["FullName"],
                    "is_primary": disk["IsPrimary"],
                    "is_shared": disk["ClientHdd"]["IsShared"],
                }
                for disk in data["DiskDrives"]
            ],
            "ips": [
                {
                    "ipv4": ip["Address"],
                    "netmask": ip["NetMask"],
                    "ipv6": ip["AddressV6"],
                    "creation_date": self.clients.parse_date(ip["CreationDate"]),
                    "dhcp_branch": ip["DhcpBranch"],
                    "gateway": ip["Gateway"],
                    "status": DictionaryItem(ip["IPStatus"]),
                    "last_change_date": self.clients.parse_date(ip["LastChangeDate"]),
                    "macaddr": ip["MacAddress"],
                }
                for ip in data["IPs"]
            ],
            "vlans": [],
        }
        if data["PrivateIpv4"]:
            res["vlans"] = [
                {
                    "ipv4": vlan["PrivateIpAddress"],
                    "creation_date": self.clients.parse_date(vlan["CreationDate"]),
                    "macaddr": vlan["MacAddress"],
                }
                for vlan in data["PrivateIpv4"]
            ]

        return res

    def OCI_Classes(self):
        self.logon(only_common=True)
        resp = self.common.call("GetVirtualMachineClassConfigurations")
        for oci_class in resp:
            yield {
                "name": DictionaryItem(oci_class["VirtualMachineClass"]),
                "category": DictionaryItem(oci_class["Category"]),
                "cpu_count": oci_class["CpuCount"],
                "memory_mb": oci_class["RamMB"],
            }

    def OCI_ClassChangeNeedsRestart(self, oci_id, oci_class):
        """Will OCI class change require reboot?"""
        self.logon()
        oci_class_obj = self._oci_class(oci_class)
        if not oci_class_obj:
            raise OktawaveOCIClassNotFound()
        return self.clients.call(
            "IsRestartNeededForClassChange",
            virtualMachineId=oci_id,
            clientId=self.client_id,
            targetClassId=oci_class_obj.id,
        )

    def OCI_ChangeClass(self, oci_id, oci_class, at_midnight=False):
        """Changes running VM class, potentially rebooting it"""
        oci = self._simple_vm_method("GetVirtualMachineById", oci_id)
        oci_class_obj = self._oci_class(oci_class)
        if not oci_class_obj:
            raise OktawaveOCIClassNotFound()
        oci["VMClass"] = oci_class_obj.item
        self._d(oci)
        oci.setdefault("PrivateIpv4", "")
        self.clients.call(
            "UpdateVirtualMachine", machine=oci, clientId=self.client_id, classChangeInScheduler=at_midnight
        )

    def OCI_Subregions(self):
        self.logon(only_common=True)
        resp = self.common.call("GetClusters", onlyClientClusters=False, clientId=self.client_id)
        for cluster in resp:
            yield {"id": cluster["ClusterId"], "name": cluster["DisplayName"], "active": cluster["IsActive"]}

    def OCI_Create(
        self,
        name,
        template,
        oci_class=None,
        forced_type=TemplateType.Machine,
        db_type=None,
        subregion="Auto",
        disk_size_gb=None,
        ip_address_id=None,
    ):
        """Creates a new instance from template"""
        self.logon()
        oci_class_id = None
        if oci_class is not None:
            oci_class_obj = self._oci_class(oci_class)
            if not oci_class_obj:
                raise OktawaveOCIClassNotFound()
            oci_class_id = oci_class_obj.id

        args = dict(
            templateId=template,
            additionalDisks=None,
            machineName=name,
            selectedClass=oci_class_id,
            selectedContainer=None,
            selectedPaymentMethod=DICT["OCI_PAYMENT_ID"],
            selectedConnectionType=DICT["OCI_CONNECTION_ID"],
            clientId=self.client_id,
            providervAppClientId=None,
            vAppType=forced_type,
            databaseTypeId=db_type,
            clientVmParameter=None,
            autoScalingTypeId=DICT["OCI_AUTOSCALING_ID"],
        )

        if disk_size_gb is None and ip_address_id is None:
            self.clients.call("CreateVirtualMachine", disks=None, clusterId=_subregion_id(subregion), **args)
        else:
            if disk_size_gb is None:
                disk_size_gb = 1  # minimum possible size, template will probably override
            if ip_address_id is None:
                ip_address_id = 0
            self.clients.call(
                "CreateVirtualMachineWithSpecificDiskSizeAndIp",
                diskSizeGB=disk_size_gb,
                ipId=ip_address_id,
                subRegionId=_subregion_id(subregion),
                instancesCount=1,
                **args
            )

    def OCI_Clone(self, oci_id, name, clonetype):
        """Clones a VM"""
        self.logon()
        self.clients.call(
            "CloneVirtualMachine", virtualMachineId=oci_id, cloneName=name, cloneType=clonetype, clientId=self.client_id
        )

    # OVS (disks) ###

    def OVS_List(self):
        """Lists disks"""
        self.logon()
        dsp = {"ClientId": self.client_id}
        data = self.clients.call("GetDisks", searchParams=dsp)
        for disk in data["_results"]:
            if disk["VirtualMachineHdds"] is None:
                vms = []
            else:
                vms = [
                    {
                        "id": vm["VirtualMachine"]["VirtualMachineId"],
                        "name": vm["VirtualMachine"]["VirtualMachineName"],
                        "primary": vm["IsPrimary"],
                        "vm_status": PowerStatus(vm["VirtualMachine"]["StatusDictId"]),
                    }
                    for vm in disk["VirtualMachineHdds"]
                ]
            yield {
                "id": disk["ClientHddId"],
                "name": disk["HddName"],
                "tier": DictionaryItem(disk["HddStandard"]),
                "capacity_gb": disk["CapacityGB"],
                "used_gb": disk["UsedCapacityGB"],
                "is_shared": disk["IsShared"],
                "vms": vms,
            }

    def OVS_Delete(self, ovs_id):
        """Deletes a disk"""
        self.logon()
        res = self.clients.call("DeleteDisk", clientHddId=ovs_id, clientId=self.client_id)
        if not res:
            raise OktawaveOVSDeleteError()

    def OVS_Create(self, name, capacity_gb, tier, shared, subregion="Auto"):
        """Adds a disk"""
        self.logon()
        disk = {
            "CapacityGB": capacity_gb,
            "HddName": name,
            "HddStandardId": self._ovs_tier(tier).id,
            "IsShared": shared,
            "PaymentTypeId": DICT["OVS_PAYMENT_ID"],
            "VirtualMachineIds": [],
            "ClusterId": _subregion_id(subregion),
        }
        self.clients.call("CreateDisk", clientHdd=disk, clientId=self.client_id)

    def OVS_Map(self, ovs_id, oci_id):
        """Maps a disk into an instance"""
        self.logon()
        disk = self._find_disk(ovs_id)
        if disk is None:
            raise OktawaveOVSNotFoundError()

        disk_mod = _ovs_disk_mod(disk)
        if oci_id in disk_mod["VirtualMachineIds"]:
            raise OktawaveOVSMappedError()
        disk_mod["VirtualMachineIds"].append(oci_id)

        res = self.clients.call("UpdateDisk", clientHdd=disk_mod, clientId=self.client_id)
        if not res:
            raise OktawaveOVSMapError()

    def OVS_Unmap(self, ovs_id, oci_id):
        """Unmaps a disk from an instance"""
        self.logon()
        disk = self._find_disk(ovs_id)
        if disk is None:
            raise OktawaveOVSNotFoundError()

        disk_mod = _ovs_disk_mod(disk)
        if oci_id not in disk_mod["VirtualMachineIds"]:
            raise OktawaveOVSUnmappedError()

        disk_mod["VirtualMachineIds"].remove(oci_id)

        res = self.clients.call("UpdateDisk", clientHdd=disk_mod, clientId=self.client_id)
        if not res:
            raise OktawaveOVSUnmapError()

    def OVS_ChangeTier(self, ovs_id, tier):
        self.logon()
        disk = self._find_disk(ovs_id)
        if disk is None:
            raise OktawaveOVSNotFoundError()

        disk_mod = _ovs_disk_mod(disk)
        disk_mod["HddStandardId"] = self._ovs_tier(tier).id

        self.clients.call("UpdateDisk", clientHdd=disk_mod, clientId=self.client_id)

    def OVS_Extend(self, ovs_id, capacity_gb):
        self.logon()
        disk = self._find_disk(ovs_id)
        if disk is None:
            raise OktawaveOVSNotFoundError()

        disk_mod = _ovs_disk_mod(disk)
        if disk_mod.pop("LockVirtualMachineIds"):
            raise OktawaveOVSMappedError()

        if disk_mod["CapacityGB"] > capacity_gb:
            raise OktawaveOVSTooSmallError()

        disk_mod["CapacityGB"] = capacity_gb

        self.clients.call("UpdateDisk", clientHdd=disk_mod, clientId=self.client_id)

    # ORDB (databases) ###

    def ORDB_List(self):
        """Lists databases"""
        self.logon()
        sp = {"ClientId": self.client_id}
        data = self.clients.call("GetDatabaseInstances", searchParams=sp)
        for db in data["_results"]:
            yield {
                "id": db["VirtualMachineId"],
                "name": db["VirtualMachineName"],
                "type": DictionaryItem(db["DatabaseType"]),
                "size": db["Size"],
                "available_space": db["AvailableSpace"],
            }

    ORDB_TurnOn = OCI_TurnOn
    ORDB_TurnOff = OCI_TurnOff
    ORDB_Restart = OCI_Restart
    ORDB_Clone = OCI_Clone

    def ORDB_Delete(self, oci_id, db_name=None):
        """Deletes a database or VM"""
        self.logon()
        if db_name is None:
            self._simple_vm_method("DeleteVirtualMachine", oci_id)
        else:
            self.clients.call("DeleteDatabase", virtualMachineId=oci_id, databaseName=db_name, clientId=self.client_id)

    ORDB_Logs = OCI_Logs

    def ORDB_LogicalDatabases(self, oci_id):
        """Shows logical databases"""
        self.logon()
        sp = {"ClientId": self.client_id}
        data = self.clients.call("GetDatabaseInstances", searchParams=sp)

        for vm in data["_results"]:
            if oci_id is not None and str(vm["VirtualMachineId"]) != str(oci_id):
                continue

            for db in vm["Databases"]:
                yield {
                    "id": db["VirtualMachineId"],
                    "name": db["DatabaseName"],
                    "type": DictionaryItem(db["DatabaseType"]),
                    "encoding": db["Encoding"],
                    "is_running": db["IsRunning"],
                    "qps": db["QPS"],
                    "size": db["Size"],
                }

    ORDB_Settings = OCI_Settings

    def ORDB_Create(self, name, template, oci_class=None, subregion="Auto"):
        """Creates a database VM"""
        self.logon()
        data = self.clients.call("GetTemplate", templateId=template, clientId=self.client_id)
        if str(data["TemplateType"]["DictionaryItemId"]) != str(DICT["DB_VM_CATEGORY"]):
            raise OktawaveORDBInvalidTemplateError()
        self.OCI_Create(
            name,
            template,
            forced_type=TemplateType.Database,
            db_type=data["DatabaseType"]["DictionaryItemId"],
            subregion=subregion,
            oci_class=oci_class,
        )

    def ORDB_GlobalSettings(self, oci_id):
        """Shows global database engine settings"""
        self.logon()
        data = self.clients.call("GetDatabaseConfig", virtualMachineId=oci_id, clientId=self.client_id)

        for item in data:
            yield {"name": item.Name, "value": item.Value}

    def ORDB_CreateLogicalDatabase(self, oci_id, name, encoding):
        """Creates a new logical database within an instance"""
        self.logon()
        self.clients.call(
            "CreateDatabase",
            virtualMachineId=oci_id,
            databaseName=name,
            encodingDictId=DICT[encoding.upper() + "_ENCODING"],
            clientId=self.client_id,
        )

    def ORDB_BackupLogicalDatabase(self, oci_id, name):
        """Creates a backup of logical database"""
        self.logon()
        self.clients.call("BackupDatabase", virtualMachineId=oci_id, databaseName=name, clientId=self.client_id)

    def ORDB_MoveLogicalDatabase(self, oci_id_from, oci_id_to, name):
        """Moves a logical database"""
        self.logon()
        self.clients.call(
            "MoveDatabase",
            virtualMachineIdFrom=oci_id_from,
            virtualMachineIdTo=oci_id_to,
            databaseName=name,
            clientId=self.client_id,
        )

    def ORDB_Backups(self):
        """Lists logical database backups"""
        self.logon()
        mysql_data = self.clients.call("GetBackups", databaseTypeDictId=DICT["MYSQL_DB"], clientId=self.client_id) or []
        pgsql_data = (
            self.clients.call("GetBackups", databaseTypeDictId=DICT["POSTGRESQL_DB"], clientId=self.client_id) or []
        )

        for b in mysql_data:
            yield {"file_name": b["Name"], "type": "MySQL", "path": b["ContainerName"] + "/" + b["FullPath"]}

        for b in pgsql_data:
            yield {"file_name": b["Name"], "type": "PostgreSQL", "path": b["ContainerName"] + "/" + b["FullPath"]}

    def ORDB_RestoreLogicalDatabase(self, oci_id, name, backup_file):
        """Restores a database from backup"""
        self.logon()
        self.clients.call(
            "RestoreDatabase",
            virtualMachineId=oci_id,
            databaseName=name,
            backupFileName=backup_file,
            clientId=self.client_id,
        )

    def Container_List(self):
        """Lists client's containers' basic info"""
        self.logon()
        containers = self.clients.call("GetContainers", clientId=self.client_id)
        for c in containers:
            yield {"id": c["ContainerId"], "name": c["ContainerName"], "vms": c["VirtualMachineCount"]}

    def Container_Get(self, container_id):
        """Displays a container's information"""
        self.logon()
        c = self.clients.call("GetContainer", containerId=container_id)
        res = {
            "autoscaling": DictionaryItem(c["AutoScalingType"]),
            "id": c["ContainerId"],
            "name": c["ContainerName"],
            "healthcheck": c["IsServiceCheckAvailable"],
            "load_balancer": c["IsLoadBalancer"],
            "master_service_id": c["MasterServiceId"],
            "master_service_name": c["MasterServiceName"],
            "proxy_cache": c["IsProxyCache"],
            "ssl": c["IsSSLUsed"],
            "port": c["PortNumber"],
            "schedulers": c["SchedulersCount"],
            "vms": c["VirtualMachineCount"],
            "db_user": c["DatabaseUserLogin"],
            "db_password": c["DatabaseUserPassword"],
        }
        for label, item in (
            ("ip_version", "IPVersion"),
            ("load_balancer_algorithm", "LoadBalancerAlgorithm"),
            ("service", "Service"),
            ("session_type", "SessionType"),
        ):
            if c[item]:
                res[label] = DictionaryItem(c[item])
            else:
                res[label] = None
        res["ips"] = [{"ipv4": ip["Address"], "ipv6": ip["AddressV6"]} for ip in c["IPs"]]
        return res

    def Container_OCIList(self, container_id):
        c_simple = self._container_simple(container_id)
        for vm in c_simple["VirtualMachines"]:
            vms = vm["VirtualMachineSimple"]
            yield {
                "oci_id": vms["VirtualMachineId"],
                "oci_name": vms["VirtualMachineName"],
                "status": PowerStatus(vms["StatusDictId"]),
            }

    def Container_RemoveOCI(self, container_id, oci_id):
        """Removes an instance from container"""
        self.logon()
        c_simple = self._container_simple(container_id)
        found = False
        for vm in c_simple["VirtualMachines"]:
            if vm["VirtualMachineId"] == oci_id:
                found = True
                break
        if not found:
            raise OktawaveOCINotInContainer()
        vm_ids = [vm["VirtualMachineId"] for vm in c_simple["VirtualMachines"] if vm["VirtualMachineId"] != oci_id]
        c = self.clients.call("GetContainer", containerId=container_id)
        self._d(vm_ids)
        self.clients.call("UpdateContainer", container=c, virtualMachinesId=vm_ids)

    def Container_AddOCI(self, container_id, oci_id):
        """Adds an instance to container"""
        self.logon()
        c_simple = self._container_simple(container_id)
        found = False
        for vm in c_simple["VirtualMachines"]:
            if vm["VirtualMachineId"] == oci_id:
                found = True
                break
        if found:
            raise OktawaveOCIInContainer()
        vm_ids = [vm["VirtualMachineId"] for vm in c_simple["VirtualMachines"]] + [oci_id]
        c = self.clients.call("GetContainer", containerId=container_id)
        self.clients.call("UpdateContainer", container=c, virtualMachinesId=vm_ids)

    def Container_Delete(self, container_id):
        self.logon()
        self.clients.call("DeleteContainers", containerIds=[container_id], clientId=self.client_id)

    def Container_Create(
        self,
        name,
        load_balancer,
        service,
        port,
        proxy_cache,
        ssl,
        healthcheck,
        master_id,
        session,
        lb_algorithm,
        ip_version,
        autoscaling,
    ):
        if lb_algorithm == "least_response_time" and service != "HTTP" and service != "HTTPS":
            raise OktawaveLRTNotAllowed()
        self.logon()
        vm_ids = [] if master_id is None else [master_id]
        result = self.clients.call(
            "CreateContainer",
            container={
                "OwnerClientId": self.client_id,
                "ContainerName": name,
                "IsLoadBalancer": load_balancer,
                "Service": {"DictionaryItemId": _container_service_id(service)},
                "LoadBalancerAlgorithm": {"DictionaryItemId": _load_balancer_algorithm_id(lb_algorithm)},
                "IsSSLUsed": ssl,
                "IsProxyCache": proxy_cache,
                "MasterServiceId": master_id,
                "PortNumber": port,
                "SessionType": {"DictionaryItemId": _session_type_id(session)},
                "IPVersion": {"DictionaryItemId": _ip_version_id(ip_version)},
                "AutoScalingType": {"DictionaryItemId": _autoscaling_id(autoscaling)},
                "IsServiceCheckAvailable": healthcheck,
            },
            virtualMachinesId=vm_ids,
        )
        return result

    # TODO: allow to change only selected parameters, add more validation
    # without relying on the UpdateContainer API method.
    def Container_Edit(
        self,
        container_id,
        name,
        load_balancer,
        service,
        port,
        proxy_cache,
        ssl,
        healthcheck,
        master_id,
        session,
        lb_algorithm,
        ip_version,
        autoscaling,
    ):
        self.logon()
        if lb_algorithm == "least_response_time" and service != "HTTP" and service != "HTTPS":
            raise OktawaveLRTNotAllowed()
        c = self.clients.call("GetContainer", containerId=container_id)
        c_simple = self._container_simple(container_id)
        c["ContainerName"] = name
        c["IsLoadBalancer"] = load_balancer
        c["Service"] = {"DictionaryItemId": _container_service_id(service)}
        c["LoadBalancerAlgorithm"] = {"DictionaryItemId": _load_balancer_algorithm_id(lb_algorithm)}
        c["IsSSLUsed"] = ssl
        c["IsProxyCache"] = proxy_cache
        c["MasterServiceId"] = master_id
        c["PortNumber"] = port
        c["SessionType"] = {"DictionaryItemId": _session_type_id(session)}
        c["IPVersion"] = {"DictionaryItemId": _ip_version_id(ip_version)}
        c["AutoScalingType"] = {"DictionaryItemId": _autoscaling_id(autoscaling)}
        c["AutoScalingTypeDictId"] = _autoscaling_id(autoscaling)
        c["IsServiceCheckAvailable"] = healthcheck
        self._d(c)
        self.clients.call(
            "UpdateContainer",
            container=c,
            virtualMachinesId=[vm["VirtualMachineId"] for vm in c_simple["VirtualMachines"]],
        )

    def OPN_List(self):
        """Lists client's OPNs"""
        self.logon()
        vlans = self.clients.call("GetVlansByClientId", clientId=self.client_id)
        for v in vlans:
            yield {
                "id": v["VlanId"],
                "name": v["VlanName"],
                "address_pool": DictionaryItem(v["AddressPool"]),
                "payment_type": DictionaryItem(v["PaymentType"]),
            }

    def OPN_Get(self, opn_id):
        self.logon()
        v = self.clients.call("GetVlanById", vlanId=opn_id, clientId=self.client_id)
        vms = self.clients.call("GetVirtualMachineVlansByVlanId", vlanId=opn_id, clientId=self.client_id)
        return {
            "id": v["VlanId"],
            "name": v["VlanName"],
            "address_pool": DictionaryItem(v["AddressPool"]),
            "payment_type": DictionaryItem(v["PaymentType"]),
            "vms": vms,
        }

    def OPN_Create(self, name, address_pool):
        self.logon()
        self._d(self.client_object)
        return self.clients.call(
            "CreateVlan",
            vlan={
                "VlanName": name,
                "AddressPool": {"DictionaryItemId": _address_pool_id(address_pool)},
                "OwnerClient": self.client_object["Client"],
                "PaymentType": {"DictionaryItemId": DICT["OPN_PAYMENT_ID"]},
                "CreationUserId": self.client_id,
            },
        )

    def OPN_Delete(self, opn_id):
        self.logon()
        return self.clients.call("DeleteVlan", vlanId=opn_id, clientId=self.client_id)

    def OPN_AddOCI(self, opn_id, oci_id, ip_address):
        self.logon()
        oci = self.clients.call("GetVirtualMachineById", virtualMachineId=oci_id, clientId=self.client_id)
        vlan = self.clients.call("GetVlanById", vlanId=opn_id, clientId=self.client_id)
        for opn in oci["PrivateIpv4"]:
            if opn["Vlan"]["VlanId"] == opn_id:
                raise OktawaveOCIInOPN()
        oci["PrivateIpv4"].append(
            {
                "PrivateIpAddress": ip_address,
                "VirtualMachine": {
                    "VirtualMachineName": oci["VirtualMachineName"],
                    "VirtualMachineId": oci_id,
                    "StatusDictId": oci["Status"]["DictionaryItemId"],
                },
                "Vlan": vlan,
                "CreationDate": "/Date(" + str(int(time()) * 100) + "+0000)/",
                # for some reason API server does not fill this field automatically
            }
        )
        return self.clients.call(
            "UpdateVirtualMachine", machine=oci, clientId=self.client_id, classChangeInScheduler=False
        )

    def OPN_RemoveOCI(self, opn_id, oci_id):
        self.logon()
        oci = self.clients.call("GetVirtualMachineById", virtualMachineId=oci_id, clientId=self.client_id)
        l1 = len(oci["PrivateIpv4"])
        oci["PrivateIpv4"] = filter(lambda x: x["Vlan"]["VlanId"] != opn_id, oci["PrivateIpv4"])
        if l1 == len(oci["PrivateIpv4"]):
            raise OktawaveOCINotInOPN()
        return self.clients.call(
            "UpdateVirtualMachine", machine=oci, clientId=self.client_id, classChangeInScheduler=False
        )

    def OPN_Rename(self, opn_id, name):
        self.logon()
        vlan = self.clients.call("GetVlanById", vlanId=opn_id, clientId=self.client_id)
        vlan["VlanName"] = name
        return self.clients.call("UpdateVlan", vlan=vlan)
Example #26
0
class Master(object):
    """Interface for the /masters/<masterId> endpoints.

    This class allows you to interract with your Puppet Masters

    This class has the following behavior:
      * When loaded it will cache some data in self.cached_data (it will
        cache its json representation according to the API)
      * Everytime you want to get data from the object, like certificate.fingerprint,
        an HTTP call will be issued, so make sure to use the cache if needed.
      * Dictionnary lookup is done via the __getattr__ overloaded method. It
        is a bit hacky but it does the job. For instance to get the hostname
        of your master, you can type `master.hostname`, this will issue an
        HTTP request and return the corresponding dictionary value

    An example json representation of what this class may look like :
    .. code-block:: json
        {
            "allowed_networks": [
                "0.0.0.0/0"
            ],
            "ca_certificate": "-----BEGIN [.]CATE-----",
            "created_at": "2015-12-07T13:28:28",
            "deploy_key": "github",
            "hierarchy": [],
            "hieras": [],
            "hostname": "master1.user.puppet.runabove.io",
            "id": "1e42115b-34f9-4f86-a4a7-67e30a24a825",
            "name": "master1",
            "nb": 1,
            "servers": {},
            "source": "[email protected]:puppet/puppet.git",
            "status": {
                "code": 0,
                "msg": "Deploying server"
            },
            "token": "d4K1cxIPklE",
            "type": "eg-7",
            "vars": {}
        }
    """
    def __init__(self, uuid):
        """Creates a new object representing an *existing* puppet master

        :param uuid: UUID of the master
        :type uuid: str

        :Example:
        >>> ppaas.Master('0e85b81f-5a29-4e2b-a46c-e024049acb07')
        <Puppet Master 0e85b81f-5a29-4e2b-a46c-e024049acb07>
        >>> master.name
        'thomas'

        .. seealso:: get_masters()
        """
        self.client = ApiClient()
        self.uuid = uuid
        self.cached_data, _ = self.client.get('/masters/%s' % self.uuid)

    @staticmethod
    def get_masters(client=None):
        """Retrieves all your puppet masters

        :param client: A client object you want to pass, if empty a new one will be created
        :type client: ppaas.ApiClient

        :return: The list of your puppet masters
        :rtype: List of Master objects

        :Example:

        >>> ppaas.Master.get_deploy_keys()
        [<Puppet Master 0e85b81f-5a29-4e2b-a46c-e024049acb07>]
        """
        if not client:
            client = ApiClient()
        result, status = client.get('/masters')
        masters = []
        for master in result['masters']:
            masters.append(Master(master['id']))
        return masters

    @staticmethod
    def get_master(name, client=None):
        """Gets a master by name, because who the hell can remember uuids ?

        :param name: Name of the Puppet Master you want to retrieve
        :param client: A client object you want to pass, if empty a new one will be created
        :type name: str
        :type client: ppaas.ApiClient

        :return: A Master object, or None if no matching master was found
        :rtype: ppaas.Master, or None

        :Example:

        >>> ppaas.Master.get_master('thomas')
        <Puppet Master 0e85b81f-5a29-4e2b-a46c-e024049acb07>
        """
        if not client:
            client = ApiClient()
        masters = Master.get_masters(client)
        for master in masters:
            if master.cached_data['name'] == name:
                return master
        return None

    def get_certificates(self, status=None):
        """Returns all the certificates attached to a master

        Optionally you can specify a `status` for the certificates. The statuses can either be
          * "SIGNATURE PENDING"
          * "SIGNED"
          * "REVOKED"
        If status is None, all the certifictes will be returned regardless of their status

        Note that it is just for conveinence that this option is provided. From the API's point
        of view we will issue the same request anyway.

        :param status: The status of the certificates
        :type status: str

        :return: A list of matching certificates
        :rtype: List of ppaas.Certificate

        """
        if status is None:
            return Certificate.get_certificates(self, self.client)
        else:
            certificates = Certificate.get_certificates(self, self.client)
            return [
                cert for cert in certificates
                if cert.status['message'] == status
            ]

    def __repr__(self):
        """String representation of the object"""
        return "<Puppet Master %s>" % self.uuid

    def refresh(self):
        """Asks the master to refresh itself.

        You usually want to do it to trigger the pull of your git repository

        :return: Wether the refresh has been accepted
        :rtype: boolean

        .. note:: The API can answer False if a refresh is already in progress.
        """
        try:
            self.client.post('/masters/%s/refresh' % self.uuid)
            return True
        except:
            return False

    def restart(self):
        """Asks the master to restart

        You usually want to do it when you have edited your hiera or your
        custom puppet functions

        :return: Wether the restart has been accepted
        :rtype: boolean
        """
        try:
            self.client.post('/masters/%s/restart' % self.uuid)
            return True
        except:
            return False

    def certificate(self, hostname):
        """Returns the certificate of a particular hostname

        :param hostname: The hostname you want the certificate of
        :type hostname: str

        :return: The ppaas.Certificate object, or raises an exception
        :rtype: ppaas.Certificate
        """
        return Certificate(self, hostname)

    @property
    def crl(self):
        """Gets the CRL of the master

        :return: The CRL
        :rtype: str
        """
        data, result = self.client.get('/masters/%s/crl' % self.uuid)
        return data['crl']

    @property
    def certificates(self):
        """Gets all the certificates of the master

        :return: The list of the certificates
        :rtype: List of dicts !!!

        .. warnings:: Does not return an object, but a dict
        """
        data, result = self.client.get('/masters/%s/certs' % self.uuid)
        return data['certs']

    @property
    def environments(self):
        """Gets the environments

        It can look like :
        .. code-block:: json
            {
                "environments": {
                    "production": {
                        "settings": {
                            "config_version": "",
                            "environment_timeout": 0,
                            "manifest": "environments/production/manifests",
                            "modulepath": [
                                "/etc/puppet/environments/production/modules",
                                "/etc/puppet/modules",
                                "/usr/share/puppet/modules"
                            ]
                        }
                    }
                }
            }

        :return: The environments of the master
        :rtype: dictionary
        """
        data, result = self.client.get('/masters/%s/environments' % self.uuid)
        return data['environments']

    @property
    def last_update(self):
        """Gets the last update of the master

        Can look like: "2015-12-07T13:28:28"

        :return: Last master update
        :rtype: str
        """
        data, result = self.client.get('/masters/%s/last-update' % self.uuid)
        return data['result']

    def to_dict(self):
        """Returns the JSON representation of the object"

        :return: A dictionary containing the object as served by the API
        :rtype: dict
        """
        result, status = self.client.get('/masters')
        return result

    def __getattr__(self, name):
        """Retrieves an attribute of the class.

        This is kind of a hack. We use the __getattr__ method to access fields of the
        json representation of the class. For instance if my class is represented by

        {
            "foo": "bar",
            "lel": true
        }

        Then obj.foo will return be "bar" eventough the property has not been defined
        in an explicit way.

        :param name: Name of the attribute you want to retrieve
        :type name: str

        :return: The value of the field
        :rtype: Any primitive type
        """
        data, status = self.client.get('/masters/%s' % self.uuid)
        if name in data:
            return data[name]
        return super(Master, self).__getattr__(name)
class Certificate(object):
    """Interface for the /masters/<masterId>/certs endpoints.

    This class allows you to interract with your agent certificates.

    This class has the following behavior:
      * When loaded it will cache some data in self.cached_data (it will
        cache its json representation according to the API)
      * Everytime you want to get data from the object, like certificate.fingerprint,
        an HTTP call will be issued, so make sure to use the cache if needed.
      * Dictionnary lookup is done via the __getattr__ overloaded method. It
        is a bit hacky but it does the job. For instance to get the fingerprint
        of your certificate, you can type `cert.fingerprint`, this will issue an
        HTTP request and return the corresponding dictionary value

    An example json representation of what this class may look like :
    .. code-block:: json
        {
            "created_at": "2015-12-07T13:28:28",
            "fingerprint": "A7:DA:BE:17:09:9E:18:7D:E6:24:25:7C:65:48:EF",
            "hostname": "web.domain.tld",
            "revoked_at": null,
            "serial_number": null,
            "signed_at": null,
            "status": {
                "code": 0,
                "message": "SIGNATURE PENDING"
            }
        }
    """
    def __init__(self, master, hostname):
        """Creates a new object representing an *existing* agent certificate

        :param master: The Master the wanted certificate is attached to
        :param hostname: The hostname of the agent
        :type master: ppaas.Master
        :type hostname: str

        :Example:
        >>> ppaas.Master.get_masters()
        [<Puppet Master 0e85b81f-5a29-4e2b-a46c-e024049acb07>]
        >>> master = _[0]
        >>> ppaas.Certificate(master, 'machine.maurice.fr')
        <Agent Certificate machine.maurice.fr@0e85b81f-5a29-4e2b-a46c-e024049acb07>

        .. note:: You will probably never call this directly and instead use the
                  ppaas.Master.certificate() method instead
        .. seealso:: get_certificates(), ppaas.Master.certificate()
        """
        self.client = ApiClient()
        self.hostname = hostname
        self.master = master
        self.cached_data, _ = self.client.get('/masters/%s/certs/%s' % (self.master.uuid, hostname))

    @staticmethod
    def get_certificates(master, client=None):
        """Returns all the agent certificates for a Master

        :param master: The master in question
        :param client: The ApiClient to use
        :type master: ppaas.Master
        :type client: ppaas.ApiClient

        :Example:

        >>> ppaas.Master.get_masters()
        [<Puppet Master 0e85b81f-5a29-4e2b-a46c-e024049acb07>]
        >>> master = _[0]
        >>> ppaas.Certificate.get_certificates(master)
        [<Agent Certificate machine.maurice.fr@0e85b81f-5a29-4e2b-a46c-e024049acb07>]

        .. note:: You will probably never use this method neither and use the one
                  shipped with the Master class I guess.
        """
        if not client:
            client = ApiClient()
        result, status = client.get('/masters/%s/certs' % master.uuid)
        certificates = []
        for certificate in result['certs']:
            certificates.append(Certificate(master, certificate['hostname']))
        return certificates

    def to_dict(self):
        """Returns the JSON representation of the object"

        :return: A dictionary containing the object as served by the API
        :rtype: dict

        :Example:

        >>> ppaas.Certificate(master, 'machine.maurice.fr').to_dict()
        {u'revoked_at': None, u'signed_at': None, u'created_at': u'2016-02-21T11:21:58', u'hostname': u'machine.maurice.fr', u'status': {u'message': u'SIGNATURE PENDING', u'code': 0}, u'fingerprint': u'9F:1F:B2:C6:8F:D2:62:26:7B:A3:49:00:45:6F:D6:81:3A:28:D8:ED:42:C4:23:F6:FF:82:64:F9:60:7F:36:9B', u'serial_number': None}
        """
        result, status = self.client.get('/masters/%s/certs/%s' % (self.master.uuid, self.hostname))
        return result

    def delete(self):
        """Deletes a certificate.

        If the certificate has not been revoked yet it will be revoked and deleted.

        :return: None, or raises an exception
        :rtype: None
        """
        result, status = self.client.delete('/masters/%s/certs/%s' % (self.master.uuid, self.hostname))
        return result

    def revoke(self):
        """Revokes a certificate.

        :return: None, or raises an exception
        :rtype: None
        """
        result, status = self.client.post('/masters/%s/certs/%s/revoke' % (self.master.uuid, self.hostname))
        return result

    def sign(self):
        """Signes a certificate.

        :return: None, or raises an exception
        :rtype: None
        """
        result, status = self.client.post('/masters/%s/certs/%s/sign' % (self.master.uuid, self.hostname))
        return result

    def __repr__(self):
        """String representation of the object"""
        return "<Agent Certificate %s@%s>" % (self.hostname, self.master.uuid)

    def __getattr__(self, name):
        """Retrieves an attribute of the class.

        This is kind of a hack. We use the __getattr__ method to access fields of the
        json representation of the class. For instance if my class is represented by

        {
            "foo": "bar",
            "lel": true
        }

        Then obj.foo will return be "bar" eventough the property has not been defined
        in an explicit way.

        :param name: Name of the attribute you want to retrieve
        :type name: str

        :return: The value of the field
        :rtype: Any primitive type
        """
        data, status = self.client.get('/masters/%s/certs/%s' % (self.master.uuid, self.hostname))
        if name in data:
            return data[name]
        return super(Certificate, self).__getattr__(name)
class Master(object):
    """Interface for the /masters/<masterId> endpoints.

    This class allows you to interract with your Puppet Masters

    This class has the following behavior:
      * When loaded it will cache some data in self.cached_data (it will
        cache its json representation according to the API)
      * Everytime you want to get data from the object, like certificate.fingerprint,
        the cache will be used, so make sure to call reload_datas if updates has been done.
      * Dictionnary lookup is done via the __getattr__ overloaded method. It
        is a bit hacky but it does the job. For instance to get the hostname
        of your master, you can type `master.hostname`, this will query the
        cached value in the object


    An example json representation of what this class may look like :
    .. code-block:: json
        {
            "allowed_networks": [
                "0.0.0.0/0"
            ],
            "ca_certificate": "-----BEGIN [.]CATE-----",
            "created_at": "2015-12-07T13:28:28",
            "deploy_key": "github",
            "hierarchy": [],
            "hieras": [],
            "hostname": "master1.user.puppet.runabove.io",
            "id": "1e42115b-34f9-4f86-a4a7-67e30a24a825",
            "name": "master1",
            "nb": 1,
            "servers": {},
            "source": "[email protected]:puppet/puppet.git",
            "status": {
                "code": 0,
                "msg": "Deploying server"
            },
            "token": "d4K1cxIPklE",
            "type": "eg-7",
            "vars": {}
        }
    """
    def __init__(self, uuid, cached_data=None):
        """Creates a new object representing an *existing* puppet master

        :param uuid: UUID of the master
        :type uuid: str
        :param cached_data: Cached data to instantiate the master
        :type cached_data: dict


        :Example:
        >>> ppaas.Master('0e85b81f-5a29-4e2b-a46c-e024049acb07')
        <Puppet Master 0e85b81f-5a29-4e2b-a46c-e024049acb07>
        >>> master.name
        'thomas'

        .. seealso:: get_masters()
        """
        self.client = ApiClient()
        self.uuid = uuid
        self.reload_data(cached_data)

    def reload_data(self, refreshed_datas=None):
        """Reloads datas in the cached_data properties of the pupet master

        :param refreshed_datas: Data to use to reload cached_data property of master
        :type refreshed_datas: dict

        """
        if refreshed_datas:
            self.cached_data = refreshed_datas
        else:
            self.cached_data, _ = self.client.get('/masters/%s' % self.uuid)

    @staticmethod
    def create_master(name, source, deploy_key, vars={}, nb=1, type=None, hierarchy=[], hieras=[], client=None):
        """ Creates a Pupper master

        :param name: Name of the puppet master
        :type name: str
        :param source: Source git repository of the puppet master
        :type source: str
        :param deploy_key: Deploy key to link with your puppet master
        :type deploy_key: ppaas.DeployKey
        :param nb: Number of servers for the master
        :type nb: int
        :param type: Kind of server to use
        :type type: str
        :param hierarchy: Array of hierarchies
        :type hierarchy: list
        :param hieras: Array of hiera backend
        :type hieras: list
        :param client: A client object you want to pass, if empty a new one will be created
        :type client: ppaas.ApiClient

        :return: The newly created puppet master
        :rtype: Master

        :Example:
        >>> ppaas.Master.create_master("master1", "[email protected]:puppet/puppet.git", "github")
        <Puppet Master 0e85b81f-5a29-4e2b-a46c-e024049acb07>
        >>> master.name
        'master1'

        """
        payload = {"name": name, "source": source, "deploy_key": deploy_key, "nb": nb,
                "hierarchy": hierarchy, "hieras": hieras, "vars": vars}
        if type:
            payload["type"] = type

        if not client:
            client = ApiClient()

        result, _ = client.post("/masters", data=payload)
        return Master(result["id"], result)

    @staticmethod
    def get_masters(client=None):
        """Retrieves all your puppet masters

        :param client: A client object you want to pass, if empty a new one will be created
        :type client: ppaas.ApiClient

        :return: The list of your puppet masters
        :rtype: List of Master objects

        :Example:

        >>> ppaas.Master.get_masters()
        [<Puppet Master 0e85b81f-5a29-4e2b-a46c-e024049acb07>]
        """
        if not client:
            client = ApiClient()
        result, status = client.get('/masters')
        masters = []
        for master in result['masters']:
            masters.append(Master(master['id'], master))
        return masters

    @staticmethod
    def get_master(name, client=None):
        """Gets a master by name, because who the hell can remember uuids ?

        :param name: Name of the Puppet Master you want to retrieve
        :param client: A client object you want to pass, if empty a new one will be created
        :type name: str
        :type client: ppaas.ApiClient

        :return: A Master object, or None if no matching master was found
        :rtype: ppaas.Master, or None

        :Example:

        >>> ppaas.Master.get_master('thomas')
        <Puppet Master 0e85b81f-5a29-4e2b-a46c-e024049acb07>
        """
        if not client:
            client = ApiClient()
        masters = Master.get_masters(client)
        for master in masters:
            if master.cached_data['name'] == name:
                return master
        return None

    def get_certificates(self, status=None):
        """Returns all the certificates attached to a master

        Optionally you can specify a `status` for the certificates. The statuses can either be
          * "SIGNATURE PENDING"
          * "SIGNED"
          * "REVOKED"
        If status is None, all the certifictes will be returned regardless of their status

        Note that it is just for conveinence that this option is provided. From the API's point
        of view we will issue the same request anyway.

        :param status: The status of the certificates
        :type status: str

        :return: A list of matching certificates
        :rtype: List of ppaas.Certificate

        """
        certificates = Certificate.get_certificates(self, self.client)
        if status is None:
            return certificates
        else:
            return [cert for cert in certificates if cert.status['message'] == status]

    def __repr__(self):
        """String representation of the object"""
        return "<Puppet Master %s>" % self.uuid

    def refresh(self):
        """Asks the master to refresh itself.

        You usually want to do it to trigger the pull of your git repository

        :return: Wether the refresh has been accepted
        :rtype: boolean

        .. note:: The API can answer False if a refresh is already in progress.
        """
        try:
            self.client.post('/masters/%s/refresh' % self.uuid)
            return True
        except:
            return False

    def restart(self):
        """Asks the master to restart

        You usually want to do it when you have edited your hiera or your
        custom puppet functions

        :return: Wether the restart has been accepted
        :rtype: boolean
        """
        try:
            self.client.post('/masters/%s/restart' % self.uuid)
            return True
        except:
            return False

    def certificate(self, hostname):
        """Returns the certificate of a particular hostname

        :param hostname: The hostname you want the certificate of
        :type hostname: str

        :return: The ppaas.Certificate object, or raises an exception
        :rtype: ppaas.Certificate
        """
        return Certificate(self, hostname)

    @property
    def crl(self):
        """Gets the CRL of the master

        :return: The CRL
        :rtype: str
        """
        data, result = self.client.get('/masters/%s/crl' % self.uuid)
        return data['crl']

    @property
    def certificates(self):
        """Gets all the certificates of the master

        :return: The list of the certificates
        :rtype: List of dicts !!!

        .. warnings:: Does not return an object, but a dict
        """
        data, result = self.client.get('/masters/%s/certs' % self.uuid)
        return data['certs']

    @property
    def environments(self):
        """Gets the environments

        It can look like :
        .. code-block:: json
            {
                "environments": {
                    "production": {
                        "settings": {
                            "config_version": "",
                            "environment_timeout": 0,
                            "manifest": "environments/production/manifests",
                            "modulepath": [
                                "/etc/puppet/environments/production/modules",
                                "/etc/puppet/modules",
                                "/usr/share/puppet/modules"
                            ]
                        }
                    }
                }
            }

        :return: The environments of the master
        :rtype: dictionary
        """
        data, result = self.client.get('/masters/%s/environments' % self.uuid)
        return data['environments']

    @property
    def last_update(self):
        """Gets the last update of the master

        Can look like: "2015-12-07T13:28:28"

        :return: Last master update
        :rtype: str
        """
        data, result = self.client.get('/masters/%s/last-update' % self.uuid)
        return data['result']

    def to_dict(self):
        """Returns the JSON representation of the object"

        :return: A dictionary containing the object as served by the API
        :rtype: dict
        """
        result, status = self.client.get('/masters')
        return result

    def __getattr__(self, name):
        """Retrieves an attribute of the class.

        This is kind of a hack. We use the __getattr__ method to access fields of the
        json representation of the class. For instance if my class is represented by

        {
            "foo": "bar",
            "lel": true
        }

        Then obj.foo will return be "bar" eventough the property has not been defined
        in an explicit way.

        :param name: Name of the attribute you want to retrieve
        :type name: str

        :return: The value of the field
        :rtype: Any primitive type
        """
        if name in self.cached_data:
            return self.cached_data[name]
        return super(Master, self).__getattr__(name)
Example #29
0
def api_client(url):
    config = Configuration()
    config.host = url + "/v1"
    return ApiClient(config)
Example #30
0
class Certificate(object):
    """Interface for the /masters/<masterId>/certs endpoints.

    This class allows you to interract with your agent certificates.

    This class has the following behavior:
      * When loaded it will cache some data in self.cached_data (it will
        cache its json representation according to the API)
      * Everytime you want to get data from the object, like certificate.fingerprint,
        an HTTP call will be issued, so make sure to use the cache if needed.
      * Dictionnary lookup is done via the __getattr__ overloaded method. It
        is a bit hacky but it does the job. For instance to get the fingerprint
        of your certificate, you can type `cert.fingerprint`, this will issue an
        HTTP request and return the corresponding dictionary value

    An example json representation of what this class may look like :
    .. code-block:: json
        {
            "created_at": "2015-12-07T13:28:28",
            "fingerprint": "A7:DA:BE:17:09:9E:18:7D:E6:24:25:7C:65:48:EF",
            "hostname": "web.domain.tld",
            "revoked_at": null,
            "serial_number": null,
            "signed_at": null,
            "status": {
                "code": 0,
                "message": "SIGNATURE PENDING"
            }
        }
    """
    def __init__(self, master, hostname):
        """Creates a new object representing an *existing* agent certificate

        :param master: The Master the wanted certificate is attached to
        :param hostname: The hostname of the agent
        :type master: ppaas.Master
        :type hostname: str

        :Example:
        >>> ppaas.Master.get_masters()
        [<Puppet Master 0e85b81f-5a29-4e2b-a46c-e024049acb07>]
        >>> master = _[0]
        >>> ppaas.Certificate(master, 'machine.maurice.fr')
        <Agent Certificate machine.maurice.fr@0e85b81f-5a29-4e2b-a46c-e024049acb07>

        .. note:: You will probably never call this directly and instead use the
                  ppaas.Master.certificate() method instead
        .. seealso:: get_certificates(), ppaas.Master.certificate()
        """
        self.client = ApiClient()
        self.hostname = hostname
        self.master = master
        self.cached_data, _ = self.client.get('/masters/%s/certs/%s' %
                                              (self.master.uuid, hostname))

    @staticmethod
    def get_certificates(master, client=None):
        """Returns all the agent certificates for a Master

        :param master: The master in question
        :param client: The ApiClient to use
        :type master: ppaas.Master
        :type client: ppaas.ApiClient

        :Example:

        >>> ppaas.Master.get_masters()
        [<Puppet Master 0e85b81f-5a29-4e2b-a46c-e024049acb07>]
        >>> master = _[0]
        >>> ppaas.Certificate.get_certificates(master)
        [<Agent Certificate machine.maurice.fr@0e85b81f-5a29-4e2b-a46c-e024049acb07>]

        .. note:: You will probably never use this method neither and use the one
                  shipped with the Master class I guess.
        """
        if not client:
            client = ApiClient()
        result, status = client.get('/masters/%s/certs' % master.uuid)
        certificates = []
        for certificate in result['certs']:
            certificates.append(Certificate(master, certificate['hostname']))
        return certificates

    def to_dict(self):
        """Returns the JSON representation of the object"

        :return: A dictionary containing the object as served by the API
        :rtype: dict

        :Example:

        >>> ppaas.Certificate(master, 'machine.maurice.fr').to_dict()
        {u'revoked_at': None, u'signed_at': None, u'created_at': u'2016-02-21T11:21:58', u'hostname': u'machine.maurice.fr', u'status': {u'message': u'SIGNATURE PENDING', u'code': 0}, u'fingerprint': u'9F:1F:B2:C6:8F:D2:62:26:7B:A3:49:00:45:6F:D6:81:3A:28:D8:ED:42:C4:23:F6:FF:82:64:F9:60:7F:36:9B', u'serial_number': None}
        """
        result, status = self.client.get('/masters/%s/certs/%s' %
                                         (self.master.uuid, self.hostname))
        return result

    def delete(self):
        """Deletes a certificate.

        If the certificate has not been revoked yet it will be revoked and deleted.

        :return: None, or raises an exception
        :rtype: None
        """
        result, status = self.client.delete('/masters/%s/certs/%s' %
                                            (self.master.uuid, self.hostname))
        return result

    def revoke(self):
        """Revokes a certificate.

        :return: None, or raises an exception
        :rtype: None
        """
        result, status = self.client.post('/masters/%s/certs/%s/revoke' %
                                          (self.master.uuid, self.hostname))
        return result

    def sign(self):
        """Signes a certificate.

        :return: None, or raises an exception
        :rtype: None
        """
        result, status = self.client.post('/masters/%s/certs/%s/sign' %
                                          (self.master.uuid, self.hostname))
        return result

    def __repr__(self):
        """String representation of the object"""
        return "<Agent Certificate %s@%s>" % (self.hostname, self.master.uuid)

    def __getattr__(self, name):
        """Retrieves an attribute of the class.

        This is kind of a hack. We use the __getattr__ method to access fields of the
        json representation of the class. For instance if my class is represented by

        {
            "foo": "bar",
            "lel": true
        }

        Then obj.foo will return be "bar" eventough the property has not been defined
        in an explicit way.

        :param name: Name of the attribute you want to retrieve
        :type name: str

        :return: The value of the field
        :rtype: Any primitive type
        """
        data, status = self.client.get('/masters/%s/certs/%s' %
                                       (self.master.uuid, self.hostname))
        if name in data:
            return data[name]
        return super(Certificate, self).__getattr__(name)
Example #31
0
import os
import sched
import time

from client import ApiClient
from processing import resolve_all

launch_hour = int(os.environ['LAUNCH_HOUR'])
launch_minute = int(os.environ['LAUNCH_MINUTE'])
days_frequency = int(os.environ['DAYS_FREQUENCY'])
scheduler = sched.scheduler(time.time, time.sleep)

host = os.environ['API_HOST']
username = os.environ['API_USERNAME']
password = os.environ['API_PASSWORD']
client = ApiClient(host, username, password)

thread_count = int(os.environ['THREAD_COUNT'])

retry_timeout = 5


def first_login():
    while True:
        try:
            client.login()
            return
        except Exception as e:
            print(f"cant connect to the API: {str(e)}")
            print(f"retrying in {retry_timeout} seconds...")
            time.sleep(retry_timeout)
Example #32
0
# -*- coding: UTF-8 -*-
__author__ = 'mcxiaoke'
"""

数据抓取流程:

1. 使用帐号密码XAuth登录豆瓣,保存AccessToken,如果已经有Token,直接使用,初始化API
2. 读取种子用户ID列表,逐个取User信息写入actions数据表(只执行一次)
3. 读取actions的数据库数据,按以下流程循环:
    1. 检查action_following标志,读取followings列表,写入actions(包括ID和action_user),写入users
    2. 检查action_followers标志,读取followers列表,写入actions(包括ID和action_user),写入users
4. 读取actions的数据库数据,按以下流程循环:
    1. 检查action_user标志,读取user信息,写入actions,写入users

"""

import config
from client import ApiClient

if __name__ == "__main__":
    client = ApiClient(config.API_KEY_SHUO_ANDROID,
                       config.API_SECRET_SHUO_ANDROID)
    if not client.token_code:
        username = raw_input("please input username:"******"please input password:")
        client.auth_with_password(username, password)
        client.save_token()
    print client.token_code
    # print client.me().body
    # print client.user(1376127).body
Example #33
0
class OktawaveApi(object):
    def __init__(self, username, password, debug=False):
        """Initialize the API instance

        Arguments:
        - username (string) - Oktawave account username
        - password (string) - Oktawave account password
        - debug (bool) - enable debug output?
        """
        self.username = username
        self.password = password
        self.debug = debug

    # HELPER METHODS ###
    # methods starting with "_" will not be autodispatched to client commands
    # ###

    def _d(self, what):
        if self.debug:
            print what

    def _init_common(self):
        """Convenience method to initialize CommonService client"""
        if hasattr(self, 'common'):
            return
        self.common = ApiClient(
            jsonapi_common, self.username, self.password, self.debug)
        self._d(self.common)

    def _init_clients(self):
        """Convenience method to initialize ClientsService client"""
        if hasattr(self, 'clients'):
            return
        self.clients = ApiClient(
            jsonapi_clients, self.username, self.password, self.debug)
        self._d(self.clients)

    def _logon(self, only_common=False):
        """Initializes CommonService client and calls LogonUser method.

        Returns the User object, as returned by LogonUser.
        Also sets self.client_id for convenience.
        """
        self._init_common()
        if not only_common:
            self._init_clients()
        if hasattr(self, 'client_object'):
            return self.client_object
        try:
            res = self.common.call(
                'LogonUser',
                user=self.username,
                password=self.password,
                ipAddress=self._get_machine_ip(),
                userAgent="Oktawave CLI")
        except AttributeError:
            raise OktawaveLoginError()
        self.client_id = res['User']['Client']['ClientId']
        self.client_object = res
        return res

    def _simple_vm_method(self, method, vm_id):
        """Wraps around common simple virtual machine method call pattern"""
        self._logon()
        return self.clients.call(method, virtualMachineId=vm_id, clientId=self.client_id)

    def _find_disk(self, disk_id):
        """Finds a disk (OVS) by id"""
        dsp = {
            'ClientId': self.client_id,
        }
        disks = [d for d in self.clients.call(
            'GetDisks', searchParams=dsp)['_results'] if d['ClientHddId'] == disk_id]
        if len(disks) == 0:
            return None
        res = disks[0]
        if res['VirtualMachineHdds'] is None:
            res['VirtualMachineHdds'] = []
        return res

    def _get_machine_ip(self):
        return '127.0.0.1'

    def _dict_item(self, dict_id, key):
        items = self.common.call(
            'GetDictionaryItems', dictionary=dict_id, clientId=self.client_id)
        for item in items:
            item = DictionaryItem(item)
            if item.name == key:
                return item

    def _oci_class(self, class_name):
        """Returns a dictionary item for OCI class with a given name"""
        return self._dict_item(DICT['OCI_CLASSES_DICT_ID'], class_name)

    def _ovs_tier(self, tier):
        """Returns ID of a given disk tier"""
        tier_name = 'Tier ' + str(tier)
        tier_obj = self._dict_item(DICT['OVS_TIERS_DICT_ID'], tier_name)
        if not tier_obj:
            raise OktawaveOVSTierNotFound()
        return tier_obj

    def _ovs_disk_mod(self, disk):
        vms = [
            vm['VirtualMachine']['VirtualMachineId'] for vm in disk['VirtualMachineHdds']]

        lock_vms = [
            vm['VirtualMachine']['VirtualMachineId'] for vm in disk['VirtualMachineHdds'] if
            vm['VirtualMachine']['StatusDictId'] == PowerStatus.PowerOn or
            not vm['IsPrimary']
        ]

        disk_mod = {
            'CapacityGB': disk['CapacityGB'],
            'ClientHddId': disk['ClientHddId'],
            'ClusterId': disk['Cluster']['ClusterId'],
            'HddName': disk['HddName'],
            'IsShared': disk['IsShared'],
            'HddStandardId': disk['HddStandard']['DictionaryItemId'],
            'PaymentTypeId': disk['PaymentType']['DictionaryItemId'],
            'VirtualMachineIds': vms,
            'LockVirtualMachineIds': lock_vms,
        }
        return disk_mod

    def _container_simple(self, container_id):
        """Fetches a container's information using GetContainersSimpleWithVM"""
        self._logon()
        cs = self.clients.call('GetContainersSimpleWithVM', clientId=self.client_id)
        for c in cs:
            self._d([c, container_id])
            if str(c['ContainerId']) == str(container_id):
                return c
        raise OktawaveContainerNotFoundError()

    # API methods below ###

    # General / Account ###

    def Account_Settings(self):
        """Print basic settings of the client account

        args is an object containing at least the following fields:
        - username - Oktawave username
        - password - Oktawave client password
        Typically args will be the object returned from argparse.

        """
        self._logon(only_common=True)
        client = self.client_object
        # TODO: probably get more settings
        return {
            'time_zone': client['TimeZone']['DisplayName'],
            'currency': DictionaryItem(client['Currency']),
            'date_format': DictionaryItem(client['DateFormat']),
            'availability_zone': DictionaryItem(
                self.common.call('GetDictionaryItemById', dictionaryItemId=client['AvailabilityZone'])),
            '24h_clock': client['Is24HourClock'],
        }

    def Account_RunningJobs(self):
        self._logon()
        res = self.common.call('GetRunningOperations', clientId=self.client_id)
        if not res:
            return
        for op in res:
            yield {
                'id': op['AsynchronousOperationId'],
                'creation_date': op['CreationDate'],
                'creation_user_name': op['CreationUserFullName'],
                'type': RawDictionaryItem(op['OperationTypeId'], op['OperationTypeName']),
                'object_type': RawDictionaryItem(op['ObjectTypeId'], op['ObjectTypeName']),
                'object_name': op['ObjectName'],
                'progress_percent': op['Progress'],
                'status': RawDictionaryItem(op['StatusId'], op['StatusName'])
            }

    def Account_Users(self):
        """Print users in client account."""
        self._logon()
        users = self.clients.call('GetClientUsers', clientId=self.client_id)
        self._d(users)
        for user in users:
            yield {
                'email': user['Email'],
                'name': user['FullName'],
            }

    ### OCI Templates ###

    def templates_in_category(self, category_id, name_filter=''):
        """Lists templates in a category"""
        self._logon()
        data = self.common.call(
            'GetTemplatesByCategory', categoryId=category_id, categorySystemId=None, type=None, clientId=self.client_id)
        if data:
            return dict((template['TemplateId'], template['TemplateName'])
                        for template in data if name_filter in template['TemplateName'])

    def Template_Show(self, template_id):
        """Shows more detailed info about a particular template"""
        self._logon()
        data = self.clients.call('GetTemplate', templateId=template_id, clientId=self.client_id)

        template_category = TemplateCategory(data['TemplateCategory'], None)
        software = [SoftwareItem(item['Software']) for item in data['SoftwareList']]

        return {
            'template_id': data['TemplateId'],
            'template_name': data['TemplateName'],
            'template_category': template_category.tree_path,
            'vm_class_id': data['VMClass']['DictionaryItemId'],
            'vm_class_name': DictionaryItem(data['VMClass']),
            'system_category_name': DictionaryItem(data['TemplateSystemCategory']),
            'label': data['Name'],
            'software': software,
            'eth_count': data['EthernetControllersCount'],
            'connection_type': DictionaryItem(data['ConnectionType']),
            'disks': [{
                'name': hdd['HddName'],
                'capacity_gb': hdd['CapacityGB'],
                'is_primary': hdd['IsPrimary']
            } for hdd in data['DiskDrives']],
            'description': data['TemplateDescription']['TemplateDescriptionsNames'][0]['Description'],
        }

    def Template_List(self, origin, name_filter=''):
        """Lists templates of a chosen origin"""
        self._logon()
        data = self.common.call('GetTemplatesByOrigin', clientId=self.client_id, origin=TemplateOrigin(origin).id)
        if data:
            return [{
                'id': template['TemplateId'],
                'name': template['TemplateName'],
                'category': str(TemplateOrigin(origin)),
                'system_category': DictionaryItem(template['TemplateSystemCategory'])
            } for template in data if name_filter in template['TemplateName']]

    ### OCI (VMs) ###

    def OCI_List(self):
        """Lists client's virtual machines' basic info"""
        self._logon()
        vms = self.clients.call('GetVirtualMachinesSimple', clientId=self.client_id)
        self._d(vms)
        for vm in vms:
            yield {
                'id': vm['VirtualMachineId'],
                'name': vm['VirtualMachineName'],
                'status': PowerStatus(vm['StatusDictId']),
            }

    def OCI_ListDetails(self):
        """Lists client's virtual machines"""
        self._logon()
        sp = {'ClientId': self.client_id}
        vms = self.clients.call('GetVirtualMachines', searchParams=sp)
        self._d(vms)
        for vm in vms['_results']:
            yield {
                'id': vm['VirtualMachineId'],
                'name': vm['VirtualMachineName'],
                'status': PowerStatus(vm['StatusDictId']),
                'class_name': DictionaryItem(vm['VMClass']),
                'cpu_mhz': vm['CpuMhz'],
                'cpu_usage_mhz': vm['CpuMhzUsage'],
                'memory_mb': vm['RamMB'],
                'memory_usage_mb': vm['RamMBUsage'],
            }

    def OCI_Restart(self, oci_id):
        """Restarts given VM"""
        self._simple_vm_method('RestartVirtualMachine', oci_id)

    def OCI_TurnOff(self, oci_id, force=False):
        """Turns given VM off"""
        if not force:
            try:
                self._simple_vm_method('ShutdownVirtualMachine', oci_id)
                return
            except OktawaveAPIError:
                # XXX: swallow only the "clean shutdown not supported" exception
                pass

        self._simple_vm_method('TurnoffVirtualMachine', oci_id)

    def OCI_TurnOn(self, oci_id):
        """Turns given virtual machine on"""
        self._simple_vm_method('TurnOnVirtualMachine', oci_id)

    def OCI_Delete(self, oci_id):
        """Deletes given virtual machine"""
        self._simple_vm_method('DeleteVirtualMachine', oci_id)

    def OCI_Logs(self, oci_id):
        """Shows virtual machine logs"""
        self._logon()
        sp = {
            'VirtualMachineId': oci_id,
            'PageSize': 100,
            'SortingDirection': 0,  # descending
        }
        data = self.clients.call(
            'GetVirtualMachineHistories', searchParams=sp, clientId=self.client_id)
        self._d(data)
        for op in data['_results']:
            yield {
                'time': self.clients.parse_date(op['CreationDate']),
                'type': DictionaryItem(op['OperationType']),
                'user_name': op['CreationUser']['FullName'],
                'status': DictionaryItem(op['Status']),
                'parameters': [item['Value'] for item in op['Parameters']],
            }

    def OCI_DefaultPassword(self, oci_id):
        logs = self.OCI_Logs(oci_id)
        for entry in logs:
            if entry['type'] == 'Instance access details':
                try:
                    return entry['parameters'][0]
                except IndexError:
                    return  # no data yet

    def OCI_Settings(self, oci_id):
        """Shows basic VM settings (IP addresses, OS, names, autoscaling etc.)"""
        data = self._simple_vm_method('GetVirtualMachineById', oci_id)

        res = {
            'autoscaling': DictionaryItem(data['AutoScalingType']),
            'connection_type': DictionaryItem(data['ConnectionType']),
            'cpu_mhz': data['CpuMhz'],
            'cpu_usage_mhz': data['CpuMhzUsage'],
            'creation_date': self.clients.parse_date(data['CreationDate']),
            'creation_user_name': data['CreationUserSimple']['FullName'],
            'iops_usage': data['IopsUsage'],
            'last_change_date': self.clients.parse_date(data['LastChangeDate']),
            'payment_type': DictionaryItem(data['PaymentType']),
            'memory_mb': data['RamMB'],
            'memory_usage_mb': data['RamMBUsage'],
            'status': DictionaryItem(data['Status']),
            'name': data['VirtualMachineName'],
            'vm_class_name': DictionaryItem(data['VMClass']),
            'disks': [{
                'id': disk['ClientHddId'],
                'name': disk['ClientHdd']['HddName'],
                'capacity_gb': disk['ClientHdd']['CapacityGB'],
                'creation_date': self.clients.parse_date(disk['ClientHdd']['CreationDate']),
                'creation_user_name': disk['ClientHdd']['CreationUser']['FullName'],
                'is_primary': disk['IsPrimary'],
                'is_shared': disk['ClientHdd']['IsShared']
            } for disk in data['DiskDrives']],
            'ips': [{
                'ipv4': ip['Address'],
                'netmask': ip['NetMask'],
                'ipv6': ip['AddressV6'],
                'creation_date': self.clients.parse_date(ip['CreationDate']),
                'dhcp_branch': ip['DhcpBranch'],
                'gateway': ip['Gateway'],
                'status': DictionaryItem(ip['IPStatus']),
                'last_change_date': self.clients.parse_date(ip['LastChangeDate']),
                'macaddr': ip['MacAddress'],
            } for ip in data['IPs']],
            'vlans': [],
        }
        if data['PrivateIpv4']:
            res['vlans'] = [{
                'ipv4': vlan['PrivateIpAddress'],
                'creation_date': self.clients.parse_date(vlan['CreationDate']),
                'macaddr': vlan['MacAddress'],
            } for vlan in data['PrivateIpv4']]

        return res

    def OCI_ChangeClass(self, oci_id, oci_class, at_midnight=False):
        """Changes running VM class, potentially rebooting it"""
        oci = self._simple_vm_method('GetVirtualMachineById', oci_id)
        oci_class_obj = self._oci_class(oci_class)
        if not oci_class_obj:
            raise OktawaveOCIClassNotFound()
        oci['VMClass'] = oci_class_obj.item
        self._d(oci)
        oci.setdefault('PrivateIpv4', '')
        self.clients.call(
            'UpdateVirtualMachine', machine=oci, clientId=self.client_id, classChangeInScheduler=at_midnight)

    def _subregion_id(self, subregion):
        if str(subregion) == 'Auto':
            return None
        if str(subregion) == '1':
            return 1
        return 4

    def OCI_Create(self, name, template, oci_class=None, forced_type=TemplateType.Machine, db_type=None,
                   subregion='Auto'):
        """Creates a new instance from template"""
        self._logon()
        oci_class_id = None
        if oci_class is not None:
            oci_class_obj = self._oci_class(oci_class)
            if not oci_class_obj:
                raise OktawaveOCIClassNotFound()
            oci_class_id = oci_class_obj.id
        self.clients.call('CreateVirtualMachine',
                          templateId=template,
                          disks=None,
                          additionalDisks=None,
                          machineName=name,
                          selectedClass=oci_class_id,
                          selectedContainer=None,
                          selectedPaymentMethod=DICT['OCI_PAYMENT_ID'],
                          selectedConnectionType=DICT['OCI_CONNECTION_ID'],
                          clientId=self.client_id,
                          providervAppClientId=None,
                          vAppType=forced_type,
                          databaseTypeId=db_type,
                          clientVmParameter=None,
                          autoScalingTypeId=DICT['OCI_AUTOSCALING_ID'],
                          clusterId=self._subregion_id(subregion))

    def OCI_Clone(self, oci_id, name, clonetype):
        """Clones a VM"""
        self._logon()
        self.clients.call('CloneVirtualMachine',
                          virtualMachineId=oci_id,
                          cloneName=name,
                          cloneType=clonetype,
                          clientId=self.client_id)

    # OVS (disks) ###

    def OVS_List(self):
        """Lists disks"""
        self._logon()
        dsp = {
            'ClientId': self.client_id,
        }
        data = self.clients.call('GetDisks', searchParams=dsp)
        for disk in data['_results']:
            if disk['VirtualMachineHdds'] is None:
                vms = []
            else:
                vms = [{
                    'id': vm['VirtualMachine']['VirtualMachineId'],
                    'name': vm['VirtualMachine']['VirtualMachineName'],
                    'primary': vm['IsPrimary'],
                    'vm_status': PowerStatus(vm['VirtualMachine']['StatusDictId']),
                } for vm in disk['VirtualMachineHdds']]
            yield {
                'id': disk['ClientHddId'],
                'name': disk['HddName'],
                'tier': DictionaryItem(disk['HddStandard']),
                'capacity_gb': disk['CapacityGB'],
                'used_gb': disk['UsedCapacityGB'],
                'is_shared': disk['IsShared'],
                'vms': vms,
            }

    def OVS_Delete(self, ovs_id):
        """Deletes a disk"""
        self._logon()
        res = self.clients.call('DeleteDisk', clientHddId=ovs_id, clientId=self.client_id)
        if not res:
            raise OktawaveOVSDeleteError()

    def OVS_Create(self, name, capacity_gb, tier, shared, subregion='Auto'):
        """Adds a disk"""
        self._logon()
        disk = {
            'CapacityGB': capacity_gb,
            'HddName': name,
            'HddStandardId': self._ovs_tier(tier).id,
            'IsShared': shared,
            'PaymentTypeId': DICT['OVS_PAYMENT_ID'],
            'VirtualMachineIds': [],
            'ClusterId': self._subregion_id(subregion)
        }
        self.clients.call('CreateDisk', clientHdd=disk, clientId=self.client_id)

    def OVS_Map(self, ovs_id, oci_id):
        """Maps a disk into an instance"""
        self._logon()
        disk = self._find_disk(ovs_id)
        if disk is None:
            raise OktawaveOVSNotFoundError()

        disk_mod = self._ovs_disk_mod(disk)
        if oci_id in disk_mod['VirtualMachineIds']:
            raise OktawaveOVSMappedError()
        disk_mod['VirtualMachineIds'].append(oci_id)

        res = self.clients.call('UpdateDisk', clientHdd=disk_mod, clientId=self.client_id)
        if not res:
            raise OktawaveOVSMapError()

    def OVS_Unmap(self, ovs_id, oci_id):
        """Unmaps a disk from an instance"""
        self._logon()
        disk = self._find_disk(ovs_id)
        if disk is None:
            raise OktawaveOVSNotFoundError()

        disk_mod = self._ovs_disk_mod(disk)
        if oci_id not in disk_mod['VirtualMachineIds']:
            raise OktawaveOVSUnmappedError()

        disk_mod['VirtualMachineIds'].remove(oci_id)

        res = self.clients.call('UpdateDisk', clientHdd=disk_mod, clientId=self.client_id)
        if not res:
            raise OktawaveOVSUnmapError()

    def OVS_ChangeTier(self, ovs_id, tier):
        self._logon()
        disk = self._find_disk(ovs_id)
        if disk is None:
            raise OktawaveOVSNotFoundError()

        disk_mod = self._ovs_disk_mod(disk)
        disk_mod['HddStandardId'] = self._ovs_tier(tier).id

        self.clients.call('UpdateDisk', clientHdd=disk_mod, clientId=self.client_id)

    def OVS_Extend(self, ovs_id, capacity_gb):
        self._logon()
        disk = self._find_disk(ovs_id)
        if disk is None:
            raise OktawaveOVSNotFoundError()

        disk_mod = self._ovs_disk_mod(disk)
        if disk_mod.pop('LockVirtualMachineIds'):
            raise OktawaveOVSMappedError()

        if disk_mod['CapacityGB'] > capacity_gb:
            raise OktawaveOVSTooSmallError()

        disk_mod['CapacityGB'] = capacity_gb

        self.clients.call('UpdateDisk', clientHdd=disk_mod, clientId=self.client_id)

    # ORDB (databases) ###

    def ORDB_List(self):
        """Lists databases"""
        self._logon()
        sp = {
            'ClientId': self.client_id,
        }
        data = self.clients.call('GetDatabaseInstances', searchParams=sp)
        for db in data['_results']:
            yield {
                'id': db['VirtualMachineId'],
                'name': db['VirtualMachineName'],
                'type': DictionaryItem(db['DatabaseType']),
                'size': db['Size'],
                'available_space': db['AvailableSpace'],
            }

    ORDB_TurnOn = OCI_TurnOn
    ORDB_TurnOff = OCI_TurnOff
    ORDB_Restart = OCI_Restart
    ORDB_Clone = OCI_Clone

    def ORDB_Delete(self, oci_id, db_name=None):
        """Deletes a database or VM"""
        self._logon()
        if db_name is None:
            self._simple_vm_method('DeleteVirtualMachine', oci_id)
        else:
            self.clients.call(
                'DeleteDatabase', virtualMachineId=oci_id, databaseName=db_name,
                clientId=self.client_id)

    ORDB_Logs = OCI_Logs

    def ORDB_LogicalDatabases(self, oci_id):
        """Shows logical databases"""
        self._logon()
        sp = {
            'ClientId': self.client_id,
        }
        data = self.clients.call('GetDatabaseInstances', searchParams=sp)

        for vm in data['_results']:
            if oci_id is not None and str(vm['VirtualMachineId']) != str(oci_id):
                continue

            for db in vm['Databases']:
                yield {
                    'id': db['VirtualMachineId'],
                    'name': db['DatabaseName'],
                    'type': DictionaryItem(db['DatabaseType']),
                    'encoding': db['Encoding'],
                    'is_running': db['IsRunning'],
                    'qps': db['QPS'],
                    'size': db['Size']
                }

    ORDB_Settings = OCI_Settings

    def ORDB_Create(self, name, template, oci_class=None, subregion='Auto'):
        """Creates a database VM"""
        self._logon()
        data = self.clients.call('GetTemplate', templateId=template, clientId=self.client_id)
        if str(data['TemplateType']['DictionaryItemId']) != str(DICT['DB_VM_CATEGORY']):
            raise OktawaveORDBInvalidTemplateError()
        self.OCI_Create(name, template,
                        forced_type=TemplateType.Database,
                        db_type=data['DatabaseType']['DictionaryItemId'],
                        subregion=subregion,
                        oci_class=oci_class)

    def ORDB_GlobalSettings(self, oci_id):
        """Shows global database engine settings"""
        self._logon()
        data = self.clients.call('GetDatabaseConfig', virtualMachineId=oci_id, clientId=self.client_id)

        for item in data:
            yield {
                'name': item.Name,
                'value': item.Value
            }

    def ORDB_CreateLogicalDatabase(self, oci_id, name, encoding):
        """Creates a new logical database within an instance"""
        self._logon()
        self.clients.call(
            'CreateDatabase',
            virtualMachineId=oci_id,
            databaseName=name,
            encodingDictId=DICT[encoding.upper() + '_ENCODING'],
            clientId=self.client_id)

    def ORDB_BackupLogicalDatabase(self, oci_id, name):
        """Creates a backup of logical database"""
        self._logon()
        self.clients.call('BackupDatabase', virtualMachineId=oci_id,
                          databaseName=name, clientId=self.client_id)

    def ORDB_MoveLogicalDatabase(self, oci_id_from, oci_id_to, name):
        """Moves a logical database"""
        self._logon()
        self.clients.call(
            'MoveDatabase',
            virtualMachineIdFrom=oci_id_from,
            virtualMachineIdTo=oci_id_to,
            databaseName=name,
            clientId=self.client_id)

    def ORDB_Backups(self):
        """Lists logical database backups"""
        self._logon()
        mysql_data = self.clients.call(
            'GetBackups', databaseTypeDictId=DICT['MYSQL_DB'], clientId=self.client_id) or []
        pgsql_data = self.clients.call(
            'GetBackups', databaseTypeDictId=DICT['POSTGRESQL_DB'], clientId=self.client_id) or []

        for b in mysql_data:
            yield {
                'file_name': b['Name'],
                'type': 'MySQL',
                'path': b['ContainerName'] +
                        "/" + b['FullPath']
            }

        for b in pgsql_data:
            yield {
                'file_name': b['Name'],
                'type': 'PostgreSQL',
                'path': b['ContainerName'] +
                        "/" + b['FullPath']
            }

    def ORDB_RestoreLogicalDatabase(self, oci_id, name, backup_file):
        """Restores a database from backup"""
        self._logon()
        self.clients.call('RestoreDatabase', virtualMachineId=oci_id,
                          databaseName=name, backupFileName=backup_file,
                          clientId=self.client_id)

    def Container_List(self):
        """Lists client's containers' basic info"""
        self._logon()
        containers = self.clients.call('GetContainers', clientId=self.client_id)
        for c in containers:
            yield {
                'id': c['ContainerId'],
                'name': c['ContainerName'],
                'vms': c['VirtualMachineCount']
            }

    def Container_Get(self, container_id):
        """Displays a container's information"""
        self._logon()
        c = self.clients.call('GetContainer', containerId=container_id)
        res = {
            'autoscaling': DictionaryItem(c['AutoScalingType']),
            'id': c['ContainerId'],
            'name': c['ContainerName'],
            'healthcheck': c['IsServiceCheckAvailable'],
            'load_balancer': c['IsLoadBalancer'],
            'master_service_id': c['MasterServiceId'],
            'master_service_name': c['MasterServiceName'],
            'proxy_cache': c['IsProxyCache'],
            'ssl': c['IsSSLUsed'],
            'port': c['PortNumber'],
            'schedulers': c['SchedulersCount'],
            'vms': c['VirtualMachineCount'],
            'db_user': c['DatabaseUserLogin'],
            'db_password': c['DatabaseUserPassword']
        }
        for label, item in (
                ('ip_version', 'IPVersion'),
                ('load_balancer_algorithm', 'LoadBalancerAlgorithm'),
                ('service', 'Service'),
                ('session_type', 'SessionType')):
            if c[item]:
                res[label] = DictionaryItem(c[item])
            else:
                res[label] = None
        res['ips'] = [
            {'ipv4': ip['Address'], 'ipv6': ip['AddressV6']} for ip in c['IPs']
        ]
        return res

    def Container_OCIList(self, container_id):
        c_simple = self._container_simple(container_id)
        for vm in c_simple['VirtualMachines']:
            vms = vm['VirtualMachineSimple']
            yield {
                'oci_id': vms['VirtualMachineId'],
                'oci_name': vms['VirtualMachineName'],
                'status': PowerStatus(vms['StatusDictId'])
            }

    def Container_RemoveOCI(self, container_id, oci_id):
        """Removes an instance from container"""
        self._logon()
        c_simple = self._container_simple(container_id)
        found = False
        for vm in c_simple['VirtualMachines']:
            if vm['VirtualMachineId'] == oci_id:
                found = True
                break
        if not found:
            raise OktawaveOCINotInContainer()
        vm_ids = [vm['VirtualMachineId']
                  for vm in c_simple['VirtualMachines']
                  if vm['VirtualMachineId'] != oci_id]
        c = self.clients.call('GetContainer', containerId=container_id)
        self._d(vm_ids)
        self.clients.call('UpdateContainer', container=c, virtualMachinesId=vm_ids)

    def Container_AddOCI(self, container_id, oci_id):
        """Adds an instance to container"""
        self._logon()
        c_simple = self._container_simple(container_id)
        found = False
        for vm in c_simple['VirtualMachines']:
            if vm['VirtualMachineId'] == oci_id:
                found = True
                break
        if found:
            raise OktawaveOCIInContainer()
        vm_ids = [vm['VirtualMachineId']
                  for vm in c_simple['VirtualMachines']] + [oci_id]
        c = self.clients.call('GetContainer', containerId=container_id)
        self.clients.call('UpdateContainer', container=c, virtualMachinesId=vm_ids)

    def Container_Delete(self, container_id):
        self._logon()
        self.clients.call('DeleteContainers', containerIds=[container_id],
                          clientId=self.client_id)

    def _container_service_id(self, service):
        services = {'HTTP': 43, 'HTTPS': 44, 'SMTP': 45, 'MySQL': 287, 'Port': 155}
        return services[service]

    def _load_balancer_algorithm_id(self, algorithm):
        algorithms = {'least_response_time': 282, 'least_connections': 281, 'source_ip_hash': 288, 'round_robin': 612}
        return algorithms[algorithm]

    def _session_type_id(self, s_type):
        s_types = {'none': 47, 'by_source_ip': 46, 'by_cookie': 280}
        return s_types[s_type]

    def _ip_version_id(self, version):
        versions = {'4': 115, '6': 116, 'both': 565}
        return versions[version]

    def _autoscaling_id(self, autoscaling):
        types = {'on': 185, 'off': 184}
        return types[autoscaling]

    def Container_Create(
            self, name, load_balancer, service, port, proxy_cache, ssl,
            healthcheck, master_id, session, lb_algorithm, ip_version, autoscaling):
        if lb_algorithm == 'least_response_time' and service != 'HTTP' and service != 'HTTPS':
            raise OktawaveLRTNotAllowed()
        self._logon()
        vm_ids = [] if master_id is None else [master_id]
        result = self.clients.call('CreateContainer', container={
            'OwnerClientId': self.client_id,
            'ContainerName': name,
            'IsLoadBalancer': load_balancer,
            'Service': {'DictionaryItemId': self._container_service_id(service)},
            'LoadBalancerAlgorithm': {'DictionaryItemId': self._load_balancer_algorithm_id(lb_algorithm)},
            'IsSSLUsed': ssl,
            'IsProxyCache': proxy_cache,
            'MasterServiceId': master_id,
            'PortNumber': port,
            'SessionType': {'DictionaryItemId': self._session_type_id(session)},
            'IPVersion': {'DictionaryItemId': self._ip_version_id(ip_version)},
            'AutoScalingType': {'DictionaryItemId': self._autoscaling_id(autoscaling)},
            'IsServiceCheckAvailable': healthcheck
        }, virtualMachinesId=vm_ids)
        return result

    # TODO: allow to change only selected parameters, add more validation
    # without relying on the UpdateContainer API method.
    def Container_Edit(
            self, container_id, name, load_balancer, service, port, proxy_cache, ssl,
            healthcheck, master_id, session, lb_algorithm, ip_version, autoscaling):
        self._logon()
        if lb_algorithm == 'least_response_time' and service != 'HTTP' and service != 'HTTPS':
            raise OktawaveLRTNotAllowed()
        c = self.clients.call('GetContainer', containerId=container_id)
        c_simple = self._container_simple(container_id)
        c['ContainerName'] = name
        c['IsLoadBalancer'] = load_balancer
        c['Service'] = {'DictionaryItemId': self._container_service_id(service)}
        c['LoadBalancerAlgorithm'] = {'DictionaryItemId': self._load_balancer_algorithm_id(lb_algorithm)}
        c['IsSSLUsed'] = ssl
        c['IsProxyCache'] = proxy_cache
        c['MasterServiceId'] = master_id
        c['PortNumber'] = port
        c['SessionType'] = {'DictionaryItemId': self._session_type_id(session)}
        c['IPVersion'] = {'DictionaryItemId': self._ip_version_id(ip_version)}
        c['AutoScalingType'] = {'DictionaryItemId': self._autoscaling_id(autoscaling)}
        c['AutoScalingTypeDictId'] = self._autoscaling_id(autoscaling)
        c['IsServiceCheckAvailable'] = healthcheck
        self._d(c)
        self.clients.call('UpdateContainer', container=c,
                          virtualMachinesId=[vm['VirtualMachineId'] for vm in c_simple['VirtualMachines']])

    def _address_pool_id(self, name):
        pools = {'10.0.0.0/24': 278, '192.168.0.0/24': 279}
        return pools[name]

    def OPN_List(self):
        """Lists client's OPNs"""
        self._logon()
        vlans = self.clients.call('GetVlansByClientId', clientId=self.client_id)
        for v in vlans:
            yield {
                'id': v['VlanId'],
                'name': v['VlanName'],
                'address_pool': DictionaryItem(v['AddressPool']),
                'payment_type': DictionaryItem(v['PaymentType'])
            }

    def OPN_Get(self, opn_id):
        self._logon()
        v = self.clients.call('GetVlanById', vlanId=opn_id, clientId=self.client_id)
        vms = self.clients.call('GetVirtualMachineVlansByVlanId', vlanId=opn_id, clientId=self.client_id)
        return {
            'id': v['VlanId'],
            'name': v['VlanName'],
            'address_pool': DictionaryItem(v['AddressPool']),
            'payment_type': DictionaryItem(v['PaymentType']),
            'vms': vms
        }

    def OPN_Create(self, name, address_pool):
        self._logon()
        self._d(self.client_object)
        return self.clients.call('CreateVlan', vlan={
            'VlanName': name,
            'AddressPool': {'DictionaryItemId': self._address_pool_id(address_pool)},
            'OwnerClient': self.client_object['Client'],
            'PaymentType': {'DictionaryItemId': DICT['OPN_PAYMENT_ID']},
            'CreationUserId': self.client_id
        })

    def OPN_Delete(self, opn_id):
        self._logon()
        return self.clients.call('DeleteVlan', vlanId=opn_id, clientId=self.client_id)

    def OPN_AddOCI(self, opn_id, oci_id, ip_address):
        self._logon()
        oci = self.clients.call('GetVirtualMachineById', virtualMachineId=oci_id, clientId=self.client_id)
        vlan = self.clients.call('GetVlanById', vlanId=opn_id, clientId=self.client_id)
        for opn in oci['PrivateIpv4']:
            if opn['Vlan']['VlanId'] == opn_id:
                raise OktawaveOCIInOPN()
        oci['PrivateIpv4'].append({
            'PrivateIpAddress': ip_address,
            'VirtualMachine': {'VirtualMachineName': oci['VirtualMachineName'], 'VirtualMachineId': oci_id,
                               'StatusDictId': oci['Status']['DictionaryItemId']},
            'Vlan': vlan,
            'CreationDate': '/Date(' + str(int(time()) * 100) + '+0000)/',
            # for some reason API server does not fill this field automatically
        })
        return self.clients.call('UpdateVirtualMachine', machine=oci, clientId=self.client_id,
                                 classChangeInScheduler=False)

    def OPN_RemoveOCI(self, opn_id, oci_id):
        self._logon()
        oci = self.clients.call('GetVirtualMachineById', virtualMachineId=oci_id, clientId=self.client_id)
        vlan = self.clients.call('GetVlanById', vlanId=opn_id, clientId=self.client_id)
        l1 = len(oci['PrivateIpv4'])
        oci['PrivateIpv4'] = filter(lambda x: x['Vlan']['VlanId'] != opn_id, oci['PrivateIpv4'])
        if l1 == len(oci['PrivateIpv4']):
            raise OktawaveOCINotInOPN()
        return self.clients.call('UpdateVirtualMachine', machine=oci, clientId=self.client_id,
                                 classChangeInScheduler=False)

    def OPN_Rename(self, opn_id, name):
        self._logon()
        vlan = self.clients.call('GetVlanById', vlanId=opn_id, clientId=self.client_id)
        vlan['VlanName'] = name
        return self.clients.call('UpdateVlan', vlan=vlan)
Example #34
0
class OktawaveApi(object):
    def __init__(self, username, password, debug=False):
        """Initialize the API instance

        Arguments:
        - username (string) - Oktawave account username
        - password (string) - Oktawave account password
        - debug (bool) - enable debug output?
        """
        self.username = username
        self.password = password
        self.debug = debug

    # HELPER METHODS ###
    # methods starting with "_" will not be autodispatched to client commands
    # ###

    def _d(self, what):
        if self.debug:
            print what

    def _init_common(self):
        """Convenience method to initialize CommonService client"""
        if hasattr(self, 'common'):
            return
        self.common = ApiClient(jsonapi_common, self.username, self.password,
                                self.debug)
        self._d(self.common)

    def _init_clients(self):
        """Convenience method to initialize ClientsService client"""
        if hasattr(self, 'clients'):
            return
        self.clients = ApiClient(jsonapi_clients, self.username, self.password,
                                 self.debug)
        self._d(self.clients)

    def _logon(self, only_common=False):
        """Initializes CommonService client and calls LogonUser method.

        Returns the User object, as returned by LogonUser.
        Also sets self.client_id for convenience.
        """
        self._init_common()
        if not only_common:
            self._init_clients()
        if hasattr(self, 'client_object'):
            return self.client_object
        try:
            res = self.common.call('LogonUser',
                                   user=self.username,
                                   password=self.password,
                                   ipAddress=self._get_machine_ip(),
                                   userAgent="Oktawave CLI")
        except AttributeError:
            raise OktawaveLoginError()
        self.client_id = res['User']['Client']['ClientId']
        self.client_object = res
        return res

    def _simple_vm_method(self, method, vm_id):
        """Wraps around common simple virtual machine method call pattern"""
        self._logon()
        return self.clients.call(method,
                                 virtualMachineId=vm_id,
                                 clientId=self.client_id)

    def _find_disk(self, disk_id):
        """Finds a disk (OVS) by id"""
        dsp = {
            'ClientId': self.client_id,
        }
        disks = [
            d for d in self.clients.call('GetDisks', searchParams=dsp)
            ['_results'] if d['ClientHddId'] == disk_id
        ]
        if len(disks) == 0:
            return None
        res = disks[0]
        if res['VirtualMachineHdds'] is None:
            res['VirtualMachineHdds'] = []
        return res

    def _get_machine_ip(self):
        return '127.0.0.1'

    def _dict_item(self, dict_id, key):
        items = self.common.call('GetDictionaryItems',
                                 dictionary=dict_id,
                                 clientId=self.client_id)
        for item in items:
            item = DictionaryItem(item)
            if item.name == key:
                return item

    def _oci_class(self, class_name):
        """Returns a dictionary item for OCI class with a given name"""
        return self._dict_item(DICT['OCI_CLASSES_DICT_ID'], class_name)

    def _ovs_tier(self, tier):
        """Returns ID of a given disk tier"""
        tier_name = 'Tier ' + str(tier)
        tier_obj = self._dict_item(DICT['OVS_TIERS_DICT_ID'], tier_name)
        if not tier_obj:
            raise OktawaveOVSTierNotFound()
        return tier_obj

    def _ovs_disk_mod(self, disk):
        vms = [
            vm['VirtualMachine']['VirtualMachineId']
            for vm in disk['VirtualMachineHdds']
        ]

        lock_vms = [
            vm['VirtualMachine']['VirtualMachineId']
            for vm in disk['VirtualMachineHdds']
            if vm['VirtualMachine']['StatusDictId'] == PowerStatus.PowerOn
            or not vm['IsPrimary']
        ]

        disk_mod = {
            'CapacityGB': disk['CapacityGB'],
            'ClientHddId': disk['ClientHddId'],
            'ClusterId': disk['Cluster']['ClusterId'],
            'HddName': disk['HddName'],
            'IsShared': disk['IsShared'],
            'HddStandardId': disk['HddStandard']['DictionaryItemId'],
            'PaymentTypeId': disk['PaymentType']['DictionaryItemId'],
            'VirtualMachineIds': vms,
            'LockVirtualMachineIds': lock_vms,
        }
        return disk_mod

    def _container_simple(self, container_id):
        """Fetches a container's information using GetContainersSimpleWithVM"""
        self._logon()
        cs = self.clients.call('GetContainersSimpleWithVM',
                               clientId=self.client_id)
        for c in cs:
            self._d([c, container_id])
            if str(c['ContainerId']) == str(container_id):
                return c
        raise OktawaveContainerNotFoundError()

    # API methods below ###

    # General / Account ###

    def Account_Settings(self):
        """Print basic settings of the client account

        args is an object containing at least the following fields:
        - username - Oktawave username
        - password - Oktawave client password
        Typically args will be the object returned from argparse.

        """
        self._logon(only_common=True)
        client = self.client_object
        # TODO: probably get more settings
        return {
            'time_zone':
            client['TimeZone']['DisplayName'],
            'currency':
            DictionaryItem(client['Currency']),
            'date_format':
            DictionaryItem(client['DateFormat']),
            'availability_zone':
            DictionaryItem(
                self.common.call('GetDictionaryItemById',
                                 dictionaryItemId=client['AvailabilityZone'])),
            '24h_clock':
            client['Is24HourClock'],
        }

    def Account_RunningJobs(self):
        self._logon()
        res = self.common.call('GetRunningOperations', clientId=self.client_id)
        if not res:
            return
        for op in res:
            yield {
                'id':
                op['AsynchronousOperationId'],
                'creation_date':
                op['CreationDate'],
                'creation_user_name':
                op['CreationUserFullName'],
                'type':
                RawDictionaryItem(op['OperationTypeId'],
                                  op['OperationTypeName']),
                'object_type':
                RawDictionaryItem(op['ObjectTypeId'], op['ObjectTypeName']),
                'object_name':
                op['ObjectName'],
                'progress_percent':
                op['Progress'],
                'status':
                RawDictionaryItem(op['StatusId'], op['StatusName'])
            }

    def Account_Users(self):
        """Print users in client account."""
        self._logon()
        users = self.clients.call('GetClientUsers', clientId=self.client_id)
        self._d(users)
        for user in users:
            yield {
                'email': user['Email'],
                'name': user['FullName'],
            }

    ### OCI Templates ###

    def templates_in_category(self, category_id, name_filter=''):
        """Lists templates in a category"""
        self._logon()
        data = self.common.call('GetTemplatesByCategory',
                                categoryId=category_id,
                                categorySystemId=None,
                                type=None,
                                clientId=self.client_id)
        if data:
            return dict((template['TemplateId'], template['TemplateName'])
                        for template in data
                        if name_filter in template['TemplateName'])

    def Template_Show(self, template_id):
        """Shows more detailed info about a particular template"""
        self._logon()
        data = self.clients.call('GetTemplate',
                                 templateId=template_id,
                                 clientId=self.client_id)

        template_category = TemplateCategory(data['TemplateCategory'], None)
        software = [
            SoftwareItem(item['Software']) for item in data['SoftwareList']
        ]

        return {
            'template_id':
            data['TemplateId'],
            'template_name':
            data['TemplateName'],
            'template_category':
            template_category.tree_path,
            'vm_class_id':
            data['VMClass']['DictionaryItemId'],
            'vm_class_name':
            DictionaryItem(data['VMClass']),
            'system_category_name':
            DictionaryItem(data['TemplateSystemCategory']),
            'label':
            data['Name'],
            'software':
            software,
            'eth_count':
            data['EthernetControllersCount'],
            'connection_type':
            DictionaryItem(data['ConnectionType']),
            'disks': [{
                'name': hdd['HddName'],
                'capacity_gb': hdd['CapacityGB'],
                'is_primary': hdd['IsPrimary']
            } for hdd in data['DiskDrives']],
            'description':
            data['TemplateDescription']['TemplateDescriptionsNames'][0]
            ['Description'],
        }

    def Template_List(self, origin, name_filter=''):
        """Lists templates of a chosen origin"""
        self._logon()
        data = self.common.call('GetTemplatesByOrigin',
                                clientId=self.client_id,
                                origin=TemplateOrigin(origin).id)
        if data:
            return [{
                'id':
                template['TemplateId'],
                'name':
                template['TemplateName'],
                'category':
                str(TemplateOrigin(origin)),
                'system_category':
                DictionaryItem(template['TemplateSystemCategory'])
            } for template in data if name_filter in template['TemplateName']]

    ### OCI (VMs) ###

    def OCI_List(self):
        """Lists client's virtual machines' basic info"""
        self._logon()
        vms = self.clients.call('GetVirtualMachinesSimple',
                                clientId=self.client_id)
        self._d(vms)
        for vm in vms:
            yield {
                'id': vm['VirtualMachineId'],
                'name': vm['VirtualMachineName'],
                'status': PowerStatus(vm['StatusDictId']),
            }

    def OCI_ListDetails(self):
        """Lists client's virtual machines"""
        self._logon()
        sp = {'ClientId': self.client_id}
        vms = self.clients.call('GetVirtualMachines', searchParams=sp)
        self._d(vms)
        for vm in vms['_results']:
            yield {
                'id': vm['VirtualMachineId'],
                'name': vm['VirtualMachineName'],
                'status': PowerStatus(vm['StatusDictId']),
                'class_name': DictionaryItem(vm['VMClass']),
                'cpu_mhz': vm['CpuMhz'],
                'cpu_usage_mhz': vm['CpuMhzUsage'],
                'memory_mb': vm['RamMB'],
                'memory_usage_mb': vm['RamMBUsage'],
            }

    def OCI_Restart(self, oci_id):
        """Restarts given VM"""
        self._simple_vm_method('RestartVirtualMachine', oci_id)

    def OCI_TurnOff(self, oci_id, force=False):
        """Turns given VM off"""
        if not force:
            try:
                self._simple_vm_method('ShutdownVirtualMachine', oci_id)
                return
            except OktawaveAPIError:
                # XXX: swallow only the "clean shutdown not supported" exception
                pass

        self._simple_vm_method('TurnoffVirtualMachine', oci_id)

    def OCI_TurnOn(self, oci_id):
        """Turns given virtual machine on"""
        self._simple_vm_method('TurnOnVirtualMachine', oci_id)

    def OCI_Delete(self, oci_id):
        """Deletes given virtual machine"""
        self._simple_vm_method('DeleteVirtualMachine', oci_id)

    def OCI_Logs(self, oci_id):
        """Shows virtual machine logs"""
        self._logon()
        sp = {
            'VirtualMachineId': oci_id,
            'PageSize': 100,
            'SortingDirection': 0,  # descending
        }
        data = self.clients.call('GetVirtualMachineHistories',
                                 searchParams=sp,
                                 clientId=self.client_id)
        self._d(data)
        for op in data['_results']:
            yield {
                'time': self.clients.parse_date(op['CreationDate']),
                'type': DictionaryItem(op['OperationType']),
                'user_name': op['CreationUser']['FullName'],
                'status': DictionaryItem(op['Status']),
                'parameters': [item['Value'] for item in op['Parameters']],
            }

    def OCI_DefaultPassword(self, oci_id):
        logs = self.OCI_Logs(oci_id)
        for entry in logs:
            if entry['type'] == 'Instance access details':
                try:
                    return entry['parameters'][0]
                except IndexError:
                    return  # no data yet

    def OCI_Settings(self, oci_id):
        """Shows basic VM settings (IP addresses, OS, names, autoscaling etc.)"""
        data = self._simple_vm_method('GetVirtualMachineById', oci_id)

        res = {
            'autoscaling':
            DictionaryItem(data['AutoScalingType']),
            'connection_type':
            DictionaryItem(data['ConnectionType']),
            'cpu_mhz':
            data['CpuMhz'],
            'cpu_usage_mhz':
            data['CpuMhzUsage'],
            'creation_date':
            self.clients.parse_date(data['CreationDate']),
            'creation_user_name':
            data['CreationUserSimple']['FullName'],
            'iops_usage':
            data['IopsUsage'],
            'last_change_date':
            self.clients.parse_date(data['LastChangeDate']),
            'payment_type':
            DictionaryItem(data['PaymentType']),
            'memory_mb':
            data['RamMB'],
            'memory_usage_mb':
            data['RamMBUsage'],
            'status':
            DictionaryItem(data['Status']),
            'name':
            data['VirtualMachineName'],
            'vm_class_name':
            DictionaryItem(data['VMClass']),
            'disks': [{
                'id':
                disk['ClientHddId'],
                'name':
                disk['ClientHdd']['HddName'],
                'capacity_gb':
                disk['ClientHdd']['CapacityGB'],
                'creation_date':
                self.clients.parse_date(disk['ClientHdd']['CreationDate']),
                'creation_user_name':
                disk['ClientHdd']['CreationUser']['FullName'],
                'is_primary':
                disk['IsPrimary'],
                'is_shared':
                disk['ClientHdd']['IsShared']
            } for disk in data['DiskDrives']],
            'ips': [{
                'ipv4':
                ip['Address'],
                'netmask':
                ip['NetMask'],
                'ipv6':
                ip['AddressV6'],
                'creation_date':
                self.clients.parse_date(ip['CreationDate']),
                'dhcp_branch':
                ip['DhcpBranch'],
                'gateway':
                ip['Gateway'],
                'status':
                DictionaryItem(ip['IPStatus']),
                'last_change_date':
                self.clients.parse_date(ip['LastChangeDate']),
                'macaddr':
                ip['MacAddress'],
            } for ip in data['IPs']],
            'vlans': [],
        }
        if data['PrivateIpv4']:
            res['vlans'] = [{
                'ipv4':
                vlan['PrivateIpAddress'],
                'creation_date':
                self.clients.parse_date(vlan['CreationDate']),
                'macaddr':
                vlan['MacAddress'],
            } for vlan in data['PrivateIpv4']]

        return res

    def OCI_ChangeClass(self, oci_id, oci_class, at_midnight=False):
        """Changes running VM class, potentially rebooting it"""
        oci = self._simple_vm_method('GetVirtualMachineById', oci_id)
        oci_class_obj = self._oci_class(oci_class)
        if not oci_class_obj:
            raise OktawaveOCIClassNotFound()
        oci['VMClass'] = oci_class_obj.item
        self._d(oci)
        oci.setdefault('PrivateIpv4', '')
        self.clients.call('UpdateVirtualMachine',
                          machine=oci,
                          clientId=self.client_id,
                          classChangeInScheduler=at_midnight)

    def _subregion_id(self, subregion):
        if str(subregion) == 'Auto':
            return None
        if str(subregion) == '1':
            return 1
        return 4

    def OCI_Create(self,
                   name,
                   template,
                   oci_class=None,
                   forced_type=TemplateType.Machine,
                   db_type=None,
                   subregion='Auto'):
        """Creates a new instance from template"""
        self._logon()
        oci_class_id = None
        if oci_class is not None:
            oci_class_obj = self._oci_class(oci_class)
            if not oci_class_obj:
                raise OktawaveOCIClassNotFound()
            oci_class_id = oci_class_obj.id
        self.clients.call('CreateVirtualMachine',
                          templateId=template,
                          disks=None,
                          additionalDisks=None,
                          machineName=name,
                          selectedClass=oci_class_id,
                          selectedContainer=None,
                          selectedPaymentMethod=DICT['OCI_PAYMENT_ID'],
                          selectedConnectionType=DICT['OCI_CONNECTION_ID'],
                          clientId=self.client_id,
                          providervAppClientId=None,
                          vAppType=forced_type,
                          databaseTypeId=db_type,
                          clientVmParameter=None,
                          autoScalingTypeId=DICT['OCI_AUTOSCALING_ID'],
                          clusterId=self._subregion_id(subregion))

    def OCI_Clone(self, oci_id, name, clonetype):
        """Clones a VM"""
        self._logon()
        self.clients.call('CloneVirtualMachine',
                          virtualMachineId=oci_id,
                          cloneName=name,
                          cloneType=clonetype,
                          clientId=self.client_id)

    # OVS (disks) ###

    def OVS_List(self):
        """Lists disks"""
        self._logon()
        dsp = {
            'ClientId': self.client_id,
        }
        data = self.clients.call('GetDisks', searchParams=dsp)
        for disk in data['_results']:
            if disk['VirtualMachineHdds'] is None:
                vms = []
            else:
                vms = [{
                    'id':
                    vm['VirtualMachine']['VirtualMachineId'],
                    'name':
                    vm['VirtualMachine']['VirtualMachineName'],
                    'primary':
                    vm['IsPrimary'],
                    'vm_status':
                    PowerStatus(vm['VirtualMachine']['StatusDictId']),
                } for vm in disk['VirtualMachineHdds']]
            yield {
                'id': disk['ClientHddId'],
                'name': disk['HddName'],
                'tier': DictionaryItem(disk['HddStandard']),
                'capacity_gb': disk['CapacityGB'],
                'used_gb': disk['UsedCapacityGB'],
                'is_shared': disk['IsShared'],
                'vms': vms,
            }

    def OVS_Delete(self, ovs_id):
        """Deletes a disk"""
        self._logon()
        res = self.clients.call('DeleteDisk',
                                clientHddId=ovs_id,
                                clientId=self.client_id)
        if not res:
            raise OktawaveOVSDeleteError()

    def OVS_Create(self, name, capacity_gb, tier, shared, subregion='Auto'):
        """Adds a disk"""
        self._logon()
        disk = {
            'CapacityGB': capacity_gb,
            'HddName': name,
            'HddStandardId': self._ovs_tier(tier).id,
            'IsShared': shared,
            'PaymentTypeId': DICT['OVS_PAYMENT_ID'],
            'VirtualMachineIds': [],
            'ClusterId': self._subregion_id(subregion)
        }
        self.clients.call('CreateDisk',
                          clientHdd=disk,
                          clientId=self.client_id)

    def OVS_Map(self, ovs_id, oci_id):
        """Maps a disk into an instance"""
        self._logon()
        disk = self._find_disk(ovs_id)
        if disk is None:
            raise OktawaveOVSNotFoundError()

        disk_mod = self._ovs_disk_mod(disk)
        if oci_id in disk_mod['VirtualMachineIds']:
            raise OktawaveOVSMappedError()
        disk_mod['VirtualMachineIds'].append(oci_id)

        res = self.clients.call('UpdateDisk',
                                clientHdd=disk_mod,
                                clientId=self.client_id)
        if not res:
            raise OktawaveOVSMapError()

    def OVS_Unmap(self, ovs_id, oci_id):
        """Unmaps a disk from an instance"""
        self._logon()
        disk = self._find_disk(ovs_id)
        if disk is None:
            raise OktawaveOVSNotFoundError()

        disk_mod = self._ovs_disk_mod(disk)
        if oci_id not in disk_mod['VirtualMachineIds']:
            raise OktawaveOVSUnmappedError()

        disk_mod['VirtualMachineIds'].remove(oci_id)

        res = self.clients.call('UpdateDisk',
                                clientHdd=disk_mod,
                                clientId=self.client_id)
        if not res:
            raise OktawaveOVSUnmapError()

    def OVS_ChangeTier(self, ovs_id, tier):
        self._logon()
        disk = self._find_disk(ovs_id)
        if disk is None:
            raise OktawaveOVSNotFoundError()

        disk_mod = self._ovs_disk_mod(disk)
        disk_mod['HddStandardId'] = self._ovs_tier(tier).id

        self.clients.call('UpdateDisk',
                          clientHdd=disk_mod,
                          clientId=self.client_id)

    def OVS_Extend(self, ovs_id, capacity_gb):
        self._logon()
        disk = self._find_disk(ovs_id)
        if disk is None:
            raise OktawaveOVSNotFoundError()

        disk_mod = self._ovs_disk_mod(disk)
        if disk_mod.pop('LockVirtualMachineIds'):
            raise OktawaveOVSMappedError()

        if disk_mod['CapacityGB'] > capacity_gb:
            raise OktawaveOVSTooSmallError()

        disk_mod['CapacityGB'] = capacity_gb

        self.clients.call('UpdateDisk',
                          clientHdd=disk_mod,
                          clientId=self.client_id)

    # ORDB (databases) ###

    def ORDB_List(self):
        """Lists databases"""
        self._logon()
        sp = {
            'ClientId': self.client_id,
        }
        data = self.clients.call('GetDatabaseInstances', searchParams=sp)
        for db in data['_results']:
            yield {
                'id': db['VirtualMachineId'],
                'name': db['VirtualMachineName'],
                'type': DictionaryItem(db['DatabaseType']),
                'size': db['Size'],
                'available_space': db['AvailableSpace'],
            }

    ORDB_TurnOn = OCI_TurnOn
    ORDB_TurnOff = OCI_TurnOff
    ORDB_Restart = OCI_Restart
    ORDB_Clone = OCI_Clone

    def ORDB_Delete(self, oci_id, db_name=None):
        """Deletes a database or VM"""
        self._logon()
        if db_name is None:
            self._simple_vm_method('DeleteVirtualMachine', oci_id)
        else:
            self.clients.call('DeleteDatabase',
                              virtualMachineId=oci_id,
                              databaseName=db_name,
                              clientId=self.client_id)

    ORDB_Logs = OCI_Logs

    def ORDB_LogicalDatabases(self, oci_id):
        """Shows logical databases"""
        self._logon()
        sp = {
            'ClientId': self.client_id,
        }
        data = self.clients.call('GetDatabaseInstances', searchParams=sp)

        for vm in data['_results']:
            if oci_id is not None and str(
                    vm['VirtualMachineId']) != str(oci_id):
                continue

            for db in vm['Databases']:
                yield {
                    'id': db['VirtualMachineId'],
                    'name': db['DatabaseName'],
                    'type': DictionaryItem(db['DatabaseType']),
                    'encoding': db['Encoding'],
                    'is_running': db['IsRunning'],
                    'qps': db['QPS'],
                    'size': db['Size']
                }

    ORDB_Settings = OCI_Settings

    def ORDB_Create(self, name, template, oci_class=None, subregion='Auto'):
        """Creates a database VM"""
        self._logon()
        data = self.clients.call('GetTemplate',
                                 templateId=template,
                                 clientId=self.client_id)
        if str(data['TemplateType']['DictionaryItemId']) != str(
                DICT['DB_VM_CATEGORY']):
            raise OktawaveORDBInvalidTemplateError()
        self.OCI_Create(name,
                        template,
                        forced_type=TemplateType.Database,
                        db_type=data['DatabaseType']['DictionaryItemId'],
                        subregion=subregion,
                        oci_class=oci_class)

    def ORDB_GlobalSettings(self, oci_id):
        """Shows global database engine settings"""
        self._logon()
        data = self.clients.call('GetDatabaseConfig',
                                 virtualMachineId=oci_id,
                                 clientId=self.client_id)

        for item in data:
            yield {'name': item.Name, 'value': item.Value}

    def ORDB_CreateLogicalDatabase(self, oci_id, name, encoding):
        """Creates a new logical database within an instance"""
        self._logon()
        self.clients.call('CreateDatabase',
                          virtualMachineId=oci_id,
                          databaseName=name,
                          encodingDictId=DICT[encoding.upper() + '_ENCODING'],
                          clientId=self.client_id)

    def ORDB_BackupLogicalDatabase(self, oci_id, name):
        """Creates a backup of logical database"""
        self._logon()
        self.clients.call('BackupDatabase',
                          virtualMachineId=oci_id,
                          databaseName=name,
                          clientId=self.client_id)

    def ORDB_MoveLogicalDatabase(self, oci_id_from, oci_id_to, name):
        """Moves a logical database"""
        self._logon()
        self.clients.call('MoveDatabase',
                          virtualMachineIdFrom=oci_id_from,
                          virtualMachineIdTo=oci_id_to,
                          databaseName=name,
                          clientId=self.client_id)

    def ORDB_Backups(self):
        """Lists logical database backups"""
        self._logon()
        mysql_data = self.clients.call('GetBackups',
                                       databaseTypeDictId=DICT['MYSQL_DB'],
                                       clientId=self.client_id) or []
        pgsql_data = self.clients.call(
            'GetBackups',
            databaseTypeDictId=DICT['POSTGRESQL_DB'],
            clientId=self.client_id) or []

        for b in mysql_data:
            yield {
                'file_name': b['Name'],
                'type': 'MySQL',
                'path': b['ContainerName'] + "/" + b['FullPath']
            }

        for b in pgsql_data:
            yield {
                'file_name': b['Name'],
                'type': 'PostgreSQL',
                'path': b['ContainerName'] + "/" + b['FullPath']
            }

    def ORDB_RestoreLogicalDatabase(self, oci_id, name, backup_file):
        """Restores a database from backup"""
        self._logon()
        self.clients.call('RestoreDatabase',
                          virtualMachineId=oci_id,
                          databaseName=name,
                          backupFileName=backup_file,
                          clientId=self.client_id)

    def Container_List(self):
        """Lists client's containers' basic info"""
        self._logon()
        containers = self.clients.call('GetContainers',
                                       clientId=self.client_id)
        for c in containers:
            yield {
                'id': c['ContainerId'],
                'name': c['ContainerName'],
                'vms': c['VirtualMachineCount']
            }

    def Container_Get(self, container_id):
        """Displays a container's information"""
        self._logon()
        c = self.clients.call('GetContainer', containerId=container_id)
        res = {
            'autoscaling': DictionaryItem(c['AutoScalingType']),
            'id': c['ContainerId'],
            'name': c['ContainerName'],
            'healthcheck': c['IsServiceCheckAvailable'],
            'load_balancer': c['IsLoadBalancer'],
            'master_service_id': c['MasterServiceId'],
            'master_service_name': c['MasterServiceName'],
            'proxy_cache': c['IsProxyCache'],
            'ssl': c['IsSSLUsed'],
            'port': c['PortNumber'],
            'schedulers': c['SchedulersCount'],
            'vms': c['VirtualMachineCount'],
            'db_user': c['DatabaseUserLogin'],
            'db_password': c['DatabaseUserPassword']
        }
        for label, item in (('ip_version', 'IPVersion'),
                            ('load_balancer_algorithm',
                             'LoadBalancerAlgorithm'), ('service', 'Service'),
                            ('session_type', 'SessionType')):
            if c[item]:
                res[label] = DictionaryItem(c[item])
            else:
                res[label] = None
        res['ips'] = [{
            'ipv4': ip['Address'],
            'ipv6': ip['AddressV6']
        } for ip in c['IPs']]
        return res

    def Container_OCIList(self, container_id):
        c_simple = self._container_simple(container_id)
        for vm in c_simple['VirtualMachines']:
            vms = vm['VirtualMachineSimple']
            yield {
                'oci_id': vms['VirtualMachineId'],
                'oci_name': vms['VirtualMachineName'],
                'status': PowerStatus(vms['StatusDictId'])
            }

    def Container_RemoveOCI(self, container_id, oci_id):
        """Removes an instance from container"""
        self._logon()
        c_simple = self._container_simple(container_id)
        found = False
        for vm in c_simple['VirtualMachines']:
            if vm['VirtualMachineId'] == oci_id:
                found = True
                break
        if not found:
            raise OktawaveOCINotInContainer()
        vm_ids = [
            vm['VirtualMachineId'] for vm in c_simple['VirtualMachines']
            if vm['VirtualMachineId'] != oci_id
        ]
        c = self.clients.call('GetContainer', containerId=container_id)
        self._d(vm_ids)
        self.clients.call('UpdateContainer',
                          container=c,
                          virtualMachinesId=vm_ids)

    def Container_AddOCI(self, container_id, oci_id):
        """Adds an instance to container"""
        self._logon()
        c_simple = self._container_simple(container_id)
        found = False
        for vm in c_simple['VirtualMachines']:
            if vm['VirtualMachineId'] == oci_id:
                found = True
                break
        if found:
            raise OktawaveOCIInContainer()
        vm_ids = [
            vm['VirtualMachineId'] for vm in c_simple['VirtualMachines']
        ] + [oci_id]
        c = self.clients.call('GetContainer', containerId=container_id)
        self.clients.call('UpdateContainer',
                          container=c,
                          virtualMachinesId=vm_ids)

    def Container_Delete(self, container_id):
        self._logon()
        self.clients.call('DeleteContainers',
                          containerIds=[container_id],
                          clientId=self.client_id)

    def _container_service_id(self, service):
        services = {
            'HTTP': 43,
            'HTTPS': 44,
            'SMTP': 45,
            'MySQL': 287,
            'Port': 155
        }
        return services[service]

    def _load_balancer_algorithm_id(self, algorithm):
        algorithms = {
            'least_response_time': 282,
            'least_connections': 281,
            'source_ip_hash': 288,
            'round_robin': 612
        }
        return algorithms[algorithm]

    def _session_type_id(self, s_type):
        s_types = {'none': 47, 'by_source_ip': 46, 'by_cookie': 280}
        return s_types[s_type]

    def _ip_version_id(self, version):
        versions = {'4': 115, '6': 116, 'both': 565}
        return versions[version]

    def _autoscaling_id(self, autoscaling):
        types = {'on': 185, 'off': 184}
        return types[autoscaling]

    def Container_Create(self, name, load_balancer, service, port, proxy_cache,
                         ssl, healthcheck, master_id, session, lb_algorithm,
                         ip_version, autoscaling):
        if lb_algorithm == 'least_response_time' and service != 'HTTP' and service != 'HTTPS':
            raise OktawaveLRTNotAllowed()
        self._logon()
        vm_ids = [] if master_id is None else [master_id]
        result = self.clients.call(
            'CreateContainer',
            container={
                'OwnerClientId': self.client_id,
                'ContainerName': name,
                'IsLoadBalancer': load_balancer,
                'Service': {
                    'DictionaryItemId': self._container_service_id(service)
                },
                'LoadBalancerAlgorithm': {
                    'DictionaryItemId':
                    self._load_balancer_algorithm_id(lb_algorithm)
                },
                'IsSSLUsed': ssl,
                'IsProxyCache': proxy_cache,
                'MasterServiceId': master_id,
                'PortNumber': port,
                'SessionType': {
                    'DictionaryItemId': self._session_type_id(session)
                },
                'IPVersion': {
                    'DictionaryItemId': self._ip_version_id(ip_version)
                },
                'AutoScalingType': {
                    'DictionaryItemId': self._autoscaling_id(autoscaling)
                },
                'IsServiceCheckAvailable': healthcheck
            },
            virtualMachinesId=vm_ids)
        return result

    # TODO: allow to change only selected parameters, add more validation
    # without relying on the UpdateContainer API method.
    def Container_Edit(self, container_id, name, load_balancer, service, port,
                       proxy_cache, ssl, healthcheck, master_id, session,
                       lb_algorithm, ip_version, autoscaling):
        self._logon()
        if lb_algorithm == 'least_response_time' and service != 'HTTP' and service != 'HTTPS':
            raise OktawaveLRTNotAllowed()
        c = self.clients.call('GetContainer', containerId=container_id)
        c_simple = self._container_simple(container_id)
        c['ContainerName'] = name
        c['IsLoadBalancer'] = load_balancer
        c['Service'] = {
            'DictionaryItemId': self._container_service_id(service)
        }
        c['LoadBalancerAlgorithm'] = {
            'DictionaryItemId': self._load_balancer_algorithm_id(lb_algorithm)
        }
        c['IsSSLUsed'] = ssl
        c['IsProxyCache'] = proxy_cache
        c['MasterServiceId'] = master_id
        c['PortNumber'] = port
        c['SessionType'] = {'DictionaryItemId': self._session_type_id(session)}
        c['IPVersion'] = {'DictionaryItemId': self._ip_version_id(ip_version)}
        c['AutoScalingType'] = {
            'DictionaryItemId': self._autoscaling_id(autoscaling)
        }
        c['AutoScalingTypeDictId'] = self._autoscaling_id(autoscaling)
        c['IsServiceCheckAvailable'] = healthcheck
        self._d(c)
        self.clients.call('UpdateContainer',
                          container=c,
                          virtualMachinesId=[
                              vm['VirtualMachineId']
                              for vm in c_simple['VirtualMachines']
                          ])

    def _address_pool_id(self, name):
        pools = {'10.0.0.0/24': 278, '192.168.0.0/24': 279}
        return pools[name]

    def OPN_List(self):
        """Lists client's OPNs"""
        self._logon()
        vlans = self.clients.call('GetVlansByClientId',
                                  clientId=self.client_id)
        for v in vlans:
            yield {
                'id': v['VlanId'],
                'name': v['VlanName'],
                'address_pool': DictionaryItem(v['AddressPool']),
                'payment_type': DictionaryItem(v['PaymentType'])
            }

    def OPN_Get(self, opn_id):
        self._logon()
        v = self.clients.call('GetVlanById',
                              vlanId=opn_id,
                              clientId=self.client_id)
        vms = self.clients.call('GetVirtualMachineVlansByVlanId',
                                vlanId=opn_id,
                                clientId=self.client_id)
        return {
            'id': v['VlanId'],
            'name': v['VlanName'],
            'address_pool': DictionaryItem(v['AddressPool']),
            'payment_type': DictionaryItem(v['PaymentType']),
            'vms': vms
        }

    def OPN_Create(self, name, address_pool):
        self._logon()
        self._d(self.client_object)
        return self.clients.call('CreateVlan',
                                 vlan={
                                     'VlanName': name,
                                     'AddressPool': {
                                         'DictionaryItemId':
                                         self._address_pool_id(address_pool)
                                     },
                                     'OwnerClient':
                                     self.client_object['Client'],
                                     'PaymentType': {
                                         'DictionaryItemId':
                                         DICT['OPN_PAYMENT_ID']
                                     },
                                     'CreationUserId': self.client_id
                                 })

    def OPN_Delete(self, opn_id):
        self._logon()
        return self.clients.call('DeleteVlan',
                                 vlanId=opn_id,
                                 clientId=self.client_id)

    def OPN_AddOCI(self, opn_id, oci_id, ip_address):
        self._logon()
        oci = self.clients.call('GetVirtualMachineById',
                                virtualMachineId=oci_id,
                                clientId=self.client_id)
        vlan = self.clients.call('GetVlanById',
                                 vlanId=opn_id,
                                 clientId=self.client_id)
        for opn in oci['PrivateIpv4']:
            if opn['Vlan']['VlanId'] == opn_id:
                raise OktawaveOCIInOPN()
        oci['PrivateIpv4'].append({
            'PrivateIpAddress':
            ip_address,
            'VirtualMachine': {
                'VirtualMachineName': oci['VirtualMachineName'],
                'VirtualMachineId': oci_id,
                'StatusDictId': oci['Status']['DictionaryItemId']
            },
            'Vlan':
            vlan,
            'CreationDate':
            '/Date(' + str(int(time()) * 100) + '+0000)/',
            # for some reason API server does not fill this field automatically
        })
        return self.clients.call('UpdateVirtualMachine',
                                 machine=oci,
                                 clientId=self.client_id,
                                 classChangeInScheduler=False)

    def OPN_RemoveOCI(self, opn_id, oci_id):
        self._logon()
        oci = self.clients.call('GetVirtualMachineById',
                                virtualMachineId=oci_id,
                                clientId=self.client_id)
        vlan = self.clients.call('GetVlanById',
                                 vlanId=opn_id,
                                 clientId=self.client_id)
        l1 = len(oci['PrivateIpv4'])
        oci['PrivateIpv4'] = filter(lambda x: x['Vlan']['VlanId'] != opn_id,
                                    oci['PrivateIpv4'])
        if l1 == len(oci['PrivateIpv4']):
            raise OktawaveOCINotInOPN()
        return self.clients.call('UpdateVirtualMachine',
                                 machine=oci,
                                 clientId=self.client_id,
                                 classChangeInScheduler=False)

    def OPN_Rename(self, opn_id, name):
        self._logon()
        vlan = self.clients.call('GetVlanById',
                                 vlanId=opn_id,
                                 clientId=self.client_id)
        vlan['VlanName'] = name
        return self.clients.call('UpdateVlan', vlan=vlan)
class DeployKey(object):
    """Interface for the /deploy-keys endpoints.

    This class allows you to interract with your deployments keys.

    This class has the following behavior:
      * When loaded it will cache some data in self.cached_data (it will
        cache its json representation according to the API)
      * Everytime you want to get data from the object, like key.fingerprint,
        the cache will be used, so make sure to call reload_datas if updates has been done.
      * Dictionnary lookup is done via the __getattr__ overloaded method. It
        is a bit hacky but it does the job. For instance to get the public part
        of your key, you can type `key.public`, this will query the
        cached value in the object

    An example json representation of what this class may look like :
    .. code-block:: json
        {
            "created_at": "2015-12-07T13:28:28",
            "name": "github",
            "fingerprint": "69:2f:e1:29:82:10:66:fa:59:a7:1e:22:40:66:1a",
            "public": "ssh-rsa AAAAB3NzaC1yc2EAAAAD[...]XP1BmhOtTOw=="
        }
    """
    def __init__(self, name, cached_data):
        """Creates a new object representing an *existing* deploy key

        :param name: The name of the deploy key you want to load
        :type name: str
        :param cached_data: Cached data to instantiate the master
        :type cached_data: dict

        :Example:

        >>> ppaas.DeployKey('thomas')
        <Deploy Key thomas>
        >>> ppaas.DeployKey('thomas').fingerprint
        u'52:35:1c:6c:12:57:5f:64:48:3b:ef:89:4c:c5:08:f9'
        >>> ppaas.DeployKey('Idontexist').fingerprint
        Traceback (most recent call last):
          File "<stdin>", line 1, in <module>
          File "ppaas/deploy_key.py", line 36, in __init__
            self.cached_data, _ = self.client.get('/deploy-keys/%s' % (self.name))
          File "ppaas/client.py", line 72, in get
            return self.call('GET', self.endpoint + url, params=params)
          File "ppaas/client.py", line 112, in call
            raise ResourceNotFoundError(result)
        ppaas.client.ResourceNotFoundError: {u'message': u'The requested resource could not be found.'}

        .. seealso:: get_deploy_keys(), create_deploy_key()
        """
        self.client = ApiClient()
        self.name = name
        self.reload_data(cached_data)

    def reload_data(self, refreshed_datas=None):
        """Reloads datas in the cached_data properties of a deploy key

        :param refreshed_datas: Data to use to reload cached_data property of deploy key
        :type refreshed_datas: dict

        """
        if refreshed_datas:
            self.cached_data = refreshed_datas
        else:
            self.cached_data, _ = self.client.get('/deploy-keys/%s' % (self.name))

    @staticmethod
    def get_deploy_keys(client=None):
        """Retrieves all your deployment keys.

        :param client: A client object you want to pass, if empty a new one will be created
        :type client: ApiClient

        :return: The list of your deployment keys
        :rtype: List of DeployKey objects

        :Example:

        >>> ppaas.DeployKey.get_deploy_keys()
        [<Deploy Key github>, <Deploy Key thomas>]
        """
        if not client:
            client = ApiClient()
        result, status = client.get('/deploy-keys')
        keys = []
        for key in result['deploy_keys']:
            keys.append(DeployKey(key['name'], key))
        return keys

    @staticmethod
    def create_deploy_key(name, client=None):
        """Creates a new deployment key with a given name.

        :param name: Name of the new key
        :type name: str

        :return: The newly created key
        :rtype: DeployKey

        :Example:

        >>> ppaas.DeployKey.create_deploy_key('fookey')
        <Deploy Key fookey>
        """
        if not client:
            client = ApiClient()
        result, status = client.post('/deploy-keys', data={'name': name})
        return DeployKey(name, result)

    def delete(self):
        """Deletes the current instance of DeployKey.

        :Exemple:

        >>> ppaas.DeployKey.get_deploy_keys()
        [<Deploy Key github>, <Deploy Key thomas>]
        >>> ppaas.DeployKey('github').delete()
        >>> ppaas.DeployKey.get_deploy_keys()
        [<Deploy Key thomas>]

        .. warnings:: This action is irreversible.
        """
        result, status = self.client.delete('/deploy-keys/%s' % (self.name))
        return result

    def __repr__(self):
        """String representation of the object"""
        return "<Deploy Key %s>" % (self.name)

    def __getattr__(self, name):
        """Retrieves an attribute of the class.

        This is kind of a hack. We use the __getattr__ method to access fields of the
        json representation of the class. For instance if my class is represented by

        {
            "foo": "bar",
            "lel": true
        }

        Then obj.foo will return be "bar" eventough the property has not been defined
        in an explicit way.

        :param name: Name of the attribute you want to retrieve
        :type name: str

        :return: The value of the field
        :rtype: Any primitive type
        """
        if name in self.cached_data:
            return self.cached_data[name]
        return super(DeployKey, self).__getattr__(name)
Example #36
0
"""

数据抓取流程:

1. 使用帐号密码XAuth登录豆瓣,保存AccessToken,如果已经有Token,直接使用,初始化API
2. 读取种子用户ID列表,逐个取User信息写入actions数据表(只执行一次)
3. 读取actions的数据库数据,按以下流程循环:
    1. 检查action_following标志,读取followings列表,写入actions(包括ID和action_user),写入users
    2. 检查action_followers标志,读取followers列表,写入actions(包括ID和action_user),写入users
4. 读取actions的数据库数据,按以下流程循环:
    1. 检查action_user标志,读取user信息,写入actions,写入users

"""

import config
from client import ApiClient

if __name__ == "__main__":
    client = ApiClient(config.API_KEY_SHUO_ANDROID, config.API_SECRET_SHUO_ANDROID)
    if not client.token_code:
        username = raw_input("please input username:"******"please input password:")
        client.auth_with_password(username, password)
        client.save_token()
    print client.token_code
    # print client.me().body
    # print client.user(1376127).body


Example #37
0
class OktawaveApi(object):

    def __init__(self, username, password, debug=False):
        """Initialize the API instance

        Arguments:
        - username (string) - Oktawave account username
        - password (string) - Oktawave account password
        - debug (bool) - enable debug output?
        """
        self.username = username
        self.password = password
        self.debug = debug

    # HELPER METHODS ###
    # methods starting with "_" will not be autodispatched to client commands
    # ###

    def _d(self, what):
        if self.debug:
            print what

    def _init_common(self):
        """Convenience method to initialize CommonService client"""
        if hasattr(self, 'common'):
            return
        self.common = ApiClient(
            jsonapi_common, self.username, self.password, self.debug)
        self._d(self.common)

    def _init_clients(self):
        """Convenience method to initialize ClientsService client"""
        if hasattr(self, 'clients'):
            return
        self.clients = ApiClient(
            jsonapi_clients, self.username, self.password, self.debug)
        self._d(self.clients)

    def _logon(self, only_common=False):
        """Initializes CommonService client and calls LogonUser method.

        Returns the User object, as returned by LogonUser.
        Also sets self.client_id for convenience.
        """
        self._init_common()
        if not only_common:
            self._init_clients()
        if hasattr(self, 'client_object'):
            return self.client_object
        try:
            res = self.common.call(
                'LogonUser',
                user=self.username,
                password=self.password,
                ipAddress=self._get_machine_ip(),
                userAgent="Oktawave CLI")
        except AttributeError:
            raise
            raise OktawaveLoginError()
        self.client_id = res['Client']['ClientId']
        self.client_object = res
        return res

    def _dict_names(self, data, field='ItemName'):
        return [item[field] for item in data if item['LanguageDictId'] == 2]

    def _dict_item_name(self, data):
        return self._dict_names(data['DictionaryItemNames'], 'ItemName')[0]

    def _simple_vm_method(self, method, vm_id):
        """Wraps around common simple virtual machine method call pattern"""
        self._logon()
        return self.clients.call(method, virtualMachineId=vm_id, clientId=self.client_id)

    def _find_disk(self, disk_id):
        """Finds a disk (OVS) by id"""
        dsp = {
            'ClientId': self.client_id,
        }
        disks = [d for d in self.clients.call(
            'GetDisks', searchParams=dsp)['_results'] if d['ClientHddId'] == disk_id]
        if len(disks) == 0:
            return None
        res = disks[0]
        if res['VirtualMachineHdds'] is None:
            res['VirtualMachineHdds'] = []
        return res

    def _get_machine_ip(self):
        return '127.0.0.1'

    def _dict_item(self, dict_id, key, default=0):
        items = self.common.call(
            'GetDictionaryItems', dictionaryId=dict_id, clientId=self.client_id)
        name2id = dict((self._dict_item_name(item), item['DictionaryItemId']) for item in items)
        self._d(name2id)
        return name2id.get(key, default)

    def _oci_class_id(self, class_name):
        """Returns ID of an OCI class with a given name"""
        return self._dict_item(DICT['OCI_CLASSES_DICT_ID'], class_name)

    def _ovs_tier_id(self, tier):
        """Returns ID of a given disk tier"""
        tier_name = 'Tier ' + str(tier)
        return self._dict_item(DICT['OVS_TIERS_DICT_ID'], tier_name)

    def _ovs_disk_mod(self, disk):
        vms = [
            vm['VirtualMachine']['VirtualMachineId'] for vm in disk['VirtualMachineHdds']]

        disk_mod = {
            'CapacityGB': disk['CapacityGB'],
            'ClientHddId': disk['ClientHddId'],
            'HddName': disk['HddName'],
            'IsShared': disk['IsShared'],
            'HddStandardId': disk['HddStandard']['DictionaryItemId'],
            'PaymentTypeId': disk['PaymentType']['DictionaryItemId'],
            'VirtualMachineIds': vms,
        }
        return disk_mod

    # API methods below ###

    # General / Account ###

    def Account_Settings(self):
        """Print basic settings of the client account

        args is an object containing at least the following fields:
        - username - Oktawave username
        - password - Oktawave client password
        Typically args will be the object returned from argparse.

        """
        self._logon(only_common=True)
        client = self.client_object
        # TODO: probably get more settings
        return {
            'time_zone': client['TimeZone']['DisplayName'],
            'currency': self._dict_item_name(client['Currency']),
            'date_format': self._dict_item_name(client['DateFormat']),
            'availability_zone': self._dict_item_name(
                self.common.call('GetDictionaryItemById', dictionaryItemId=client['AvailabilityZone'])),
            '24h_clock': client['Is24HourClock'],
        }

    def Account_RunningJobs(self):
        self._logon()
        res = self.common.call('GetRunningOperations', clientId=self.client_id)
        if not res:
            return
        for op in res:
            yield {
                'id': op['AsynchronousOperationId'],
                'creation_date': op['CreationDate'],
                'creation_user_name': op['CreationUserFullName'],
                'type': self._dict_item_name(op['OperationType']),
                'object_type': self._dict_item_name(op['ObjectType']),
                'object_name': op['ObjectName'],
                'progress_percent': op['Progress'],
                'status': self._dict_item_name(op['Status'])
            }

    def Account_Users(self):
        """Print users in client account."""
        self._logon()
        users = self.clients.call('GetClientUsers', clientId=self.client_id)
        self._d(users)
        for user in users:
            yield {
                'email': user['Email'],
                'name': user['FullName'],
            }

    # OCI (VMs) ###

    def OCI_Test(self):
        self._logon()
        self._d(self._oci_class_id('Large'))

    def OCI_TemplateCategories(self):
        """Lists available template categories"""
        self._logon()
        data = self.common.call('GetTemplateCategories', clientId=self.client_id)
        self._d(data)

        def _tc_info(tc, parent_id):
            return {
                'id': tc['TemplateCategoryId'],
                'name': self._dict_names(
                    tc['TemplateCategoryNames'], 'CategoryName')[0],
                'description': self._dict_names(
                    tc['TemplateCategoryNames'], 'CategoryDescription')[0],
                'parent_id': parent_id,
            }

        for tc in data:
            yield _tc_info(tc, None)
            if tc['CategoryChildren'] is not None:
                for tcc in tc['CategoryChildren']:
                    yield _tc_info(tcc, tc['TemplateCategoryId'])

    def OCI_Templates(self, category_id, name_filter=''):
        """Lists templates in a category"""
        self._logon()
        data = self.common.call(
            'GetTemplatesByCategory', categoryId=category_id, categorySystemId=None, type=None, clientId=self.client_id)
        if data:
            return dict((template['TemplateId'], template['TemplateName'])
                        for template in data if name_filter in template['TemplateName'])

    def OCI_TemplateInfo(self, template_id):
        """Shows more detailed info about a particular template"""
        self._logon()
        data = self.clients.call('GetTemplate', templateId=template_id, clientId=self.client_id)

        template_category = '/'.join(self._dict_names(
            data['TemplateCategory']['TemplateCategoryNames'], field='CategoryName'))

        software = ', '.join(
            '/'.join(self._dict_names(s['Software']['SoftwareNames'], field="Name"))
            for s in data['SoftwareList'])

        return {
            'template_id': data['TemplateId'],
            'template_name': data['TemplateName'],
            'template_category': template_category,
            'vm_class_id': data['VMClass']['DictionaryItemId'],
            'vm_class_name': self._dict_item_name(data['VMClass']),
            'system_category_name': self._dict_item_name(data['TemplateSystemCategory']),
            'label': data['Name'],
            'software': software,
            'eth_count': data['EthernetControllersCount'],
            'connection_type': self._dict_item_name(data['ConnectionType']),
            'disks': [{
                'name': hdd['HddName'],
                'capacity_gb': hdd['CapacityGB'],
                'is_primary': hdd['IsPrimary']
                } for hdd in data['DiskDrives']],
            'description': data['Description']
        }

    def OCI_List(self):
        """Lists client's virtual machines' basic info"""
        self._logon()
        vms = self.clients.call('GetVirtualMachinesSimple', clientId=self.client_id)
        self._d(vms)
        for vm in vms:
            yield {
                'id': vm['VirtualMachineId'],
                'name': vm['VirtualMachineName'],
                'status': PowerStatus(vm['StatusDictId']),
            }

    def OCI_ListDetails(self):
        """Lists client's virtual machines"""
        self._logon()
        sp = { 'ClientId': self.client_id }
        vms = self.clients.call('GetVirtualMachines', searchParams=sp)
        self._d(vms)
        for vm in vms['_results']:
            yield {
                'id': vm['VirtualMachineId'],
                'name': vm['VirtualMachineName'],
                'status': PowerStatus(vm['StatusDictId']),
                'class_name': self._dict_item_name(vm['VMClass']),
                'cpu_mhz': vm['CpuMhz'],
                'cpu_usage_mhz': vm['CpuMhzUsage'],
                'memory_mb': vm['RamMB'],
                'memory_usage_mb': vm['RamMBUsage'],
            }

    def OCI_Restart(self, oci_id):
        """Restarts given VM"""
        self._simple_vm_method('RestartVirtualMachine', oci_id)

    def OCI_TurnOff(self, oci_id):
        """Turns given VM off"""
        self._simple_vm_method('TurnoffVirtualMachine', oci_id)

    def OCI_TurnOn(self, oci_id):
        """Turns given virtual machine on"""
        self._simple_vm_method('TurnOnVirtualMachine', oci_id)

    def OCI_Delete(self, oci_id):
        """Deletes given virtual machine"""
        self._simple_vm_method('DeleteVirtualMachine', oci_id)

    def OCI_Logs(self, oci_id):
        """Shows virtual machine logs"""
        self._logon()
        sp = {
            'VirtualMachineId': oci_id,
            'PageSize': 100,
            'SortingDirection': 0,  # descending
        }
        data = self.clients.call(
            'GetVirtualMachineHistories', searchParams=sp, clientId=self.client_id)
        self._d(data)
        for op in data['_results']:
            yield {
                'time': self.clients.parse_date(op['CreationDate']),
                'type': self._dict_item_name(op['OperationType']),
                'user_name': op['CreationUser']['FullName'],
                'status': self._dict_item_name(op['Status']),
                'parameters': [item['Value'] for item in op['Parameters']],
            }

    def OCI_Settings(self, oci_id):
        """Shows basic VM settings (IP addresses, OS, names, autoscaling etc.)"""
        data = self._simple_vm_method('GetVirtualMachineById', oci_id)

        res = {
            'autoscaling': self._dict_item_name(data['AutoScalingType']),
            'connection_type': self._dict_item_name(data['ConnectionType']),
            'cpu_mhz': data['CpuMhz'],
            'cpu_usage_mhz': data['CpuMhzUsage'],
            'creation_date': self.clients.parse_date(data['CreationDate']),
            'creation_user_name': data['CreationUserSimple']['FullName'],
            'iops_usage': data['IopsUsage'],
            'last_change_date': self.clients.parse_date(data['LastChangeDate']),
            'payment_type': self._dict_item_name(data['PaymentType']),
            'memory_mb': data['RamMB'],
            'memory_usage_mb': data['RamMBUsage'],
            'status': self._dict_item_name(data['Status']),
            'name': data['VirtualMachineName'],
            'vm_class_name': self._dict_item_name(data['VMClass']),
            'disks': [{
                'name': disk['ClientHdd']['HddName'],
                'capacity_gb': disk['ClientHdd']['CapacityGB'],
                'creation_date': self.clients.parse_date(disk['ClientHdd']['CreationDate']),
                'creation_user_name': disk['ClientHdd']['CreationUser']['FullName'],
                'is_primary': disk['IsPrimary']
                } for disk in data['DiskDrives']],
            'ips': [{
                'ipv4': ip['Address'],
                'netmask': ip['NetMask'],
                'ipv6': ip['AddressV6'],
                'creation_date': self.clients.parse_date(ip['CreationDate']),
                'dhcp_branch': ip['DhcpBranch'],
                'gateway': ip['Gateway'],
                'status': self._dict_item_name(ip['IPStatus']),
                'last_change_date': self.clients.parse_date(ip['LastChangeDate']),
                'macaddr': ip['MacAddress'],
                } for ip in data['IPs']],
            'vlans': [],
        }
        if data['PrivateIpv4']:
            res['vlans'] = [{
                'ipv4': vlan['PrivateIpAddress'],
                'creation_date': self.clients.parse_date(vlan['CreationDate']),
                'macaddr': vlan['MacAddress'],
                } for vlan in data['PrivateIpv4']]

        return res

    def OCI_ChangeClass(self, oci_id, oci_class, at_midnight=False):
        """Changes running VM class, potentially rebooting it"""
        oci = self._simple_vm_method('GetVirtualMachineById', oci_id)
        oci_class_id = self._oci_class_id(oci_class)
        if not oci_class_id:
            raise OktawaveOCIClassNotFound()
        oci['VMClass'] = self.common.call('GetDictionaryItemById', dictionaryItemId=oci_class_id)
        self._d(oci)
        oci.setdefault('PrivateIpv4', '')
        self.clients.call(
            'UpdateVirtualMachine', machine=oci, clientId=self.client_id, classChangeInScheduler=at_midnight)

    def OCI_Create(self, name, template, oci_class=None, forced_type=TemplateType.Machine, db_type=None):
        """Creates a new instance from template"""
        self._logon()
        oci_class_id = None
        if oci_class is not None:
            oci_class_id = self._oci_class_id(oci_class)
            if not oci_class_id:
                raise OktawaveOCIClassNotFound()
        self.clients.call('CreateVirtualMachine',
                          templateId=template,
                          disks=None,
                          additionalDisks=None,
                          machineName=name,
                          selectedClass=oci_class_id,
                          selectedContainer=None,
                          selectedPaymentMethod=DICT['OCI_PAYMENT_ID'],
                          selectedConnectionType=DICT['OCI_CONNECTION_ID'],
                          clientId=self.client_id,
                          providervAppClientId=None,
                          vAppType=forced_type,
                          databaseTypeId=db_type,
                          clientVmParameter=None,
                          autoScalingTypeId=DICT['OCI_AUTOSCALING_ID']
                          )

    def OCI_Clone(self, oci_id, name, clonetype):
        """Clones a VM"""
        self._logon()
        self.clients.call('CloneVirtualMachine',
                          virtualMachineId=oci_id,
                          cloneName=name,
                          cloneType=clonetype,
                          clientId=self.client_id)

    # OVS (disks) ###

    def OVS_List(self):
        """Lists disks"""
        self._logon()
        dsp = {
            'ClientId': self.client_id,
        }
        data = self.clients.call('GetDisks', searchParams=dsp)
        for disk in data['_results']:
            if disk['VirtualMachineHdds'] is None:
                vms = []
            else:
                vms = [{
                    'id': vm['VirtualMachine']['VirtualMachineId'],
                    'name': vm['VirtualMachine']['VirtualMachineName'],
                    } for vm in disk['VirtualMachineHdds']]
            yield {
                'id': disk['ClientHddId'],
                'name': disk['HddName'],
                'tier': self._dict_item_name(disk['HddStandard']),
                'capacity_gb': disk['CapacityGB'],
                'used_gb': disk['UsedCapacityGB'],
                'is_shared': disk['IsShared'],
                'vms': vms,
            }

    def OVS_Delete(self, ovs_id):
        """Deletes a disk"""
        self._logon()
        res = self.clients.call('DeleteDisk', clientHddId=ovs_id, clientId=self.client_id)
        if not res:
            raise OktawaveOVSDeleteError()

    def OVS_Create(self, name, capacity_gb, tier, shared):
        """Adds a disk"""
        self._logon()
        disk = {
            'CapacityGB': capacity_gb,
            'HddName': name,
            'HddStandardId': self._ovs_tier_id(tier),
            'IsShared': shared,
            'PaymentTypeId': DICT['OVS_PAYMENT_ID'],
            'VirtualMachineIds': [],
        }
        self.clients.call('CreateDisk', clientHdd=disk, clientId=self.client_id)

    def OVS_Map(self, ovs_id, oci_id):
        """Maps a disk into an instance"""
        self._logon()
        disk = self._find_disk(ovs_id)
        if disk is None:
            raise OktawaveOVSNotFoundError()

        disk_mod = self._ovs_disk_mod(disk)
        if oci_id in disk_mod['VirtualMachineIds']:
            raise OktawaveOVSMappedError()
        disk_mod['VirtualMachineIds'].append('oci_id')

        res = self.clients.call('UpdateDisk', clientHdd=disk_mod, clientId=self.client_id)
        if not res:
            raise OktawaveOVSMapError()

    def OVS_Unmap(self, ovs_id, oci_id):
        """Unmaps a disk from an instance"""
        self._logon()
        disk = self._find_disk(ovs_id)
        if disk is None:
            raise OktawaveOVSNotFoundError()

        disk_mod = self._ovs_disk_mod(disk)
        if oci_id not in disk_mod['VirtualMachineIds']:
            raise OktawaveOVSUnmappedError()

        disk_mod['VirtualMachineIds'].remove(oci_id)

        res = self.clients.call('UpdateDisk', clientHdd=disk_mod, clientId=self.client_id)
        if not res:
            raise OktawaveOVSUnmapError()

    def OVS_ChangeTier(self, ovs_id, tier):
        self._logon()
        disk = self._find_disk(ovs_id)
        if disk is None:
            raise OktawaveOVSNotFoundError()

        disk_mod = self._ovs_disk_mod(disk)
        disk_mod['HddStandardId'] = self._ovs_tier_id(tier)

        self.clients.call('UpdateDisk', clientHdd=disk_mod, clientId=self.client_id)

    def OVS_Extend(self, ovs_id, capacity_gb):
        self._logon()
        disk = self._find_disk(ovs_id)
        if disk is None:
            raise OktawaveOVSNotFoundError()

        disk_mod = self._ovs_disk_mod(disk)
        if disk_mod['VirtualMachineIds']:
            raise OktawaveOVSMappedError()

        if disk_mod['CapacityGB'] > capacity_gb:
            raise OktawaveOVSTooSmallError()

        disk_mod['CapacityGB'] = capacity_gb

        self.clients.call('UpdateDisk', clientHdd=disk_mod, clientId=self.client_id)

    # ORDB (databases) ###

    def ORDB_List(self):
        """Lists databases"""
        self._logon()
        sp = {
            'ClientId': self.client_id,
        }
        data = self.clients.call('GetDatabaseInstances', searchParams=sp)
        for db in data['_results']:
            yield {
                'id': db['VirtualMachineId'],
                'name': db['VirtualMachineName'],
                'type': self._dict_item_name(db['DatabaseType']),
                'size': db['Size'],
                'available_space': db['AvailableSpace'],
            }

    def ORDB_TurnOn(self, oci_id):
        """Turns a database on"""
        self._simple_vm_method('TurnOnVirtualMachine', oci_id)

    def ORDB_TurnOff(self, oci_id):
        """Turns a database off"""
        self._simple_vm_method('TurnoffVirtualMachine', oci_id)

    def ORDB_Restart(self, oci_id):
        """Restarts a database"""
        self._simple_vm_method('RestartVirtualMachine', oci_id)

    ORDB_Clone = OCI_Clone

    def ORDB_Delete(self, oci_id, db_name=None):
        """Deletes a database or VM"""
        self._logon()
        if db_name is None:
            self._simple_vm_method('DeleteVirtualMachine', oci_id)
        else:
            self.clients.call(
                'DeleteDatabase', virtualMachineId=oci_id, databaseName=db_name,
                clientId=self.client_id)

    ORDB_Logs = OCI_Logs

    def ORDB_LogicalDatabases(self, oci_id):
        """Shows logical databases"""
        self._logon()
        sp = {
            'ClientId': self.client_id,
        }
        data = self.clients.call('GetDatabaseInstances', searchParams=sp)

        for vm in data['_results']:
            if oci_id is not None and str(vm['VirtualMachineId']) != str(oci_id):
                continue

            for db in vm['Databases']:
                yield {
                    'id': db['VirtualMachineId'],
                    'name': db['DatabaseName'],
                    'type': self._dict_item_name(db['DatabaseType']),
                    'encoding': db['Encoding'],
                    'is_running': db['IsRunning'],
                    'qps': db['QPS'],
                    'size': db['Size']
                }

    ORDB_Settings = OCI_Settings

    def ORDB_Create(self, name, template, oci_class=None):
        """Creates a database VM"""
        self._logon()
        data = self.clients.call('GetTemplate', templateId=template, clientId=self.client_id)
        if str(data['TemplateType']['DictionaryItemId']) != str(DICT['DB_VM_CATEGORY']):
            raise OktawaveORDBInvalidTemplateError()
        self.OCI_Create(name, template,
                        forced_type=TemplateType.Database, db_type=data.DatabaseType.DictionaryItemId)

    def ORDB_GlobalSettings(self, oci_id):
        """Shows global database engine settings"""
        self._logon()
        data = self.clients.call('GetDatabaseConfig', virtualMachineId=oci_id, clientId=self.client_id)

        for item in data:
            yield {
                'name': item.Name,
                'value': item.Value
            }

    def ORDB_CreateLogicalDatabase(self, oci_id, name, encoding):
        """Creates a new logical database within an instance"""
        self._logon()
        self.clients.call(
            'CreateDatabase',
            virtualMachineId=oci_id,
            databaseName=name,
            encodingDictId=DICT[encoding.upper() + '_ENCODING'],
            clientId=self.client_id)

    def ORDB_BackupLogicalDatabase(self, oci_id, name):
        """Creates a backup of logical database"""
        self._logon()
        self.clients.call('BackupDatabase', virtualMachineId=oci_id,
                          databaseName=name, clientId=self.client_id)

    def ORDB_MoveLogicalDatabase(self, oci_id_from, oci_id_to, name):
        """Moves a logical database"""
        self._logon()
        self.clients.call(
            'MoveDatabase',
            virtualMachineIdFrom=oci_id_from,
            virtualMachineIdTo=oci_id_to,
            databaseName=name,
            clientId=self.client_id)

    def ORDB_Backups(self):
        """Lists logical database backups"""
        self._logon()
        mysql_data = self.clients.call(
            'GetBackups', databaseTypeDictId=DICT['MYSQL_DB'], clientId=self.client_id) or []
        pgsql_data = self.clients.call(
            'GetBackups', databaseTypeDictId=DICT['POSTGRESQL_DB'], clientId=self.client_id) or []

        for b in mysql_data:
            yield {
                'file_name': b['Name'],
                'type': 'MySQL',
                'path': b['ContainerName'] +
                "/" + b['FullPath']
            }

        for b in pgsql_data:
            yield {
                'file_name': b['Name'],
                'type': 'PostgreSQL',
                'path': b['ContainerName'] +
                "/" + b['FullPath']
            }

    def ORDB_RestoreLogicalDatabase(self, oci_id, name, backup_file):
        """Restores a database from backup"""
        self._logon()
        self.clients.call('RestoreDatabase', virtualMachineId=oci_id,
                          databaseName=name, backupFileName=backup_file,
                          clientId=self.client_id)