def test_get_subtree_1_level(self): """ Test get_subtree() for a read with tree 1 level deep. """ response = { "node": { 'key': "/test", 'value': "hello", 'expiration': None, 'ttl': None, 'modifiedIndex': 5, 'createdIndex': 1, 'newKey': False, 'dir': False, } } result = etcd.EtcdResult(**response) self.assertEqual(result.key, response["node"]["key"]) self.assertEqual(result.value, response["node"]["value"]) # Get subtree returns itself, whether or not leaves_only subtree = list(result.get_subtree(leaves_only=True)) self.assertListEqual([result], subtree) subtree = list(result.get_subtree(leaves_only=False)) self.assertListEqual([result], subtree)
def etcd_watch(self, key, index=None, timeout=None, recursive=None): if timeout == 2.0: raise etcd.EtcdWatchTimedOut elif timeout == 5.0: return etcd.EtcdResult('delete', {}) elif timeout == 10.0: raise etcd.EtcdException
def test_acquired_no_timeout(self): self.locker._sequence = 4 returns = [('/_locks/test_lock/4', None, 1), ('/_locks/test_lock/1', etcd.EtcdResult(node={ "key": '/_locks/test_lock/4', "modifiedIndex": 1 }), 1)] def side_effect(): return returns.pop() d = { u'action': u'get', u'node': { u'modifiedIndex': 190, u'key': u'/_locks/test_lock/4', u'value': self.locker.uuid } } self._mock_api(200, d) self.locker._get_locker = mock.create_autospec(self.locker._get_locker, side_effect=side_effect) self.assertTrue(self.locker._acquired())
def etcd_read(self, key, **kwargs): if key == '/service/noleader/': raise DCSError('noleader') elif key == '/service/nocluster/': raise etcd.EtcdKeyNotFound response = {"action": "get", "node": {"key": "/service/batman5", "dir": True, "nodes": [ {"key": "/service/batman5/failover", "value": "", "modifiedIndex": 1582, "createdIndex": 1582}, {"key": "/service/batman5/initialize", "value": "postgresql0", "modifiedIndex": 1582, "createdIndex": 1582}, {"key": "/service/batman5/leader", "value": "postgresql1", "expiration": "2015-05-15T09:11:00.037397538Z", "ttl": 21, "modifiedIndex": 20728, "createdIndex": 20434}, {"key": "/service/batman5/optime", "dir": True, "nodes": [ {"key": "/service/batman5/optime/leader", "value": "2164261704", "modifiedIndex": 20729, "createdIndex": 20729}], "modifiedIndex": 20437, "createdIndex": 20437}, {"key": "/service/batman5/members", "dir": True, "nodes": [ {"key": "/service/batman5/members/postgresql1", "value": "postgres://*****:*****@127.0.0.1:5434/postgres" + "?application_name=http://127.0.0.1:8009/patroni", "expiration": "2015-05-15T09:10:59.949384522Z", "ttl": 21, "modifiedIndex": 20727, "createdIndex": 20727}, {"key": "/service/batman5/members/postgresql0", "value": "postgres://*****:*****@127.0.0.1:5433/postgres" + "?application_name=http://127.0.0.1:8008/patroni", "expiration": "2015-05-15T09:11:09.611860899Z", "ttl": 30, "modifiedIndex": 20730, "createdIndex": 20730}], "modifiedIndex": 1581, "createdIndex": 1581}], "modifiedIndex": 1581, "createdIndex": 1581}} return etcd.EtcdResult(**response)
def test_index_watch(self): """ Can watch values from index """ client = etcd.Client() client.api_execute = mock.Mock( return_value=FakeHTTPResponse(200, '{"action":"SET",' '"node": {' '"key":"/testkey",' '"value":"test",' '"newKey":true,' '"expiration":"2013-09-14T01:35:07.623681365+02:00",' '"ttl":19,' '"modifiedIndex":180}}') ) result = client.watch('/testkey', index=180) self.assertEquals( etcd.EtcdResult( **{u'action': u'SET', u'node': { u'expiration': u'2013-09-14T01:35:07.623681365+02:00', u'modifiedIndex': 180, u'key': u'/testkey', u'newKey': True, u'ttl': 19, u'value': u'test'} }), result)
def test_set(self): """ Can set a value """ client = etcd.Client() client.api_execute = mock.Mock( return_value=FakeHTTPResponse(201, '{"action":"SET",' '"node": {' '"key":"/testkey",' '"value":"test",' '"newKey":true,' '"expiration":"2013-09-14T00:56:59.316195568+02:00",' '"ttl":19,"modifiedIndex":183}}') ) result = client.set('/testkey', 'test', ttl=19) self.assertEquals( etcd.EtcdResult( **{u'action': u'SET', 'node': { u'expiration': u'2013-09-14T00:56:59.316195568+02:00', u'modifiedIndex': 183, u'key': u'/testkey', u'newKey': True, u'ttl': 19, u'value': u'test'}}), result)
def test_get_dir(self): """Can get values in dirs""" d = { u'action': u'get', u'node': { u'modifiedIndex': 190, u'key': u'/testkey', u'dir': True, u'nodes': [{ u'key': u'/testDir/testKey', u'modifiedIndex': 150, u'value': 'test' }, { u'key': u'/testDir/testKey2', u'modifiedIndex': 190, u'value': 'test2' }] } } self._mock_api(200, d) res = self.client.read('/testDir', recursive=True) self.assertEquals(res, etcd.EtcdResult(**d))
def test_test_and_set(self): """ Can test and set a value """ client = etcd.Client() client.api_execute = mock.Mock( return_value=FakeHTTPResponse(200, '{"action":"SET",' '"node": {' '"key":"/testkey",' '"prevValue":"test",' '"value":"newvalue",' '"expiration":"2013-09-14T02:09:44.24390976+02:00",' '"ttl":49,"modifiedIndex":203}}') ) result = client.test_and_set('/testkey', 'newvalue', 'test', ttl=19) self.assertEquals( etcd.EtcdResult( **{u'action': u'SET', u'node': { u'expiration': u'2013-09-14T02:09:44.24390976+02:00', u'modifiedIndex': 203, u'key': u'/testkey', u'prevValue': u'test', u'ttl': 49, u'value': u'newvalue'} }), result)
def test_event_index_cleared(self): self.locker._sequence = 4 returns = [('/_locks/test_lock/4', None, 1), ('/_locks/test_lock/1', etcd.EtcdResult(node={ "key": '/_locks/test_lock/4', "modifiedIndex": 1 }), 1)] def side_effect(): return returns.pop() d = { u'action': u'get', u'node': { u'modifiedIndex': 190, u'key': u'/_locks/test_lock/4', u'value': self.locker.uuid } } self._mock_api(200, d) self.locker._get_locker = mock.create_autospec(self.locker._get_locker, side_effect=side_effect) # Raise the event index cleared exception and test that we # can recover from it. self._mock_exception(etcd.EtcdEventIndexCleared, self.locker.lock_key) self.assertTrue(self.locker._acquired())
def stub_read(self, k): res = {} res['key'] = k if k in self.kdb.keys(): res['value'] = self.kdb[k] r = etcd.EtcdResult(None, res) return (r)
def etcd_watch(key, index=None, timeout=None, recursive=None): if timeout == 2.0: raise urllib3.exceptions.TimeoutError elif timeout == 5.0: return etcd.EtcdResult('delete', {}) elif timeout == 10.0: raise etcd.EtcdException elif index == 20729: return etcd.EtcdResult('set', { 'value': 'postgresql1', 'modifiedIndex': index + 1 }) elif index == 20731: return etcd.EtcdResult('set', { 'value': 'postgresql2', 'modifiedIndex': index + 1 })
def etcd_watch(self, key, index=None, timeout=None, recursive=None): if timeout == 2.0: raise etcd.EtcdWatchTimedOut elif timeout == 5.0: return etcd.EtcdResult('compareAndSwap', {}) elif 5 < timeout <= 10.0: raise etcd.EtcdException elif timeout == 20.0: raise etcd.EtcdEventIndexCleared
def children(self): if self.root is None or not hasattr(self.root, "_children"): return [] else: return [(child["key"].split("/")[-1], EtcdDocument(None, None, root=etcd.EtcdResult(None, node=child))) for child in self.root._children]
def check_watch(self, result): assert etcd.EtcdResult( **{u'action': u'SET', u'node': { u'expiration': u'2013-09-14T01:35:07.623681365+02:00', u'modifiedIndex': 180, u'key': u'/testkey', u'newKey': True, u'ttl': 19, u'value': u'test'} }) == result
def get_etcd_read_list(path, *args): """Return EtcdResult object for read list""" values = [] for val in args: node = {u'key': None, u'value': val} values.append(node) data = _get_etcd_data(path) data['node']['dir'] = 'true' data['node']['nodes'] = values return etcd.EtcdResult(**data)
def _result_from_response(self, response): """ Creates an EtcdResult from json dictionary """ try: res = json.loads(response.data.decode('utf-8')) r = etcd.EtcdResult(**res) if response.status == 201: r.newKey = True r.parse_headers(response) return r except Exception as e: raise etcd.EtcdException('Unable to decode server response: %s' % e)
def test_get_subtree_2_level(self): """ Test get_subtree() for a read with tree 2 levels deep. """ leaf0 = { 'key': "/test/leaf0", 'value': "hello1", 'expiration': None, 'ttl': None, 'modifiedIndex': 5, 'createdIndex': 1, 'newKey': False, 'dir': False, } leaf1 = { 'key': "/test/leaf1", 'value': "hello2", 'expiration': None, 'ttl': None, 'modifiedIndex': 6, 'createdIndex': 2, 'newKey': False, 'dir': False, } testnode = { "node": { 'key': "/test/", 'expiration': None, 'ttl': None, 'modifiedIndex': 6, 'createdIndex': 2, 'newKey': False, 'dir': True, 'nodes': [leaf0, leaf1] } } result = etcd.EtcdResult(**testnode) self.assertEqual(result.key, "/test/") self.assertTrue(result.dir) # Get subtree returns just two leaves for leaves only. subtree = list(result.get_subtree(leaves_only=True)) self.assertEqual(subtree[0].key, "/test/leaf0") self.assertEqual(subtree[1].key, "/test/leaf1") self.assertEqual(len(subtree), 2) # Get subtree returns leaves and directory. subtree = list(result.get_subtree(leaves_only=False)) self.assertEqual(subtree[0].key, "/test/") self.assertEqual(subtree[1].key, "/test/leaf0") self.assertEqual(subtree[2].key, "/test/leaf1") self.assertEqual(len(subtree), 3)
def test_watch_index(self): """ Can watch a key starting from the given Index """ d = { u'action': u'get', u'node': { u'modifiedIndex': 170, u'key': u'/testkey', u'value': u'testold' } } self._mock_api(200, d) res = self.client.read('/testkey', wait=True, waitIndex=True) self.assertEquals(res, etcd.EtcdResult(**d))
def test_watch(self): """ Can watch a key """ d = { u'action': u'get', u'node': { u'modifiedIndex': 190, u'key': u'/testkey', u'value': u'test' } } self._mock_api(200, d) res = self.client.read('/testkey', wait=True) self.assertEquals(res, etcd.EtcdResult(**d))
def test_delete(self): """ Can delete a value """ d = { u'action': u'delete', u'node': { u'key': u'/testkey', "modifiedIndex": 3, "createdIndex": 2 } } self._mock_api(200, d) res = self.client.delete('/testKey') self.assertEquals(res, etcd.EtcdResult(**d))
def get_etcd_write_result(key, value): """Return EtcdResult object for write regular key""" data = { u'action': u'set', u'node': { u'expiration': u'2013-09-14T00:56:59.316195568+02:00', u'modifiedIndex': 183, u'key': key, u'ttl': 19, u'value': value } } return etcd.EtcdResult(**data)
def test_get_subtree_3_level(self): """ Test get_subtree() for a read with tree 3 levels deep. """ leaf0 = { 'key': "/test/mid0/leaf0", 'value': "hello1", } leaf1 = { 'key': "/test/mid0/leaf1", 'value': "hello2", } leaf2 = { 'key': "/test/mid1/leaf2", 'value': "hello1", } leaf3 = { 'key': "/test/mid1/leaf3", 'value': "hello2", } mid0 = {'key': "/test/mid0/", 'dir': True, 'nodes': [leaf0, leaf1]} mid1 = {'key': "/test/mid1/", 'dir': True, 'nodes': [leaf2, leaf3]} testnode = { "node": { 'key': "/test/", 'dir': True, 'nodes': [mid0, mid1] } } result = etcd.EtcdResult(**testnode) self.assertEqual(result.key, "/test/") self.assertTrue(result.dir) # Get subtree returns just two leaves for leaves only. subtree = list(result.get_subtree(leaves_only=True)) self.assertEqual(subtree[0].key, "/test/mid0/leaf0") self.assertEqual(subtree[1].key, "/test/mid0/leaf1") self.assertEqual(subtree[2].key, "/test/mid1/leaf2") self.assertEqual(subtree[3].key, "/test/mid1/leaf3") self.assertEqual(len(subtree), 4) # Get subtree returns leaves and directory. subtree = list(result.get_subtree(leaves_only=False)) self.assertEqual(subtree[0].key, "/test/") self.assertEqual(subtree[1].key, "/test/mid0/") self.assertEqual(subtree[2].key, "/test/mid0/leaf0") self.assertEqual(subtree[3].key, "/test/mid0/leaf1") self.assertEqual(subtree[4].key, "/test/mid1/") self.assertEqual(subtree[5].key, "/test/mid1/leaf2") self.assertEqual(subtree[6].key, "/test/mid1/leaf3") self.assertEqual(len(subtree), 7)
def test_set_plain(self): """ Can set a value """ d = {u'action': u'set', u'node': { u'expiration': u'2013-09-14T00:56:59.316195568+02:00', u'modifiedIndex': 183, u'key': u'/testkey', u'ttl': 19, u'value': u'test' } } self._mock_api(200, d) res = self.client.write('/testkey', 'test') self.assertEquals(res, etcd.EtcdResult(**d))
def test_compare_and_swap(self): """ Can set compare-and-swap a value """ d = {u'action': u'compareAndSwap', u'node': { u'expiration': u'2013-09-14T00:56:59.316195568+02:00', u'modifiedIndex': 183, u'key': u'/testkey', u'ttl': 19, u'value': u'test' } } self._mock_api(200, d) res = self.client.write('/testkey', 'test', prevValue='test_old') self.assertEquals(res, etcd.EtcdResult(**d))
def get_etcd_alerts(path, recursive): etcd_tree = { "node": { 'key': "/alerts/", 'expiration': None, 'ttl': None, 'modifiedIndex': 5, 'createdIndex': 1, 'newKey': False, 'dir': True, 'nodes': [etcd_alert1, etcd_alert2, etcd_alert3, etcd_alert4] } } return etcd.EtcdResult(**etcd_tree)
def read(key): if key == 'indexes/tags/tendrl/integration/None': raise etcd.EtcdKeyNotFound elif key == 'indexes/tags/tendrl/integration/' \ '94ac63ba-de73-4e7f-8dfa-9010d9554084': node_ids = maps.NamedDict() node_ids['value'] = '["bc4cad92-b7e3-4c63-b820-a439db3a0516",' \ '"a71af0e5-5241-4856-9e9c-22627a466b8d"]' return node_ids else: return etcd.EtcdResult( node={ 'newKey': False, 'raft_index': 449389, '_children': [{ u'createdIndex': 1657, u'modifiedIndex': 1657, u'dir': True, u'key': u'/clusters/' u'b7d4b5ae-d33d-' u'49cf-ae6d-5d6bb' u'494ece7' }], 'createdIndex': 1657, 'modifiedIndex': 1657, 'value': None, 'etcd_index': 101021, 'expiration': None, 'key': u'/clusters', 'ttl': None, 'action': u'get', 'dir': True })
def test_refresh(self): """ Can refresh a new value """ d = { u'action': u'update', u'node': { u'expiration': u'2016-05-31T08:27:54.660337Z', u'modifiedIndex': 183, u'key': u'/testkey', u'ttl': 600, u'value': u'test' } } self._mock_api(200, d) res = self.client.refresh('/testkey', ttl=600) self.assertEquals(res, etcd.EtcdResult(**d))
def _result_from_response(self, response): """ Creates an EtcdResult from json dictionary """ raw_response = response.data try: res = json.loads(raw_response.decode('utf-8')) except (TypeError, ValueError, UnicodeError) as e: raise etcd.EtcdException( 'Server response was not valid JSON: %r' % e) try: r = etcd.EtcdResult(**res) if response.status == 201: r.newKey = True r.parse_headers(response) return r except Exception as e: raise etcd.EtcdException( 'Unable to decode server response: %r' % e)
def after_scenario(context, scenario): """ Runs after every scenario. """ # Wait for investigator processes to finish. busy_states = (C.HOST_STATUS_INVESTIGATING, C.HOST_STATUS_BOOTSTRAPPING) try: etcd_resp = context.etcd.read('/commissaire/hosts', recursive=True) for child in etcd_resp._children: resp_data = etcd.EtcdResult(node=child) host_data = json.loads(resp_data.value) while host_data.get('status') in busy_states: context.etcd.watch(resp_data.key) resp_data = context.etcd.get(resp_data.key) host_data = json.loads(resp_data.value) except etcd.EtcdKeyNotFound: pass
def test_get_locker(self): self.recursive_read() self.assertEquals((u'/_locks/test_lock/1', etcd.EtcdResult( node={ 'newKey': False, '_children': [], 'createdIndex': 33, 'modifiedIndex': 33, 'value': u'2qwwwq', 'expiration': None, 'key': u'/_locks/test_lock/1', 'ttl': None, 'action': None, 'dir': False }), 1), self.locker._get_locker()) with self.assertRaises(etcd.EtcdLockExpired): self.locker._sequence = '35' self.locker._get_locker()