summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGiuseppe Lavagetto <lavagetto@gmail.com>2015-05-10 19:11:25 +0200
committerGiuseppe Lavagetto <lavagetto@gmail.com>2015-05-10 19:11:25 +0200
commit3e64d0af5e0cd0b8d2cdaa145689840b74444c04 (patch)
tree9b4f0d2cad17a5ccacd9b3554cc0f158416812b5 /src
parentf8f69e293443ffcd9c3a73bc077067dedf5ccf94 (diff)
Remove locking and election modules support
Given the lock and election modules have been removed from etcd in recent, stable versions, there is no point in keeping this code lying around. Instead, we will re-implement both functionalities in our library at a later time. At the moment these just make integration tests fail with etcd 2.0.x
Diffstat (limited to 'src')
-rw-r--r--src/etcd/client.py4
-rw-r--r--src/etcd/election.py79
-rw-r--r--src/etcd/lock.py106
-rw-r--r--src/etcd/tests/integration/test_election.py34
-rw-r--r--src/etcd/tests/integration/test_lock.py92
5 files changed, 2 insertions, 313 deletions
diff --git a/src/etcd/client.py b/src/etcd/client.py
index e5acafc..3502162 100644
--- a/src/etcd/client.py
+++ b/src/etcd/client.py
@@ -543,11 +543,11 @@ class Client(object):
yield response
def get_lock(self, *args, **kwargs):
- return etcd.Lock(self, *args, **kwargs)
+ raise NotImplementedError('Lock primitives were removed from etcd 2.0')
@property
def election(self):
- return etcd.LeaderElection(self)
+ raise NotImplementedError('Election primitives were removed from etcd 2.0')
def _result_from_response(self, response):
""" Creates an EtcdResult from json dictionary """
diff --git a/src/etcd/election.py b/src/etcd/election.py
deleted file mode 100644
index 25ea403..0000000
--- a/src/etcd/election.py
+++ /dev/null
@@ -1,79 +0,0 @@
-import etcd
-import platform
-
-
-class LeaderElection(object):
-
- """
- Leader Election class using the etcd module
- """
-
- def __init__(self, client):
- """
- Initialize a leader election object.
-
- Args:
- client (etcd.Client): etcd client to use for the connection
- """
- self.client = client
-
- def get_path(self, key):
- if key.startswith('/'):
- return '/mod/v2/leader{}'.format(key)
- return '/mod/v2/leader/{}'.format(key)
-
- def set(self, key, name=None, ttl=0, timeout=None):
- """
- Initialize a leader election object.
-
- Args:
- key (string): name of the leader key,
-
- ttl (int): ttl (in seconds) for the lock to live.
-
- name (string): the name to store as the leader name. Defaults to the
- client's hostname
-
- """
-
- name = name or platform.node()
- params = {'ttl': ttl, 'name': name}
- path = self.get_path(key)
-
- res = self.client.api_execute(
- path, self.client._MPUT, params=params, timeout=timeout)
- return res.data.decode('utf-8')
-
- 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')
-
- def delete(self, key, name=None):
- """
- Delete a leader object.
-
- Args:
- key (string): the leader key,
-
- name (string): name of the elected leader
-
- Raises:
- etcd.EtcdException
-
- """
- path = self.get_path(key)
- name = name or platform.node()
- res = self.client.api_execute(path, self.client._MDELETE, {'name': name})
- return res.data.decode('utf-8') == ''
diff --git a/src/etcd/lock.py b/src/etcd/lock.py
deleted file mode 100644
index 9068576..0000000
--- a/src/etcd/lock.py
+++ /dev/null
@@ -1,106 +0,0 @@
-import contextlib
-
-import etcd
-
-
-class Lock(object):
-
- """
- Lock object using etcd's lock module.
- """
-
- def __init__(self, client, key, ttl=0, value=None):
- """
- Initialize a lock object.
-
- Args:
- client (Client): etcd client to use for communication.
-
- key (string): key to lock.
-
- ttl (int): ttl (in seconds) for the lock to live.
- 0 or None to lock forever.
-
- value (mixed): value to store on the lock.
- """
- self.client = client
- if not key.startswith('/'):
- key = '/' + key
- self.key = key
- self.ttl = ttl
- self.value = value
- self._index = None
-
- def __enter__(self):
- self.acquire()
-
- def __exit__(self, type, value, traceback):
- self.release()
-
- @property
- def _path(self):
- return u'/mod/v2/lock{}'.format(self.key)
-
- def acquire(self, timeout=None):
- """Acquire the lock from etcd. Blocks until lock is acquired."""
- params = {u'ttl': self.ttl}
- if self.value is not None:
- params[u'value'] = self.value
-
- res = self.client.api_execute(
- self._path, self.client._MPOST, params=params, timeout=timeout)
- self._index = res.data.decode('utf-8')
- return self
-
- 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
-
- 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')
-
- def is_locked(self):
- """Check if lock is currently locked."""
- params = {u'field': u'index'}
- res = self.client.api_execute(
- self._path, self.client._MGET, params=params)
- return bool(res.data)
-
- 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
-
- 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)
diff --git a/src/etcd/tests/integration/test_election.py b/src/etcd/tests/integration/test_election.py
deleted file mode 100644
index 46ea2bb..0000000
--- a/src/etcd/tests/integration/test_election.py
+++ /dev/null
@@ -1,34 +0,0 @@
-import etcd
-from . import test_simple
-import time
-import unittest
-
-class TestElection(test_simple.EtcdIntegrationTest):
- def setUp(self):
- self.client = etcd.Client(port=6001)
-
- def test_set_get_delete(self):
- e = self.client.election
- res = e.set('/mysql', name='foo.example.com', ttl=30)
- self.assertTrue(res != '')
- res = e.get('/mysql')
- self.assertEquals(res, 'foo.example.com')
- self.assertTrue(e.delete('/mysql', name='foo.example.com'))
-
-
- def test_set_invalid_ttl(self):
- self.assertRaises(ValueError, self.client.election.set, '/mysql', name='foo.example.com', ttl='ciao')
-
- def test_get_non_existing(self):
- """This is actually expected to fail. See https://github.com/coreos/etcd/issues/446"""
- self.assertRaises(etcd.EtcdException, self.client.election.get, '/foobar')
-
- def test_delete_non_existing(self):
- self.assertRaises(etcd.EtcdException, self.client.election.delete, '/foobar')
-
- def test_get_delete_after_ttl_expired_raises(self):
- e = self.client.election
- e.set('/mysql', name='foo', ttl=1)
- time.sleep(2)
- self.assertRaises(etcd.EtcdException, e.get, '/mysql')
- self.assertRaises(etcd.EtcdKeyNotFound, e.delete, '/mysql', name='foo')
diff --git a/src/etcd/tests/integration/test_lock.py b/src/etcd/tests/integration/test_lock.py
deleted file mode 100644
index a5d8744..0000000
--- a/src/etcd/tests/integration/test_lock.py
+++ /dev/null
@@ -1,92 +0,0 @@
-import etcd
-from . import test_simple
-import time
-
-class TestLocks(test_simple.EtcdIntegrationTest):
- def setUp(self):
- self.client = etcd.Client(port=6001)
-
- def test_acquire_lock(self):
- """ Can acquire a lock. """
- key = '/testkey'
- ttl = 1
- expected_index = '2'
- lock = self.client.get_lock(key, ttl=ttl).acquire()
- self.assertEquals(lock._index, expected_index)
- lock.release()
- self.assertEquals(lock._index, None)
-
- def test_acquire_lock_invalid_ttl(self):
- """ Invalid TTL throws an error """
- key = '/testkey'
- ttl = 'invalid'
- expected_index = 'invalid'
- lock = self.client.get_lock(key, ttl=ttl)
- self.assertRaises(ValueError, lock.acquire)
-
- def test_acquire_lock_with_context_manager(self):
- key = '/testkey'
- ttl = 1
- lock = self.client.get_lock(key, ttl=ttl)
- with lock:
- self.assertTrue(lock.is_locked())
- self.assertFalse(lock.is_locked())
-
- def test_is_locked(self):
- key = '/testkey'
- ttl = 1
- lock = self.client.get_lock(key, ttl=ttl)
- self.assertFalse(lock.is_locked())
- lock.acquire()
- self.assertTrue(lock.is_locked())
- lock.release()
-
- def test_is_locked_on_expired_key(self):
- key = '/testkey'
- ttl = 1
- lock = self.client.get_lock(key, value='test', ttl=ttl).acquire()
- time.sleep(3)
- self.assertFalse(lock.is_locked())
-
- def test_renew(self):
- key = '/testkey'
- ttl = 1
- lock = self.client.get_lock(key, ttl=ttl)
- lock.acquire()
- self.assertTrue(lock.is_locked())
- lock.renew(2)
- # TODO sleep(1)?
- self.assertTrue(lock.is_locked())
- lock.release()
-
- def test_renew_fails_without_locking(self):
- key = '/testkey'
- ttl = 1
- lock = self.client.get_lock(key, ttl=ttl)
- self.assertEquals(lock._index, None)
- self.assertRaises(etcd.EtcdException, lock.renew, 2)
-
- def test_release(self):
- key = '/testkey'
- ttl = 1
- index = '2'
- lock = self.client.get_lock(key, ttl=ttl)
- lock.acquire()
- self.assertTrue(lock.is_locked())
- lock.release()
- self.assertFalse(lock.is_locked())
-
- def test_release_fails_without_locking(self):
- key = '/testkey'
- ttl = 1
- lock = self.client.get_lock(key, ttl=ttl)
- self.assertEquals(lock._index, None)
- self.assertRaises(etcd.EtcdException, lock.release)
-
- def test_get(self):
- key = '/testkey'
- ttl = 5
- with self.client.get_lock(key, ttl=ttl) as lock:
- lock2 = self.client.get_lock(key).get()
- self.assertTrue(lock2.is_locked())
- self.assertFalse(lock2.is_locked())