
This uses a cache and lets us update metadata about components and act on changes quickly (as compared to the current launcher registry which doesn't have provision for live updates). This removes the launcher registry, so operators should take care to update all launchers within a short period of time since the functionality to yield to a specific provider depends on it. Change-Id: I6409db0edf022d711f4e825e2b3eb487e7a79922
1123 lines
42 KiB
Python
1123 lines
42 KiB
Python
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
# implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
import testtools
|
|
import time
|
|
import uuid
|
|
import socket
|
|
|
|
from nodepool import exceptions as npe
|
|
from nodepool import tests
|
|
from nodepool.zk import zookeeper as zk
|
|
from nodepool.zk.components import PoolComponent
|
|
from nodepool.config import ZooKeeperConnectionConfig, buildZooKeeperHosts
|
|
from nodepool.nodeutils import iterate_timeout
|
|
from nodepool.version import get_version_string
|
|
|
|
|
|
class TestComponentRegistry(tests.DBTestCase):
|
|
|
|
def test_pool_component(self):
|
|
hostname = socket.gethostname()
|
|
launcher = PoolComponent(
|
|
self.zk.zk_client, hostname,
|
|
version=get_version_string())
|
|
launcher.content.update({
|
|
'id': "launcher-Poolworker.provider-main-" + uuid.uuid4().hex,
|
|
'provider_name': 'provider',
|
|
'supported_labels': [],
|
|
'state': launcher.RUNNING,
|
|
})
|
|
launcher.register()
|
|
|
|
launchers = self.zk.getRegisteredPools()
|
|
self.assertEqual(1, len(launchers))
|
|
self.assertEqual(launcher.id, list(launchers)[0].id)
|
|
|
|
launcher.unregister()
|
|
launchers = self.zk.getRegisteredPools()
|
|
self.assertEqual(0, len(launchers))
|
|
|
|
|
|
class TestZooKeeper(tests.DBTestCase):
|
|
|
|
def setUp(self):
|
|
super(TestZooKeeper, self).setUp()
|
|
|
|
def test_buildZooKeeperHosts_single(self):
|
|
hosts = [
|
|
ZooKeeperConnectionConfig('127.0.0.1', port=2181,
|
|
chroot='/test1')
|
|
]
|
|
self.assertEqual('127.0.0.1:2181/test1',
|
|
buildZooKeeperHosts(hosts))
|
|
|
|
def test_buildZooKeeperHosts_multiple(self):
|
|
hosts = [
|
|
ZooKeeperConnectionConfig('127.0.0.1', port=2181,
|
|
chroot='/test1'),
|
|
ZooKeeperConnectionConfig('127.0.0.2', port=2182,
|
|
chroot='/test2')
|
|
]
|
|
self.assertEqual('127.0.0.1:2181/test1,127.0.0.2:2182/test2',
|
|
buildZooKeeperHosts(hosts))
|
|
|
|
def test_buildZooKeeperHosts_ipv6(self):
|
|
hosts = [
|
|
ZooKeeperConnectionConfig(
|
|
'2001:4800:7817:103:be76:4eff:fe04:e359', port=2181,
|
|
chroot='/test1'),
|
|
ZooKeeperConnectionConfig(
|
|
'[2002:4800:7817:103:be76:4eff:fe04:e359]', port=2181,
|
|
chroot='/test2'),
|
|
ZooKeeperConnectionConfig('127.0.0.2', port=2182,
|
|
chroot='/test3')
|
|
]
|
|
self.assertEqual((
|
|
'[2001:4800:7817:103:be76:4eff:fe04:e359]:2181/test1,'
|
|
'[2002:4800:7817:103:be76:4eff:fe04:e359]:2181/test2,'
|
|
'127.0.0.2:2182/test3'
|
|
), buildZooKeeperHosts(hosts))
|
|
|
|
def test_imageBuildLock(self):
|
|
path = self.zk._imageBuildLockPath("ubuntu-trusty")
|
|
with self.zk.imageBuildLock("ubuntu-trusty", blocking=False):
|
|
self.assertIsNotNone(self.zk.client.exists(path))
|
|
|
|
def test_imageBuildLock_exception_nonblocking(self):
|
|
image = "ubuntu-trusty"
|
|
with self.zk.imageBuildLock(image, blocking=False):
|
|
with testtools.ExpectedException(
|
|
npe.ZKLockException, "Did not get lock on .*"
|
|
):
|
|
with self.zk.imageBuildLock(image, blocking=False):
|
|
pass
|
|
|
|
def test_imageBuildLock_exception_blocking(self):
|
|
image = "ubuntu-trusty"
|
|
with self.zk.imageBuildLock(image, blocking=False):
|
|
with testtools.ExpectedException(npe.TimeoutException):
|
|
with self.zk.imageBuildLock(image, blocking=True, timeout=1):
|
|
pass
|
|
|
|
def test_imageBuildNumberLock(self):
|
|
path = self.zk._imageBuildNumberLockPath("ubuntu-trusty", "0000")
|
|
with self.zk.imageBuildNumberLock(
|
|
"ubuntu-trusty", "0000", blocking=False
|
|
):
|
|
self.assertIsNotNone(self.zk.client.exists(path))
|
|
|
|
def test_imageBuildNumberLock_exception_nonblocking(self):
|
|
image = "ubuntu-trusty"
|
|
bnum = "0000000000"
|
|
with self.zk.imageBuildNumberLock(image, bnum, blocking=False):
|
|
with testtools.ExpectedException(
|
|
npe.ZKLockException, "Did not get lock on .*"
|
|
):
|
|
with self.zk.imageBuildNumberLock(image, bnum, blocking=False):
|
|
pass
|
|
|
|
def test_imageBuildNumberLock_exception_blocking(self):
|
|
image = "ubuntu-trusty"
|
|
bnum = "0000000000"
|
|
with self.zk.imageBuildNumberLock(image, bnum, blocking=False):
|
|
with testtools.ExpectedException(npe.TimeoutException):
|
|
with self.zk.imageBuildNumberLock(
|
|
image, bnum, blocking=True, timeout=1
|
|
):
|
|
pass
|
|
|
|
def test_imageUploadNumberLock_delete(self):
|
|
'''
|
|
Test that deleting an image upload number while we hold the lock
|
|
on it works properly.
|
|
'''
|
|
upload = zk.ImageUpload()
|
|
upload.image_name = "ubuntu-trusty"
|
|
upload.build_id = "0000000003"
|
|
upload.provider_name = "providerA"
|
|
upload.id = "0000000001"
|
|
path = self.zk._imageUploadNumberLockPath(upload.image_name,
|
|
upload.build_id,
|
|
upload.provider_name,
|
|
upload.id)
|
|
with self.zk.imageUploadNumberLock(upload, blocking=False):
|
|
self.assertIsNotNone(self.zk.client.exists(path))
|
|
self.zk.deleteUpload(upload.image_name,
|
|
upload.build_id,
|
|
upload.provider_name,
|
|
upload.id)
|
|
self.assertIsNone(self.zk.client.exists(path))
|
|
|
|
def test_imageUploadNumberLock_orphan(self):
|
|
upload = zk.ImageUpload()
|
|
upload.image_name = "ubuntu-trusty"
|
|
upload.build_id = "0000000003"
|
|
upload.provider_name = "providerA"
|
|
|
|
path = self.zk._imageUploadNumberLockPath(upload.image_name,
|
|
upload.build_id,
|
|
upload.provider_name,
|
|
upload.id)
|
|
|
|
with self.zk.imageUploadNumberLock(upload, blocking=False):
|
|
self.assertIsNotNone(self.zk.client.exists(path))
|
|
self.zk.deleteUpload(upload.image_name,
|
|
upload.build_id,
|
|
upload.provider_name,
|
|
upload.id)
|
|
|
|
# Pretend we still think the image upload exists
|
|
# (e.g. multiple cleanup workers itertating over uploads)
|
|
with self.zk.imageUploadNumberLock(upload, blocking=False):
|
|
# We now recreated an empty image upload number node
|
|
pass
|
|
|
|
self.assertIsNotNone(self.zk.client.exists(path))
|
|
|
|
# Should not throw an exception because of the empty upload
|
|
self.zk.getImageUpload(upload.image_name, upload.build_id,
|
|
upload.provider_name, upload.id)
|
|
|
|
def test_imageUploadNumberLock(self):
|
|
upload = zk.ImageUpload()
|
|
upload.image_name = "ubuntu-trusty"
|
|
upload.build_id = "0000000003"
|
|
upload.provider_name = "providerA"
|
|
upload.id = "0000000001"
|
|
path = self.zk._imageUploadNumberLockPath(upload.image_name,
|
|
upload.build_id,
|
|
upload.provider_name,
|
|
upload.id)
|
|
with self.zk.imageUploadNumberLock(upload, blocking=False):
|
|
self.assertIsNotNone(self.zk.client.exists(path))
|
|
|
|
def test_imageUploadNumberLock_exception_nonblocking(self):
|
|
upload = zk.ImageUpload()
|
|
upload.image_name = "ubuntu-trusty"
|
|
upload.build_id = "0000000003"
|
|
upload.provider_name = "providerA"
|
|
upload.id = "0000000001"
|
|
with self.zk.imageUploadNumberLock(upload, blocking=False):
|
|
with testtools.ExpectedException(
|
|
npe.ZKLockException, "Did not get lock on .*"
|
|
):
|
|
with self.zk.imageUploadNumberLock(upload, blocking=False):
|
|
pass
|
|
|
|
def test_imageUploadNumberLock_exception_blocking(self):
|
|
upload = zk.ImageUpload()
|
|
upload.image_name = "ubuntu-trusty"
|
|
upload.build_id = "0000000003"
|
|
upload.provider_name = "providerA"
|
|
upload.id = "0000000001"
|
|
with self.zk.imageUploadNumberLock(upload, blocking=False):
|
|
with testtools.ExpectedException(npe.TimeoutException):
|
|
with self.zk.imageUploadNumberLock(
|
|
upload, blocking=True, timeout=1
|
|
):
|
|
pass
|
|
|
|
def test_imageUploadLock(self):
|
|
path = self.zk._imageUploadLockPath("ubuntu-trusty", "0000", "prov1")
|
|
with self.zk.imageUploadLock("ubuntu-trusty", "0000", "prov1",
|
|
blocking=False):
|
|
self.assertIsNotNone(self.zk.client.exists(path))
|
|
|
|
def test_imageUploadLock_exception_nonblocking(self):
|
|
image = "ubuntu-trusty"
|
|
bnum = "0000000000"
|
|
prov = "rax"
|
|
with self.zk.imageUploadLock(image, bnum, prov, blocking=False):
|
|
with testtools.ExpectedException(
|
|
npe.ZKLockException, "Did not get lock on .*"
|
|
):
|
|
with self.zk.imageUploadLock(image, bnum, prov,
|
|
blocking=False):
|
|
pass
|
|
|
|
def test_imageUploadLock_exception_blocking(self):
|
|
image = "ubuntu-trusty"
|
|
bnum = "0000000000"
|
|
prov = "rax"
|
|
with self.zk.imageUploadLock(image, bnum, prov, blocking=False):
|
|
with testtools.ExpectedException(npe.TimeoutException):
|
|
with self.zk.imageUploadLock(image, bnum, prov,
|
|
blocking=True, timeout=1):
|
|
pass
|
|
|
|
def test_storeBuild(self):
|
|
image = "ubuntu-trusty"
|
|
b1 = self.zk.storeBuild(image, zk.ImageBuild())
|
|
b2 = self.zk.storeBuild(image, zk.ImageBuild())
|
|
self.assertLess(int(b1), int(b2))
|
|
|
|
def test_store_and_get_build(self):
|
|
image = "ubuntu-trusty"
|
|
orig_data = zk.ImageBuild()
|
|
orig_data.builder = 'host.domain.com'
|
|
orig_data.builder_id = 'ABC-123'
|
|
orig_data.state = zk.READY
|
|
with self.zk.imageBuildLock(image, blocking=True, timeout=1):
|
|
build_num = self.zk.storeBuild(image, orig_data)
|
|
|
|
data = self.zk.getBuild(image, build_num)
|
|
self.assertEqual(orig_data.builder, data.builder)
|
|
self.assertEqual(orig_data.builder_id, data.builder_id)
|
|
self.assertEqual(orig_data.state, data.state)
|
|
self.assertEqual(orig_data.state_time, data.state_time)
|
|
self.assertEqual(build_num, data.id)
|
|
self.assertEqual(self.zk.getImageNames(), ["ubuntu-trusty"])
|
|
self.assertEqual(self.zk.getBuildNumbers("ubuntu-trusty"), [build_num])
|
|
|
|
def test_getImageNames_not_found(self):
|
|
self.assertEqual(self.zk.getImageNames(), [])
|
|
|
|
def test_getBuildNumbers_not_found(self):
|
|
self.assertEqual(self.zk.getBuildNumbers("ubuntu-trusty"), [])
|
|
|
|
def test_getBuildProviders_not_found(self):
|
|
self.assertEqual(self.zk.getBuildProviders(
|
|
"ubuntu-trusty", "0000000000"), [])
|
|
|
|
def test_getImageUploadNumbers_not_found(self):
|
|
self.assertEqual(self.zk.getImageUploadNumbers(
|
|
"ubuntu-trusty", "0000000000", "rax"), [])
|
|
|
|
def test_getBuild_not_found(self):
|
|
self.assertIsNone(self.zk.getBuild("ubuntu-trusty", "0000000000"))
|
|
|
|
def test_getImageUpload_not_found(self):
|
|
self.assertIsNone(
|
|
self.zk.getImageUpload("trusty", "0001", "rax", "0000000001")
|
|
)
|
|
|
|
def test_storeImageUpload(self):
|
|
image = "ubuntu-trusty"
|
|
provider = "rax"
|
|
bnum = self.zk.storeBuild(image, zk.ImageBuild())
|
|
up1 = self.zk.storeImageUpload(image, bnum, provider, zk.ImageUpload())
|
|
up2 = self.zk.storeImageUpload(image, bnum, provider, zk.ImageUpload())
|
|
self.assertLess(int(up1), int(up2))
|
|
|
|
def test_storeImageUpload_invalid_build(self):
|
|
image = "ubuntu-trusty"
|
|
build_number = "0000000001"
|
|
provider = "rax"
|
|
orig_data = zk.ImageUpload()
|
|
|
|
with testtools.ExpectedException(
|
|
npe.ZKException, "Cannot find build .*"
|
|
):
|
|
self.zk.storeImageUpload(image, build_number, provider, orig_data)
|
|
|
|
def test_store_and_get_image_upload(self):
|
|
image = "ubuntu-trusty"
|
|
provider = "rax"
|
|
orig_data = zk.ImageUpload()
|
|
orig_data.external_id = "deadbeef"
|
|
orig_data.state = zk.READY
|
|
orig_data.format = "qcow2"
|
|
|
|
build_number = self.zk.storeBuild(image, zk.ImageBuild())
|
|
upload_id = self.zk.storeImageUpload(image, build_number, provider,
|
|
orig_data)
|
|
data = self.zk.getImageUpload(image, build_number, provider, upload_id)
|
|
|
|
self.assertEqual(upload_id, data.id)
|
|
self.assertEqual(orig_data.external_id, data.external_id)
|
|
self.assertEqual(orig_data.state, data.state)
|
|
self.assertEqual(orig_data.state_time, data.state_time)
|
|
self.assertEqual(orig_data.format, data.format)
|
|
self.assertEqual(self.zk.getBuildProviders("ubuntu-trusty",
|
|
build_number),
|
|
[provider])
|
|
self.assertEqual(self.zk.getImageUploadNumbers("ubuntu-trusty",
|
|
build_number,
|
|
provider),
|
|
[upload_id])
|
|
|
|
def test_build_request(self):
|
|
'''Test the build request API methods (has/submit/remove)'''
|
|
image = "ubuntu-trusty"
|
|
self.zk.submitBuildRequest(image)
|
|
self.assertTrue(self.zk.hasBuildRequest(image))
|
|
self.zk.removeBuildRequest(image)
|
|
self.assertFalse(self.zk.hasBuildRequest(image))
|
|
|
|
def test_buildLock_orphan(self):
|
|
image = "ubuntu-trusty"
|
|
build_number = "0000000003"
|
|
|
|
path = self.zk._imageBuildNumberLockPath(image, build_number)
|
|
|
|
# Pretend we still think the image build exists
|
|
# (e.g. multiple cleanup workers itertating over builds)
|
|
with self.zk.imageBuildNumberLock(image, build_number, blocking=False):
|
|
# We now created an empty build number node
|
|
pass
|
|
|
|
self.assertIsNotNone(self.zk.client.exists(path))
|
|
|
|
# Should not throw an exception because of the empty upload
|
|
self.assertIsNone(self.zk.getBuild(image, build_number))
|
|
|
|
def test_getMostRecentBuilds(self):
|
|
image = "ubuntu-trusty"
|
|
v1 = {'state': zk.READY, 'state_time': int(time.time())}
|
|
v2 = {'state': zk.READY, 'state_time': v1['state_time'] + 10}
|
|
v3 = {'state': zk.READY, 'state_time': v1['state_time'] + 20}
|
|
v4 = {'state': zk.DELETING, 'state_time': v2['state_time'] + 10}
|
|
self.zk.storeBuild(image, zk.ImageBuild.fromDict(v1))
|
|
v2_id = self.zk.storeBuild(image, zk.ImageBuild.fromDict(v2))
|
|
v3_id = self.zk.storeBuild(image, zk.ImageBuild.fromDict(v3))
|
|
self.zk.storeBuild(image, zk.ImageBuild.fromDict(v4))
|
|
|
|
# v2 and v3 should be the 2 most recent 'ready' builds
|
|
matches = self.zk.getMostRecentBuilds(2, image, zk.READY)
|
|
self.assertEqual(2, len(matches))
|
|
|
|
# Should be in descending order, according to state_time
|
|
self.assertEqual(matches[0].id, v3_id)
|
|
self.assertEqual(matches[1].id, v2_id)
|
|
|
|
def test_getMostRecentBuildImageUploads_with_state(self):
|
|
image = "ubuntu-trusty"
|
|
provider = "rax"
|
|
build = {'state': zk.READY, 'state_time': int(time.time())}
|
|
up1 = zk.ImageUpload()
|
|
up1.state = zk.READY
|
|
up2 = zk.ImageUpload()
|
|
up2.state = zk.READY
|
|
up2.state_time = up1.state_time + 10
|
|
up3 = zk.ImageUpload()
|
|
up3.state = zk.DELETING
|
|
up3.state_time = up2.state_time + 10
|
|
|
|
bnum = self.zk.storeBuild(image, zk.ImageBuild.fromDict(build))
|
|
self.zk.storeImageUpload(image, bnum, provider, up1)
|
|
up2_id = self.zk.storeImageUpload(image, bnum, provider, up2)
|
|
self.zk.storeImageUpload(image, bnum, provider, up3)
|
|
|
|
# up2 should be the most recent 'ready' upload
|
|
data = self.zk.getMostRecentBuildImageUploads(
|
|
1, image, bnum, provider, zk.READY)
|
|
self.assertNotEqual([], data)
|
|
self.assertEqual(1, len(data))
|
|
self.assertEqual(data[0].id, up2_id)
|
|
|
|
def test_getMostRecentBuildImageUploads_any_state(self):
|
|
image = "ubuntu-trusty"
|
|
provider = "rax"
|
|
build = {'state': zk.READY, 'state_time': int(time.time())}
|
|
up1 = zk.ImageUpload()
|
|
up1.state = zk.READY
|
|
up2 = zk.ImageUpload()
|
|
up2.state = zk.READY
|
|
up2.state_time = up1.state_time + 10
|
|
up3 = zk.ImageUpload()
|
|
up3.state = zk.UPLOADING
|
|
up3.state_time = up2.state_time + 10
|
|
|
|
bnum = self.zk.storeBuild(image, zk.ImageBuild.fromDict(build))
|
|
self.zk.storeImageUpload(image, bnum, provider, up1)
|
|
self.zk.storeImageUpload(image, bnum, provider, up2)
|
|
up3_id = self.zk.storeImageUpload(image, bnum, provider, up3)
|
|
|
|
# up3 should be the most recent upload, regardless of state
|
|
data = self.zk.getMostRecentBuildImageUploads(
|
|
1, image, bnum, provider, None)
|
|
self.assertNotEqual([], data)
|
|
self.assertEqual(1, len(data))
|
|
self.assertEqual(data[0].id, up3_id)
|
|
|
|
def test_getMostRecentImageUpload(self):
|
|
image = "ubuntu-trusty"
|
|
provider = "rax"
|
|
|
|
build1 = zk.ImageBuild()
|
|
build1.state = zk.READY
|
|
build2 = zk.ImageBuild()
|
|
build2.state = zk.READY
|
|
build2.state_time = build1.state_time + 10
|
|
|
|
bnum1 = self.zk.storeBuild(image, build1)
|
|
bnum2 = self.zk.storeBuild(image, build2)
|
|
|
|
upload1 = zk.ImageUpload()
|
|
upload1.state = zk.READY
|
|
upload2 = zk.ImageUpload()
|
|
upload2.state = zk.READY
|
|
upload2.state_time = upload1.state_time + 10
|
|
|
|
self.zk.storeImageUpload(image, bnum1, provider, upload1)
|
|
self.zk.storeImageUpload(image, bnum2, provider, upload2)
|
|
|
|
d = self.zk.getMostRecentImageUpload(image, provider, zk.READY)
|
|
self.assertEqual(upload2.state_time, d.state_time)
|
|
|
|
def test_getProviderUploads(self):
|
|
image = "ubuntu-trusty"
|
|
provider = "rax"
|
|
|
|
build = zk.ImageBuild()
|
|
build.state = zk.READY
|
|
bnum = self.zk.storeBuild(image, build)
|
|
|
|
upload = zk.ImageUpload()
|
|
upload.state = zk.READY
|
|
upnum = self.zk.storeImageUpload(image, bnum, provider, upload)
|
|
|
|
d = self.zk.getProviderUploads(provider)
|
|
self.assertIn(image, d)
|
|
self.assertIn(bnum, d[image])
|
|
self.assertEqual(1, len(d[image][bnum]))
|
|
self.assertIsInstance(d[image][bnum][0], zk.ImageUpload)
|
|
self.assertEqual(upnum, d[image][bnum][0].id)
|
|
|
|
def test_getBuilds_any(self):
|
|
image = "ubuntu-trusty"
|
|
path = self.zk._imageBuildsPath(image)
|
|
v1 = zk.ImageBuild()
|
|
v1.state = zk.READY
|
|
v2 = zk.ImageBuild()
|
|
v2.state = zk.BUILDING
|
|
v3 = zk.ImageBuild()
|
|
v3.state = zk.FAILED
|
|
v4 = zk.ImageBuild()
|
|
v4.state = zk.DELETING
|
|
self.zk.client.create(path + "/1", value=v1.serialize(), makepath=True)
|
|
self.zk.client.create(path + "/2", value=v2.serialize(), makepath=True)
|
|
self.zk.client.create(path + "/3", value=v3.serialize(), makepath=True)
|
|
self.zk.client.create(path + "/4", value=v4.serialize(), makepath=True)
|
|
self.zk.client.create(path + "/lock", makepath=True)
|
|
|
|
matches = self.zk.getBuilds(image, None)
|
|
self.assertEqual(4, len(matches))
|
|
|
|
def test_getBuilds(self):
|
|
image = "ubuntu-trusty"
|
|
path = self.zk._imageBuildsPath(image)
|
|
v1 = zk.ImageBuild()
|
|
v1.state = zk.READY
|
|
v2 = zk.ImageBuild()
|
|
v2.state = zk.BUILDING
|
|
v3 = zk.ImageBuild()
|
|
v3.state = zk.FAILED
|
|
v4 = zk.ImageBuild()
|
|
v4.state = zk.DELETING
|
|
self.zk.client.create(path + "/1", value=v1.serialize(), makepath=True)
|
|
self.zk.client.create(path + "/2", value=v2.serialize(), makepath=True)
|
|
self.zk.client.create(path + "/3", value=v3.serialize(), makepath=True)
|
|
self.zk.client.create(path + "/4", value=v4.serialize(), makepath=True)
|
|
self.zk.client.create(path + "/lock", makepath=True)
|
|
|
|
matches = self.zk.getBuilds(image, [zk.DELETING, zk.FAILED])
|
|
self.assertEqual(2, len(matches))
|
|
|
|
def test_getUploads(self):
|
|
path = self.zk._imageUploadPath("trusty", "000", "rax")
|
|
v1 = zk.ImageUpload()
|
|
v1.state = zk.READY
|
|
v2 = zk.ImageUpload()
|
|
v2.state = zk.UPLOADING
|
|
v3 = zk.ImageUpload()
|
|
v3.state = zk.FAILED
|
|
v4 = zk.ImageUpload()
|
|
v4.state = zk.DELETING
|
|
self.zk.client.create(path + "/1", value=v1.serialize(), makepath=True)
|
|
self.zk.client.create(path + "/2", value=v2.serialize(), makepath=True)
|
|
self.zk.client.create(path + "/3", value=v3.serialize(), makepath=True)
|
|
self.zk.client.create(path + "/4", value=v4.serialize(), makepath=True)
|
|
self.zk.client.create(path + "/lock", makepath=True)
|
|
|
|
matches = self.zk.getUploads("trusty", "000", "rax",
|
|
[zk.DELETING, zk.FAILED])
|
|
self.assertEqual(2, len(matches))
|
|
|
|
def test_getUploads_any(self):
|
|
path = self.zk._imageUploadPath("trusty", "000", "rax")
|
|
v1 = zk.ImageUpload()
|
|
v1.state = zk.READY
|
|
v2 = zk.ImageUpload()
|
|
v2.state = zk.UPLOADING
|
|
v3 = zk.ImageUpload()
|
|
v3.state = zk.FAILED
|
|
v4 = zk.ImageUpload()
|
|
v4.state = zk.DELETING
|
|
self.zk.client.create(path + "/1", value=v1.serialize(), makepath=True)
|
|
self.zk.client.create(path + "/2", value=v2.serialize(), makepath=True)
|
|
self.zk.client.create(path + "/3", value=v3.serialize(), makepath=True)
|
|
self.zk.client.create(path + "/4", value=v4.serialize(), makepath=True)
|
|
self.zk.client.create(path + "/lock", makepath=True)
|
|
|
|
matches = self.zk.getUploads("trusty", "000", "rax", None)
|
|
self.assertEqual(4, len(matches))
|
|
|
|
def test_deleteBuild(self):
|
|
image = 'trusty'
|
|
build = zk.ImageBuild()
|
|
build.state = zk.READY
|
|
bnum = self.zk.storeBuild(image, build)
|
|
self.assertTrue(self.zk.deleteBuild(image, bnum))
|
|
|
|
def test_deleteBuild_with_uploads(self):
|
|
image = 'trusty'
|
|
provider = 'rax'
|
|
|
|
build = zk.ImageBuild()
|
|
build.state = zk.READY
|
|
bnum = self.zk.storeBuild(image, build)
|
|
|
|
upload = zk.ImageUpload()
|
|
upload.state = zk.READY
|
|
self.zk.storeImageUpload(image, bnum, provider, upload)
|
|
|
|
self.assertFalse(self.zk.deleteBuild(image, bnum))
|
|
|
|
def test_deleteUpload(self):
|
|
path = self.zk._imageUploadPath("trusty", "000", "rax") + "/000001"
|
|
self.zk.client.create(path, makepath=True)
|
|
self.zk.deleteUpload("trusty", "000", "rax", "000001")
|
|
self.assertIsNone(self.zk.client.exists(path))
|
|
|
|
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.REQUESTED
|
|
path = self.zk._requestPath(r.id)
|
|
self.zk.client.create(path, value=r.serialize(),
|
|
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"))
|
|
|
|
def test_getNodes(self):
|
|
self.zk.client.create(self.zk._nodePath('100'), makepath=True)
|
|
self.zk.client.create(self.zk._nodePath('200'), makepath=True)
|
|
nodes = self.zk.getNodes()
|
|
self.assertIn('100', nodes)
|
|
self.assertIn('200', nodes)
|
|
|
|
def test_getNode(self):
|
|
n = zk.Node('100')
|
|
n.state = zk.BUILDING
|
|
path = self.zk._nodePath(n.id)
|
|
self.zk.client.create(path, value=n.serialize(), makepath=True)
|
|
o = self.zk.getNode(n.id)
|
|
self.assertIsInstance(o, zk.Node)
|
|
self.assertEqual(n.id, o.id)
|
|
|
|
def test_getNode_not_found(self):
|
|
self.assertIsNone(self.zk.getNode("invalid"))
|
|
|
|
def test_lockNode_multi(self):
|
|
node = zk.Node('100')
|
|
self.zk.lockNode(node)
|
|
with testtools.ExpectedException(
|
|
npe.ZKLockException, "Did not get lock on .*"
|
|
):
|
|
self.zk.lockNode(node, blocking=False)
|
|
|
|
def test_lockNode_unlockNode(self):
|
|
node = zk.Node('100')
|
|
self.zk.lockNode(node)
|
|
self.assertIsNotNone(node.lock)
|
|
self.assertIsNotNone(
|
|
self.zk.client.exists(self.zk._nodeLockPath(node.id))
|
|
)
|
|
self.zk.unlockNode(node)
|
|
self.assertIsNone(node.lock)
|
|
|
|
def test_unlockNode_not_locked(self):
|
|
node = zk.Node('100')
|
|
with testtools.ExpectedException(npe.ZKLockException):
|
|
self.zk.unlockNode(node)
|
|
|
|
def _create_node(self):
|
|
node = zk.Node()
|
|
node.state = zk.BUILDING
|
|
node.provider = 'rax'
|
|
|
|
self.assertIsNone(node.id)
|
|
self.zk.storeNode(node)
|
|
self.assertIsNotNone(node.id)
|
|
self.assertIsNotNone(
|
|
self.zk.client.exists(self.zk._nodePath(node.id))
|
|
)
|
|
return node
|
|
|
|
def test_storeNode(self):
|
|
node = self._create_node()
|
|
node2 = self.zk.getNode(node.id)
|
|
self.assertEqual(node, node2)
|
|
|
|
def test_storeNode_update(self):
|
|
node = self._create_node()
|
|
node.state = zk.READY
|
|
self.zk.storeNode(node)
|
|
node2 = self.zk.getNode(node.id)
|
|
self.assertEqual(node, node2)
|
|
|
|
def _create_node_request(self):
|
|
req = zk.NodeRequest()
|
|
req.state = zk.REQUESTED
|
|
req.node_types.append('label1')
|
|
self.zk.storeNodeRequest(req)
|
|
self.assertIsNotNone(
|
|
self.zk.client.exists(self.zk._requestPath(req.id))
|
|
)
|
|
return req
|
|
|
|
def test_storeNodeRequest(self):
|
|
req = self._create_node_request()
|
|
self.assertNotEqual(req.event_id, None)
|
|
req2 = self.zk.getNodeRequest(req.id)
|
|
self.assertEqual(req, req2)
|
|
|
|
def test_storeNodeRequest_update(self):
|
|
req = self._create_node_request()
|
|
req.state = zk.FULFILLED
|
|
self.zk.storeNodeRequest(req)
|
|
self.assertIsNotNone(req.id)
|
|
req2 = self.zk.getNodeRequest(req.id)
|
|
self.assertEqual(req, req2)
|
|
|
|
def test_deleteNodeRequest(self):
|
|
req = self._create_node_request()
|
|
self.zk.deleteNodeRequest(req)
|
|
self.assertIsNone(
|
|
self.zk.client.exists(self.zk._requestPath(req.id))
|
|
)
|
|
|
|
def test_deleteNode(self):
|
|
n1 = self._create_node()
|
|
self.zk.deleteNode(n1)
|
|
self.assertIsNone(
|
|
self.zk.client.exists(self.zk._nodePath(n1.id))
|
|
)
|
|
|
|
def test_getReadyNodesOfTypes(self):
|
|
n1 = self._create_node()
|
|
n1.type = 'label1'
|
|
n1.state = zk.READY
|
|
self.zk.storeNode(n1)
|
|
n2 = self._create_node()
|
|
n2.state = zk.READY
|
|
n2.type = 'label1'
|
|
self.zk.storeNode(n2)
|
|
n3 = self._create_node()
|
|
n3.state = zk.READY
|
|
n3.type = 'label2'
|
|
self.zk.storeNode(n3)
|
|
|
|
r = self.zk.getReadyNodesOfTypes(['label1'], cached=False)
|
|
self.assertIn('label1', r)
|
|
self.assertEqual(2, len(r['label1']))
|
|
self.assertIn(n1, r['label1'])
|
|
self.assertIn(n2, r['label1'])
|
|
|
|
def test_getReadyNodesOfTypes_multilabel(self):
|
|
n1 = self._create_node()
|
|
n1.type = 'label1'
|
|
n1.state = zk.READY
|
|
self.zk.storeNode(n1)
|
|
n2 = self._create_node()
|
|
n2.state = zk.READY
|
|
n2.type = ['label1', 'label3']
|
|
self.zk.storeNode(n2)
|
|
n3 = self._create_node()
|
|
n3.state = zk.READY
|
|
n3.type = 'label2'
|
|
self.zk.storeNode(n3)
|
|
|
|
r = self.zk.getReadyNodesOfTypes(['label1', 'label3'], cached=False)
|
|
self.assertIn('label1', r)
|
|
self.assertIn('label3', r)
|
|
self.assertEqual(2, len(r['label1']))
|
|
self.assertEqual(1, len(r['label3']))
|
|
self.assertIn(n1, r['label1'])
|
|
self.assertIn(n2, r['label1'])
|
|
self.assertIn(n2, r['label3'])
|
|
|
|
def test_nodeIterator(self):
|
|
n1 = self._create_node()
|
|
i = self.zk.nodeIterator(cached=False)
|
|
self.assertEqual(n1, next(i))
|
|
with testtools.ExpectedException(StopIteration):
|
|
next(i)
|
|
|
|
def test_getNodeRequestLockIDs(self):
|
|
req = self._create_node_request()
|
|
self.zk.lockNodeRequest(req, blocking=False)
|
|
lock_ids = self.zk.getNodeRequestLockIDs()
|
|
self.assertEqual(1, len(lock_ids))
|
|
self.assertEqual(req.id, lock_ids[0])
|
|
self.zk.unlockNodeRequest(req)
|
|
self.zk.deleteNodeRequest(req)
|
|
|
|
def test_getNodeRequestLockStats(self):
|
|
req = self._create_node_request()
|
|
self.zk.lockNodeRequest(req, blocking=False)
|
|
lock_stats = self.zk.getNodeRequestLockStats(req.id)
|
|
self.assertEqual(lock_stats.lock_id, req.id)
|
|
self.assertIsNotNone(lock_stats.stat)
|
|
self.zk.unlockNodeRequest(req)
|
|
self.zk.deleteNodeRequest(req)
|
|
|
|
def test_nodeRequestLockStatsIterator(self):
|
|
req = self._create_node_request()
|
|
self.zk.lockNodeRequest(req, blocking=False)
|
|
i = self.zk.nodeRequestLockStatsIterator()
|
|
self.assertEqual(zk.NodeRequestLockStats(req.id), next(i))
|
|
with testtools.ExpectedException(StopIteration):
|
|
next(i)
|
|
self.zk.unlockNodeRequest(req)
|
|
self.zk.deleteNodeRequest(req)
|
|
|
|
def test_nodeRequestIterator(self):
|
|
req = self._create_node_request()
|
|
self.zk.lockNodeRequest(req, blocking=False)
|
|
i = self.zk.nodeRequestIterator()
|
|
self.assertEqual(req, next(i))
|
|
with testtools.ExpectedException(StopIteration):
|
|
next(i)
|
|
self.zk.unlockNodeRequest(req)
|
|
self.zk.deleteNodeRequest(req)
|
|
|
|
def test_deleteNodeRequestLock(self):
|
|
req = self._create_node_request()
|
|
self.zk.lockNodeRequest(req, blocking=False)
|
|
self.zk.unlockNodeRequest(req)
|
|
self.zk.deleteNodeRequest(req)
|
|
|
|
# We expect the lock to linger even after the request is deleted
|
|
lock_ids = self.zk.getNodeRequestLockIDs()
|
|
self.assertEqual(1, len(lock_ids))
|
|
self.assertEqual(req.id, lock_ids[0])
|
|
self.zk.deleteNodeRequestLock(lock_ids[0])
|
|
self.assertEqual([], self.zk.getNodeRequestLockIDs())
|
|
|
|
def test_node_caching(self):
|
|
'''
|
|
Test that node iteration using both cached and uncached calls
|
|
produces identical results.
|
|
'''
|
|
# Test new node in node set
|
|
n1 = self._create_node()
|
|
|
|
# uncached
|
|
a1 = self.zk.nodeIterator(cached=False)
|
|
self.assertEqual(n1, next(a1))
|
|
|
|
# cached
|
|
a2 = self.zk.nodeIterator(cached=True)
|
|
self.assertEqual(n1, next(a2))
|
|
with testtools.ExpectedException(StopIteration):
|
|
next(a2)
|
|
|
|
# Test modification of existing node set
|
|
n1.state = zk.HOLD
|
|
n1.label = "oompaloompa"
|
|
self.zk.storeNode(n1)
|
|
|
|
# uncached
|
|
b1 = self.zk.nodeIterator(cached=False)
|
|
self.assertEqual(n1, next(b1))
|
|
|
|
# cached
|
|
for _ in iterate_timeout(10, Exception,
|
|
"cached node equals original node"):
|
|
b2 = self.zk.nodeIterator(cached=True)
|
|
if n1 == next(b2):
|
|
break
|
|
|
|
|
|
class TestZKModel(tests.BaseTestCase):
|
|
|
|
def setUp(self):
|
|
super(TestZKModel, self).setUp()
|
|
|
|
def test_BaseModel_bad_id(self):
|
|
with testtools.ExpectedException(
|
|
TypeError, "'id' attribute must be a string type"
|
|
):
|
|
zk.BaseModel(123)
|
|
|
|
def test_BaseModel_bad_state(self):
|
|
with testtools.ExpectedException(
|
|
TypeError, "'blah' is not a valid state"
|
|
):
|
|
o = zk.BaseModel('0001')
|
|
o.state = 'blah'
|
|
|
|
def test_BaseModel_toDict(self):
|
|
o = zk.BaseModel('0001')
|
|
d = o.toDict()
|
|
self.assertNotIn('id', d)
|
|
|
|
def test_ImageBuild_toDict(self):
|
|
o = zk.ImageBuild('0001')
|
|
o.state = zk.BUILDING
|
|
o.builder = 'localhost'
|
|
o.builder_id = 'ABC-123'
|
|
o.formats = ['qemu', 'raw']
|
|
|
|
d = o.toDict()
|
|
self.assertNotIn('id', d)
|
|
self.assertEqual(o.state, d['state'])
|
|
self.assertIsNotNone(d['state_time'])
|
|
self.assertEqual(','.join(o.formats), d['formats'])
|
|
self.assertEqual(o.builder, d['builder'])
|
|
self.assertEqual(o.builder_id, d['builder_id'])
|
|
|
|
def test_ImageBuild_fromDict(self):
|
|
now = int(time.time())
|
|
d_id = '0001'
|
|
d = {
|
|
'builder': 'localhost',
|
|
'builder_id': 'ABC-123',
|
|
'formats': 'qemu,raw',
|
|
'state': zk.BUILDING,
|
|
'state_time': now
|
|
}
|
|
|
|
o = zk.ImageBuild.fromDict(d, d_id)
|
|
self.assertEqual(o.id, d_id)
|
|
self.assertEqual(o.state, d['state'])
|
|
self.assertEqual(o.state_time, d['state_time'])
|
|
self.assertEqual(o.builder, d['builder'])
|
|
self.assertEqual(o.builder_id, d['builder_id'])
|
|
self.assertEqual(o.formats, d['formats'].split(','))
|
|
|
|
def test_ImageUpload_toDict(self):
|
|
o = zk.ImageUpload('0001', '0003')
|
|
o.state = zk.UPLOADING
|
|
o.external_id = 'DEADBEEF'
|
|
o.external_name = 'trusty'
|
|
o.format = 'qcow2'
|
|
|
|
d = o.toDict()
|
|
self.assertNotIn('id', d)
|
|
self.assertNotIn('build_id', d)
|
|
self.assertNotIn('provider_name', d)
|
|
self.assertNotIn('image_name', d)
|
|
self.assertEqual(o.state, d['state'])
|
|
self.assertEqual(o.state_time, d['state_time'])
|
|
self.assertEqual(o.external_id, d['external_id'])
|
|
self.assertEqual(o.external_name, d['external_name'])
|
|
self.assertEqual(o.format, d['format'])
|
|
|
|
def test_ImageUpload_fromDict(self):
|
|
now = int(time.time())
|
|
upload_id = '0001'
|
|
build_id = '0003'
|
|
d = {
|
|
'external_id': 'DEADBEEF',
|
|
'external_name': 'trusty',
|
|
'format': 'qcow2',
|
|
'state': zk.READY,
|
|
'state_time': now
|
|
}
|
|
|
|
o = zk.ImageUpload.fromDict(d, build_id, 'rax', 'trusty', upload_id)
|
|
self.assertEqual(o.id, upload_id)
|
|
self.assertEqual(o.build_id, build_id)
|
|
self.assertEqual(o.provider_name, 'rax')
|
|
self.assertEqual(o.image_name, 'trusty')
|
|
self.assertEqual(o.state, d['state'])
|
|
self.assertEqual(o.state_time, d['state_time'])
|
|
self.assertEqual(o.external_id, d['external_id'])
|
|
self.assertEqual(o.external_name, d['external_name'])
|
|
self.assertEqual(o.format, d['format'])
|
|
|
|
def test_NodeRequest_toDict(self):
|
|
o = zk.NodeRequest("500-123")
|
|
o.declined_by.append("abc")
|
|
o.node_types.append('trusty')
|
|
o.nodes.append('100')
|
|
o.reuse = False
|
|
o.requestor = 'zuul'
|
|
o.provider = "test"
|
|
o.relative_priority = 1
|
|
o.event_id = "deadbeef"
|
|
d = o.toDict()
|
|
self.assertNotIn('id', d)
|
|
self.assertIn('state', d)
|
|
self.assertIn('state_time', d)
|
|
self.assertEqual(d['declined_by'], o.declined_by)
|
|
self.assertEqual(d['node_types'], o.node_types)
|
|
self.assertEqual(d['nodes'], o.nodes)
|
|
self.assertEqual(d['reuse'], o.reuse)
|
|
self.assertEqual(d['requestor'], o.requestor)
|
|
self.assertEqual(d['provider'], o.provider)
|
|
self.assertEqual(d['relative_priority'], o.relative_priority)
|
|
self.assertEqual(d['event_id'], o.event_id)
|
|
|
|
def test_NodeRequest_fromDict(self):
|
|
now = int(time.time())
|
|
req_id = "500-123"
|
|
d = {
|
|
'state': zk.REQUESTED,
|
|
'state_time': now,
|
|
'declined_by': ['abc'],
|
|
'node_types': ['trusty'],
|
|
'nodes': ['100'],
|
|
'reuse': False,
|
|
'requestor': 'zuul',
|
|
'provider': 'test',
|
|
'relative_priority': 1,
|
|
'event_id': 'deadbeef',
|
|
}
|
|
|
|
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'])
|
|
self.assertEqual(o.declined_by, d['declined_by'])
|
|
self.assertEqual(o.node_types, d['node_types'])
|
|
self.assertEqual(o.nodes, d['nodes'])
|
|
self.assertEqual(o.reuse, d['reuse'])
|
|
self.assertEqual(o.requestor, d['requestor'])
|
|
self.assertEqual(o.provider, d['provider'])
|
|
self.assertEqual(o.relative_priority, d['relative_priority'])
|
|
self.assertEqual(o.event_id, d['event_id'])
|
|
|
|
def test_Node_toDict(self):
|
|
o = zk.Node('123')
|
|
o.state = zk.INIT
|
|
o.provider = 'rax'
|
|
o.type = 'trusty'
|
|
o.allocated_to = '456-789'
|
|
o.az = 'RegionOne'
|
|
o.region = 'fake-region'
|
|
o.public_ipv4 = '<ipv4>'
|
|
o.private_ipv4 = '<pvt-ipv4>'
|
|
o.public_ipv6 = '<ipv6>'
|
|
o.host_id = 'fake-host-id'
|
|
o.image_id = 'image-id'
|
|
o.launcher = 'launcher-Poolworker.provider-main-' + uuid.uuid4().hex
|
|
o.external_id = 'ABCD'
|
|
o.hostname = 'xyz'
|
|
o.comment = 'comment'
|
|
o.hold_job = 'hold job'
|
|
o.host_keys = ['key1', 'key2']
|
|
o.attributes = {'executor-zone': 'vpn'}
|
|
|
|
d = o.toDict()
|
|
self.assertNotIn('id', d)
|
|
self.assertEqual(d['state'], o.state)
|
|
self.assertIn('state_time', d)
|
|
self.assertIn('created_time', d)
|
|
self.assertEqual(d['provider'], o.provider)
|
|
self.assertEqual(d['type'], o.type)
|
|
self.assertEqual(d['allocated_to'], o.allocated_to)
|
|
self.assertEqual(d['az'], o.az)
|
|
self.assertEqual(d['region'], o.region)
|
|
self.assertEqual(d['public_ipv4'], o.public_ipv4)
|
|
self.assertEqual(d['private_ipv4'], o.private_ipv4)
|
|
self.assertEqual(d['public_ipv6'], o.public_ipv6)
|
|
self.assertEqual(d['host_id'], o.host_id)
|
|
self.assertEqual(d['image_id'], o.image_id)
|
|
self.assertEqual(d['launcher'], o.launcher)
|
|
self.assertEqual(d['external_id'], o.external_id)
|
|
self.assertEqual(d['hostname'], o.hostname)
|
|
self.assertEqual(d['comment'], o.comment)
|
|
self.assertEqual(d['hold_job'], o.hold_job)
|
|
self.assertEqual(d['host_keys'], o.host_keys)
|
|
self.assertEqual(d['attributes'], o.attributes)
|
|
|
|
def test_Node_fromDict(self):
|
|
now = int(time.time())
|
|
node_id = '123'
|
|
launcher_id = 'launcher-Poolworker.provider-main-' + uuid.uuid4().hex
|
|
d = {
|
|
'state': zk.READY,
|
|
'state_time': now,
|
|
'created_time': now - 2,
|
|
'provider': 'rax',
|
|
'type': ['trusty'],
|
|
'allocated_to': '456-789',
|
|
'az': 'RegionOne',
|
|
'region': 'fake-region',
|
|
'public_ipv4': '<ipv4>',
|
|
'private_ipv4': '<pvt-ipv4>',
|
|
'public_ipv6': '<ipv6>',
|
|
'host_id': 'fake-host-id',
|
|
'image_id': 'image-id',
|
|
'launcher': launcher_id,
|
|
'external_id': 'ABCD',
|
|
'hostname': 'xyz',
|
|
'comment': 'comment',
|
|
'hold_job': 'hold job',
|
|
'host_keys': ['key1', 'key2'],
|
|
'connection_port': 22022,
|
|
'attributes': {'executor-zone': 'vpn'},
|
|
}
|
|
|
|
o = zk.Node.fromDict(d, node_id)
|
|
self.assertEqual(o.id, node_id)
|
|
self.assertEqual(o.state, d['state'])
|
|
self.assertEqual(o.state_time, d['state_time'])
|
|
self.assertEqual(o.created_time, d['created_time'])
|
|
self.assertEqual(o.provider, d['provider'])
|
|
self.assertEqual(o.type, d['type'])
|
|
self.assertEqual(o.allocated_to, d['allocated_to'])
|
|
self.assertEqual(o.az, d['az'])
|
|
self.assertEqual(o.region, d['region'])
|
|
self.assertEqual(o.public_ipv4, d['public_ipv4'])
|
|
self.assertEqual(o.private_ipv4, d['private_ipv4'])
|
|
self.assertEqual(o.public_ipv6, d['public_ipv6'])
|
|
self.assertEqual(o.host_id, d['host_id'])
|
|
self.assertEqual(o.image_id, d['image_id'])
|
|
self.assertEqual(o.launcher, d['launcher'])
|
|
self.assertEqual(o.external_id, d['external_id'])
|
|
self.assertEqual(o.hostname, d['hostname'])
|
|
self.assertEqual(o.comment, d['comment'])
|
|
self.assertEqual(o.hold_job, d['hold_job'])
|
|
self.assertEqual(o.host_keys, d['host_keys'])
|
|
self.assertEqual(o.connection_port, d['connection_port'])
|
|
self.assertEqual(o.attributes, d['attributes'])
|
|
|
|
def test_custom_connection_port(self):
|
|
n = zk.Node('0001')
|
|
n.state = zk.BUILDING
|
|
d = n.toDict()
|
|
self.assertEqual(d["connection_port"], 22, "Default port not 22")
|
|
n = zk.Node.fromDict(d, '0001')
|
|
self.assertEqual(n.connection_port, 22, "Default port not 22")
|
|
n.connection_port = 22022
|
|
d = n.toDict()
|
|
self.assertEqual(d["connection_port"], 22022,
|
|
"Custom ssh port not set")
|