This commit is contained in:
Dan Wendlandt 2011-08-05 22:54:37 -07:00
commit b78958b0cc
8 changed files with 1001 additions and 145 deletions

View File

@ -43,7 +43,13 @@ class QuantumController(wsgi.Controller):
des_body = self._deserialize(req.body,
req.best_match_content_type())
data = des_body and des_body.get(self._resource_name, None)
param_value = data and data.get(param_name, None)
if not data:
msg = ("Failed to parse request. Resource: " +
self._resource_name + " not found in request body")
for line in msg.split('\n'):
LOG.error(line)
raise exc.HTTPBadRequest(msg)
param_value = data.get(param_name, None)
if not param_value:
# 2- parse request headers
# prepend param name with a 'x-' prefix

View File

@ -50,12 +50,8 @@ class ViewBuilder(object):
def _build_detail(self, network_data):
"""Return a detailed model of a network."""
# net-ports might not be present in response from plugin
ports = network_data.get('net-ports', None)
portcount = ports and len(ports) or 0
return dict(network=dict(id=network_data['net-id'],
name=network_data['net-name'],
PortCount=portcount))
name=network_data['net-name']))
def _build_port(self, port_data):
"""Return details about a specific logical port."""

View File

@ -26,58 +26,9 @@ import urllib
from manager import QuantumManager
from optparse import OptionParser
from quantum.common.wsgi import Serializer
from client import Client
FORMAT = "json"
CONTENT_TYPE = "application/" + FORMAT
### --- Miniclient (taking from the test directory)
### TODO(bgh): move this to a library within quantum
class MiniClient(object):
"""A base client class - derived from Glance.BaseClient"""
action_prefix = '/v0.1/tenants/{tenant_id}'
def __init__(self, host, port, use_ssl):
self.host = host
self.port = port
self.use_ssl = use_ssl
self.connection = None
def get_connection_type(self):
if self.use_ssl:
return httplib.HTTPSConnection
else:
return httplib.HTTPConnection
def do_request(self, tenant, method, action, body=None,
headers=None, params=None):
action = MiniClient.action_prefix + action
action = action.replace('{tenant_id}', tenant)
if type(params) is dict:
action += '?' + urllib.urlencode(params)
try:
connection_type = self.get_connection_type()
headers = headers or {}
# Open connection and send request
c = connection_type(self.host, self.port)
c.request(method, action, body, headers)
res = c.getresponse()
status_code = self.get_status_code(res)
if status_code in (httplib.OK, httplib.CREATED,
httplib.ACCEPTED, httplib.NO_CONTENT):
return res
else:
raise Exception("Server returned error: %s" % res.read())
except (socket.error, IOError), e:
raise Exception("Unable to connect to server. Got error: %s" % e)
def get_status_code(self, response):
if hasattr(response, 'status_int'):
return response.status_int
else:
return response.status
### -- end of miniclient
### -- Core CLI functions
@ -94,11 +45,10 @@ def list_nets(manager, *args):
def api_list_nets(client, *args):
tenant_id = args[0]
res = client.do_request(tenant_id, 'GET', "/networks." + FORMAT)
resdict = json.loads(res.read())
LOG.debug(resdict)
res = client.list_networks()
LOG.debug(res)
print "Virtual Networks on Tenant:%s\n" % tenant_id
for n in resdict["networks"]:
for n in res["networks"]:
net_id = n["id"]
print "\tNetwork ID:%s\n" % (net_id)
# TODO(bgh): we should make this call pass back the name too
@ -115,13 +65,11 @@ def create_net(manager, *args):
def api_create_net(client, *args):
tid, name = args
data = {'network': {'net-name': '%s' % name}}
body = Serializer().serialize(data, CONTENT_TYPE)
res = client.do_request(tid, 'POST', "/networks." + FORMAT, body=body)
rd = json.loads(res.read())
LOG.debug(rd)
res = client.create_network(data)
LOG.debug(res)
nid = None
try:
nid = rd["networks"]["network"]["id"]
nid = res["networks"]["network"]["id"]
except Exception, e:
print "Failed to create network"
# TODO(bgh): grab error details from ws request result
@ -137,14 +85,12 @@ def delete_net(manager, *args):
def api_delete_net(client, *args):
tid, nid = args
res = client.do_request(tid, 'DELETE', "/networks/" + nid + "." + FORMAT)
status = res.status
if status != 202:
print "Failed to delete network"
output = res.read()
print output
else:
try:
res = client.delete_network(nid)
print "Deleted Virtual Network with ID:%s" % nid
except Exception, e:
print "Failed to delete network"
LOG.error("Failed to delete network: %s" % e)
def detail_net(manager, *args):
@ -157,23 +103,25 @@ def detail_net(manager, *args):
def api_detail_net(client, *args):
tid, nid = args
res = client.do_request(tid, 'GET',
"/networks/%s/ports.%s" % (nid, FORMAT))
output = res.read()
if res.status != 200:
LOG.error("Failed to list ports: %s" % output)
try:
res = client.list_network_details(nid)["networks"]["network"]
except Exception, e:
LOG.error("Failed to get network details: %s" % e)
return
rd = json.loads(output)
LOG.debug(rd)
try:
ports = client.list_ports(nid)
except Exception, e:
LOG.error("Failed to list ports: %s" % e)
return
print "Network %s (%s)" % (res['name'], res['id'])
print "Remote Interfaces on Virtual Network:%s\n" % nid
for port in rd["ports"]:
for port in ports["ports"]:
pid = port["id"]
res = client.do_request(tid, 'GET',
"/networks/%s/ports/%s/attachment.%s" % (nid, pid, FORMAT))
output = res.read()
rd = json.loads(output)
LOG.debug(rd)
remote_iface = rd["attachment"]
res = client.list_port_attachments(nid, pid)
LOG.debug(res)
remote_iface = res["attachment"]
print "\tRemote interface:%s" % remote_iface
@ -186,11 +134,12 @@ def rename_net(manager, *args):
def api_rename_net(client, *args):
tid, nid, name = args
data = {'network': {'net-name': '%s' % name}}
body = Serializer().serialize(data, CONTENT_TYPE)
res = client.do_request(tid, 'PUT', "/networks/%s.%s" % (nid, FORMAT),
body=body)
resdict = json.loads(res.read())
LOG.debug(resdict)
try:
res = client.update_network(nid, data)
except Exception, e:
LOG.error("Failed to rename network %s: %s" % (nid, e))
return
LOG.debug(res)
print "Renamed Virtual Network with ID:%s" % nid
@ -204,16 +153,15 @@ def list_ports(manager, *args):
def api_list_ports(client, *args):
tid, nid = args
res = client.do_request(tid, 'GET',
"/networks/%s/ports.%s" % (nid, FORMAT))
output = res.read()
if res.status != 200:
LOG.error("Failed to list ports: %s" % output)
try:
ports = client.list_ports(nid)
except Exception, e:
LOG.error("Failed to list ports: %s" % e)
return
rd = json.loads(output)
LOG.debug(rd)
LOG.debug(ports)
print "Ports on Virtual Network:%s\n" % nid
for port in rd["ports"]:
for port in ports["ports"]:
print "\tVirtual Port:%s" % port["id"]
@ -226,14 +174,12 @@ def create_port(manager, *args):
def api_create_port(client, *args):
tid, nid = args
res = client.do_request(tid, 'POST',
"/networks/%s/ports.%s" % (nid, FORMAT))
output = res.read()
if res.status != 200:
LOG.error("Failed to create port: %s" % output)
try:
res = client.create_port(nid)
except Exception, e:
LOG.error("Failed to create port: %s" % e)
return
rd = json.loads(output)
new_port = rd["ports"]["port"]["id"]
new_port = res["ports"]["port"]["id"]
print "Created Virtual Port:%s " \
"on Virtual Network:%s" % (new_port, nid)
@ -247,14 +193,15 @@ def delete_port(manager, *args):
def api_delete_port(client, *args):
tid, nid, pid = args
res = client.do_request(tid, 'DELETE',
"/networks/%s/ports/%s.%s" % (nid, pid, FORMAT))
output = res.read()
if res.status != 202:
LOG.error("Failed to delete port: %s" % output)
try:
res = client.delete_port(nid, pid)
except Exception, e:
LOG.error("Failed to delete port: %s" % e)
return
LOG.info("Deleted Virtual Port:%s " \
"on Virtual Network:%s" % (pid, nid))
print "Deleted Virtual Port:%s " \
"on Virtual Network:%s" % (pid, nid)
def detail_port(manager, *args):
@ -266,14 +213,12 @@ def detail_port(manager, *args):
def api_detail_port(client, *args):
tid, nid, pid = args
res = client.do_request(tid, 'GET',
"/networks/%s/ports/%s.%s" % (nid, pid, FORMAT))
output = res.read()
if res.status != 200:
LOG.error("Failed to get port details: %s" % output)
try:
port = client.list_port_details(nid, pid)["ports"]["port"]
except Exception, e:
LOG.error("Failed to get port details: %s" % e)
return
rd = json.loads(output)
port = rd["ports"]["port"]
id = port["id"]
attachment = port["attachment"]
LOG.debug(port)
@ -290,18 +235,15 @@ def plug_iface(manager, *args):
def api_plug_iface(client, *args):
tid, nid, pid, vid = args
data = {'port': {'attachment-id': '%s' % vid}}
body = Serializer().serialize(data, CONTENT_TYPE)
res = client.do_request(tid, 'PUT',
"/networks/%s/ports/%s/attachment.%s" % (nid, pid, FORMAT), body=body)
output = res.read()
LOG.debug(output)
if res.status != 202:
try:
data = {'port': {'attachment-id': '%s' % vid}}
res = client.attach_resource(nid, pid, data)
except Exception, e:
LOG.error("Failed to plug iface \"%s\" to port \"%s\": %s" % (vid,
pid, output))
return
print "Plugged interface \"%s\" to port:%s on network:%s" % (vid, pid,
nid)
LOG.debug(res)
print "Plugged interface \"%s\" to port:%s on network:%s" % (vid, pid, nid)
def unplug_iface(manager, *args):
@ -313,16 +255,12 @@ def unplug_iface(manager, *args):
def api_unplug_iface(client, *args):
tid, nid, pid = args
data = {'port': {'attachment-id': ''}}
body = Serializer().serialize(data, CONTENT_TYPE)
res = client.do_request(tid, 'DELETE',
"/networks/%s/ports/%s/attachment.%s" % (nid, pid, FORMAT), body=body)
output = res.read()
LOG.debug(output)
if res.status != 202:
LOG.error("Failed to unplug iface from port \"%s\": %s" % \
(pid, output))
try:
res = client.detach_resource(nid, pid)
except Exception, e:
LOG.error("Failed to unplug iface from port \"%s\": %s" % (pid, e))
return
LOG.debug(res)
print "Unplugged interface from port:%s on network:%s" % (pid, nid)
@ -440,7 +378,8 @@ if __name__ == "__main__":
sys.exit(1)
LOG.debug("Executing command \"%s\" with args: %s" % (cmd, args))
if not options.load_plugin:
client = MiniClient(options.host, options.port, options.ssl)
client = Client(options.host, options.port, options.ssl,
args[0], FORMAT)
if "api_func" not in commands[cmd]:
LOG.error("API version of \"%s\" is not yet implemented" % cmd)
sys.exit(1)

270
quantum/client.py Normal file
View File

@ -0,0 +1,270 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 Citrix Systems
# All Rights Reserved.
#
# 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.
# @author: Tyler Smith, Cisco Systems
import httplib
import socket
import urllib
from quantum.common.wsgi import Serializer
class api_call(object):
"""A Decorator to add support for format and tenant overriding"""
def __init__(self, f):
self.f = f
def __get__(self, instance, owner):
def with_params(*args, **kwargs):
# Temporarily set format and tenant for this request
(format, tenant) = (instance.format, instance.tenant)
if 'format' in kwargs:
instance.format = kwargs['format']
if 'tenant' in kwargs:
instance.tenant = kwargs['tenant']
ret = self.f(instance, *args)
(instance.format, instance.tenant) = (format, tenant)
return ret
return with_params
class Client(object):
"""A base client class - derived from Glance.BaseClient"""
action_prefix = '/v0.1/tenants/{tenant_id}'
"""Action query strings"""
networks_path = "/networks"
network_path = "/networks/%s"
ports_path = "/networks/%s/ports"
port_path = "/networks/%s/ports/%s"
attachment_path = "/networks/%s/ports/%s/attachment"
def __init__(self, host="127.0.0.1", port=9696, use_ssl=False, tenant=None,
format="xml", testingStub=None, key_file=None, cert_file=None):
"""
Creates a new client to some service.
:param host: The host where service resides
:param port: The port where service resides
:param use_ssl: True to use SSL, False to use HTTP
:param tenant: The tenant ID to make requests with
:param format: The format to query the server with
:param testingStub: A class that stubs basic server methods for tests
:param key_file: The SSL key file to use if use_ssl is true
:param cert_file: The SSL cert file to use if use_ssl is true
"""
self.host = host
self.port = port
self.use_ssl = use_ssl
self.tenant = tenant
self.format = format
self.connection = None
self.testingStub = testingStub
self.key_file = key_file
self.cert_file = cert_file
def get_connection_type(self):
"""
Returns the proper connection type
"""
if self.testingStub:
return self.testingStub
if self.use_ssl:
return httplib.HTTPSConnection
else:
return httplib.HTTPConnection
def do_request(self, method, action, body=None,
headers=None, params=None):
"""
Connects to the server and issues a request.
Returns the result data, or raises an appropriate exception if
HTTP status code is not 2xx
:param method: HTTP method ("GET", "POST", "PUT", etc...)
:param body: string of data to send, or None (default)
:param headers: mapping of key/value pairs to add as headers
:param params: dictionary of key/value pairs to add to append
to action
"""
# Ensure we have a tenant id
if not self.tenant:
raise Exception("Tenant ID not set")
# Add format and tenant_id
action += ".%s" % self.format
action = Client.action_prefix + action
action = action.replace('{tenant_id}', self.tenant)
if type(params) is dict:
action += '?' + urllib.urlencode(params)
try:
connection_type = self.get_connection_type()
headers = headers or {"Content-Type":
"application/%s" % self.format}
# Open connection and send request, handling SSL certs
certs = {'key_file': self.key_file, 'cert_file': self.cert_file}
certs = dict((x, certs[x]) for x in certs if certs[x] != None)
if self.use_ssl and len(certs):
c = connection_type(self.host, self.port, **certs)
else:
c = connection_type(self.host, self.port)
c.request(method, action, body, headers)
res = c.getresponse()
status_code = self.get_status_code(res)
if status_code in (httplib.OK,
httplib.CREATED,
httplib.ACCEPTED,
httplib.NO_CONTENT):
return self.deserialize(res)
else:
raise Exception("Server returned error: %s" % res.read())
except (socket.error, IOError), e:
raise Exception("Unable to connect to "
"server. Got error: %s" % e)
def get_status_code(self, response):
"""
Returns the integer status code from the response, which
can be either a Webob.Response (used in testing) or httplib.Response
"""
if hasattr(response, 'status_int'):
return response.status_int
else:
return response.status
def serialize(self, data):
if type(data) is dict:
return Serializer().serialize(data, self.content_type())
def deserialize(self, data):
if self.get_status_code(data) == 202:
return data.read()
return Serializer().deserialize(data.read(), self.content_type())
def content_type(self, format=None):
if not format:
format = self.format
return "application/%s" % (format)
@api_call
def list_networks(self):
"""
Queries the server for a list of networks
"""
return self.do_request("GET", self.networks_path)
@api_call
def list_network_details(self, network):
"""
Queries the server for the details of a certain network
"""
return self.do_request("GET", self.network_path % (network))
@api_call
def create_network(self, body=None):
"""
Creates a new network on the server
"""
body = self.serialize(body)
return self.do_request("POST", self.networks_path, body=body)
@api_call
def update_network(self, network, body=None):
"""
Updates a network on the server
"""
body = self.serialize(body)
return self.do_request("PUT", self.network_path % (network), body=body)
@api_call
def delete_network(self, network):
"""
Deletes a network on the server
"""
return self.do_request("DELETE", self.network_path % (network))
@api_call
def list_ports(self, network):
"""
Queries the server for a list of ports on a given network
"""
return self.do_request("GET", self.ports_path % (network))
@api_call
def list_port_details(self, network, port):
"""
Queries the server for a list of ports on a given network
"""
return self.do_request("GET", self.port_path % (network, port))
@api_call
def create_port(self, network):
"""
Creates a new port on a network on the server
"""
return self.do_request("POST", self.ports_path % (network))
@api_call
def delete_port(self, network, port):
"""
Deletes a port from a network on the server
"""
return self.do_request("DELETE", self.port_path % (network, port))
@api_call
def set_port_state(self, network, port, body=None):
"""
Sets the state of a port on the server
"""
body = self.serialize(body)
return self.do_request("PUT",
self.port_path % (network, port), body=body)
@api_call
def list_port_attachments(self, network, port):
"""
Deletes a port from a network on the server
"""
return self.do_request("GET", self.attachment_path % (network, port))
@api_call
def attach_resource(self, network, port, body=None):
"""
Deletes a port from a network on the server
"""
body = self.serialize(body)
return self.do_request("PUT",
self.attachment_path % (network, port), body=body)
@api_call
def detach_resource(self, network, port):
"""
Deletes a port from a network on the server
"""
return self.do_request("DELETE",
self.attachment_path % (network, port))

625
tests/unit/api.py Normal file
View File

@ -0,0 +1,625 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 Cisco Systems
# All Rights Reserved.
#
# 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.
# @author: Tyler Smith, Cisco Systems
import logging
import unittest
import re
from quantum.common.wsgi import Serializer
from quantum.client import Client
LOG = logging.getLogger('quantum.tests.test_api')
# Set a couple tenants to use for testing
TENANT_1 = 'totore'
TENANT_2 = 'totore2'
class ServerStub():
"""This class stubs a basic server for the API client to talk to"""
class Response(object):
"""This class stubs a basic response to send the API client"""
def __init__(self, content=None, status=None):
self.content = content
self.status = status
def read(self):
return self.content
def status(self):
return status
# To test error codes, set the host to 10.0.0.1, and the port to the code
def __init__(self, host, port=9696, key_file="", cert_file=""):
self.host = host
self.port = port
self.key_file = key_file
self.cert_file = cert_file
def request(self, method, action, body, headers):
self.method = method
self.action = action
self.body = body
def status(self, status=None):
return status or 200
def getresponse(self):
res = self.Response(status=self.status())
# If the host is 10.0.0.1, return the port as an error code
if self.host == "10.0.0.1":
res.status = self.port
return res
# Extract important information from the action string to assure sanity
match = re.search('tenants/(.+?)/(.+)\.(json|xml)$', self.action)
tenant = match.group(1)
path = match.group(2)
format = match.group(3)
data = {'data': {'method': self.method, 'action': self.action,
'body': self.body, 'tenant': tenant, 'path': path,
'format': format, 'key_file': self.key_file,
'cert_file': self.cert_file}}
# Serialize it to the proper format so the API client can handle it
if data['data']['format'] == 'json':
res.content = Serializer().serialize(data, "application/json")
else:
res.content = Serializer().serialize(data, "application/xml")
return res
class APITest(unittest.TestCase):
def setUp(self):
""" Setups a test environment for the API client """
HOST = '127.0.0.1'
PORT = 9696
USE_SSL = False
self.client = Client(HOST, PORT, USE_SSL, TENANT_1, 'json', ServerStub)
def _assert_sanity(self, call, status, method, path, data=[], params={}):
""" Perform common assertions to test the sanity of client requests """
# Handle an error case first
if status != 200:
(self.client.host, self.client.port) = ("10.0.0.1", status)
self.assertRaises(Exception, call, *data, **params)
return
# Make the call, then get the data from the root node and assert it
data = call(*data, **params)['data']
self.assertEqual(data['method'], method)
self.assertEqual(data['format'], params['format'])
self.assertEqual(data['tenant'], params['tenant'])
self.assertEqual(data['path'], path)
return data
def _test_list_networks(self, tenant=TENANT_1, format='json', status=200):
LOG.debug("_test_list_networks - tenant:%s "\
"- format:%s - START", format, tenant)
self._assert_sanity(self.client.list_networks,
status,
"GET",
"networks",
data=[],
params={'tenant': tenant, 'format': format})
LOG.debug("_test_list_networks - tenant:%s "\
"- format:%s - END", format, tenant)
def _test_list_network_details(self,
tenant=TENANT_1, format='json', status=200):
LOG.debug("_test_list_network_details - tenant:%s "\
"- format:%s - START", format, tenant)
self._assert_sanity(self.client.list_network_details,
status,
"GET",
"networks/001",
data=["001"],
params={'tenant': tenant, 'format': format})
LOG.debug("_test_list_network_details - tenant:%s "\
"- format:%s - END", format, tenant)
def _test_create_network(self, tenant=TENANT_1, format='json', status=200):
LOG.debug("_test_create_network - tenant:%s "\
"- format:%s - START", format, tenant)
self._assert_sanity(self.client.create_network,
status,
"POST",
"networks",
data=[{'network': {'net-name': 'testNetwork'}}],
params={'tenant': tenant, 'format': format})
LOG.debug("_test_create_network - tenant:%s "\
"- format:%s - END", format, tenant)
def _test_update_network(self, tenant=TENANT_1, format='json', status=200):
LOG.debug("_test_update_network - tenant:%s "\
"- format:%s - START", format, tenant)
self._assert_sanity(self.client.update_network,
status,
"PUT",
"networks/001",
data=["001",
{'network': {'net-name': 'newName'}}],
params={'tenant': tenant, 'format': format})
LOG.debug("_test_update_network - tenant:%s "\
"- format:%s - END", format, tenant)
def _test_delete_network(self, tenant=TENANT_1, format='json', status=200):
LOG.debug("_test_delete_network - tenant:%s "\
"- format:%s - START", format, tenant)
self._assert_sanity(self.client.delete_network,
status,
"DELETE",
"networks/001",
data=["001"],
params={'tenant': tenant, 'format': format})
LOG.debug("_test_delete_network - tenant:%s "\
"- format:%s - END", format, tenant)
def _test_list_ports(self, tenant=TENANT_1, format='json', status=200):
LOG.debug("_test_list_ports - tenant:%s "\
"- format:%s - START", format, tenant)
self._assert_sanity(self.client.list_ports,
status,
"GET",
"networks/001/ports",
data=["001"],
params={'tenant': tenant, 'format': format})
LOG.debug("_test_list_ports - tenant:%s "\
"- format:%s - END", format, tenant)
def _test_list_port_details(self,
tenant=TENANT_1, format='json', status=200):
LOG.debug("_test_list_port_details - tenant:%s "\
"- format:%s - START", format, tenant)
self._assert_sanity(self.client.list_port_details,
status,
"GET",
"networks/001/ports/001",
data=["001", "001"],
params={'tenant': tenant, 'format': format})
LOG.debug("_test_list_port_details - tenant:%s "\
"- format:%s - END", format, tenant)
def _test_create_port(self, tenant=TENANT_1, format='json', status=200):
LOG.debug("_test_create_port - tenant:%s "\
"- format:%s - START", format, tenant)
self._assert_sanity(self.client.create_port,
status,
"POST",
"networks/001/ports",
data=["001"],
params={'tenant': tenant, 'format': format})
LOG.debug("_test_create_port - tenant:%s "\
"- format:%s - END", format, tenant)
def _test_delete_port(self, tenant=TENANT_1, format='json', status=200):
LOG.debug("_test_delete_port - tenant:%s "\
"- format:%s - START", format, tenant)
self._assert_sanity(self.client.delete_port,
status,
"DELETE",
"networks/001/ports/001",
data=["001", "001"],
params={'tenant': tenant, 'format': format})
LOG.debug("_test_delete_port - tenant:%s "\
"- format:%s - END", format, tenant)
def _test_set_port_state(self, tenant=TENANT_1, format='json', status=200):
LOG.debug("_test_set_port_state - tenant:%s "\
"- format:%s - START", format, tenant)
self._assert_sanity(self.client.set_port_state,
status,
"PUT",
"networks/001/ports/001",
data=["001", "001",
{'port': {'state': 'ACTIVE'}}],
params={'tenant': tenant, 'format': format})
LOG.debug("_test_set_port_state - tenant:%s "\
"- format:%s - END", format, tenant)
def _test_list_port_attachments(self,
tenant=TENANT_1, format='json', status=200):
LOG.debug("_test_list_port_attachments - tenant:%s "\
"- format:%s - START", format, tenant)
self._assert_sanity(self.client.list_port_attachments,
status,
"GET",
"networks/001/ports/001/attachment",
data=["001", "001"],
params={'tenant': tenant, 'format': format})
LOG.debug("_test_list_port_attachments - tenant:%s "\
"- format:%s - END", format, tenant)
def _test_attach_resource(self, tenant=TENANT_1,
format='json', status=200):
LOG.debug("_test_attach_resource - tenant:%s "\
"- format:%s - START", format, tenant)
self._assert_sanity(self.client.attach_resource,
status,
"PUT",
"networks/001/ports/001/attachment",
data=["001", "001",
{'resource': {'id': '1234'}}],
params={'tenant': tenant, 'format': format})
LOG.debug("_test_attach_resource - tenant:%s "\
"- format:%s - END", format, tenant)
def _test_detach_resource(self, tenant=TENANT_1,
format='json', status=200):
LOG.debug("_test_detach_resource - tenant:%s "\
"- format:%s - START", format, tenant)
self._assert_sanity(self.client.detach_resource,
status,
"DELETE",
"networks/001/ports/001/attachment",
data=["001", "001"],
params={'tenant': tenant, 'format': format})
LOG.debug("_test_detach_resource - tenant:%s "\
"- format:%s - END", format, tenant)
def _test_ssl_certificates(self, tenant=TENANT_1,
format='json', status=200):
LOG.debug("_test_ssl_certificates - tenant:%s "\
"- format:%s - START", format, tenant)
# Set SSL, and our cert file
self.client.use_ssl = True
cert_file = "/fake.cert"
self.client.key_file = self.client.cert_file = cert_file
data = self._assert_sanity(self.client.list_networks,
status,
"GET",
"networks",
data=[],
params={'tenant': tenant, 'format': format})
self.assertEquals(data["key_file"], cert_file)
self.assertEquals(data["cert_file"], cert_file)
LOG.debug("_test_ssl_certificates - tenant:%s "\
"- format:%s - END", format, tenant)
def test_list_networks_json(self):
self._test_list_networks(format='json')
def test_list_networks_xml(self):
self._test_list_networks(format='xml')
def test_list_networks_alt_tenant(self):
self._test_list_networks(tenant=TENANT_2)
def test_list_networks_error_470(self):
self._test_list_networks(status=470)
def test_list_networks_error_401(self):
self._test_list_networks(status=401)
def test_list_network_details_json(self):
self._test_list_network_details(format='json')
def test_list_network_details_xml(self):
self._test_list_network_details(format='xml')
def test_list_network_details_alt_tenant(self):
self._test_list_network_details(tenant=TENANT_2)
def test_list_network_details_error_470(self):
self._test_list_network_details(status=470)
def test_list_network_details_error_401(self):
self._test_list_network_details(status=401)
def test_list_network_details_error_420(self):
self._test_list_network_details(status=420)
def test_create_network_json(self):
self._test_create_network(format='json')
def test_create_network_xml(self):
self._test_create_network(format='xml')
def test_create_network_alt_tenant(self):
self._test_create_network(tenant=TENANT_2)
def test_create_network_error_470(self):
self._test_create_network(status=470)
def test_create_network_error_401(self):
self._test_create_network(status=401)
def test_create_network_error_400(self):
self._test_create_network(status=400)
def test_create_network_error_422(self):
self._test_create_network(status=422)
def test_update_network_json(self):
self._test_update_network(format='json')
def test_update_network_xml(self):
self._test_update_network(format='xml')
def test_update_network_alt_tenant(self):
self._test_update_network(tenant=TENANT_2)
def test_update_network_error_470(self):
self._test_update_network(status=470)
def test_update_network_error_401(self):
self._test_update_network(status=401)
def test_update_network_error_400(self):
self._test_update_network(status=400)
def test_update_network_error_420(self):
self._test_update_network(status=420)
def test_update_network_error_422(self):
self._test_update_network(status=422)
def test_delete_network_json(self):
self._test_delete_network(format='json')
def test_delete_network_xml(self):
self._test_delete_network(format='xml')
def test_delete_network_alt_tenant(self):
self._test_delete_network(tenant=TENANT_2)
def test_delete_network_error_470(self):
self._test_delete_network(status=470)
def test_delete_network_error_401(self):
self._test_delete_network(status=401)
def test_delete_network_error_420(self):
self._test_delete_network(status=420)
def test_delete_network_error_421(self):
self._test_delete_network(status=421)
def test_list_ports_json(self):
self._test_list_ports(format='json')
def test_list_ports_xml(self):
self._test_list_ports(format='xml')
def test_list_ports_alt_tenant(self):
self._test_list_ports(tenant=TENANT_2)
def test_list_ports_error_470(self):
self._test_list_ports(status=470)
def test_list_ports_error_401(self):
self._test_list_ports(status=401)
def test_list_ports_error_420(self):
self._test_list_ports(status=420)
def test_list_port_details_json(self):
self._test_list_ports(format='json')
def test_list_port_details_xml(self):
self._test_list_ports(format='xml')
def test_list_port_details_alt_tenant(self):
self._test_list_ports(tenant=TENANT_2)
def test_list_port_details_error_470(self):
self._test_list_port_details(status=470)
def test_list_port_details_error_401(self):
self._test_list_ports(status=401)
def test_list_port_details_error_420(self):
self._test_list_ports(status=420)
def test_list_port_details_error_430(self):
self._test_list_ports(status=430)
def test_create_port_json(self):
self._test_create_port(format='json')
def test_create_port_xml(self):
self._test_create_port(format='xml')
def test_create_port_alt_tenant(self):
self._test_create_port(tenant=TENANT_2)
def test_create_port_error_470(self):
self._test_create_port(status=470)
def test_create_port_error_401(self):
self._test_create_port(status=401)
def test_create_port_error_400(self):
self._test_create_port(status=400)
def test_create_port_error_420(self):
self._test_create_port(status=420)
def test_create_port_error_430(self):
self._test_create_port(status=430)
def test_create_port_error_431(self):
self._test_create_port(status=431)
def test_delete_port_json(self):
self._test_delete_port(format='json')
def test_delete_port_xml(self):
self._test_delete_port(format='xml')
def test_delete_port_alt_tenant(self):
self._test_delete_port(tenant=TENANT_2)
def test_delete_port_error_470(self):
self._test_delete_port(status=470)
def test_delete_port_error_401(self):
self._test_delete_port(status=401)
def test_delete_port_error_420(self):
self._test_delete_port(status=420)
def test_delete_port_error_430(self):
self._test_delete_port(status=430)
def test_delete_port_error_432(self):
self._test_delete_port(status=432)
def test_set_port_state_json(self):
self._test_set_port_state(format='json')
def test_set_port_state_xml(self):
self._test_set_port_state(format='xml')
def test_set_port_state_alt_tenant(self):
self._test_set_port_state(tenant=TENANT_2)
def test_set_port_state_error_470(self):
self._test_set_port_state(status=470)
def test_set_port_state_error_401(self):
self._test_set_port_state(status=401)
def test_set_port_state_error_400(self):
self._test_set_port_state(status=400)
def test_set_port_state_error_420(self):
self._test_set_port_state(status=420)
def test_set_port_state_error_430(self):
self._test_set_port_state(status=430)
def test_set_port_state_error_431(self):
self._test_set_port_state(status=431)
def test_list_port_attachments_json(self):
self._test_list_port_attachments(format='json')
def test_list_port_attachments_xml(self):
self._test_list_port_attachments(format='xml')
def test_list_port_attachments_alt_tenant(self):
self._test_list_port_attachments(tenant=TENANT_2)
def test_list_port_attachments_error_470(self):
self._test_list_port_attachments(status=470)
def test_list_port_attachments_error_401(self):
self._test_list_port_attachments(status=401)
def test_list_port_attachments_error_400(self):
self._test_list_port_attachments(status=400)
def test_list_port_attachments_error_420(self):
self._test_list_port_attachments(status=420)
def test_list_port_attachments_error_430(self):
self._test_list_port_attachments(status=430)
def test_attach_resource_json(self):
self._test_attach_resource(format='json')
def test_attach_resource_xml(self):
self._test_attach_resource(format='xml')
def test_attach_resource_alt_tenant(self):
self._test_attach_resource(tenant=TENANT_2)
def test_attach_resource_error_470(self):
self._test_attach_resource(status=470)
def test_attach_resource_error_401(self):
self._test_attach_resource(status=401)
def test_attach_resource_error_400(self):
self._test_attach_resource(status=400)
def test_attach_resource_error_420(self):
self._test_attach_resource(status=420)
def test_attach_resource_error_430(self):
self._test_attach_resource(status=430)
def test_attach_resource_error_432(self):
self._test_attach_resource(status=432)
def test_attach_resource_error_440(self):
self._test_attach_resource(status=440)
def test_detach_resource_json(self):
self._test_detach_resource(format='json')
def test_detach_resource_xml(self):
self._test_detach_resource(format='xml')
def test_detach_resource_alt_tenant(self):
self._test_detach_resource(tenant=TENANT_2)
def test_detach_resource_error_470(self):
self._test_detach_resource(status=470)
def test_detach_resource_error_401(self):
self._test_detach_resource(status=401)
def test_detach_resource_error_420(self):
self._test_detach_resource(status=420)
def test_detach_resource_error_430(self):
self._test_detach_resource(status=430)
def test_ssl_certificates(self):
self._test_ssl_certificates()

View File

@ -114,8 +114,7 @@ class APITest(unittest.TestCase):
network_data = self._net_serializer.deserialize(
show_network_res.body, content_type)
self.assertEqual({'id': network_id,
'name': self.network_name,
'PortCount': 0},
'name': self.network_name},
network_data['network'])
LOG.debug("_test_show_network - format:%s - END", format)
@ -147,8 +146,7 @@ class APITest(unittest.TestCase):
network_data = self._net_serializer.deserialize(
show_network_res.body, content_type)
self.assertEqual({'id': network_id,
'name': new_name,
'PortCount': 0},
'name': new_name},
network_data['network'])
LOG.debug("_test_rename_network - format:%s - END", format)
@ -298,6 +296,21 @@ class APITest(unittest.TestCase):
self.assertEqual(show_port_res.status_int, 430)
LOG.debug("_test_show_port_portnotfound - format:%s - END", format)
def _test_create_port_noreqbody(self, format):
LOG.debug("_test_create_port_noreqbody - format:%s - START", format)
content_type = "application/%s" % format
network_id = self._create_network(format)
port_id = self._create_port(network_id, None, format,
custom_req_body='')
show_port_req = testlib.show_port_request(self.tenant_id,
network_id, port_id, format)
show_port_res = show_port_req.get_response(self.api)
self.assertEqual(show_port_res.status_int, 200)
port_data = self._port_serializer.deserialize(
show_port_res.body, content_type)
self.assertEqual(port_id, port_data['port']['id'])
LOG.debug("_test_create_port_noreqbody - format:%s - END", format)
def _test_create_port(self, format):
LOG.debug("_test_create_port - format:%s - START", format)
content_type = "application/%s" % format
@ -777,6 +790,12 @@ class APITest(unittest.TestCase):
def test_create_port_xml(self):
self._test_create_port('xml')
def test_create_port_noreqbody_json(self):
self._test_create_port_noreqbody('json')
def test_create_port_noreqbody_xml(self):
self._test_create_port_noreqbody('xml')
def test_create_port_networknotfound_json(self):
self._test_create_port_networknotfound('json')

View File

@ -77,9 +77,10 @@ def new_port_request(tenant_id, network_id, port_state,
method = 'POST'
path = "/tenants/%(tenant_id)s/networks/" \
"%(network_id)s/ports.%(format)s" % locals()
data = custom_req_body or {'port': {'port-state': '%s' % port_state}}
data = custom_req_body or port_state and \
{'port': {'port-state': '%s' % port_state}}
content_type = "application/%s" % format
body = Serializer().serialize(data, content_type)
body = data and Serializer().serialize(data, content_type)
return create_request(path, body, content_type, method)

View File

@ -3,9 +3,9 @@ Routes>=1.12.3
nose
Paste
PasteDeploy
pep8==0.5.0
pep8>=0.5.0
python-gflags
routes
sqlalchemy
simplejson
webob
webtest