Add ZK API methods for node requests
Adds ZooKeeper API methods to get the current list of outstanding node requests, and to get the data for an individual node request. A new NodeRequest object is introduced to the data model. The model will be expanded on in future reviews. Change-Id: I4af96e4e307cc5ce5d3208462e7335c24eece952
This commit is contained in:
parent
0456fc5f37
commit
08b720364f
@ -437,27 +437,58 @@ class TestZooKeeper(tests.DBTestCase):
|
||||
self.assertEqual(1, len(launchers))
|
||||
self.assertEqual(name, launchers[0])
|
||||
|
||||
def test_getNodeRequests_empty(self):
|
||||
self.assertEqual([], self.zk.getNodeRequests())
|
||||
|
||||
def test_getNodeRequests(self):
|
||||
r1 = self.zk._requestPath("500-123")
|
||||
r2 = self.zk._requestPath("100-456")
|
||||
r3 = self.zk._requestPath("100-123")
|
||||
r4 = self.zk._requestPath("400-123")
|
||||
self.zk.client.create(r1, makepath=True, ephemeral=True)
|
||||
self.zk.client.create(r2, makepath=True, ephemeral=True)
|
||||
self.zk.client.create(r3, makepath=True, ephemeral=True)
|
||||
self.zk.client.create(r4, makepath=True, ephemeral=True)
|
||||
|
||||
self.assertEqual(
|
||||
["100-123", "100-456", "400-123", "500-123"],
|
||||
self.zk.getNodeRequests()
|
||||
)
|
||||
|
||||
def test_getNodeRequest(self):
|
||||
r = zk.NodeRequest("500-123")
|
||||
r.state = zk.READY
|
||||
path = self.zk._requestPath(r.id)
|
||||
self.zk.client.create(path, value=self.zk._dictToStr(r.toDict()),
|
||||
makepath=True, ephemeral=True)
|
||||
o = self.zk.getNodeRequest(r.id)
|
||||
self.assertIsInstance(o, zk.NodeRequest)
|
||||
self.assertEqual(r.id, o.id)
|
||||
|
||||
def test_getNodeRequest_not_found(self):
|
||||
self.assertIsNone(self.zk.getNodeRequest("invalid"))
|
||||
|
||||
|
||||
class TestZKModel(tests.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestZKModel, self).setUp()
|
||||
|
||||
def test_BaseBuilderModel_bad_id(self):
|
||||
def test_BaseModel_bad_id(self):
|
||||
with testtools.ExpectedException(
|
||||
TypeError, "'id' attribute must be a string type"
|
||||
):
|
||||
zk.BaseBuilderModel(123)
|
||||
zk.BaseModel(123)
|
||||
|
||||
def test_BaseBuilderModel_bad_state(self):
|
||||
def test_BaseModel_bad_state(self):
|
||||
with testtools.ExpectedException(
|
||||
TypeError, "'blah' is not a valid state"
|
||||
):
|
||||
o = zk.BaseBuilderModel('0001')
|
||||
o = zk.BaseModel('0001')
|
||||
o.state = 'blah'
|
||||
|
||||
def test_BaseBuilderModel_toDict(self):
|
||||
o = zk.BaseBuilderModel('0001')
|
||||
def test_BaseModel_toDict(self):
|
||||
o = zk.BaseModel('0001')
|
||||
o.state = zk.BUILDING
|
||||
d = o.toDict()
|
||||
self.assertNotIn('id', d)
|
||||
@ -524,3 +555,23 @@ class TestZKModel(tests.BaseTestCase):
|
||||
self.assertEqual(o.state_time, d['state_time'])
|
||||
self.assertEqual(o.external_id, d['external_id'])
|
||||
self.assertEqual(o.external_name, d['external_name'])
|
||||
|
||||
def test_NodeRequest_toDict(self):
|
||||
o = zk.NodeRequest("500-123")
|
||||
d = o.toDict()
|
||||
self.assertNotIn('id', d)
|
||||
self.assertIn('state', d)
|
||||
self.assertIn('state_time', d)
|
||||
|
||||
def test_NodeRequest_fromDict(self):
|
||||
now = int(time.time())
|
||||
req_id = "500-123"
|
||||
d = {
|
||||
'state': zk.READY,
|
||||
'state_time': now
|
||||
}
|
||||
|
||||
o = zk.NodeRequest.fromDict(d, req_id)
|
||||
self.assertEqual(o.id, req_id)
|
||||
self.assertEqual(o.state, d['state'])
|
||||
self.assertEqual(o.state_time, d['state_time'])
|
||||
|
@ -106,7 +106,7 @@ class ZooKeeperWatchEvent(object):
|
||||
self.image = image
|
||||
|
||||
|
||||
class BaseBuilderModel(object):
|
||||
class BaseModel(object):
|
||||
def __init__(self, o_id):
|
||||
if o_id:
|
||||
self.id = o_id
|
||||
@ -137,7 +137,7 @@ class BaseBuilderModel(object):
|
||||
|
||||
def toDict(self):
|
||||
'''
|
||||
Convert a BaseBuilderModel object's attributes to a dictionary.
|
||||
Convert a BaseModel object's attributes to a dictionary.
|
||||
'''
|
||||
d = {}
|
||||
d['state'] = self.state
|
||||
@ -157,7 +157,7 @@ class BaseBuilderModel(object):
|
||||
self.state_time = d['state_time']
|
||||
|
||||
|
||||
class ImageBuild(BaseBuilderModel):
|
||||
class ImageBuild(BaseModel):
|
||||
'''
|
||||
Class representing a DIB image build within the ZooKeeper cluster.
|
||||
'''
|
||||
@ -216,7 +216,7 @@ class ImageBuild(BaseBuilderModel):
|
||||
return o
|
||||
|
||||
|
||||
class ImageUpload(BaseBuilderModel):
|
||||
class ImageUpload(BaseModel):
|
||||
'''
|
||||
Class representing a provider image upload within the ZooKeeper cluster.
|
||||
'''
|
||||
@ -277,6 +277,42 @@ class ImageUpload(BaseBuilderModel):
|
||||
return o
|
||||
|
||||
|
||||
class NodeRequest(BaseModel):
|
||||
'''
|
||||
Class representing a node request.
|
||||
'''
|
||||
|
||||
def __init__(self, id=None):
|
||||
super(NodeRequest, self).__init__(id)
|
||||
|
||||
def __repr__(self):
|
||||
d = self.toDict()
|
||||
d['id'] = self.id
|
||||
d['stat'] = self.stat
|
||||
return '<NodeRequest %s>' % d
|
||||
|
||||
def toDict(self):
|
||||
'''
|
||||
Convert a NodeRequest object's attributes to a dictionary.
|
||||
'''
|
||||
d = super(NodeRequest, self).toDict()
|
||||
return d
|
||||
|
||||
@staticmethod
|
||||
def fromDict(d, o_id=None):
|
||||
'''
|
||||
Create a NodeRequest object from a dictionary.
|
||||
|
||||
:param dict d: The dictionary.
|
||||
:param str o_id: The object ID.
|
||||
|
||||
:returns: An initialized ImageBuild object.
|
||||
'''
|
||||
o = NodeRequest(o_id)
|
||||
super(NodeRequest, o).fromDict(d)
|
||||
return o
|
||||
|
||||
|
||||
class ZooKeeper(object):
|
||||
'''
|
||||
Class implementing the ZooKeeper interface.
|
||||
@ -297,6 +333,7 @@ class ZooKeeper(object):
|
||||
|
||||
IMAGE_ROOT = "/nodepool/images"
|
||||
LAUNCHER_ROOT = "/nodepool/launchers"
|
||||
REQUEST_ROOT = "/nodepool/requests"
|
||||
|
||||
def __init__(self):
|
||||
'''
|
||||
@ -341,6 +378,9 @@ class ZooKeeper(object):
|
||||
def _launcherPath(self, launcher):
|
||||
return "%s/%s" % (self.LAUNCHER_ROOT, launcher)
|
||||
|
||||
def _requestPath(self, request):
|
||||
return "%s/%s" % (self.REQUEST_ROOT, request)
|
||||
|
||||
def _dictToStr(self, data):
|
||||
return json.dumps(data)
|
||||
|
||||
@ -1024,3 +1064,32 @@ class ZooKeeper(object):
|
||||
return []
|
||||
|
||||
return launchers
|
||||
|
||||
def getNodeRequests(self):
|
||||
'''
|
||||
Get the current list of all node requests in priority sorted order.
|
||||
|
||||
:returns: A list of request nodes.
|
||||
'''
|
||||
try:
|
||||
requests = self.client.get_children(self.REQUEST_ROOT)
|
||||
except kze.NoNodeError:
|
||||
return []
|
||||
|
||||
return sorted(requests)
|
||||
|
||||
def getNodeRequest(self, request):
|
||||
'''
|
||||
Get the data for a specific node request.
|
||||
|
||||
:returns: The request data, or None if the request was not found.
|
||||
'''
|
||||
path = self._requestPath(request)
|
||||
try:
|
||||
data, stat = self.client.get(path)
|
||||
except kze.NoNodeError:
|
||||
return None
|
||||
|
||||
d = NodeRequest.fromDict(self._strToDict(data), request)
|
||||
d.stat = stat
|
||||
return d
|
||||
|
Loading…
x
Reference in New Issue
Block a user