Merge "Fix API reference links in volume client"
diff --git a/tempest/api/compute/servers/test_novnc.py b/tempest/api/compute/servers/test_novnc.py
index a72df5e..6354c57 100644
--- a/tempest/api/compute/servers/test_novnc.py
+++ b/tempest/api/compute/servers/test_novnc.py
@@ -13,14 +13,13 @@
# License for the specific language governing permissions and limitations
# under the License.
-import socket
import struct
import six
-from six.moves.urllib import parse as urlparse
import urllib3
from tempest.api.compute import base
+from tempest.common import compute
from tempest import config
from tempest.lib import decorators
@@ -158,14 +157,6 @@
self._websocket.response.find(b'Server: WebSockify') > 0,
'Did not get the expected WebSocket HTTP Response.')
- def _create_websocket(self, url):
- url = urlparse.urlparse(url)
- client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- client_socket.connect((url.hostname, url.port))
- # Turn the Socket into a WebSocket to do the communication
- return _WebSocket(client_socket, url)
-
@decorators.idempotent_id('c640fdff-8ab4-45a4-a5d8-7e6146cbd0dc')
def test_novnc(self):
body = self.client.get_vnc_console(self.server['id'],
@@ -174,7 +165,7 @@
# Do the initial HTTP Request to novncproxy to get the NoVNC JavaScript
self._validate_novnc_html(body['url'])
# Do the WebSockify HTTP Request to novncproxy to do the RFB connection
- self._websocket = self._create_websocket(body['url'])
+ self._websocket = compute.create_websocket(body['url'])
# Validate that we succesfully connected and upgraded to Web Sockets
self._validate_websocket_upgrade()
# Validate the RFB Negotiation to determine if a valid VNC session
@@ -187,84 +178,9 @@
self.assertEqual('novnc', body['type'])
# Do the WebSockify HTTP Request to novncproxy with a bad token
url = body['url'].replace('token=', 'token=bad')
- self._websocket = self._create_websocket(url)
+ self._websocket = compute.create_websocket(url)
# Make sure the novncproxy rejected the connection and closed it
data = self._websocket.receive_frame()
self.assertTrue(data is None or len(data) == 0,
"The novnc proxy actually sent us some data, but we "
"expected it to close the connection.")
-
-
-class _WebSocket(object):
- def __init__(self, client_socket, url):
- """Contructor for the WebSocket wrapper to the socket."""
- self._socket = client_socket
- # Upgrade the HTTP connection to a WebSocket
- self._upgrade(url)
-
- def receive_frame(self):
- """Wrapper for receiving data to parse the WebSocket frame format"""
- # We need to loop until we either get some bytes back in the frame
- # or no data was received (meaning the socket was closed). This is
- # done to handle the case where we get back some empty frames
- while True:
- header = self._socket.recv(2)
- # If we didn't receive any data, just return None
- if len(header) == 0:
- return None
- # We will make the assumption that we are only dealing with
- # frames less than 125 bytes here (for the negotiation) and
- # that only the 2nd byte contains the length, and since the
- # server doesn't do masking, we can just read the data length
- if ord_func(header[1]) & 127 > 0:
- return self._socket.recv(ord_func(header[1]) & 127)
-
- def send_frame(self, data):
- """Wrapper for sending data to add in the WebSocket frame format."""
- frame_bytes = list()
- # For the first byte, want to say we are sending binary data (130)
- frame_bytes.append(130)
- # Only sending negotiation data so don't need to worry about > 125
- # We do need to add the bit that says we are masking the data
- frame_bytes.append(len(data) | 128)
- # We don't really care about providing a random mask for security
- # So we will just hard-code a value since a test program
- mask = [7, 2, 1, 9]
- for i in range(len(mask)):
- frame_bytes.append(mask[i])
- # Mask each of the actual data bytes that we are going to send
- for i in range(len(data)):
- frame_bytes.append(ord_func(data[i]) ^ mask[i % 4])
- # Convert our integer list to a binary array of bytes
- frame_bytes = struct.pack('!%iB' % len(frame_bytes), * frame_bytes)
- self._socket.sendall(frame_bytes)
-
- def close(self):
- """Helper method to close the connection."""
- # Close down the real socket connection and exit the test program
- if self._socket is not None:
- self._socket.shutdown(1)
- self._socket.close()
- self._socket = None
-
- def _upgrade(self, url):
- """Upgrade the HTTP connection to a WebSocket and verify."""
- # The real request goes to the /websockify URI always
- reqdata = 'GET /websockify HTTP/1.1\r\n'
- reqdata += 'Host: %s:%s\r\n' % (url.hostname, url.port)
- # Tell the HTTP Server to Upgrade the connection to a WebSocket
- reqdata += 'Upgrade: websocket\r\nConnection: Upgrade\r\n'
- # The token=xxx is sent as a Cookie not in the URI
- reqdata += 'Cookie: %s\r\n' % url.query
- # Use a hard-coded WebSocket key since a test program
- reqdata += 'Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r\n'
- reqdata += 'Sec-WebSocket-Version: 13\r\n'
- # We are choosing to use binary even though browser may do Base64
- reqdata += 'Sec-WebSocket-Protocol: binary\r\n\r\n'
- # Send the HTTP GET request and get the response back
- self._socket.sendall(reqdata.encode('utf8'))
- self.response = data = self._socket.recv(4096)
- # Loop through & concatenate all of the data in the response body
- while len(data) > 0 and self.response.find(b'\r\n\r\n') < 0:
- data = self._socket.recv(4096)
- self.response += data
diff --git a/tempest/api/image/v2/test_images_negative.py b/tempest/api/image/v2/test_images_negative.py
index 04c752a..6e5e726 100644
--- a/tempest/api/image/v2/test_images_negative.py
+++ b/tempest/api/image/v2/test_images_negative.py
@@ -98,3 +98,16 @@
self.assertRaises(lib_exc.BadRequest, self.client.create_image,
name='test', container_format='bare',
disk_format='wrong')
+
+ @test.attr(type=['negative'])
+ @decorators.idempotent_id('ab980a34-8410-40eb-872b-f264752f46e5')
+ def test_delete_protected_image(self):
+ # Create a protected image
+ image = self.create_image(protected=True)
+ self.addCleanup(self.client.update_image, image['id'],
+ [dict(replace="/protected", value=False)])
+
+ # Try deleting the protected image
+ self.assertRaises(lib_exc.Forbidden,
+ self.client.delete_image,
+ image['id'])
diff --git a/tempest/api/volume/test_volumes_negative.py b/tempest/api/volume/test_volumes_negative.py
index 8990a15..5c48015 100644
--- a/tempest/api/volume/test_volumes_negative.py
+++ b/tempest/api/volume/test_volumes_negative.py
@@ -47,99 +47,70 @@
@test.attr(type=['negative'])
@decorators.idempotent_id('1ed83a8a-682d-4dfb-a30e-ee63ffd6c049')
def test_create_volume_with_invalid_size(self):
- # Should not be able to create volume with invalid size
- # in request
- v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
- params = {'name': v_name}
+ # Should not be able to create volume with invalid size in request
self.assertRaises(lib_exc.BadRequest,
- self.volumes_client.create_volume,
- size='#$%', params=params)
+ self.volumes_client.create_volume, size='#$%')
@test.attr(type=['negative'])
@decorators.idempotent_id('9387686f-334f-4d31-a439-33494b9e2683')
def test_create_volume_without_passing_size(self):
# Should not be able to create volume without passing size
# in request
- v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
- params = {'name': v_name}
self.assertRaises(lib_exc.BadRequest,
- self.volumes_client.create_volume,
- size='', params=params)
+ self.volumes_client.create_volume, size='')
@test.attr(type=['negative'])
@decorators.idempotent_id('41331caa-eaf4-4001-869d-bc18c1869360')
def test_create_volume_with_size_zero(self):
# Should not be able to create volume with size zero
- v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
- params = {'name': v_name}
self.assertRaises(lib_exc.BadRequest,
- self.volumes_client.create_volume,
- size='0', params=params)
+ self.volumes_client.create_volume, size='0')
@test.attr(type=['negative'])
@decorators.idempotent_id('8b472729-9eba-446e-a83b-916bdb34bef7')
def test_create_volume_with_size_negative(self):
# Should not be able to create volume with size negative
- v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
- params = {'name': v_name}
self.assertRaises(lib_exc.BadRequest,
- self.volumes_client.create_volume,
- size='-1', params=params)
+ self.volumes_client.create_volume, size='-1')
@test.attr(type=['negative'])
@decorators.idempotent_id('10254ed8-3849-454e-862e-3ab8e6aa01d2')
def test_create_volume_with_nonexistent_volume_type(self):
# Should not be able to create volume with non-existent volume type
- v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
- params = {'name': v_name}
self.assertRaises(lib_exc.NotFound, self.volumes_client.create_volume,
- size='1', volume_type=data_utils.rand_uuid(),
- params=params)
+ size='1', volume_type=data_utils.rand_uuid())
@test.attr(type=['negative'])
@decorators.idempotent_id('0c36f6ae-4604-4017-b0a9-34fdc63096f9')
def test_create_volume_with_nonexistent_snapshot_id(self):
# Should not be able to create volume with non-existent snapshot
- v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
- params = {'name': v_name}
self.assertRaises(lib_exc.NotFound, self.volumes_client.create_volume,
- size='1', snapshot_id=data_utils.rand_uuid(),
- params=params)
+ size='1', snapshot_id=data_utils.rand_uuid())
@test.attr(type=['negative'])
@decorators.idempotent_id('47c73e08-4be8-45bb-bfdf-0c4e79b88344')
def test_create_volume_with_nonexistent_source_volid(self):
# Should not be able to create volume with non-existent source volume
- v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
- params = {'name': v_name}
self.assertRaises(lib_exc.NotFound, self.volumes_client.create_volume,
- size='1', source_volid=data_utils.rand_uuid(),
- params=params)
+ size='1', source_volid=data_utils.rand_uuid())
@test.attr(type=['negative'])
@decorators.idempotent_id('0186422c-999a-480e-a026-6a665744c30c')
def test_update_volume_with_nonexistent_volume_id(self):
- v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
- params = {'name': v_name}
self.assertRaises(lib_exc.NotFound, self.volumes_client.update_volume,
- volume_id=data_utils.rand_uuid(), params=params)
+ volume_id=data_utils.rand_uuid())
@test.attr(type=['negative'])
@decorators.idempotent_id('e66e40d6-65e6-4e75-bdc7-636792fa152d')
def test_update_volume_with_invalid_volume_id(self):
- v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
- params = {'name': v_name}
self.assertRaises(lib_exc.NotFound, self.volumes_client.update_volume,
- volume_id=data_utils.rand_name('invalid'),
- params=params)
+ volume_id=data_utils.rand_name('invalid'))
@test.attr(type=['negative'])
@decorators.idempotent_id('72aeca85-57a5-4c1f-9057-f320f9ea575b')
def test_update_volume_with_empty_volume_id(self):
- v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
- params = {'name': v_name}
self.assertRaises(lib_exc.NotFound, self.volumes_client.update_volume,
- volume_id='', params=params)
+ volume_id='')
@test.attr(type=['negative'])
@decorators.idempotent_id('30799cfd-7ee4-446c-b66c-45b383ed211b')
diff --git a/tempest/common/compute.py b/tempest/common/compute.py
index dcf0de9..38daffe 100644
--- a/tempest/common/compute.py
+++ b/tempest/common/compute.py
@@ -14,8 +14,13 @@
# limitations under the License.
import base64
+import socket
+import struct
import textwrap
+import six
+from six.moves.urllib import parse as urlparse
+
from oslo_log import log as logging
from oslo_utils import excutils
@@ -25,6 +30,11 @@
from tempest.lib.common import rest_client
from tempest.lib.common.utils import data_utils
+if six.PY2:
+ ord_func = ord
+else:
+ ord_func = int
+
CONF = config.CONF
LOG = logging.getLogger(__name__)
@@ -222,3 +232,87 @@
servers_client.shelve_offload_server(server_id)
waiters.wait_for_server_status(servers_client, server_id,
'SHELVED_OFFLOADED')
+
+
+def create_websocket(url):
+ url = urlparse.urlparse(url)
+ client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ client_socket.connect((url.hostname, url.port))
+ # Turn the Socket into a WebSocket to do the communication
+ return _WebSocket(client_socket, url)
+
+
+class _WebSocket(object):
+ def __init__(self, client_socket, url):
+ """Contructor for the WebSocket wrapper to the socket."""
+ self._socket = client_socket
+ # Upgrade the HTTP connection to a WebSocket
+ self._upgrade(url)
+
+ def receive_frame(self):
+ """Wrapper for receiving data to parse the WebSocket frame format"""
+ # We need to loop until we either get some bytes back in the frame
+ # or no data was received (meaning the socket was closed). This is
+ # done to handle the case where we get back some empty frames
+ while True:
+ header = self._socket.recv(2)
+ # If we didn't receive any data, just return None
+ if len(header) == 0:
+ return None
+ # We will make the assumption that we are only dealing with
+ # frames less than 125 bytes here (for the negotiation) and
+ # that only the 2nd byte contains the length, and since the
+ # server doesn't do masking, we can just read the data length
+ if ord_func(header[1]) & 127 > 0:
+ return self._socket.recv(ord_func(header[1]) & 127)
+
+ def send_frame(self, data):
+ """Wrapper for sending data to add in the WebSocket frame format."""
+ frame_bytes = list()
+ # For the first byte, want to say we are sending binary data (130)
+ frame_bytes.append(130)
+ # Only sending negotiation data so don't need to worry about > 125
+ # We do need to add the bit that says we are masking the data
+ frame_bytes.append(len(data) | 128)
+ # We don't really care about providing a random mask for security
+ # So we will just hard-code a value since a test program
+ mask = [7, 2, 1, 9]
+ for i in range(len(mask)):
+ frame_bytes.append(mask[i])
+ # Mask each of the actual data bytes that we are going to send
+ for i in range(len(data)):
+ frame_bytes.append(ord_func(data[i]) ^ mask[i % 4])
+ # Convert our integer list to a binary array of bytes
+ frame_bytes = struct.pack('!%iB' % len(frame_bytes), * frame_bytes)
+ self._socket.sendall(frame_bytes)
+
+ def close(self):
+ """Helper method to close the connection."""
+ # Close down the real socket connection and exit the test program
+ if self._socket is not None:
+ self._socket.shutdown(1)
+ self._socket.close()
+ self._socket = None
+
+ def _upgrade(self, url):
+ """Upgrade the HTTP connection to a WebSocket and verify."""
+ # The real request goes to the /websockify URI always
+ reqdata = 'GET /websockify HTTP/1.1\r\n'
+ reqdata += 'Host: %s:%s\r\n' % (url.hostname, url.port)
+ # Tell the HTTP Server to Upgrade the connection to a WebSocket
+ reqdata += 'Upgrade: websocket\r\nConnection: Upgrade\r\n'
+ # The token=xxx is sent as a Cookie not in the URI
+ reqdata += 'Cookie: %s\r\n' % url.query
+ # Use a hard-coded WebSocket key since a test program
+ reqdata += 'Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r\n'
+ reqdata += 'Sec-WebSocket-Version: 13\r\n'
+ # We are choosing to use binary even though browser may do Base64
+ reqdata += 'Sec-WebSocket-Protocol: binary\r\n\r\n'
+ # Send the HTTP GET request and get the response back
+ self._socket.sendall(reqdata.encode('utf8'))
+ self.response = data = self._socket.recv(4096)
+ # Loop through & concatenate all of the data in the response body
+ while len(data) > 0 and self.response.find(b'\r\n\r\n') < 0:
+ data = self._socket.recv(4096)
+ self.response += data
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 144ef60..9319d2a 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -81,12 +81,6 @@
cmd = 'sudo sh -c "echo \\"%s\\" >/dev/console"' % message
return self.exec_command(cmd)
- def set_mac_address(self, nic, address):
- self.exec_command("sudo ip link set %s down" % nic)
- cmd = "sudo ip link set dev {0} address {1}".format(nic, address)
- self.exec_command(cmd)
- self.exec_command("sudo ip link set %s up" % nic)
-
def get_mac_address(self, nic=""):
show_nic = "show {nic} ".format(nic=nic) if nic else ""
cmd = "ip addr %s| awk '/ether/ {print $2}'" % show_nic
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 91b863c..dec0ad0 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -834,7 +834,13 @@
peer_address = peer['addresses'][self.new_net['name']][0]['addr']
self.check_remote_connectivity(ssh_client, dest=peer_address,
nic=spoof_nic, should_succeed=True)
- ssh_client.set_mac_address(spoof_nic, spoof_mac)
+ # Set a mac address by making nic down temporary
+ cmd = ("sudo ip link set {nic} down;"
+ "sudo ip link set dev {nic} address {mac};"
+ "sudo ip link set {nic} up").format(nic=spoof_nic,
+ mac=spoof_mac)
+ ssh_client.exec_command(cmd)
+
new_mac = ssh_client.get_mac_address(nic=spoof_nic)
self.assertEqual(spoof_mac, new_mac)
self.check_remote_connectivity(ssh_client, dest=peer_address,