class TokenDatabase(object): """A hash map of principal names to their identity tokens. Identity tokens are used to construct node ACLs. """ def __init__(self, client, path="/auth-tokens"): self._state = YAMLState(client, path) @inlineCallbacks def add(self, principal): """Add a principal to the token database. """ yield self._state.read() self._state[principal.name] = principal.get_token() yield self._state.write() @inlineCallbacks def get(self, name): """Return the identity token for a principal name. """ yield self._state.read() try: returnValue(self._state[name]) except KeyError: raise PrincipalNotFound(name) @inlineCallbacks def remove(self, name): """Remove a principal by name from the token database. """ yield self._state.read() if name in self._state: del self._state[name] yield self._state.write()
class TokenDatabase(object): """A hash map of principal names to their identity tokens. Identity tokens are used to construct node ACLs. """ def __init__(self, client, path="/auth-tokens"): self._state = YAMLState(client, path) @inlineCallbacks def add(self, principal): """Add a principal to the token database. """ yield self._state.read() self._state[principal.name] = principal.get_token() yield self._state.write() @inlineCallbacks def get(self, name): """Return the identity token for a principal name. """ yield self._state.read() try: returnValue(self._state[name]) except KeyError: raise PrincipalNotFound(name) @inlineCallbacks def remove(self, name): """Remove a principal by name from the token database. """ yield self._state.read() if name in self._state: del self._state[name] yield self._state.write()
def test_multiple_writes(self): d1 = YAMLState(self.client, self.path) yield d1.read() d1.update(dict(foo="bar", this="that")) changes = yield d1.write() self.assertEqual( set(changes), set([AddedItem("foo", "bar"), AddedItem("this", "that")])) del d1["this"] d1["another"] = "value" changes = yield d1.write() self.assertEqual( set(changes), set([DeletedItem("this", "that"), AddedItem("another", "value")])) expected = {"foo": "bar", "another": "value"} self.assertEqual(d1, expected) changes = yield d1.write() self.assertEqual(changes, []) self.assertEqual(d1, expected) yield d1.read() self.assertEqual(d1, expected) # This shouldn't write any changes changes = yield d1.write() self.assertEqual(changes, []) self.assertEqual(d1, expected)
def test_multiple_writes(self): d1 = YAMLState(self.client, self.path) yield d1.read() d1.update(dict(foo="bar", this="that")) changes = yield d1.write() self.assertEqual( set(changes), set([AddedItem("foo", "bar"), AddedItem("this", "that")])) del d1["this"] d1["another"] = "value" changes = yield d1.write() self.assertEqual( set(changes), set([DeletedItem("this", "that"), AddedItem("another", "value")])) expected = {"foo": "bar", "another": "value"} self.assertEqual(d1, expected) changes = yield d1.write() self.assertEqual(changes, []) self.assertEqual(d1, expected) yield d1.read() self.assertEqual(d1, expected) # This shouldn't write any changes changes = yield d1.write() self.assertEqual(changes, []) self.assertEqual(d1, expected)
def test_conflict_on_set(self): """Version conflict error tests. Test that two YAMLState objects writing to the same path can and will throw version errors when elements become out of read. """ node = YAMLState(self.client, self.path) node2 = YAMLState(self.client, self.path) yield node.read() yield node2.read() options = dict(alpha="beta", one=1) node.update(options) yield node.write() node2.update(options) changes = yield node2.write() self.assertEqual( set(changes), set([AddedItem("alpha", "beta"), AddedItem("one", 1)])) # first read node2 self.assertEqual(node, options) # write on node 1 options2 = dict(alpha="gamma", one="two") node.update(options2) changes = yield node.write() self.assertEqual( set(changes), set([ModifiedItem("alpha", "beta", "gamma"), ModifiedItem("one", 1, "two")])) # verify that node 1 reports as expected self.assertEqual(node, options2) # verify that node2 has the older data still self.assertEqual(node2, options) # now issue a set/write from node2 # this will merge the data deleting 'one' # and updating other values options3 = dict(alpha="cappa", new="next") node2.update(options3) del node2["one"] expected = dict(alpha="cappa", new="next") changes = yield node2.write() self.assertEqual( set(changes), set([DeletedItem("one", 1), ModifiedItem("alpha", "beta", "cappa"), AddedItem("new", "next")])) self.assertEqual(expected, node2) # but node still reflects the old data self.assertEqual(node, options2)
def test_del_empties_state(self): d = YAMLState(self.client, self.path) yield d.read() d["a"] = "foo" changes = yield d.write() self.assertEqual(changes, [AddedItem("a", "foo")]) del d["a"] changes = yield d.write() self.assertEqual(changes, [DeletedItem("a", "foo")]) self.assertEqual(d, {})
def test_del_empties_state(self): d = YAMLState(self.client, self.path) yield d.read() d["a"] = "foo" changes = yield d.write() self.assertEqual(changes, [AddedItem("a", "foo")]) del d["a"] changes = yield d.write() self.assertEqual(changes, [DeletedItem("a", "foo")]) self.assertEqual(d, {})
def test_set_w_write(self): """Verify that write updates the local and zk state. When write is called we expect that zk state reflects this. We also expect calls to get to expect the reflected state. """ node = YAMLState(self.client, self.path) yield node.read() options = dict(alpha="beta", one=1) node.update(options) changes = yield node.write() self.assertEqual( set(changes), set([ AddedItem(key='alpha', new='beta'), AddedItem(key='one', new=1) ])) # a local get should reflect proper data self.assertEqual(node, options) # and a direct look at zk should work as well zk_data, stat = yield self.client.get(self.path) zk_data = yaml.load(zk_data) self.assertEqual(zk_data, options)
def test_set_w_write(self): """Verify that write updates the local and zk state. When write is called we expect that zk state reflects this. We also expect calls to get to expect the reflected state. """ node = YAMLState(self.client, self.path) yield node.read() options = dict(alpha="beta", one=1) node.update(options) changes = yield node.write() self.assertEqual( set(changes), set([AddedItem(key='alpha', new='beta'), AddedItem(key='one', new=1)])) # a local get should reflect proper data self.assertEqual(node, options) # and a direct look at zk should work as well zk_data, stat = yield self.client.get(self.path) zk_data = yaml.load(zk_data) self.assertEqual(zk_data, options)
def test_missing_constraints(self): """ensure compatibility with nodes written for previous versions""" yield self.add_machine_state() machine = yield self.machine_state_manager.get_machine_state(0) path = "/machines/" + machine.internal_id node = YAMLState(self.client, path) yield node.read() del node["constraints"] yield node.write() constraints = yield machine.get_constraints() self.assertEquals(constraints.data, {})
def test_write_twice(self): d1 = YAMLState(self.client, self.path) yield d1.read() d1["a"] = "foo" changes = yield d1.write() self.assertEqual(changes, [AddedItem("a", "foo")]) d2 = YAMLState(self.client, self.path) yield d2.read() d2["a"] = "bar" changes = yield d2.write() self.assertEqual(changes, [ModifiedItem("a", "foo", "bar")]) # Shouldn't write again. Changes were already # flushed and acted upon by other parties. changes = yield d1.write() self.assertEqual(changes, []) yield d1.read() self.assertEquals(d1, d2)
def test_read_resync(self): d1 = YAMLState(self.client, self.path) yield d1.read() d1["a"] = "foo" changes = yield d1.write() self.assertEqual(changes, [AddedItem("a", "foo")]) d2 = YAMLState(self.client, self.path) yield d2.read() del d2["a"] changes = yield d2.write() self.assertEqual(changes, [DeletedItem("a", "foo")]) d2["a"] = "bar" changes = yield d2.write() self.assertEqual(changes, [AddedItem("a", "bar")]) zk_data, stat = yield self.client.get(self.path) yield d1.read() # d1 should pick up the new value (from d2) on a read zk_data, stat = yield self.client.get(self.path) self.assertEqual(d1["a"], "bar")
def test_read_resync(self): d1 = YAMLState(self.client, self.path) yield d1.read() d1["a"] = "foo" changes = yield d1.write() self.assertEqual(changes, [AddedItem("a", "foo")]) d2 = YAMLState(self.client, self.path) yield d2.read() del d2["a"] changes = yield d2.write() self.assertEqual(changes, [DeletedItem("a", "foo")]) d2["a"] = "bar" changes = yield d2.write() self.assertEqual(changes, [AddedItem("a", "bar")]) zk_data, stat = yield self.client.get(self.path) yield d1.read() # d1 should pick up the new value (from d2) on a read zk_data, stat = yield self.client.get(self.path) self.assertEqual(d1["a"], "bar")
def test_write_twice(self): d1 = YAMLState(self.client, self.path) yield d1.read() d1["a"] = "foo" changes = yield d1.write() self.assertEqual(changes, [AddedItem("a", "foo")]) d2 = YAMLState(self.client, self.path) yield d2.read() d2["a"] = "bar" changes = yield d2.write() self.assertEqual(changes, [ModifiedItem("a", "foo", "bar")]) # Shouldn't write again. Changes were already # flushed and acted upon by other parties. changes = yield d1.write() self.assertEqual(changes, []) yield d1.read() self.assertEquals(d1, d2)
def test_multiple_reads(self): """Calling read resets state to ZK after multiple round-trips.""" node = YAMLState(self.client, self.path) yield node.read() node.update({"alpha": "beta", "foo": "bar"}) self.assertEqual(node["alpha"], "beta") self.assertEqual(node["foo"], "bar") yield node.read() # A read resets the data to the empty state self.assertEqual(node, {}) node.update({"alpha": "beta", "foo": "bar"}) changes = yield node.write() self.assertEqual( set(changes), set([AddedItem("alpha", "beta"), AddedItem("foo", "bar")])) # A write retains the newly set values self.assertEqual(node["alpha"], "beta") self.assertEqual(node["foo"], "bar") # now get another state instance and change zk state node2 = YAMLState(self.client, self.path) yield node2.read() node2.update({"foo": "different"}) changes = yield node2.write() self.assertEqual( changes, [ModifiedItem("foo", "bar", "different")]) # This should pull in the new state (and still have the merged old. yield node.read() self.assertEqual(node["alpha"], "beta") self.assertEqual(node["foo"], "different")
def test_multiple_reads(self): """Calling read resets state to ZK after multiple round-trips.""" node = YAMLState(self.client, self.path) yield node.read() node.update({"alpha": "beta", "foo": "bar"}) self.assertEqual(node["alpha"], "beta") self.assertEqual(node["foo"], "bar") yield node.read() # A read resets the data to the empty state self.assertEqual(node, {}) node.update({"alpha": "beta", "foo": "bar"}) changes = yield node.write() self.assertEqual( set(changes), set([AddedItem("alpha", "beta"), AddedItem("foo", "bar")])) # A write retains the newly set values self.assertEqual(node["alpha"], "beta") self.assertEqual(node["foo"], "bar") # now get another state instance and change zk state node2 = YAMLState(self.client, self.path) yield node2.read() node2.update({"foo": "different"}) changes = yield node2.write() self.assertEqual(changes, [ModifiedItem("foo", "bar", "different")]) # This should pull in the new state (and still have the merged old. yield node.read() self.assertEqual(node["alpha"], "beta") self.assertEqual(node["foo"], "different")
def test_setitem(self): node = YAMLState(self.client, self.path) yield node.read() options = dict(alpha="beta", one=1) node["alpha"] = "beta" node["one"] = 1 changes = yield node.write() self.assertEqual( set(changes), set([AddedItem("alpha", "beta"), AddedItem("one", 1)])) # a local get should reflect proper data self.assertEqual(node, options) # and a direct look at zk should work as well zk_data, stat = yield self.client.get(self.path) zk_data = yaml.load(zk_data) self.assertEqual(zk_data, options)
def test_setitem(self): node = YAMLState(self.client, self.path) yield node.read() options = dict(alpha="beta", one=1) node["alpha"] = "beta" node["one"] = 1 changes = yield node.write() self.assertEqual( set(changes), set([AddedItem("alpha", "beta"), AddedItem("one", 1)])) # a local get should reflect proper data self.assertEqual(node, options) # and a direct look at zk should work as well zk_data, stat = yield self.client.get(self.path) zk_data = yaml.load(zk_data) self.assertEqual(zk_data, options)
def test_conflict_on_set(self): """Version conflict error tests. Test that two YAMLState objects writing to the same path can and will throw version errors when elements become out of read. """ node = YAMLState(self.client, self.path) node2 = YAMLState(self.client, self.path) yield node.read() yield node2.read() options = dict(alpha="beta", one=1) node.update(options) yield node.write() node2.update(options) changes = yield node2.write() self.assertEqual( set(changes), set([AddedItem("alpha", "beta"), AddedItem("one", 1)])) # first read node2 self.assertEqual(node, options) # write on node 1 options2 = dict(alpha="gamma", one="two") node.update(options2) changes = yield node.write() self.assertEqual( set(changes), set([ ModifiedItem("alpha", "beta", "gamma"), ModifiedItem("one", 1, "two") ])) # verify that node 1 reports as expected self.assertEqual(node, options2) # verify that node2 has the older data still self.assertEqual(node2, options) # now issue a set/write from node2 # this will merge the data deleting 'one' # and updating other values options3 = dict(alpha="cappa", new="next") node2.update(options3) del node2["one"] expected = dict(alpha="cappa", new="next") changes = yield node2.write() self.assertEqual( set(changes), set([ DeletedItem("one", 1), ModifiedItem("alpha", "beta", "cappa"), AddedItem("new", "next") ])) self.assertEqual(expected, node2) # but node still reflects the old data self.assertEqual(node, options2)