Esempio n. 1
0
    def allocate_ip(self, linode, public=True):
        """
        Allocates an IP to a Linode you own.  Additional IPs must be requested
        by opening a support ticket first.

        :param linode: The Linode to allocate the new IP for.
        :type linode: Linode or int
        :param public: If True, allocate a public IP address.  Defaults to True.
        :type public: bool

        :returns: The new IPAddress
        :rtype: IPAddress
        """
        result = self.client.post('/networking/ipv4/', data={
            "linode_id": linode.id if isinstance(linode, Base) else linode,
            "type": "ipv4",
            "public": public,
        })

        if not 'address' in result:
            raise UnexpectedResponseError('Unexpected response when adding IPv4 address!',
                    json=result)

        ip = IPAddress(self.client, result['address'], result)
        return ip
Esempio n. 2
0
    def create_domain(self, domain, master=True, **kwargs):
        """
        Registers a new Domain on the acting user's account.  Make sure to point
        your registrar to Linode's nameservers so that Linode's DNS manager will
        correctly serve your domain.

        :param domain: The domain to register to Linode's DNS manager.
        :type domain: str
        :param master: Whether this is a master (defaults to true)
        :type master: bool

        :returns: The new Domain object.
        :rtype: Domain
        """
        params = {
            'domain': domain,
            'type': 'master' if master else 'slave',
        }
        params.update(kwargs)

        result = self.post('/domains', data=params)

        if not 'id' in result:
            raise UnexpectedResponseError('Unexpected response when creating Domain!', json=result)

        d = Domain(self, result['id'], result)
        return d
Esempio n. 3
0
    def create_image(self, disk, label=None, description=None):
        """
        Creates a new Image from a disk you own.

        :param disk: The Disk to imagize.
        :type disk: Disk or int
        :param label: The label for the resulting Image (defaults to the disk's
                      label.
        :type label: str
        :param description: The description for the new Image.
        :type description: str

        :returns: The new Image.
        :rtype: Image
        """
        params = {
            "disk_id": disk.id if issubclass(type(disk), Base) else disk,
        }

        if label is not None:
            params["label"] = label

        if description is not None:
            params["description"] = description

        result = self.post('/images', data=params)

        if not 'id' in result:
            raise UnexpectedResponseError('Unexpected response when creating an '
                                          'Image from disk {}'.format(disk))

        return Image(self, result['id'], result)
Esempio n. 4
0
    def clone(self, to_linode=None, region=None, service=None, configs=[], disks=[],
            label=None, group=None, with_backups=None):
        """ Clones this linode into a new linode or into a new linode in the given region """
        if to_linode and region:
            raise ValueError('You may only specify one of "to_linode" and "region"')

        if region and not service:
            raise ValueError('Specifying a region requires a "service" as well')

        if not isinstance(configs, list) and not isinstance(configs, PaginatedList):
            configs = [configs]
        if not isinstance(disks, list) and not isinstance(disks, PaginatedList):
            disks = [disks]

        cids = [ c.id if issubclass(type(c), Base) else c for c in configs ]
        dids = [ d.id if issubclass(type(d), Base) else d for d in disks ]

        params = {
            "linode_id": to_linode.id if issubclass(type(to_linode), Base) else to_linode,
            "region": region.id if issubclass(type(region), Base) else region,
            "type": service.id if issubclass(type(service), Base) else service,
            "configs": cids if cids else None,
            "disks": dids if dids else None,
            "label": label,
            "group": group,
            "with_backups": with_backups,
        }

        result = self._client.post('{}/clone'.format(Linode.api_endpoint), model=self, data=params)

        if not 'id' in result:
            raise UnexpectedResponseError('Unexpected response cloning Linode!', json=result)

        l = Linode(self._client, result['id'], result)
        return l
Esempio n. 5
0
    def allocate_ip(self, public=False):
        """
        Allocates a new :any:`IPAddress` for this Linode.  Additional public
        IPs require justification, and you may need to open a :any:`SupportTicket`
        before you can add one.  You may only have, at most, one private IP per
        Linode.

        :param public: If the new IP should be public or private.  Defaults to
                       private.
        :type public: bool

        :returns: The new IPAddress
        :rtype: IPAddress
        """
        result = self._client.post(
            "{}/ips".format(Linode.api_endpoint),
            model=self,
            data={
                "type": "ipv4",
                "public": public,
            })

        if not 'address' in result:
            raise UnexpectedResponseError('Unexpected response allocating IP!',
                                          json=result)

        i = IPAddress(self._client, result['address'], result)
        return i
Esempio n. 6
0
    def rebuild(self, image, root_pass=None, authorized_keys=None, **kwargs):
        ret_pass = None
        if not root_pass:
            ret_pass = Linode.generate_root_password()
            root_pass = ret_pass

        authorized_keys = load_and_validate_keys(authorized_keys)

        params = {
             'image': image.id if issubclass(type(image), Base) else image,
             'root_pass': root_pass,
             'authorized_keys': authorized_keys,
         }
        params.update(kwargs)

        result = self._client.post('{}/rebuild'.format(Linode.api_endpoint), model=self, data=params)

        if not 'disks' in result:
            raise UnexpectedResponseError('Unexpected response issuing rebuild!', json=result)

        self.invalidate()
        if not ret_pass:
            return True
        else:
            return ret_pass
Esempio n. 7
0
    def available_backups(self):
        """
        The backups response contains what backups are available to be restored.
        """
        if not hasattr(self, '_avail_backups'):
            result = self._client.get("{}/backups".format(Linode.api_endpoint), model=self)

            if not 'automatic' in result:
                raise UnexpectedResponseError('Unexpected response loading available backups!', json=result)

            automatic = []
            for a in result['automatic']:
                cur = Backup(self._client, a['id'], self.id, a)
                automatic.append(cur)

            snap = None
            if result['snapshot']['current']:
                snap = Backup(self._client, result['snapshot']['current']['id'], self.id,
                        result['snapshot']['current'])

            psnap = None
            if result['snapshot']['in_progress']:
                psnap = Backup(self._client, result['snapshot']['in_progress']['id'], self.id,
                        result['snapshot']['in_progress'])

            self._set('_avail_backups', MappedObject(**{
                "automatic": automatic,
                "snapshot": {
                    "current": snap,
                    "in_progress": psnap,
                }
            }))

        return self._avail_backups
Esempio n. 8
0
    def assign_ips(self, region, *assignments):
        """
        This takes a set of IPv4 Assignments and moves the IPs where they were
        asked to go.  Call this with any number of IPAddress.to(Linode) results

        For example, swapping ips between linode1 and linode2 might look like this:
            client.networking.assign_ips('newark', ip1.to(linode2), ip2.to(linode1))

        """
        for a in assignments:
            if not 'address' in a or not 'linode_id' in a:
                raise ValueError("Invalid assignment: {}".format(a))
        if isinstance(region, Region):
            region = region.id

        result = self.client.post('/networking/ip-assign', data={
            "region": region,
            "assignments": [ a for a in assignments ],
        })

        if not 'ips' in result:
            raise UnexpectedResponseError('Unexpected response when assigning IPs!',
                    json=result)

        ips = []
        for r in result['ips']:
            i = IPAddress(self.client, r['address'])
            i._populate(r)
            ips.append(i)

        return ips
Esempio n. 9
0
    def open_ticket(self, summary, description, regarding=None):
        """

        """
        params = {
            "summary": summary,
            "description": description,
        }

        if regarding:
            if isinstance(regarding, Linode):
                params['linode_id'] = regarding.id
            elif isinstance(regarding, Domain):
                params['domain_id'] = regarding.id
            elif isinstance(regarding, NodeBalancer):
                params['nodebalancer_id'] = regarding.id
            elif isinstance(regarding, Volume):
                params['volume_id'] = regarding.id
            else:
                raise ValueError('Cannot open ticket regarding type {}!'.format(type(regarding)))


        result = self.client.post('/support/tickets', data=params)

        if not 'id' in result:
            raise UnexpectedResponseError('Unexpected response when creating ticket!',
                    json=result)

        t = SupportTicket(self.client, result['id'])
        t._populate(result)
        return t
Esempio n. 10
0
    def create_stackscript(self, label, script, images, desc=None, public=False, **kwargs):
        """
        Creates a new :any:`StackScript` on your account.

        :param label: The label for this StackScript.
        :type label: str
        :param script: The script to run when a :any:`Linode` is deployed with
                       this StackScript.  Must begin with a shebang (#!).
        :type script: str
        :param images: A list of :any:`Images<Image>` that this StackScript
                       supports.  Linodes will not be deployed from this
                       StackScript unless deployed from one of these Images.
        :type images: list of Image
        :param desc: A description for this StackScript.
        :type desc: str
        :param public: Whether this StackScript is public.  Defaults to False.
                       Once a StackScript is made public, it may not be set
                       back to private.
        :type public: bool

        :returns: The new StackScript
        :rtype: StackScript
        """
        image_list = None
        if type(images) is list or type(images) is PaginatedList:
            image_list = [d.id if issubclass(type(d), Base) else d for d in images ]
        elif type(images) is Image:
            image_list = [images.id]
        elif type(images) is str:
            image_list = [images]
        else:
            raise ValueError('images must be a list of Images or a single Image')

        script_body = script
        if not script.startswith("#!"):
            # it doesn't look like a stackscript body, let's see if it's a file
            import os
            if os.path.isfile(script):
                with open(script) as f:
                    script_body = f.read()
            else:
                raise ValueError("script must be the script text or a path to a file")

        params = {
            "label": label,
            "image": image_list,
            "is_public": public,
            "script": script_body,
            "description": desc if desc else '',
        }
        params.update(kwargs)

        result = self.client.post('/linode/stackscripts', data=params)

        if not 'id' in result:
            raise UnexpectedResponseError('Unexpected response when creating StackScript!', json=result)

        s = StackScript(self.client, result['id'], result)
        return s
Esempio n. 11
0
    def duplicate(self):
        result = self._client.post(Disk.api_endpoint, model=self, data={})

        if not 'id' in result:
            raise UnexpectedResponseError('Unexpected response duplicating disk!', json=result)

        d = Disk(self._client, result['id'], self.linode_id, result)
        return d
Esempio n. 12
0
    def allocate_ip(self, public=False):
        result = self._client.post("{}/ips".format(Linode.api_endpoint), model=self,
                data={ "type": "public" if public else "private" })

        if not 'address' in result:
            raise UnexpectedResponseError('Unexpected response allocating IP!', json=result)

        i = IPAddress(self._client, result['address'], result)
        return i
Esempio n. 13
0
    def get_transfer(self):
        """
        Returns a MappedObject containing the account's transfer pool data
        """
        result = self.client.get('/account/transfer')

        if not 'used' in result:
            raise UnexpectedResponseError('Unexpected response when getting Transfer Pool!')

        return MappedObject(**result)
Esempio n. 14
0
    def get_account(self):
        """
        Returns account billing information
        """
        result = self.get('/account')

        if not 'email' in result:
            raise UnexpectedResponseError('Unexpected response when getting account!', json=result)

        return Account(self, result['email'], result)
Esempio n. 15
0
    def ips(self):
        """
        The ips related collection is not normalized like the others, so we have to
        make an ad-hoc object to return for its response
        """
        if not hasattr(self, '_ips'):
            result = self._client.get("{}/ips".format(Linode.api_endpoint), model=self)

            if not "ipv4" in result:
                raise UnexpectedResponseError('Unexpected response loading IPs', json=result)

            v4pub = []
            for c in result['ipv4']['public']:
                i = IPAddress(self._client, c['address'], c)
                v4pub.append(i)

            v4pri = []
            for c in result['ipv4']['private']:
                i = IPAddress(self._client, c['address'], c)
                v4pri.append(i)

            shared_ips = []
            for c in result['ipv4']['shared']:
                i = IPAddress(self._client, c['address'], c)
                shared_ips.append(i)

            v6 = []
            for c in result['ipv6']['addresses']:
                i = IPv6Address(self._client, c['address'], c)
                v6.append(i)

            slaac = IPv6Pool(self._client, result['ipv6']['slaac'])
            link_local = IPv6Pool(self._client, result['ipv6']['link_local'])

            pools = []
            for p in result['ipv6']['global']:
                pools.append(IPv6Pool(self._client, p['range']))

            ips = MappedObject(**{
                "ipv4": {
                    "public": v4pub,
                    "private": v4pri,
                    "shared": shared_ips,
                },
                "ipv6": {
                    "slaac": slaac,
                    "link_local": link_local,
                    "pools": pools,
                    "addresses": v6,
                },
            })

            self._set('_ips', ips)

        return self._ips
    def get_profile(self):
        """
        Returns this token's user's profile.  This is not a listing endpoint.
        """
        result = self.get('/profile')

        if not 'username' in result:
            raise UnexpectedResponseError('Unexpected response when getting profile!', json=result)

        p = Profile(self, result['username'], result)
        return p
    def allocate_ip(self, linode):
        result = self.client.post('/networking/ipv4/', data={
            "linode_id": linode.id if isinstance(linode, Base) else linode,
        })

        if not 'address' in result:
            raise UnexpectedResponseError('Unexpected response when adding IPv4 address!',
                    json=result)

        ip = IPAddress(self.client, result['address'], result)
        return ip
Esempio n. 18
0
    def snapshot(self, label=None):
        result = self._client.post("{}/backups".format(Linode.api_endpoint), model=self,
            data={ "label": label })

        if not 'id' in result:
            raise UnexpectedResponseError('Unexpected response taking snapshot!', json=result)

        # so the changes show up the next time they're accessed
        if hasattr(self, '_avail_backups'):
            del self._avail_backups

        b = Backup(self._client, result['id'], self.id, result)
        return b
    def create_nodebalancer(self, region, **kwargs):
        params = {
            "region": region.id if isinstance(region, Base) else region,
        }
        params.update(kwargs)

        result = self.post('/nodebalancers', data=params)

        if not 'id' in result:
            raise UnexpectedResponseError('Unexpected response when creating Nodebalaner!', json=result)

        n = NodeBalancer(self, result['id'], result)
        return n
Esempio n. 20
0
    def get_settings(self):
        """
        Resturns the account settings data for this acocunt.  This is not  a
        listing endpoint.
        """
        result = self.client.get('/account/settings')

        if not 'managed' in result:
            raise UnexpectedResponseError('Unexpected response when getting account settings!',
                    json=result)

        s = AccountSettings(self.client, result['managed'], result)
        return s
Esempio n. 21
0
    def get_account(self):
        """
        Retrieves information about the acting user's account, such as billing
        information.

        :returns: Returns the acting user's account information.
        :rtype: Account
        """
        result = self.get('/account')

        if not 'email' in result:
            raise UnexpectedResponseError('Unexpected response when getting account!', json=result)

        return Account(self, result['email'], result)
    def create_domain(self, domain, master=True, **kwargs):
        params = {
            'domain': domain,
            'type': 'master' if master else 'slave',
        }
        params.update(kwargs)

        result = self.post('/domains', data=params)

        if not 'id' in result:
            raise UnexpectedResponseError('Unexpected response when creating Domain!', json=result)

        d = Domain(self, result['id'], result)
        return d
Esempio n. 23
0
    def reset_secret(self):
        """
        Resets the client secret for this client.
        """
        result = self._client.post("{}/reset_secret".format(
            OAuthClient.api_endpoint),
                                   model=self)

        if not 'id' in result:
            raise UnexpectedResponseError(
                'Unexpected response when resetting secret!', json=result)

        self._populate(result)
        return self.secret
Esempio n. 24
0
    def _get_objects(self, endpoint, cls, model=None, parent_id=None, filters=None):
        response_json = self.get(endpoint, model=model, filters=filters)

        if not "data" in response_json:
            raise UnexpectedResponseError("Problem with response!", json=response_json)

        if 'pages' in response_json:
            formatted_endpoint = endpoint
            if model:
                formatted_endpoint = formatted_endpoint.format(**vars(model))
            return PaginatedList.make_paginated_list(response_json, self, cls,
                    parent_id=parent_id, page_url=formatted_endpoint[1:],
                    filters=filters)
        return PaginatedList.make_list(response_json["data"], self, cls,
                parent_id=parent_id)
Esempio n. 25
0
    def get_profile(self):
        """
        Retrieve the acting user's Profile, containing information about the
        current user such as their email address, username, and uid.

        :returns: The acting user's profile.
        :rtype: Profile
        """
        result = self.get('/profile')

        if not 'username' in result:
            raise UnexpectedResponseError('Unexpected response when getting profile!', json=result)

        p = Profile(self, result['username'], result)
        return p
Esempio n. 26
0
    def add_whitelist_entry(self, address, netmask, note=None):
        """
        Adds a new entry to this user's IP whitelist, if enabled
        """
        result = self._client.post("{}/whitelist".format(Profile.api_endpoint),
                data={
                    "address": address,
                    "netmask": netmask,
                    "note": note,
        })

        if not 'id' in result:
            raise UnexpectedResponseError("Unexpected response creating whitelist entry!")

        return WhitelistEntry(result['id'], self._client, json=result)
Esempio n. 27
0
    def post_reply(self, description):
        """
        """
        result = self._client.post("{}/replies".format(
            SupportTicket.api_endpoint),
                                   model=self,
                                   data={
                                       "description": description,
                                   })

        if not 'id' in result:
            raise UnexpectedResponseError(
                'Unexpected response when creating ticket reply!', json=result)

        r = TicketReply(self._client, result['id'], self.id, result)
        return r
Esempio n. 28
0
    def rebuild(self, image, root_pass=None, authorized_keys=None, **kwargs):
        """
        Rebuilding a Linode deletes all existing Disks and Configs and deploys
        a new :any:`Image` to it.  This can be used to reset an existing
        Linode or to install an Image on an empty Linode.

        :param image: The Image to deploy to this Linode
        :type image: str or Image
        :param root_pass: The root password for the newly rebuilt Linode.  If
                          omitted, a password will be generated and returned.
        :type root_pass: str
        :param authorized_keys: The ssh public keys to install in the linode's
                                /root/.ssh/authorized_keys file.  Each entry may
                                be a single key, or a path to a file containing
                                the key.
        :type authorized_keys: list or str

        :returns: The newly generated password, if one was not provided
                  (otherwise True)
        :rtype: str or bool
        """
        ret_pass = None
        if not root_pass:
            ret_pass = Linode.generate_root_password()
            root_pass = ret_pass

        authorized_keys = load_and_validate_keys(authorized_keys)

        params = {
             'image': image.id if issubclass(type(image), Base) else image,
             'root_pass': root_pass,
             'authorized_keys': authorized_keys,
         }
        params.update(kwargs)

        result = self._client.post('{}/rebuild'.format(Linode.api_endpoint), model=self, data=params)

        if not 'id' in result:
            raise UnexpectedResponseError('Unexpected response issuing rebuild!', json=result)

        # update ourself with the newly-returned information
        self._populate(result)

        if not ret_pass:
            return True
        else:
            return ret_pass
Esempio n. 29
0
    def create_config(self, label=None, **kwargs):
        params = kwargs
        if label:
            params['label'] = label

        result = self._client.post("{}/configs".format(
            NodeBalancer.api_endpoint),
                                   model=self,
                                   data=params)
        self.invalidate()

        if not 'id' in result:
            raise UnexpectedResponseError(
                'Unexpected response creating config!', json=result)

        c = NodeBalancerConfig(self._client, result['id'], self.id, result)
        return c
def create_user(self, email, username, password, restricted=True):
    """
    Creates a user
    """
    params = {
        "email": email,
        "username": username,
        "password": password,
        "restricted": restricted
    }
    result = self.client.post('/account/users', data=params)

    if not 'email' and 'restricted' and 'username' in result:
        raise UnexpectedResponseError('Unexpected response when creating user!', json=result)

    u = User(self.client, result['username'], result)
    return u