Merge "Infrastructure updates for Shared IPs testing"
This commit is contained in:
@@ -16,20 +16,22 @@ limitations under the License.
|
||||
|
||||
import time
|
||||
|
||||
from cloudcafe.compute.common.exceptions import ItemNotFound, TimeoutException
|
||||
from cloudcafe.compute.common.exceptions import TimeoutException
|
||||
from cloudcafe.compute.composites import ComputeComposite
|
||||
from cloudcafe.networking.networks.common.behaviors \
|
||||
import NetworkingBaseBehaviors
|
||||
from cloudcafe.networking.networks.common.config import NetworkingBaseConfig
|
||||
from cloudcafe.networking.networks.common.constants \
|
||||
import ComputeResponseCodes, NeutronResponseCodes
|
||||
import ComputeResponseCodes, ComputeStatus, NeutronResponseCodes
|
||||
from cloudcafe.networking.networks.common.exceptions \
|
||||
import NetworkGETException, SubnetGETException, UnsupportedTypeException, \
|
||||
UnavailableComputeInteractionException
|
||||
UnavailableComputeInteractionException, UnableToGetNetworkingServer
|
||||
from cloudcafe.networking.networks.common.models.response.network \
|
||||
import Network
|
||||
from cloudcafe.networking.networks.common.models.response.port \
|
||||
import Port
|
||||
from cloudcafe.networking.networks.extensions.ip_addresses_api.constants \
|
||||
import IPAddressesServerZone
|
||||
|
||||
|
||||
class NetworkingBehaviors(NetworkingBaseBehaviors):
|
||||
@@ -159,9 +161,9 @@ class NetworkingBehaviors(NetworkingBaseBehaviors):
|
||||
subnet_id=subnet_id)
|
||||
|
||||
err_msg = 'Subnet Get failure'
|
||||
resp_check = self.check_response(resp=resp,
|
||||
status_code=NeutronResponseCodes.GET_SUBNET, label=subnet_id,
|
||||
message=err_msg, network_id=network_id)
|
||||
resp_check = self.check_response(
|
||||
resp=resp, status_code=NeutronResponseCodes.GET_SUBNET,
|
||||
label=subnet_id, message=err_msg, network_id=network_id)
|
||||
|
||||
if not resp_check:
|
||||
subnet = resp.entity
|
||||
@@ -209,8 +211,9 @@ class NetworkingBehaviors(NetworkingBaseBehaviors):
|
||||
log_msg = ('Checking {resource} entity type initial {init_status} '
|
||||
'status is updated to {updated_status} status within a '
|
||||
'timeout of {timeout}').format(resource=resource_type,
|
||||
init_status=initial_status, updated_status=new_status,
|
||||
timeout=timeout)
|
||||
init_status=initial_status,
|
||||
updated_status=new_status,
|
||||
timeout=timeout)
|
||||
self._log.info(log_msg)
|
||||
|
||||
while time.time() < endtime:
|
||||
@@ -324,6 +327,58 @@ class NetworkingBehaviors(NetworkingBaseBehaviors):
|
||||
# The compute behavior verifies the response, no need to check
|
||||
return resp
|
||||
|
||||
def get_networking_server(self, server=None, server_id=None):
|
||||
"""
|
||||
@summary: takes a server entity or ID and returns its latest version
|
||||
"""
|
||||
if server is None and server_id is None:
|
||||
raise UnableToGetNetworkingServer('Must provide server entity '
|
||||
'or server_id')
|
||||
net_server_id = getattr(server, 'id', None) or server_id
|
||||
resp = self.compute.servers.client.get_server(net_server_id)
|
||||
|
||||
if resp.status_code != ComputeResponseCodes.SERVER_GET:
|
||||
msg = 'Unable to get networks server {0}'.format(net_server_id)
|
||||
raise UnableToGetNetworkingServer(msg)
|
||||
|
||||
if hasattr(server, 'admin_pass'):
|
||||
resp.entity.admin_pass = server.admin_pass
|
||||
return resp.entity
|
||||
|
||||
def wait_for_servers_to_be_active(self, server_id_list,
|
||||
interval_time=None, timeout=None,
|
||||
raise_exception=False):
|
||||
"""
|
||||
@summary: Waits for multiple servers to be ACTIVE
|
||||
@param server_id_list: The uuids of the servers to wait for ACTIVE
|
||||
@type server_id_list: List
|
||||
@param interval_time: Seconds to wait between polling
|
||||
@type interval_time: Integer
|
||||
@param timeout: The amount of time in seconds to wait before aborting
|
||||
@type timeout: Integer
|
||||
"""
|
||||
interval_time = (interval_time or
|
||||
self.compute.servers.config.server_status_interval)
|
||||
timeout = timeout or self.compute.servers.config.server_build_timeout
|
||||
end_time = time.time() + timeout
|
||||
|
||||
while time.time() < end_time:
|
||||
for server_id in server_id_list:
|
||||
resp = self.compute.servers.client.get_server(server_id)
|
||||
if (resp.status_code == ComputeResponseCodes.SERVER_GET and
|
||||
resp.entity.status == ComputeStatus.ACTIVE
|
||||
and server_id in server_id_list):
|
||||
server_id_list.remove(server_id)
|
||||
if not server_id_list:
|
||||
break
|
||||
time.sleep(interval_time)
|
||||
else:
|
||||
msg = ('wait_for_servers_to_be_active {0} seconds timeout waiting'
|
||||
'for servers: {1}').format(timeout, server_id_list)
|
||||
self._log.info(msg)
|
||||
if raise_exception:
|
||||
raise TimeoutException(msg)
|
||||
|
||||
def wait_for_servers_to_be_deleted(self, server_id_list,
|
||||
interval_time=None, timeout=None,
|
||||
raise_exception=False):
|
||||
@@ -337,29 +392,106 @@ class NetworkingBehaviors(NetworkingBaseBehaviors):
|
||||
@type timeout: Integer
|
||||
"""
|
||||
|
||||
self._wait_for_compute_delete(
|
||||
resource_id_list=server_id_list, resource='servers',
|
||||
delete_method=self.compute.servers.client.delete_server,
|
||||
get_method=self.compute.servers.client.get_server,
|
||||
interval_time=interval_time, timeout=timeout,
|
||||
raise_exception=raise_exception)
|
||||
|
||||
def _wait_for_compute_delete(self, resource_id_list, resource,
|
||||
delete_method, get_method, interval_time=None,
|
||||
timeout=None, raise_exception=False):
|
||||
"""
|
||||
@summary: Waits for compute resource deletes
|
||||
@param resource_id_list: uuids of the compute resources to be deleted
|
||||
@type resource_id_list: List
|
||||
@param resource: compute resource like servers, ip associations, etc.
|
||||
@type resource: String
|
||||
@param delete_method: method used to delete the resource
|
||||
@type delete_method: behavior or client method
|
||||
@param get_method: method used to get the resource
|
||||
@type get_method: behavior or client method
|
||||
@param interval_time: Seconds to wait between polling
|
||||
@type interval_time: Integer
|
||||
@param timeout: The amount of time in seconds to wait before aborting
|
||||
@type timeout: Integer
|
||||
@param raise_exception: flag to raise an exception if deletes fail
|
||||
@type raise_exception: bool
|
||||
"""
|
||||
|
||||
interval_time = (interval_time or
|
||||
self.compute.servers.config.server_status_interval)
|
||||
timeout = timeout or self.compute.servers.config.server_build_timeout
|
||||
end_time = time.time() + timeout
|
||||
|
||||
for server_id in server_id_list:
|
||||
self.compute.servers.client.delete_server(server_id)
|
||||
for resource_id in resource_id_list:
|
||||
delete_method(resource_id)
|
||||
|
||||
while time.time() < end_time:
|
||||
for server_id in server_id_list:
|
||||
resp = self.compute.servers.client.get_server(server_id)
|
||||
for resource_id in resource_id_list:
|
||||
resp = get_method(resource_id)
|
||||
if (resp.status_code == ComputeResponseCodes.NOT_FOUND
|
||||
and server_id in server_id_list):
|
||||
server_id_list.remove(server_id)
|
||||
if not server_id_list:
|
||||
and resource_id in resource_id_list):
|
||||
resource_id_list.remove(resource_id)
|
||||
if not resource_id_list:
|
||||
break
|
||||
time.sleep(interval_time)
|
||||
else:
|
||||
msg = ('wait_for_servers_to_be_deleted {0} seconds timeout waiting'
|
||||
'for the expected get_server HTTP {1} status code for '
|
||||
'servers: {2}').format(timeout,
|
||||
ComputeResponseCodes.NOT_FOUND,
|
||||
server_id_list)
|
||||
msg = ('Wait for compute {0} resource delete {0} seconds timeout '
|
||||
'for the expected resource get HTTP {1} status code for '
|
||||
'resources: {2}').format(resource, timeout,
|
||||
ComputeResponseCodes.NOT_FOUND,
|
||||
resource_id_list)
|
||||
self._log.info(msg)
|
||||
if raise_exception:
|
||||
raise TimeoutException(msg)
|
||||
|
||||
def create_servers_in_same_cell(self, n_servers, name='same_cell_server',
|
||||
network_ids=None, port_ids=None):
|
||||
"""
|
||||
@summary: Creates n servers in same cell using the first server ID with
|
||||
scheduler hints
|
||||
@param n_servers: number of servers to create
|
||||
@type n_servers: int
|
||||
@param name: servers name (n will be appended at the end)
|
||||
@type name: str
|
||||
@param network_ids: server network ids, for ex. public, private, etc.
|
||||
@type network_ids: list
|
||||
@param port_ids: server network port ids from an isolated network
|
||||
@type port_ids: list
|
||||
@return: server entity list
|
||||
@rtype: list
|
||||
"""
|
||||
msg = 'Creating {0} servers in same cell...'.format(n_servers)
|
||||
self._log.info(msg)
|
||||
created_servers = []
|
||||
server_id_list = []
|
||||
for n_server in range(n_servers):
|
||||
server_name = ''.join([name, str(n_server)])
|
||||
if n_server < 1:
|
||||
resp = self.create_networking_server(
|
||||
name=server_name, network_ids=network_ids,
|
||||
port_ids=port_ids, active_server=False)
|
||||
server = resp.entity
|
||||
|
||||
# Setting up the scheduler hints for creating other servers
|
||||
pz = IPAddressesServerZone.PUBLIC_IP_ZONE_NEAR
|
||||
scheduler_hints = {pz: server.id}
|
||||
else:
|
||||
resp = self.create_networking_server(
|
||||
name=server_name, network_ids=network_ids,
|
||||
port_ids=port_ids, scheduler_hints=scheduler_hints,
|
||||
active_server=False)
|
||||
server = resp.entity
|
||||
created_servers.append(server)
|
||||
server_id_list.append(server.id)
|
||||
|
||||
# Waiting for the servers to get into Active state
|
||||
self.wait_for_servers_to_be_active(server_id_list=server_id_list)
|
||||
|
||||
# Getting and returning the active server entity objects
|
||||
servers_list = [self.get_networking_server(svr)
|
||||
for svr in created_servers]
|
||||
|
||||
return servers_list
|
||||
|
||||
@@ -13,8 +13,6 @@ 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.
|
||||
"""
|
||||
|
||||
from cloudcafe.auth.config import UserAuthConfig, UserConfig
|
||||
from cloudcafe.common.models.configuration import ConfigSectionInterface
|
||||
|
||||
|
||||
@@ -40,6 +38,14 @@ class NetworkingBaseConfig(ConfigSectionInterface):
|
||||
"""
|
||||
return self.get_boolean("use_compute_api", False)
|
||||
|
||||
@property
|
||||
def device_owner(self):
|
||||
"""
|
||||
Port device owner attribute expected value when assigned to a
|
||||
server instance
|
||||
"""
|
||||
return self.get("device_owner", "compute:None")
|
||||
|
||||
@property
|
||||
def keep_servers(self):
|
||||
"""Flag for not deleting servers on tearDown"""
|
||||
@@ -50,6 +56,11 @@ class NetworkingBaseConfig(ConfigSectionInterface):
|
||||
"""Flag for not deleting servers w failures on tearDown"""
|
||||
return self.get_boolean("keep_servers_on_failure", False)
|
||||
|
||||
@property
|
||||
def keep_ip_associations(self):
|
||||
"""Flag for not deleting ip_associations on tearDown"""
|
||||
return self.get_boolean("keep_ip_associations", False)
|
||||
|
||||
@property
|
||||
def api_poll_interval(self):
|
||||
"""Time interval for api calls on while loops retries"""
|
||||
|
||||
@@ -14,6 +14,8 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
from cloudcafe.compute.common.types import NovaServerStatusTypes
|
||||
|
||||
|
||||
class NeutronResource(object):
|
||||
"""Neutron resource types"""
|
||||
@@ -35,6 +37,20 @@ class NeutronResource(object):
|
||||
return self.PLURALS.get(self.singular, self.singular)
|
||||
|
||||
|
||||
class NetworkTypes(object):
|
||||
"""Network types"""
|
||||
PUBLIC = 'public'
|
||||
SERVICE = 'service'
|
||||
ISOLATED = 'isolated'
|
||||
|
||||
|
||||
class PortTypes(object):
|
||||
"""Port types"""
|
||||
PUBLIC = 'pnet'
|
||||
SERVICE = 'snet'
|
||||
ISOLATED = 'inet'
|
||||
|
||||
|
||||
class NeutronResponseCodes(object):
|
||||
"""HTTP Neutron API Response codes"""
|
||||
|
||||
@@ -85,9 +101,16 @@ class NeutronErrorTypes(object):
|
||||
PORT_NOT_FOUND = 'PortNotFound'
|
||||
SECURITY_GROUPS_NOT_IMPLEMENTED = 'SecurityGroupsNotImplemented'
|
||||
SUBNET_NOT_FOUND = 'SubnetNotFound'
|
||||
TENANT_NETWORK_SECURITY_GROUP_RULES_NOT_ENABLED = (
|
||||
'TenantNetworkSecurityGroupRulesNotEnabled')
|
||||
|
||||
|
||||
class ComputeResponseCodes(object):
|
||||
"""HTTP Compute API Response codes"""
|
||||
|
||||
NOT_FOUND = 404
|
||||
SERVER_GET = 200
|
||||
|
||||
|
||||
class ComputeStatus(NovaServerStatusTypes):
|
||||
"""Compute server instance status"""
|
||||
|
||||
@@ -31,6 +31,10 @@ class UnavailableComputeInteractionException(BaseNetworkingException):
|
||||
'compute_endpoint_name at the compute_endpoint section')
|
||||
|
||||
|
||||
class UnableToGetNetworkingServer(BaseNetworkingException):
|
||||
MSG = 'Unable to GET nova server used for networking'
|
||||
|
||||
|
||||
class NetworkIDMissingException(BaseNetworkingException):
|
||||
MSG = 'Network ID is required'
|
||||
|
||||
|
||||
@@ -222,6 +222,14 @@ class IPAddressesBehaviors(NetworkingBaseBehaviors):
|
||||
@return: failed deletes list with IP Address IDs and failures
|
||||
@rtype: list(dict)
|
||||
"""
|
||||
|
||||
# If IP address list not given, deleting all shared IPs
|
||||
if not ip_address_list:
|
||||
resp = self.list_ip_addresses(type_='shared', raise_exception=True)
|
||||
shared_ips = resp.response.entity
|
||||
ip_address_list = self.get_id_list_from_entity_list(
|
||||
entity_list=shared_ips)
|
||||
|
||||
result = self._delete_resources(
|
||||
resource=self.ip_address_resource,
|
||||
resource_list=ip_address_list,
|
||||
|
||||
@@ -14,6 +14,8 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
from cloudcafe.networking.networks.common.config import NetworkingBaseConfig
|
||||
|
||||
|
||||
@@ -21,3 +23,17 @@ class IPAddressesConfig(NetworkingBaseConfig):
|
||||
"""IP Addresses configuration parameters"""
|
||||
|
||||
SECTION_NAME = 'ip_addresses'
|
||||
|
||||
@property
|
||||
def scheduler_hints(self):
|
||||
"""
|
||||
JSON string containing the os:scheduler_hints for server boot, for ex.
|
||||
For targeting the same cell of the server ID given,
|
||||
{"public_ip_zone:near": [serverID]}
|
||||
For targeting another cell of the server ID given,
|
||||
{"public_ip_zone:far": [serverID]}
|
||||
For targeting another host in the same cell of the server ID given,
|
||||
{"different_host": [serverID]}
|
||||
"""
|
||||
result = self.get("scheduler_hints", "{}")
|
||||
return json.loads(result)
|
||||
|
||||
@@ -33,7 +33,9 @@ class IPAddressesResponseCodes(NeutronResponseCodes):
|
||||
|
||||
LIST_IP_ADDRESSES = 200
|
||||
GET_IP_ADDRESS = 200
|
||||
CREATE_IP_ADDRESS = 201
|
||||
|
||||
# Using HTTP 200 instead of 201 till NCP-1577 is fixed
|
||||
CREATE_IP_ADDRESS = 200
|
||||
UPDATE_IP_ADDRESS = 200
|
||||
DELETE_IP_ADDRESS = 204
|
||||
|
||||
@@ -42,3 +44,14 @@ class IPAddressesErrorTypes(NeutronErrorTypes):
|
||||
"""IP Address Error Types"""
|
||||
|
||||
IP_ADDRESS_NOT_FOUND = 'IPAddressNotFound'
|
||||
|
||||
|
||||
class IPAddressesServerZone(object):
|
||||
"""
|
||||
Scheduler hint keys for targeting the same or different cell/host for
|
||||
server builds
|
||||
"""
|
||||
|
||||
PUBLIC_IP_ZONE_NEAR = 'public_ip_zone:near'
|
||||
PUBLIC_IP_ZONE_FAR = 'public_ip_zone:far'
|
||||
DIFFERENT_HOST = 'different_host'
|
||||
|
||||
313
cloudcafe/networking/networks/personas.py
Normal file
313
cloudcafe/networking/networks/personas.py
Normal file
@@ -0,0 +1,313 @@
|
||||
"""
|
||||
Copyright 2015 Rackspace
|
||||
|
||||
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.
|
||||
"""
|
||||
from cafe.engine.models.base import BaseModel
|
||||
from cloudcafe.networking.networks.common.behaviors \
|
||||
import NetworkingBaseBehaviors
|
||||
from cloudcafe.networking.networks.common.constants \
|
||||
import NetworkTypes, PortTypes
|
||||
from cloudcafe.networking.networks.composites import NetworkingComposite
|
||||
|
||||
|
||||
class ServerPersona(BaseModel, NetworkingBaseBehaviors):
|
||||
"""
|
||||
@summary: Server data object for quick access to networking data and also
|
||||
tracking expected counts for ports and fixed IPs
|
||||
"""
|
||||
def __init__(self, server=None, pnet=True, snet=True, inet=False,
|
||||
network=None, subnetv4=None, portv4=None, subnetv6=None,
|
||||
portv6=None, inet_port_count=0, snet_port_count=1,
|
||||
pnet_port_count=1, inet_fix_ipv4_count=0,
|
||||
inet_fix_ipv6_count=0, snet_fix_ipv4_count=1,
|
||||
snet_fix_ipv6_count=0, pnet_fix_ipv4_count=1,
|
||||
pnet_fix_ipv6_count=1):
|
||||
super(ServerPersona, self).__init__()
|
||||
"""
|
||||
@param server: server entity
|
||||
@type server: compute.servers_api.models.servers.Server
|
||||
@param pnet: if the server has public network flag
|
||||
@type pnet: bool
|
||||
@param snet: if the server has service (private) network flag
|
||||
@type snet: bool
|
||||
@param inet: if the server has isolated network flag
|
||||
@type inet: bool
|
||||
@param network: (optional) isolated network entity if applies
|
||||
@type network: networking.networks.common.models.response
|
||||
.network.Network
|
||||
@param subnetv4: (optional) isolated network IPv4 subnet if applies
|
||||
@type subnetv4: networking.networks.common.models.response
|
||||
.subnet.Subnet
|
||||
@param portv4: (optional) isolated network IPv4 port if applies
|
||||
@type portv4: networking.networks.common.models.response.port.Port
|
||||
@param subnetv6: (optional) isolated network IPv6 subnet if applies
|
||||
@type subnetv6: networking.networks.common.models.response
|
||||
.subnet.Subnet
|
||||
@param portv6: (optional) isolated network IPv6 port if applies
|
||||
@type portv6: networking.networks.common.models.response.port.Port
|
||||
@param inet_port_count: expected isolated network port count
|
||||
@type inet_port_count: int
|
||||
@param snet_port_count: expected service (private) network port count
|
||||
@type snet_port_count: int
|
||||
@param pnet_port_count: expected public network port count
|
||||
@type pnet_port_count: int
|
||||
@param inet_fix_ipv4_count: expected isolated network fixed IPv4s count
|
||||
@type inet_fix_ipv4_count: int
|
||||
@param inet_fix_ipv6_count: expected isolated network fixed IPv6s count
|
||||
@type inet_fix_ipv6_count: int
|
||||
@param snet_fix_ipv4_count: expected service network fixed IPv4s count
|
||||
@type snet_fix_ipv4_count: int
|
||||
@param snet_fix_ipv6_count: expected service network fixed IPv6s count
|
||||
@type snet_fix_ipv6_count: int
|
||||
@param pnet_fix_ipv4_count: expected public network fixed IPv4s count
|
||||
@type pnet_fix_ipv4_count: int
|
||||
@param pnet_fix_ipv6_count: expected public network fixed IPv6s count
|
||||
@type pnet_fix_ipv6_count: int
|
||||
"""
|
||||
|
||||
# Server entity object
|
||||
self.server = server
|
||||
|
||||
# Server expected networks (bool value)
|
||||
self.pnet = pnet
|
||||
self.snet = snet
|
||||
self.inet = inet
|
||||
|
||||
# Server isolated network, subnet and port (entity objects, if any)
|
||||
self.network = network
|
||||
self.subnetv4 = subnetv4
|
||||
self.portv4 = portv4
|
||||
self.subnetv6 = subnetv6
|
||||
self.portv6 = portv6
|
||||
|
||||
# Expected server port count by network
|
||||
self.inet_port_count = inet_port_count
|
||||
self.snet_port_count = snet_port_count
|
||||
self.pnet_port_count = pnet_port_count
|
||||
|
||||
# Expected server Fixed IP address count by network and version
|
||||
self.inet_fix_ipv4_count = inet_fix_ipv4_count
|
||||
self.inet_fix_ipv6_count = inet_fix_ipv6_count
|
||||
self.snet_fix_ipv4_count = snet_fix_ipv4_count
|
||||
self.snet_fix_ipv6_count = snet_fix_ipv6_count
|
||||
self.pnet_fix_ipv4_count = pnet_fix_ipv4_count
|
||||
self.pnet_fix_ipv6_count = pnet_fix_ipv6_count
|
||||
|
||||
# Networking composite
|
||||
self.net = NetworkingComposite()
|
||||
|
||||
# base config from networking/networks/common/config.py
|
||||
self.config = self.net.config
|
||||
|
||||
# sub-composites
|
||||
self.networks = self.net.networks
|
||||
self.subnets = self.net.subnets
|
||||
self.ports = self.net.ports
|
||||
self.behaviors = self.net.behaviors
|
||||
|
||||
# Other reusable values (service_network_id aka Private Network)
|
||||
self.public_network_id = self.networks.config.public_network_id
|
||||
self.service_network_id = self.networks.config.service_network_id
|
||||
self.isolated_network_id = getattr(self.network, 'id', None)
|
||||
|
||||
# Error list for behavior method calls
|
||||
self.errors = []
|
||||
|
||||
self.list_port_failure_msg = ('Unable to get server {0} ports for '
|
||||
'network {1}. Failures: {2}.')
|
||||
self.fixed_ips_failure_msg = ('Unable to get server {0} fixed IPs '
|
||||
'with IPv{1} version for network {2}')
|
||||
|
||||
@property
|
||||
def pnet_ports(self):
|
||||
"""
|
||||
@summary: server public network ports
|
||||
@return: public network ports
|
||||
@rtype: list of port entity objects
|
||||
"""
|
||||
return self._port_response(network_type=NetworkTypes.PUBLIC)
|
||||
|
||||
@property
|
||||
def snet_ports(self):
|
||||
"""
|
||||
@summary: server service (private) network ports
|
||||
@return: private network ports
|
||||
@rtype: list of port entity objects
|
||||
"""
|
||||
return self._port_response(network_type=NetworkTypes.SERVICE)
|
||||
|
||||
@property
|
||||
def inet_ports(self):
|
||||
"""
|
||||
@summary: server isolated network ports
|
||||
@return: isolated network ports
|
||||
@rtype: list of port entity objects
|
||||
"""
|
||||
return self._port_response(network_type=NetworkTypes.ISOLATED)
|
||||
|
||||
@property
|
||||
def inet_fix_ipv4(self):
|
||||
"""
|
||||
@summary: updates server attribute with latest isolated fixed IPs
|
||||
@return: isolated network fixed IPv4 addresses
|
||||
@rtype: list of strings
|
||||
"""
|
||||
return self._get_fixed_ips(ip_version=4, port_type=PortTypes.ISOLATED,
|
||||
network_type=NetworkTypes.ISOLATED)
|
||||
|
||||
@property
|
||||
def inet_fix_ipv6(self):
|
||||
"""
|
||||
@summary: updates server attribute with latest isolated fixed IPs
|
||||
@return: isolated network fixed IPv6 addresses
|
||||
@rtype: list of strings
|
||||
"""
|
||||
return self._get_fixed_ips(ip_version=6, port_type=PortTypes.ISOLATED,
|
||||
network_type=NetworkTypes.ISOLATED)
|
||||
|
||||
@property
|
||||
def snet_fix_ipv4(self):
|
||||
"""
|
||||
@summary: updates server attribute with latest private fixed IPs
|
||||
@return: service (private) network fixed IPv4 addresses
|
||||
@rtype: list of strings
|
||||
"""
|
||||
return self._get_fixed_ips(ip_version=4, port_type=PortTypes.SERVICE,
|
||||
network_type=NetworkTypes.SERVICE)
|
||||
|
||||
@property
|
||||
def snet_fix_ipv6(self):
|
||||
"""
|
||||
@summary: updates server attribute with latest private fixed IPs
|
||||
@return: service (private) network fixed IPv6 addresses
|
||||
@rtype: list of strings
|
||||
"""
|
||||
return self._get_fixed_ips(ip_version=6, port_type=PortTypes.SERVICE,
|
||||
network_type=NetworkTypes.SERVICE)
|
||||
|
||||
@property
|
||||
def pnet_fix_ipv4(self):
|
||||
"""
|
||||
@summary: updates server attribute with latest public fixed IPs
|
||||
@return: public network fixed IPv4 addresses
|
||||
@rtype: list of strings
|
||||
"""
|
||||
return self._get_fixed_ips(ip_version=4, port_type=PortTypes.PUBLIC,
|
||||
network_type=NetworkTypes.PUBLIC)
|
||||
|
||||
@property
|
||||
def pnet_fix_ipv6(self):
|
||||
"""
|
||||
@summary: updates server attribute with latest public fixed IPs
|
||||
@return: public network fixed IPv6 addresses
|
||||
@rtype: list of strings
|
||||
"""
|
||||
return self._get_fixed_ips(ip_version=6, port_type=PortTypes.PUBLIC,
|
||||
network_type=NetworkTypes.PUBLIC)
|
||||
|
||||
@property
|
||||
def pnet_port_ids(self):
|
||||
"""
|
||||
@summary: gets the public network port ids
|
||||
"""
|
||||
return self._get_port_ids(port_type=PortTypes.PUBLIC)
|
||||
|
||||
@property
|
||||
def snet_port_ids(self):
|
||||
"""
|
||||
@summary: gets the service (private) network port ids
|
||||
"""
|
||||
return self._get_port_ids(port_type=PortTypes.SERVICE)
|
||||
|
||||
@property
|
||||
def inet_port_ids(self):
|
||||
"""
|
||||
@summary: gets the public network port ids
|
||||
"""
|
||||
return self._get_port_ids(port_type=PortTypes.ISOLATED)
|
||||
|
||||
def update_server_persona(self, clear_errors=True):
|
||||
"""
|
||||
@summary: updates the self.server entity doing a GET server call
|
||||
"""
|
||||
self.server = self.behaviors.get_networking_server(server=self.server)
|
||||
self.isolated_network_id = getattr(self.network, 'id', None)
|
||||
|
||||
if clear_errors:
|
||||
self.errors = []
|
||||
|
||||
def _port_response(self, network_type):
|
||||
"""
|
||||
@summary: returns server network ports based on network type
|
||||
@param network_type: public, service or isolated network type
|
||||
@param network_type: str
|
||||
"""
|
||||
network_id_label = '{0}_network_id'.format(network_type.lower())
|
||||
network_id = getattr(self, network_id_label, None)
|
||||
if not network_id:
|
||||
return []
|
||||
|
||||
ports = self.ports.behaviors.list_ports(device_id=self.server.id,
|
||||
network_id=network_id)
|
||||
if ports.failures:
|
||||
msg = self.list_port_failure_msg.format(self.server.id, network_id,
|
||||
ports.failures)
|
||||
self.errors.append(msg)
|
||||
self._log.error(msg)
|
||||
return []
|
||||
return ports.response.entity
|
||||
|
||||
def _get_fixed_ips(self, ip_version, port_type, network_type):
|
||||
"""
|
||||
@summary: gets fixed IPs from server ports
|
||||
@param ip_version: 4 or 6 depending on the port IP version
|
||||
@type ip_version: int
|
||||
@param port_type: pnet, snet or inet port type
|
||||
@type port_type: str
|
||||
@param network_type: public, service or isolated network type
|
||||
@param network_type: str
|
||||
@return: fixed IP addresses
|
||||
@rtype: list of strings
|
||||
"""
|
||||
port_attr = '{0}_ports'.format(port_type)
|
||||
network_id_label = '{0}_network_id'.format(network_type.lower())
|
||||
network_id = getattr(self, network_id_label, None)
|
||||
ports = getattr(self, port_attr, [])
|
||||
|
||||
result = []
|
||||
for port in ports:
|
||||
addresses = self.ports.behaviors.get_addresses_from_fixed_ips(
|
||||
fixed_ips=port.fixed_ips, ip_version=ip_version)
|
||||
result.extend(addresses)
|
||||
|
||||
if not result:
|
||||
msg = self.fixed_ips_failure_msg.format(
|
||||
self.server.id, ip_version, network_id)
|
||||
self.errors.append(msg)
|
||||
self._log.error(msg)
|
||||
|
||||
return result
|
||||
|
||||
def _get_port_ids(self, port_type):
|
||||
"""
|
||||
@summary: gets the port ids
|
||||
@param port_type: pnet, snet or inet port type
|
||||
@type port_type: str
|
||||
@return: port IDs
|
||||
@rtype: list(str)
|
||||
"""
|
||||
port_attr = '{0}_ports'.format(port_type.lower())
|
||||
ports = getattr(self, port_attr, [])
|
||||
port_ids = [port.id for port in ports]
|
||||
return port_ids
|
||||
@@ -50,6 +50,23 @@ class PortsBehaviors(NetworkingBaseBehaviors):
|
||||
results['subnet_ids'].append(fixed_ip['subnet_id'])
|
||||
return results
|
||||
|
||||
def get_addresses_from_fixed_ips(self, fixed_ips, ip_version=4):
|
||||
"""
|
||||
@summary: gets the IP addresses from the port fixed IPs attribute
|
||||
@param fixed_ips: list of fixed_ips
|
||||
@type fixed_ips: list(dict)
|
||||
@param version: IP version of addresses to get
|
||||
@type version: int
|
||||
@return: IP addresses from fixed IPs
|
||||
@rtype: list(str)
|
||||
"""
|
||||
result = []
|
||||
for fixed_ip in fixed_ips:
|
||||
ip = netaddr.IPAddress(fixed_ip['ip_address'])
|
||||
if ip.version == ip_version:
|
||||
result.append(str(ip))
|
||||
return result
|
||||
|
||||
def format_fixed_ips(self, fixed_ips):
|
||||
"""
|
||||
@summary: formats fixed ips for assertions removing zeros on
|
||||
|
||||
@@ -45,7 +45,7 @@ class PortsConfig(NetworkingBaseConfig):
|
||||
@property
|
||||
def fixed_ips_per_port(self):
|
||||
"""Ports fixed IPs quota"""
|
||||
return int(self.get("fixed_ips_per_port", 5))
|
||||
return int(self.get("fixed_ips_per_port", 6))
|
||||
|
||||
@property
|
||||
def api_poll_interval(self):
|
||||
|
||||
Reference in New Issue
Block a user