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)
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)
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 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)
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)
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 _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, 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)
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)
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
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)
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 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
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()
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)
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)
def api_client(url): config = Configuration() config.host = url + "/v1" return ApiClient(config)
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)
# -*- 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
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 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)
""" 数据抓取流程: 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
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)