Manage a pool of nodes for a distributed test infrastructure
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
nodepool/nodepool/tests/unit/test_webapp.py

334 lines
13 KiB

# Copyright (C) 2014 OpenStack Foundation
#
# 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 json
import logging
import yaml
from urllib import request
from urllib.error import HTTPError
from nodepool import tests
from nodepool.zk import zookeeper as zk
from nodepool.nodeutils import iterate_timeout
class TestWebApp(tests.DBTestCase):
log = logging.getLogger("nodepool.TestWebApp")
# A standard browser accept header
browser_accept = (
'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8')
def test_image_list(self):
configfile = self.setup_config('node.yaml')
pool = self.useNodepool(configfile, watermark_sleep=1)
self.useBuilder(configfile)
pool.start()
webapp = self.useWebApp(pool, port=0)
webapp.start()
port = webapp.server.socket.getsockname()[1]
self.waitForImage('fake-provider', 'fake-image')
self.waitForNodes('fake-label')
req = request.Request(
"http://localhost:%s/image-list" % port)
# NOTE(ianw): we want pretty printed text/plain back, but
# simulating a normal web-browser request.
req.add_header('Accept', self.browser_accept)
f = request.urlopen(req)
self.assertEqual(f.info().get('Content-Type'),
'text/plain; charset=UTF-8')
data = f.read()
self.assertTrue('fake-image' in data.decode('utf8'))
# also ensure that text/plain works (might be hand-set by a
# command-line curl script, etc)
req = request.Request(
"http://localhost:%s/image-list" % port)
req.add_header('Accept', 'text/plain')
f = request.urlopen(req)
self.assertEqual(f.info().get('Content-Type'),
'text/plain; charset=UTF-8')
data = f.read()
self.assertTrue('fake-image' in data.decode('utf8'))
def test_image_list_filtered(self):
configfile = self.setup_config('node.yaml')
pool = self.useNodepool(configfile, watermark_sleep=1)
self.useBuilder(configfile)
pool.start()
webapp = self.useWebApp(pool, port=0)
webapp.start()
port = webapp.server.socket.getsockname()[1]
self.waitForImage('fake-provider', 'fake-image')
self.waitForNodes('fake-label')
req = request.Request(
"http://localhost:%s/image-list?fields=id,image,state" % port)
req.add_header('Accept', self.browser_accept)
f = request.urlopen(req)
self.assertEqual(f.info().get('Content-Type'),
'text/plain; charset=UTF-8')
data = f.read()
self.assertIn("| 0000000001 | fake-image | ready |",
data.decode('utf8'))
def test_image_list_json(self):
configfile = self.setup_config('node.yaml')
pool = self.useNodepool(configfile, watermark_sleep=1)
self.useBuilder(configfile)
pool.start()
webapp = self.useWebApp(pool, port=0)
webapp.start()
port = webapp.server.socket.getsockname()[1]
self.waitForImage('fake-provider', 'fake-image')
self.waitForNodes('fake-label')
req = request.Request(
"http://localhost:%s/image-list" % port)
req.add_header('Accept', 'application/json')
f = request.urlopen(req)
self.assertEqual(f.info().get('Content-Type'),
'application/json')
data = f.read()
objs = json.loads(data.decode('utf8'))
self.assertDictContainsSubset({'id': '0000000001',
'image': 'fake-image',
'provider': 'fake-provider',
'state': 'ready'}, objs[0])
def test_dib_image_list_json(self):
configfile = self.setup_config('node.yaml')
pool = self.useNodepool(configfile, watermark_sleep=1)
self.useBuilder(configfile)
pool.start()
webapp = self.useWebApp(pool, port=0)
webapp.start()
port = webapp.server.socket.getsockname()[1]
self.waitForImage('fake-provider', 'fake-image')
self.waitForNodes('fake-label')
req = request.Request(
"http://localhost:%s/dib-image-list" % port)
req.add_header('Accept', 'application/json')
f = request.urlopen(req)
self.assertEqual(f.info().get('Content-Type'),
'application/json')
data = f.read()
objs = json.loads(data.decode('utf8'))
# make sure this is valid json and has some of the
# non-changing keys
self.assertDictContainsSubset({'id': 'fake-image-0000000001',
'formats': ['qcow2'],
'state': 'ready'}, objs[0])
def test_image_status_json(self):
configfile = self.setup_config("node.yaml")
pool = self.useNodepool(configfile, watermark_sleep=1)
builder = self.useBuilder(configfile)
# Make sure we have enough time to test for the build request
# before it's processed by the build worker.
for worker in builder._build_workers:
worker._interval = 60
pool.start()
webapp = self.useWebApp(pool, port=0)
webapp.start()
port = webapp.server.socket.getsockname()[1]
self.waitForImage("fake-provider", "fake-image")
self.waitForNodes('fake-label')
req = request.Request(
"http://localhost:{}/image-status".format(port))
req.add_header("Accept", "application/json")
f = request.urlopen(req)
self.assertEqual(f.info().get("Content-Type"),
"application/json")
data = f.read()
objs = json.loads(data.decode("utf8"))
self.assertDictContainsSubset({"image": "fake-image",
"paused": False,
"build_request": None}, objs[0])
self.zk.submitBuildRequest("fake-image")
webapp.cache.cache.clear()
f = request.urlopen(req)
data = f.read()
objs = json.loads(data.decode("utf8"))
self.assertDictContainsSubset({"image": "fake-image",
"paused": False,
"build_request": "pending"}, objs[0])
builder._janitor._emitBuildRequestStats()
self.assertReportedStat('nodepool.image_build_requests', '1', 'g')
webapp.cache.cache.clear()
with self.zk.imageBuildLock('fake-image', blocking=True, timeout=1):
f = request.urlopen(req)
data = f.read()
objs = json.loads(data.decode("utf8"))
self.assertDictContainsSubset({"image": "fake-image",
"paused": False,
"build_request": "building"}, objs[0])
def test_node_list_json(self):
configfile = self.setup_config('node.yaml')
pool = self.useNodepool(configfile, watermark_sleep=1)
self.useBuilder(configfile)
pool.start()
webapp = self.useWebApp(pool, port=0)
webapp.start()
port = webapp.server.socket.getsockname()[1]
self.waitForImage('fake-provider', 'fake-image')
self.waitForNodes('fake-label')
req = request.Request(
"http://localhost:%s/node-list" % port)
req.add_header('Accept', 'application/json')
f = request.urlopen(req)
self.assertEqual(f.info().get('Content-Type'),
'application/json')
data = f.read()
objs = json.loads(data.decode('utf8'))
self.assertDictContainsSubset({'id': '0000000000',
'ipv6': '',
'label': ['fake-label'],
'locked': 'unlocked',
'provider': 'fake-provider',
'public_ipv4': 'fake',
'state': 'ready'}, objs[0])
# specify valid node_id
req = request.Request(
"http://localhost:%s/node-list?node_id=%s" % (port,
'0000000000'))
req.add_header('Accept', 'application/json')
f = request.urlopen(req)
self.assertEqual(f.info().get('Content-Type'),
'application/json')
data = f.read()
objs = json.loads(data.decode('utf8'))
self.assertDictContainsSubset({'id': '0000000000',
'ipv6': '',
'label': ['fake-label'],
'locked': 'unlocked',
'provider': 'fake-provider',
'public_ipv4': 'fake',
'state': 'ready'}, objs[0])
# node_id not found
req = request.Request(
"http://localhost:%s/node-list?node_id=%s" % (port,
'999999'))
req.add_header('Accept', 'application/json')
f = request.urlopen(req)
self.assertEqual(f.info().get('Content-Type'),
'application/json')
data = f.read()
objs = json.loads(data.decode('utf8'))
self.assertEqual(0, len(objs), objs)
def test_request_list_json(self):
configfile = self.setup_config('node.yaml')
pool = self.useNodepool(configfile, watermark_sleep=1)
self.useBuilder(configfile)
pool.start()
webapp = self.useWebApp(pool, port=0)
webapp.start()
port = webapp.server.socket.getsockname()[1]
self.waitForImage('fake-provider', 'fake-image')
self.waitForNodes('fake-label')
req = zk.NodeRequest()
req.state = zk.PENDING # so it will be ignored
req.node_types = ['fake-label']
req.requestor = 'test_request_list'
self.zk.storeNodeRequest(req)
http_req = request.Request(
"http://localhost:%s/request-list" % port)
http_req.add_header('Accept', 'application/json')
f = request.urlopen(http_req)
self.assertEqual(f.info().get('Content-Type'),
'application/json')
data = f.read()
objs = json.loads(data.decode('utf8'))
self.assertDictContainsSubset({'node_types': ['fake-label'],
'requestor': 'test_request_list',
'event_id': req.event_id, },
objs[0])
def test_label_list_json(self):
configfile = self.setup_config('node.yaml')
pool = self.useNodepool(configfile, watermark_sleep=1)
self.useBuilder(configfile)
pool.start()
webapp = self.useWebApp(pool, port=0)
webapp.start()
port = webapp.server.socket.getsockname()[1]
self.waitForImage('fake-provider', 'fake-image')
self.waitForNodes('fake-label')
req = request.Request(
"http://localhost:%s/label-list" % port)
req.add_header('Accept', 'application/json')
f = request.urlopen(req)
self.assertEqual(f.info().get('Content-Type'),
'application/json')
data = f.read()
objs = json.loads(data.decode('utf8'))
self.assertEqual([{'label': 'fake-label'}], objs)
def test_webapp_config(self):
configfile = self.setup_config('webapp.yaml')
config = yaml.safe_load(open(configfile))
self.assertEqual(config['webapp']['port'], 8080)
self.assertEqual(config['webapp']['listen_address'], '127.0.0.1')
def test_webapp_ready(self):
configfile = self.setup_config('node.yaml')
pool = self.useNodepool(configfile, watermark_sleep=1)
webapp = self.useWebApp(pool, port=0)
webapp.start()
port = webapp.server.socket.getsockname()[1]
# Query ready endpoint before the pool has been started. We expect
# an error in this case.
req = request.Request("http://localhost:%s/ready" % port)
with self.assertRaises(HTTPError, request.urlopen, req):
pass
pool.start()
# Now wait until we get a valid response.
for _ in iterate_timeout(30, Exception, 'ready succeeds'):
try:
f = request.urlopen(req)
break
except HTTPError:
pass
data = f.read()
self.assertEqual(data, b"OK")