Esempio n. 1
0
    def write(self, key, value, ttl=None, dir=False, append=False, **kwdargs):
        """
        Writes the value for a key, possibly doing atomit Compare-and-Swap

        Args:
            key (str):  Key.

            value (object):  value to set

            ttl (int):  Time in seconds of expiration (optional).

            dir (bool): Set to true if we are writing a directory; default is false.

            append (bool): If true, it will post to append the new value to the dir, creating a sequential key. Defaults to false.

            Other parameters modifying the write method are accepted:


            prevValue (str): compare key to this value, and swap only if corresponding (optional).

            prevIndex (int): modify key only if actual modifiedIndex matches the provided one (optional).

            prevExist (bool): If false, only create key; if true, only update key.

        Returns:
            client.EtcdResult

        >>> print client.write('/key', 'newValue', ttl=60, prevExist=False).value
        'newValue'

        """
        key = self._sanitize_key(key)
        params = {}
        if value is not None:
            params['value'] = value

        if ttl:
            params['ttl'] = ttl

        if dir:
            if value:
                raise etcd.EtcdException(
                    'Cannot create a directory with a value')
            params['dir'] = "true"

        for (k, v) in kwdargs.items():
            if k in self._comparison_conditions:
                if type(v) == bool:
                    params[k] = v and "true" or "false"
                else:
                    params[k] = v

        method = append and self._MPOST or self._MPUT
        if '_endpoint' in kwdargs:
            path = kwdargs['_endpoint'] + key
        else:
            path = self.key_endpoint + key

        response = self.api_execute(path, method, params=params)
        return self._result_from_response(response)
Esempio n. 2
0
    def api_execute(self, path, method, params=None, timeout=None):
        """ Executes the query. """

        some_request_failed = False
        response = False

        if timeout is None:
            timeout = self.read_timeout

        if timeout == 0:
            timeout = None

        if not path.startswith('/'):
            raise ValueError('Path does not start with /')

        while not response:
            try:
                url = self._base_uri + path
                #  if (method == self._MGET) or (method == self._MDELETE):
                #      response = self.http.request(
                #          method,
                #          url,
                #          timeout=timeout,
                #          fields=params,
                #          redirect=self.allow_redirect)

                #  elif (method == self._MPUT) or (method == self._MPOST):
                #      response = self.http.request_encode_body(
                #          method,
                #          url,
                #          fields=params,
                #          timeout=timeout,
                #          encode_multipart=False,
                #          redirect=self.allow_redirect)
                if method in (self._MGET, self._MPUT, self._MPOST,
                              self._MDELETE):
                    from urllib import urlencode
                    response = self.http.request(method,
                                                 url,
                                                 body=urlencode(params))
                if method in (self._MGET, self._MPUT):
                    response = self.http.request(
                        method, "?".join([url, urlencode(params)]))
                elif method in (self._MPOST, self._MDELETE):
                    response = self.http.request(method,
                                                 url,
                                                 body=urlencode(params))
                else:
                    raise etcd.EtcdException(
                        'HTTP method {} not supported'.format(method))

            except urllib3.exceptions.MaxRetryError:
                self._base_uri = self._next_server()
                some_request_failed = True

        if some_request_failed:
            self._machines_cache = self.machines
            self._machines_cache.remove(self._base_uri)
        return self._handle_server_response(response)
Esempio n. 3
0
 def release(self):
     """Release this lock."""
     if not self._index:
         raise etcd.EtcdException(
             u'Cannot release lock that has not been locked')
     params = {u'index': self._index}
     res = self.client.api_execute(self._path,
                                   self.client._MDELETE,
                                   params=params)
     self._index = None
Esempio n. 4
0
 def get(self):
     """
     Get Information on the lock.
     This allows to operate on locks that have not been acquired directly.
     """
     res = self.client.api_execute(self._path, self.client._MGET)
     if res.data:
         self.value = res.data.decode('utf-8')
     else:
         raise etcd.EtcdException('Lock is non-existent (or expired)')
     self._get_index()
     return self
Esempio n. 5
0
 def _result_from_response(self, response):
     """ Creates an EtcdResult from json dictionary """
     try:
         res = json.loads(response.read().decode('utf-8'))
         r = etcd.EtcdResult(**res)
         if response.status_code == 201:
             r.newKey = True
         r.parse_headers(response)
         return r
     except Exception as e:
         raise etcd.EtcdException('Unable to decode server response: %s' %
                                  e)
Esempio n. 6
0
    def renew(self, new_ttl, timeout=None):
        """
        Renew the TTL on this lock.

        Args:
            new_ttl (int): new TTL to set.
        """
        if not self._index:
            raise etcd.EtcdException(
                u'Cannot renew lock that has not been locked')
        params = {u'ttl': new_ttl, u'index': self._index}
        res = self.client.api_execute(self._path,
                                      self.client._MPUT,
                                      params=params)
Esempio n. 7
0
    def get(self, key):
        """
        Get the name of a leader object.

        Args:
            key (string): name of the leader key,

        Raises:
            etcd.EtcdException

        """
        res = self.client.api_execute(self.get_path(key), self.client._MGET)
        if not res.data:
            raise etcd.EtcdException('Leader path {} not found'.format(key))
        return res.data.decode('utf-8')
Esempio n. 8
0
    def _handle_server_response(self, response):
        """ Handles the server response """
        if response.status_code in [200, 201]:
            return response

        else:
            resp = response.read().decode('utf-8')

            # throw the appropriate exception
            try:
                r = json.loads(resp)
            except ValueError:
                r = None
            if r:
                etcd.EtcdError.handle(**r)
            else:
                raise etcd.EtcdException(resp)
Esempio n. 9
0
 def _get_index(self):
     res = self.client.api_execute(self._path, self.client._MGET,
                                   {u'field': u'index'})
     if not res.data:
         raise etcd.EtcdException('Lock is non-existent (or expired)')
     self._index = res.data.decode('utf-8')
Esempio n. 10
0
 def _next_server(self):
     """ Selects the next server in the list, refreshes the server list. """
     try:
         return self._machines_cache.pop()
     except IndexError:
         raise etcd.EtcdException('No more machines in the cluster')