Add support for load balancers
This commit is contained in:
parent
0c5f95414c
commit
faebe85829
@ -121,7 +121,7 @@ single-line-if-stmt=no
|
||||
no-space-check=trailing-comma,dict-separator
|
||||
|
||||
# Maximum number of lines in a module
|
||||
max-module-lines=2000
|
||||
max-module-lines=5000
|
||||
|
||||
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
|
||||
# tab).
|
||||
@ -394,7 +394,7 @@ max-attributes=7
|
||||
min-public-methods=1
|
||||
|
||||
# Maximum number of public methods for a class (see R0904).
|
||||
max-public-methods=20
|
||||
max-public-methods=30
|
||||
|
||||
# Maximum number of boolean expressions in a if statement
|
||||
max-bool-expr=5
|
||||
|
733
hnv/client.py
733
hnv/client.py
@ -131,6 +131,33 @@ class _BaseHNVModel(model.Model):
|
||||
allow_insecure=CONFIG.HNV.https_allow_insecure,
|
||||
ca_bundle=CONFIG.HNV.https_ca_bundle)
|
||||
|
||||
@classmethod
|
||||
def _get_all(cls, parent_id=None, grandparent_id=None):
|
||||
"""Retrives all the required resources."""
|
||||
client = cls._get_client()
|
||||
endpoint = cls._endpoint.format(resource_id="",
|
||||
parent_id=parent_id or "",
|
||||
grandparent_id=grandparent_id or "")
|
||||
resources = []
|
||||
while True:
|
||||
raw_data = client.get_resource(endpoint)
|
||||
for item in raw_data.get("value", []):
|
||||
resources.append(cls.from_raw_data(item))
|
||||
endpoint = raw_data.get("nextLink")
|
||||
if not endpoint:
|
||||
break
|
||||
return resources
|
||||
|
||||
@classmethod
|
||||
def _get(cls, resource_id, parent_id, grandparent_id):
|
||||
""""Retrieves the required resource."""
|
||||
client = cls._get_client()
|
||||
endpoint = cls._endpoint.format(resource_id=resource_id or "",
|
||||
parent_id=parent_id or "",
|
||||
grandparent_id=grandparent_id or "")
|
||||
raw_data = client.get_resource(endpoint)
|
||||
return cls.from_raw_data(raw_data)
|
||||
|
||||
@classmethod
|
||||
def get(cls, resource_id=None, parent_id=None, grandparent_id=None):
|
||||
"""Retrieves the required resources.
|
||||
@ -143,15 +170,11 @@ class _BaseHNVModel(model.Model):
|
||||
network objects that are ancestors of the
|
||||
parent of the necessary resource.
|
||||
"""
|
||||
client = cls._get_client()
|
||||
endpoint = cls._endpoint.format(resource_id=resource_id or "",
|
||||
parent_id=parent_id or "",
|
||||
grandparent_id=grandparent_id or "")
|
||||
raw_data = client.get_resource(endpoint)
|
||||
if resource_id is None:
|
||||
return [cls.from_raw_data(item) for item in raw_data["value"]]
|
||||
|
||||
if not resource_id:
|
||||
return cls._get_all(parent_id, grandparent_id)
|
||||
else:
|
||||
return cls.from_raw_data(raw_data)
|
||||
return cls._get(resource_id, parent_id, grandparent_id)
|
||||
|
||||
@classmethod
|
||||
def remove(cls, resource_id, parent_id=None, grandparent_id=None,
|
||||
@ -207,7 +230,7 @@ class _BaseHNVModel(model.Model):
|
||||
response = client.get_resource(endpoint)
|
||||
self._reset_model(response)
|
||||
|
||||
def commit(self, wait=True, timeout=None):
|
||||
def commit(self, if_match=None, wait=True, timeout=None):
|
||||
"""Apply all the changes on the current model.
|
||||
|
||||
:param wait: Whether to wait until the operation is completed
|
||||
@ -231,7 +254,8 @@ class _BaseHNVModel(model.Model):
|
||||
endpoint = self._endpoint.format(resource_id=self.resource_id or "",
|
||||
parent_id=self.parent_id or "")
|
||||
request_body = self.dump(include_read_only=False)
|
||||
response = client.update_resource(endpoint, data=request_body)
|
||||
response = client.update_resource(endpoint, data=request_body,
|
||||
if_match=if_match)
|
||||
|
||||
elapsed_time = 0
|
||||
while wait:
|
||||
@ -252,6 +276,10 @@ class _BaseHNVModel(model.Model):
|
||||
else:
|
||||
self._reset_model(response)
|
||||
|
||||
# NOTE(alexcoman): In order to keep backwards compatibility the
|
||||
# `method: commit` will return a reference to itself.
|
||||
# An example for that can be the following use case:
|
||||
# label = client.Model().commit()
|
||||
return self
|
||||
|
||||
@classmethod
|
||||
@ -573,7 +601,7 @@ class IPConfiguration(_BaseHNVModel):
|
||||
|
||||
backend_address_pools = model.Field(
|
||||
name="backend_address_pools", key="loadBalancerBackendAddressPools",
|
||||
is_required=False, is_read_only=True)
|
||||
is_required=False, is_read_only=False)
|
||||
"""Reference to backendAddressPools child resource of loadBalancers
|
||||
resource."""
|
||||
|
||||
@ -1177,7 +1205,7 @@ class VirtualSwitchManager(_BaseHNVModel):
|
||||
is_required=False)
|
||||
|
||||
def __init__(self, **fields):
|
||||
qos_settings = fields.pop("qos_settings", {})
|
||||
qos_settings = fields.get("qos_settings", {})
|
||||
if not isinstance(qos_settings, VirtualSwtichQosSettings):
|
||||
fields["qos_settings"] = VirtualSwtichQosSettings.from_raw_data(
|
||||
raw_data=qos_settings)
|
||||
@ -1469,7 +1497,7 @@ class IPSecConfiguration(model.Model):
|
||||
@classmethod
|
||||
def from_raw_data(cls, raw_data):
|
||||
"""Create a new model using raw API response."""
|
||||
raw_main = raw_data.pop("mainMode", None)
|
||||
raw_main = raw_data.get("mainMode", None)
|
||||
if raw_main is not None:
|
||||
main_mode = MainMode.from_raw_data(raw_main)
|
||||
raw_data["mainMode"] = main_mode
|
||||
@ -1838,3 +1866,682 @@ class PublicIPAddresses(_BaseHNVModel):
|
||||
associated. Private ip can be defined on NIC, loadBalancers, or
|
||||
gateways.
|
||||
"""
|
||||
|
||||
|
||||
class BackendAddressPools(_BaseHNVModel):
|
||||
|
||||
"""Model for backend address pools.
|
||||
|
||||
This resource represents the list of IPs that can receive network traffic
|
||||
that comes via the front-end IPs. The Load Balancing MUX handles incoming
|
||||
traffic via the front-end IPs and distributes them to backend IPs based
|
||||
on load balancing configuration.
|
||||
"""
|
||||
|
||||
_endpoint = ("/networking/v1/loadBalancers/{parent_id}"
|
||||
"/backendAddressPools/{resource_id}")
|
||||
|
||||
parent_id = model.Field(
|
||||
name="parent_id", key="parentResourceID",
|
||||
is_property=False, is_required=True, is_read_only=True)
|
||||
"""The parent resource ID field contains the resource ID that is
|
||||
associated with network objects that are ancestors of the necessary
|
||||
resource.
|
||||
"""
|
||||
|
||||
backend_ip_configurations = model.Field(
|
||||
name="backend_ip_configurations", key="backendIPConfigurations",
|
||||
is_required=False, is_read_only=False)
|
||||
"""Indicates an array of references to ipConfiguration Resources.
|
||||
|
||||
There is no restriction on having the same IP configurations in multiple
|
||||
backendAddressPools. An IpConfiguration can become a part of a
|
||||
backendAddressPool by setting a reference to a backendAddressPool resource
|
||||
in the loadBalancerBackendAddressPools array field on the IpConfiguration
|
||||
resource.
|
||||
"""
|
||||
|
||||
load_balancing_rules = model.Field(name="load_balancing_rules",
|
||||
key="loadBalancingRules",
|
||||
is_required=False, is_read_only=False)
|
||||
"""Indicates an array of references to the set of loadBalancingRules
|
||||
resources that use this backend address pool.
|
||||
"""
|
||||
|
||||
outbound_nat_rules = model.Field(name="outbound_nat_rules",
|
||||
key="outboundNatRules",
|
||||
is_required=False, is_read_only=False)
|
||||
"""Indicates an array of references to the set of outboundNatRules
|
||||
resources that use this backend address pool."""
|
||||
|
||||
@classmethod
|
||||
def from_raw_data(cls, raw_data):
|
||||
"""Create a new model using raw API response."""
|
||||
properties = raw_data.get("properties", {})
|
||||
|
||||
backend_ip_configurations = []
|
||||
for raw_content in properties.get("backendIPConfigurations", []):
|
||||
resource = Resource.from_raw_data(raw_content)
|
||||
backend_ip_configurations.append(resource)
|
||||
properties["backendIPConfigurations"] = backend_ip_configurations
|
||||
|
||||
load_balancing_rules = []
|
||||
for raw_content in properties.get("loadBalancingRules", []):
|
||||
resource = Resource.from_raw_data(raw_content)
|
||||
load_balancing_rules.append(resource)
|
||||
properties["loadBalancingRules"] = load_balancing_rules
|
||||
|
||||
outbound_nat_rules = []
|
||||
for raw_content in properties.get("outboundNatRules", []):
|
||||
resource = Resource.from_raw_data(raw_content)
|
||||
outbound_nat_rules.append(resource)
|
||||
properties["outboundNatRules"] = outbound_nat_rules
|
||||
|
||||
return super(BackendAddressPools, cls).from_raw_data(raw_data)
|
||||
|
||||
|
||||
class FrontendIPConfigurations(_BaseHNVModel):
|
||||
|
||||
"""Model for frontend ip configurations.
|
||||
|
||||
This resource represents the frontend IP addresses of the load balancer.
|
||||
Either a publicIPAddress or a privateIPAddress and subnet must
|
||||
be configured.
|
||||
"""
|
||||
|
||||
_endpoint = ("/networking/v1/loadBalancers/{parent_id}"
|
||||
"/frontendIpConfigurations/{resource_id}")
|
||||
|
||||
parent_id = model.Field(
|
||||
name="parent_id", key="parentResourceID",
|
||||
is_property=False, is_required=True, is_read_only=True)
|
||||
"""The parent resource ID field contains the resource ID that is
|
||||
associated with network objects that are ancestors of the necessary
|
||||
resource.
|
||||
"""
|
||||
|
||||
inbound_nat_rules = model.Field(
|
||||
name="inbound_nat_rules", key="inboundNatRules",
|
||||
is_required=False, is_read_only=True)
|
||||
"""Indicates a reference to the inboundNatRules resource used by
|
||||
the frontEndIpConfiguration."""
|
||||
|
||||
load_balancing_rules = model.Field(
|
||||
name="load_balancing_rules", key="loadBalancingRules",
|
||||
is_required=False, is_read_only=False)
|
||||
"""Indicates a reference to the loadBalancingRules resource used
|
||||
by the frontEndIpConfiguration."""
|
||||
|
||||
outbound_nat_rules = model.Field(
|
||||
name="outbound_nat_rules", key="outboundNatRules",
|
||||
is_required=False, is_read_only=True)
|
||||
"""Indicates a reference to the outboundNatRules resource used by
|
||||
the frontEndIpConfiguration."""
|
||||
|
||||
public_ip_address = model.Field(
|
||||
name="public_ip_address", key="publicIPAddress",
|
||||
is_required=False, is_read_only=False)
|
||||
"""Indicates a reference to the publicIPAddresses resource used by
|
||||
the frontEndIpConfiguration. If a publicIPAddress is specified,
|
||||
then a privateIPaddress is not specified. When a
|
||||
publicIPAddress is specified, the privateIpAllocationMethod is
|
||||
set to Dynamic.
|
||||
"""
|
||||
|
||||
private_ip_address = model.Field(name="private_ip_address",
|
||||
key="privateIPAddress",
|
||||
is_required=False, is_read_only=False)
|
||||
"""This is only specified if a specific private IP address identifies an
|
||||
IP address which is statically configured for use with this
|
||||
frontendIpConfiguration.
|
||||
|
||||
PrivateIPAllocation method MUST be allocated static for this case.
|
||||
If a privateIPAddress is specified, a reference to a publicIPaddress
|
||||
cannot be specified at the same time. privateIPAddresses can be either
|
||||
from the infrastructure address space or from a tenant address space,
|
||||
in either case they MUST be accompanied with a valid subnet specified in
|
||||
subnet element reference.
|
||||
"""
|
||||
|
||||
private_ip_allocation_method = model.Field(
|
||||
name="private_ip_allocation_method", key="privateIPAllocationMethod",
|
||||
is_required=False, is_read_only=False)
|
||||
"""Static or Dynamic."""
|
||||
|
||||
subnet = model.Field(name="subnet", key="subnet",
|
||||
is_required=False, is_read_only=False)
|
||||
"""Indicates a references to the subnet resource used by the
|
||||
frontendIpConfiguration resource. MUST be specified if a
|
||||
privateIPaddress is specified.
|
||||
A subnet reference to a logical network subnet is needed if the
|
||||
privateIpAddress is from the infrastructure address space. A
|
||||
subnet reference to a virtual network subnet is needed if the
|
||||
privateIpAddress is from a tenant address space.
|
||||
The subnet MUST include the IP address specified in
|
||||
privateIpAddress.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def from_raw_data(cls, raw_data):
|
||||
"""Create a new model using raw API response."""
|
||||
properties = raw_data.get("properties", {})
|
||||
|
||||
load_balancing_rules = []
|
||||
for raw_content in properties.get("loadBalancingRules", []):
|
||||
resource = Resource.from_raw_data(raw_content)
|
||||
load_balancing_rules.append(resource)
|
||||
properties["loadBalancingRules"] = load_balancing_rules
|
||||
|
||||
inbound_nat_rules = []
|
||||
for raw_content in properties.get("inboundNatRules", []):
|
||||
resource = Resource.from_raw_data(raw_content)
|
||||
inbound_nat_rules.append(resource)
|
||||
properties["inboundNatRules"] = inbound_nat_rules
|
||||
|
||||
outbound_nat_rules = []
|
||||
for raw_content in properties.get("outboundNatRules", []):
|
||||
resource = Resource.from_raw_data(raw_content)
|
||||
outbound_nat_rules.append(resource)
|
||||
properties["outboundNatRules"] = outbound_nat_rules
|
||||
|
||||
raw_content = properties.get("subnet", None)
|
||||
if raw_content is not None:
|
||||
resource = Resource.from_raw_data(raw_content)
|
||||
properties["subnet"] = resource
|
||||
|
||||
return super(FrontendIPConfigurations, cls).from_raw_data(raw_data)
|
||||
|
||||
|
||||
class InboundNATRules(_BaseHNVModel):
|
||||
|
||||
"""Model for inbound nat rules.
|
||||
|
||||
This resource is used to configure the load balancer to apply
|
||||
Network Address Translation of inbound traffic.
|
||||
"""
|
||||
|
||||
_endpoint = ("/networking/v1/loadBalancers/{parent_id}"
|
||||
"/inboundNatRules/{resource_id}")
|
||||
|
||||
parent_id = model.Field(
|
||||
name="parent_id", key="parentResourceID",
|
||||
is_property=False, is_required=True, is_read_only=True)
|
||||
"""The parent resource ID field contains the resource ID that is
|
||||
associated with network objects that are ancestors of the necessary
|
||||
resource.
|
||||
"""
|
||||
|
||||
backend_ip_configuration = model.Field(
|
||||
name="backend_ip_configuration", key="backendIPConfiguration",
|
||||
is_required=False, is_read_only=False)
|
||||
"""Indicates a references to backendAddressPool resource. Traffic
|
||||
sent to frontendPort of each of the frontendIPConfigurations is
|
||||
forwarded to the backend IP.
|
||||
"""
|
||||
|
||||
backend_port = model.Field(name="backend_port", key="backendPort",
|
||||
is_required=False, is_read_only=False)
|
||||
"""Indicates a port used for internal connections on the endpoint.
|
||||
The localPort attribute maps the external port on the endpoint
|
||||
to an internal port on a role. This is useful in scenarios where a
|
||||
role has to communicate to an internal component on a port
|
||||
that different from the one that is exposed externally.
|
||||
Possible values range between 1 and 65535, inclusive.
|
||||
This parameter is required if the protocol is TCP or UDP.
|
||||
"""
|
||||
|
||||
frontend_ip_configurations = model.Field(
|
||||
name="frontend_ip_configurations", key="frontendIPConfigurations",
|
||||
is_required=True, is_read_only=False)
|
||||
"""Indicates an array of references to frontendIPConfigurations
|
||||
resources."""
|
||||
|
||||
frontend_port = model.Field(name="frontend_port", key="frontendPort",
|
||||
is_required=False, is_read_only=False)
|
||||
"""The port for the external endpoint. Any port number can be
|
||||
specified, but the port numbers specified for each role in the
|
||||
service MUST be unique. Possible values range between 1 and
|
||||
65535, inclusive.
|
||||
This parameter must be specified if protocol is TCP or UDP.
|
||||
"""
|
||||
|
||||
protocol = model.Field(name="protocol", key="protocol",
|
||||
is_required=True, is_read_only=False)
|
||||
"""Indicates the inbound transport protocol for the external
|
||||
endpoint. Valid values include `UDP`, `TCP`, `GRE`, `ESP` or `ALL`.
|
||||
`ALL` indicates a wildcard.
|
||||
"""
|
||||
|
||||
idle_timeout = model.Field(name="idle_timeout",
|
||||
key="idleTimeoutInMinutes",
|
||||
is_required=False, is_read_only=False)
|
||||
"""Specifies the timeout for the TCP idle connection.
|
||||
|
||||
The value can be set between 4 and 30 minutes. The default is 4
|
||||
minutes. If public IP is used as a frontend IP of a Load Balancer
|
||||
this value is ignored.
|
||||
"""
|
||||
|
||||
floating_ip = model.Field(name="floating_ip", key="enableFloatingIP",
|
||||
is_required=False, is_read_only=False)
|
||||
"""
|
||||
This specifies that a floating IP will be used on the available servers
|
||||
behind a load balancer. Floating IP (VIP) will be forwarded by the load
|
||||
balancer to the backend server. The back-end server will be configured
|
||||
with that VIP, a datacenter IP and weakhost forwarding.
|
||||
|
||||
Floating IP configuration is required if you are using the SQL AlwaysOn
|
||||
Availability Group feature. This setting can't be changed after you create
|
||||
the endpoint.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def from_raw_data(cls, raw_data):
|
||||
"""Create a new model using raw API response."""
|
||||
properties = raw_data.get("properties", {})
|
||||
|
||||
raw_ip_configuration = properties.get("backendIPConfiguration", [])
|
||||
if isinstance(raw_ip_configuration, dict):
|
||||
raw_ip_configuration = [raw_ip_configuration]
|
||||
|
||||
for raw_content in raw_ip_configuration:
|
||||
backend_ip_configuration = Resource.from_raw_data(raw_content)
|
||||
properties["backendIPConfiguration"] = backend_ip_configuration
|
||||
|
||||
frontend_ip_configurations = []
|
||||
for raw_content in properties.get("frontendIPConfigurations", []):
|
||||
resource = Resource.from_raw_data(raw_content)
|
||||
frontend_ip_configurations.append(resource)
|
||||
properties["frontendIPConfigurations"] = frontend_ip_configurations
|
||||
|
||||
return super(InboundNATRules, cls).from_raw_data(raw_data)
|
||||
|
||||
|
||||
class LoadBalancingRules(_BaseHNVModel):
|
||||
|
||||
"""Model for load balancing rules.
|
||||
|
||||
This resource is used to configure load balancing policies. The policies
|
||||
dictate the kind of traffic that is load-balanced, and port mapping
|
||||
between frontend IPs and backend IPs.
|
||||
"""
|
||||
|
||||
_endpoint = ("/networking/v1/loadBalancers/{parent_id}"
|
||||
"/loadBalancingRules/{resource_id}")
|
||||
|
||||
parent_id = model.Field(
|
||||
name="parent_id", key="parentResourceID",
|
||||
is_property=False, is_required=True, is_read_only=True)
|
||||
"""The parent resource ID field contains the resource ID that is
|
||||
associated with network objects that are ancestors of the necessary
|
||||
resource.
|
||||
"""
|
||||
|
||||
backend_address_pool = model.Field(
|
||||
name="backend_address_pool", key="backendAddressPool",
|
||||
is_required=False, is_read_only=False)
|
||||
"""Indicates an array of references to a BackendAddressPool resource.
|
||||
|
||||
Inbound traffic is randomly load balanced across IPs in the backend pool.
|
||||
"""
|
||||
|
||||
backend_port = model.Field(name="backend_port", key="backendPort",
|
||||
is_required=False, is_read_only=False)
|
||||
"""Indicates the port used for internal connections on the endpoint.
|
||||
|
||||
The localPort attribute maps the external port on the endpoint to an
|
||||
internal port on a role. This is useful in scenarios where a role has
|
||||
to communicate to an internal component on a port that different from
|
||||
the one that is exposed externally. If not specified, the value of
|
||||
localPort is the same as the port attribute. Set the value of localPort
|
||||
to "*" to automatically assign an unallocated port that is discoverable
|
||||
using the runtime API.
|
||||
Possible values range between 1 and 65535, inclusive.
|
||||
This parameter is required if the protocol is TCP or UDP.
|
||||
"""
|
||||
|
||||
frontend_ip_configurations = model.Field(
|
||||
name="frontend_ip_configurations", key="frontendIPConfigurations",
|
||||
is_required=True, is_read_only=False)
|
||||
"""Indicates an array of references to FrontendIPAddress resources."""
|
||||
|
||||
frontend_port = model.Field(name="frontend_port", key="frontendPort",
|
||||
is_required=False, is_read_only=False)
|
||||
"""Indicates the port for the external endpoint.
|
||||
|
||||
Possible values range between 1 and 65535, inclusive. This value MUST
|
||||
be unique for the loadbalancer resource.
|
||||
This parameter is required if the protocol is TCP or UDP.
|
||||
"""
|
||||
|
||||
idle_timeout = model.Field(
|
||||
name="idle_timeout", key="idleTimeoutInMinutes",
|
||||
is_required=False, is_read_only=False)
|
||||
"""Indicates the timeout for the Tcp idle connection in the inbound
|
||||
direction, i.e. a connection initiated by an internet client to a VIP.
|
||||
The value can be set between 4 and 30 minutes. The default value is
|
||||
4 minutes.
|
||||
"""
|
||||
|
||||
protocol = model.Field(name="protocol", key="protocol",
|
||||
is_required=True, is_read_only=False)
|
||||
"""Indicates the inbound transport protocol for the external endpoint.
|
||||
Valid values include `UDP`, `TCP`, `GRE`, `ESP` or `ALL`.
|
||||
"""
|
||||
|
||||
probe = model.Field(name="probe", key="probe",
|
||||
is_required=False, is_read_only=False)
|
||||
"""Indicates a reference to the probe resource used by this
|
||||
LoadBalancingRule.
|
||||
"""
|
||||
|
||||
floating_ip = model.Field(name="floating_ip", key="enableFloatingIP",
|
||||
is_required=False, is_read_only=False)
|
||||
"""
|
||||
This specifies that a floating IP will be used on the available servers
|
||||
behind a load balancer. Floating IP (VIP) will be forwarded by the load
|
||||
balancer to the backend server. The back-end server will be configured
|
||||
with that VIP, a datacenter IP and weakhost forwarding.
|
||||
|
||||
Floating IP configuration is required if you are using the SQL AlwaysOn
|
||||
Availability Group feature. This setting can't be changed after you create
|
||||
the endpoint.
|
||||
"""
|
||||
|
||||
load_distribution = model.Field(
|
||||
name="load_distribution", key="loadDistribution",
|
||||
is_required=False, is_read_only=False)
|
||||
"""This specifies the load balancing distribution type to be used by
|
||||
the load balancer. The loadBalancer uses a distribution algorithm which
|
||||
is a 5 tuple (source IP, source port, destination IP, destination port,
|
||||
protocol type) hash to map traffic to available servers. It provides
|
||||
stickiness only within a transport session, which is a feature that routes
|
||||
the requests for a particular session to the same physical machine that
|
||||
serviced the first request for that session. Packets in the same TCP or
|
||||
UDP session will be directed to the same datacenter IP instance behind the
|
||||
load balanced endpoint. When the client closes and re-opens the connection
|
||||
or starts a new session from the same source IP, the source port changes
|
||||
and causes the traffic to go to a different datacenter IP endpoint.
|
||||
|
||||
The loadBalancer can be configured to use a 2 tuple (Source IP,
|
||||
Destination IP) or 3 tuple (Source IP, Destination IP, Protocol) to map
|
||||
traffic to the available servers. By using SourceIPProtocol, connections
|
||||
initiated from the same client computer goes to the same datacenter IP
|
||||
endpoint.
|
||||
* Default - The load balancer is configured to use a 5 tuple hash
|
||||
to map traffic to available servers
|
||||
* SourceIP - The load balancer is configured to use a 2 tuple hash
|
||||
to map traffic to available servers
|
||||
* SourceIPProtocol - The load balancer is configured to use a 3 tuple
|
||||
hash to map traffic to available servers
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def from_raw_data(cls, raw_data):
|
||||
"""Create a new model using raw API response."""
|
||||
properties = raw_data.get("properties", {})
|
||||
|
||||
frontend_ip_configurations = []
|
||||
for raw_content in properties.get("frontendIPConfigurations", []):
|
||||
resource = Resource.from_raw_data(raw_content)
|
||||
frontend_ip_configurations.append(resource)
|
||||
properties["frontendIPConfigurations"] = frontend_ip_configurations
|
||||
|
||||
raw_content = properties.get("backendAddressPool", None)
|
||||
if raw_content is not None:
|
||||
resource = Resource.from_raw_data(raw_content)
|
||||
properties["backendAddressPool"] = resource
|
||||
|
||||
raw_content = properties.get("probe", None)
|
||||
if raw_content is not None:
|
||||
resource = Resource.from_raw_data(raw_content)
|
||||
properties["probe"] = resource
|
||||
|
||||
return super(LoadBalancingRules, cls).from_raw_data(raw_data)
|
||||
|
||||
|
||||
class OutboundNATRules(_BaseHNVModel):
|
||||
|
||||
"""Model for outbound NAT rules.
|
||||
|
||||
This resource is used to configure the load balancer to apply
|
||||
Network Address Translation of outbound traffic.
|
||||
"""
|
||||
|
||||
_endpoint = ("/networking/v1/loadBalancers/{parent_id}"
|
||||
"/outboundNatRules/{resource_id}")
|
||||
|
||||
parent_id = model.Field(
|
||||
name="parent_id", key="parentResourceID",
|
||||
is_property=False, is_required=True, is_read_only=True)
|
||||
"""The parent resource ID field contains the resource ID that is
|
||||
associated with network objects that are ancestors of the necessary
|
||||
resource.
|
||||
"""
|
||||
|
||||
frontend_ip_configurations = model.Field(
|
||||
name="frontend_ip_configurations", key="frontendIPConfigurations",
|
||||
is_required=True, is_read_only=False)
|
||||
"""Indicates an array of frontendIpConfigurations resources.
|
||||
|
||||
Indicates an array of references to frontendIpAddress resources.
|
||||
"""
|
||||
|
||||
backend_address_pool = model.Field(
|
||||
name="backend_address_pool", key="backendAddressPool",
|
||||
is_required=True, is_read_only=False)
|
||||
"""Indicates a reference to the backendAddressPool resource.
|
||||
|
||||
This is the pool of IP addresses where outbound traffic originates.
|
||||
"""
|
||||
|
||||
protocol = model.Field(
|
||||
name="protocol", key="protocol",
|
||||
is_required=True, is_read_only=False)
|
||||
"""Protocol for outbound traffic. For transparent outbound NAT
|
||||
specify "all".
|
||||
Valid values include `TCP`, `UDP`, `GRE`, `ESP` or `All`.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def from_raw_data(cls, raw_data):
|
||||
"""Create a new model using raw API response."""
|
||||
properties = raw_data.get("properties", {})
|
||||
|
||||
frontend_ip_configurations = []
|
||||
for raw_content in properties.get("frontendIPConfigurations", []):
|
||||
resource = Resource.from_raw_data(raw_content)
|
||||
frontend_ip_configurations.append(resource)
|
||||
properties["frontendIPConfigurations"] = frontend_ip_configurations
|
||||
|
||||
raw_content = properties.get("backendAddressPool", None)
|
||||
if raw_content is not None:
|
||||
resource = Resource.from_raw_data(raw_content)
|
||||
properties["backendAddressPool"] = resource
|
||||
|
||||
return super(OutboundNATRules, cls).from_raw_data(raw_data)
|
||||
|
||||
|
||||
class Probes(_BaseHNVModel):
|
||||
|
||||
"""Model for probes."""
|
||||
|
||||
_endpoint = ("/networking/v1/loadBalancers/{parent_id}"
|
||||
"/probes/{resource_id}")
|
||||
|
||||
parent_id = model.Field(
|
||||
name="parent_id", key="parentResourceID",
|
||||
is_property=False, is_required=True, is_read_only=True)
|
||||
"""The parent resource ID field contains the resource ID that is
|
||||
associated with network objects that are ancestors of the necessary
|
||||
resource.
|
||||
"""
|
||||
|
||||
interval = model.Field(name="interval", key="intervalInSeconds",
|
||||
is_required=False, is_read_only=False)
|
||||
"""Indicates the interval, in seconds, for how frequently to probe the
|
||||
endpoint for health status. Typically, the interval is slightly less than
|
||||
half the allocated timeout period (in seconds) which allows two full
|
||||
probes before taking the instance out of rotation. The default value is
|
||||
15, the minimum value is 5.
|
||||
"""
|
||||
|
||||
load_balancing_rules = model.Field(
|
||||
name="load_balancing_rules", key="loadBalancingRules",
|
||||
is_required=False, is_read_only=True)
|
||||
"""Indicates an array of references to loadBalancingRule resources that
|
||||
use this probe.
|
||||
"""
|
||||
|
||||
number_of_probes = model.Field(
|
||||
name="number_of_probes", key="numberOfProbes",
|
||||
is_required=False, is_read_only=False)
|
||||
"""Indicates the timeout period, in seconds, applied to the probe where
|
||||
no response will result in stopping further traffic from being delivered
|
||||
to the endpoint. This value allows endpoints to be taken out of rotation
|
||||
faster or slower than the typical times (which are the defaults).
|
||||
The default value is 31, the minimum value is 11.
|
||||
"""
|
||||
|
||||
protocol = model.Field(name="protocol", key="protocol",
|
||||
is_required=True, is_read_only=False)
|
||||
"""Indicates the protocol of the end point.
|
||||
|
||||
Valid values are `HTTP` or `TCP`. If `TCP` is specified, a received ACK
|
||||
is required for the probe to be successful. If `HTTP` is specified,
|
||||
a 200 OK response from the specified URI is required for the probe to
|
||||
be successful.
|
||||
"""
|
||||
|
||||
port = model.Field(name="port", key="port",
|
||||
is_required=True, is_read_only=False)
|
||||
"""Indicates the port for communicating the probe. Possible values range
|
||||
from 1 to 65535, inclusive.
|
||||
"""
|
||||
|
||||
request_path = model.Field(name="request_path", key="requestPath",
|
||||
is_required=True, is_read_only=False)
|
||||
"""Indicates the URI used for requesting health status from the VM.
|
||||
|
||||
The path is required if protocol is set to HTTP. Otherwise, it is not
|
||||
allowed. There is no default value.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def from_raw_data(cls, raw_data):
|
||||
"""Create a new model using raw API response."""
|
||||
properties = raw_data.get("properties", {})
|
||||
|
||||
load_balancing_rules = []
|
||||
for raw_content in properties.get("loadBalancingRules", []):
|
||||
resource = Resource.from_raw_data(raw_content)
|
||||
load_balancing_rules.append(resource)
|
||||
properties["loadBalancingRules"] = load_balancing_rules
|
||||
|
||||
return super(Probes, cls).from_raw_data(raw_data)
|
||||
|
||||
|
||||
class LoadBalancers(_BaseHNVModel):
|
||||
|
||||
"""Model for load balancers.
|
||||
|
||||
The loadBalancers resource allows fine-grained configuration of the
|
||||
distribution of incoming traffic across VM instances that are hosted
|
||||
in a Windows Server and System Center cloud. This resource has two
|
||||
main parts: a frontend and a backend configuration.
|
||||
|
||||
The frontend configuration exposes the IP address of the load balancer.
|
||||
For example, this address can be a reserved public or private IP address
|
||||
previously provided to the client, or it can be an IP address that is
|
||||
dynamically allocated from a subnet of a virtual network.
|
||||
"""
|
||||
|
||||
_endpoint = "/networking/v1/loadBalancers/{resource_id}"
|
||||
|
||||
backend_address_pools = model.Field(name="backend_address_pools",
|
||||
key="backendAddressPools",
|
||||
is_required=False, is_read_only=False)
|
||||
"""Indicates the backend Address Pool of the load balancer."""
|
||||
|
||||
frontend_ip_configurations = model.Field(
|
||||
name="frontend_ip_configurations", key="frontendIPConfigurations",
|
||||
is_required=True, is_read_only=False)
|
||||
"""Indicates the frontend IP addresses of the load balancer."""
|
||||
|
||||
load_balancing_rules = model.Field(name="load_balancing_rules",
|
||||
key="loadBalancingRules",
|
||||
is_required=False, is_read_only=False)
|
||||
"""A list of load balancing configurations.
|
||||
|
||||
Each configuration describes what traffic and how it gets load balanced
|
||||
between backend IPs.
|
||||
"""
|
||||
|
||||
inbound_nat_rules = model.Field(name="inbound_nat_rules",
|
||||
key="inboundNatRules",
|
||||
is_required=False, is_read_only=False)
|
||||
"""Indicates an array of inbound NAT rules configured for the
|
||||
load balancer.
|
||||
"""
|
||||
|
||||
outbound_nat_rules = model.Field(name="outbound_nat_rules",
|
||||
key="outboundNatRules",
|
||||
is_required=False, is_read_only=False)
|
||||
"""Indicates an array of outbound NAT rules configured for the
|
||||
load balancer.
|
||||
"""
|
||||
|
||||
probes = model.Field(name="probes", key="probes",
|
||||
is_required=False, is_read_only=False)
|
||||
"""Indicates an array of probes configured for the
|
||||
load balancer.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def from_raw_data(cls, raw_data):
|
||||
properties = raw_data.get("properties", {})
|
||||
|
||||
backend_address_pools = []
|
||||
for raw_content in properties.get("backendAddressPools", []):
|
||||
raw_content["parentResourceID"] = raw_data["resourceId"]
|
||||
address_pool = BackendAddressPools.from_raw_data(raw_content)
|
||||
backend_address_pools.append(address_pool)
|
||||
properties["backendAddressPools"] = backend_address_pools
|
||||
|
||||
frontend_ip_configurations = []
|
||||
for raw_content in properties.get("frontendIPConfigurations", []):
|
||||
raw_content["parentResourceID"] = raw_data["resourceId"]
|
||||
ip_configurations = FrontendIPConfigurations.from_raw_data(
|
||||
raw_content)
|
||||
frontend_ip_configurations.append(ip_configurations)
|
||||
properties["frontendIPConfigurations"] = frontend_ip_configurations
|
||||
|
||||
inbound_nat_rules = []
|
||||
for raw_content in properties.get("inboundNatRules", []):
|
||||
raw_content["parentResourceID"] = raw_data["resourceId"]
|
||||
inbound_nat_rule = InboundNATRules.from_raw_data(raw_content)
|
||||
inbound_nat_rules.append(inbound_nat_rule)
|
||||
properties["inboundNatRules"] = inbound_nat_rules
|
||||
|
||||
outbound_nat_rules = []
|
||||
for raw_content in properties.get("outboundNatRules", []):
|
||||
raw_content["parentResourceID"] = raw_data["resourceId"]
|
||||
inbound_nat_rule = OutboundNATRules.from_raw_data(raw_content)
|
||||
outbound_nat_rules.append(inbound_nat_rule)
|
||||
properties["outboundNatRules"] = outbound_nat_rules
|
||||
|
||||
load_balancing_rules = []
|
||||
for raw_content in properties.get("loadBalancingRules", []):
|
||||
raw_content["parentResourceID"] = raw_data["resourceId"]
|
||||
balancing_rule = LoadBalancingRules.from_raw_data(raw_content)
|
||||
load_balancing_rules.append(balancing_rule)
|
||||
properties["loadBalancingRules"] = load_balancing_rules
|
||||
|
||||
probes = []
|
||||
for raw_content in properties.get("probes", []):
|
||||
raw_content["parentResourceID"] = raw_data["resourceId"]
|
||||
probe = Probes.from_raw_data(raw_content)
|
||||
probes.append(probe)
|
||||
properties["probes"] = probes
|
||||
|
||||
return super(LoadBalancers, cls).from_raw_data(raw_data)
|
||||
|
@ -317,7 +317,7 @@ class Model(object):
|
||||
self._changes[field.key] = fields[field_name]
|
||||
self._data.update(self._changes)
|
||||
|
||||
def commit(self, wait=False, timeout=None):
|
||||
def commit(self, if_match=None, wait=False, timeout=None):
|
||||
"""Apply all the changes on the current model."""
|
||||
# pylint: disable=unused-argument
|
||||
self._data.update(self._changes)
|
||||
|
@ -104,13 +104,19 @@ class _HNVClient(object):
|
||||
else:
|
||||
return not self._https_allow_insecure
|
||||
|
||||
def _http_request(self, resource, method=constant.GET, body=None):
|
||||
url = requests.compat.urljoin(self._base_url, resource)
|
||||
def _http_request(self, resource, method=constant.GET, body=None,
|
||||
if_match=None):
|
||||
if not resource.startswith("http"):
|
||||
url = requests.compat.urljoin(self._base_url, resource)
|
||||
else:
|
||||
url = resource
|
||||
|
||||
headers = self._get_headers()
|
||||
if method in (constant.PUT, constant.PATCH):
|
||||
etag = (body or {}).get("etag", None)
|
||||
if etag is not None:
|
||||
headers["If-Match"] = etag
|
||||
if not isinstance(if_match, six.string_types):
|
||||
if_match = (body or {}).get("etag", None)
|
||||
if if_match is not None:
|
||||
headers["If-Match"] = if_match
|
||||
|
||||
attemts = 0
|
||||
while True:
|
||||
@ -162,9 +168,10 @@ class _HNVClient(object):
|
||||
except ValueError:
|
||||
raise exception.ServiceException("Invalid service response.")
|
||||
|
||||
def update_resource(self, path, data):
|
||||
def update_resource(self, path, data, if_match=None):
|
||||
"""Update the required resource."""
|
||||
response = self._http_request(path, method="PUT", body=data)
|
||||
response = self._http_request(resource=path, method="PUT", body=data,
|
||||
if_match=if_match)
|
||||
try:
|
||||
return response.json()
|
||||
except ValueError:
|
||||
|
@ -105,31 +105,31 @@ class TestHNVClient(unittest.TestCase):
|
||||
if isinstance(expected_response, requests.exceptions.SSLError):
|
||||
self.assertRaises(exception.CertificateVerifyFailed,
|
||||
client._http_request,
|
||||
mock.sentinel.resource, method, body)
|
||||
"/fake/resource", method, body)
|
||||
return
|
||||
elif isinstance(expected_response, requests.ConnectionError):
|
||||
self.assertRaises(requests.ConnectionError,
|
||||
client._http_request,
|
||||
mock.sentinel.resource, method, body)
|
||||
"/fake/resource", method, body)
|
||||
return
|
||||
elif status_code == 400:
|
||||
self.assertRaises(exception.ServiceException,
|
||||
client._http_request,
|
||||
mock.sentinel.resource, method, body)
|
||||
"/fake/resource", method, body)
|
||||
elif status_code == 404:
|
||||
self.assertRaises(exception.NotFound,
|
||||
client._http_request,
|
||||
mock.sentinel.resource, method, body)
|
||||
"/fake/resource", method, body)
|
||||
elif status_code != 200:
|
||||
self.assertRaises(requests.HTTPError,
|
||||
client._http_request,
|
||||
mock.sentinel.resource, method, body)
|
||||
"/fake/resource", method, body)
|
||||
else:
|
||||
client_response = client._http_request(mock.sentinel.resource,
|
||||
client_response = client._http_request("/fake/resource",
|
||||
method, body)
|
||||
|
||||
mock_join.assert_called_once_with(mock.sentinel.url,
|
||||
mock.sentinel.resource)
|
||||
"/fake/resource")
|
||||
mock_headers.assert_called_once_with()
|
||||
if not method == constant.GET:
|
||||
etag = (body or {}).get("etag", None)
|
||||
@ -236,9 +236,9 @@ class TestHNVClient(unittest.TestCase):
|
||||
mock.sentinel.data)
|
||||
|
||||
self.assertIs(response, mock.sentinel.response)
|
||||
mock_http_request.assert_called_once_with(mock.sentinel.path,
|
||||
method="PUT",
|
||||
body=mock.sentinel.data)
|
||||
mock_http_request.assert_called_once_with(
|
||||
resource=mock.sentinel.path, method="PUT", body=mock.sentinel.data,
|
||||
if_match=None)
|
||||
self.assertRaises(exception.ServiceException,
|
||||
client.update_resource,
|
||||
mock.sentinel.path, mock.sentinel.data)
|
||||
|
@ -89,3 +89,31 @@ class FakeResponse(object):
|
||||
def public_ip_addresses(self):
|
||||
"""Fake GET(all) response for public IP addresses."""
|
||||
return self._load_resource("public_ip_addresses.json")
|
||||
|
||||
def backend_address_pools(self):
|
||||
"""Fake GET(all) response for backend address pools."""
|
||||
return self._load_resource("backend_address_pools.json")
|
||||
|
||||
def frontend_ip_configurations(self):
|
||||
"""Fake GET(all) response for frontend ip configurations."""
|
||||
return self._load_resource("frontend_ip_configurations.json")
|
||||
|
||||
def inbound_nat_rules(self):
|
||||
"""Fake GET(all) response for inbound nat rules."""
|
||||
return self._load_resource("inbound_nat_rules.json")
|
||||
|
||||
def load_balancing_rules(self):
|
||||
"""Fake GET(all) response for load balacing rules."""
|
||||
return self._load_resource("load_balancing_rules.json")
|
||||
|
||||
def outbound_nat_rules(self):
|
||||
"""Fake GET(all) response for outbound nat rules."""
|
||||
return self._load_resource("outbound_nat_rules.json")
|
||||
|
||||
def probes(self):
|
||||
"""Fake GET(all) response for probes."""
|
||||
return self._load_resource("probes.json")
|
||||
|
||||
def load_balancers(self):
|
||||
"""Fake GET(all) response for load balancers."""
|
||||
return self._load_resource("load_balancers.json")
|
||||
|
51
hnv/tests/fake/response/backend_address_pools.json
Normal file
51
hnv/tests/fake/response/backend_address_pools.json
Normal file
@ -0,0 +1,51 @@
|
||||
{
|
||||
"value": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971- 2682d597e098/backendAddressPools/b32b5ef0-5332-49a8-b383-f91090135f71",
|
||||
"resourceId": "b32b5ef0-5332-49a8-b383-f91090135f71",
|
||||
"etag": "W/\"fb318cf6-9102-4e34-a684-5e25aee8d3f4\"",
|
||||
"instanceId": "f980604c-258c-4d60-8be4-559edd085384",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"backendIPConfigurations": [
|
||||
{
|
||||
"resourceRef": "/networkInterfaces/97c69782-f173-4793-a408-64074e601dd1/ipConfigurations/1b94ce74-b012-49a7-8e93-9315252c6ab2"
|
||||
},
|
||||
{
|
||||
"resourceRef": "/networkInterfaces/e5ea0c14-ce85-4eb7-909a-993f0477f5ac/ipConfigurations/45af7ff3-555f-43b0-ae74-7fcce88c5197"
|
||||
}
|
||||
],
|
||||
"outboundNatRules": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/outboundNatRules/49053c15-2d0f-45a2-8148-be8615282160"
|
||||
}
|
||||
],
|
||||
"loadBalancingRules": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/backendAddressPools/b32b5ef0-5332-49a8-b383-f91090135f71",
|
||||
"resourceId": "b32b5ef0-5332-49a8-b383-f91090135f71",
|
||||
"etag": "W/\"fb318cf6-9102-4e34-a684-5e25aee8d3f4\"",
|
||||
"instanceId": "f980604c-258c-4d60-8be4-559edd085384",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"backendIPConfigurations": [
|
||||
{
|
||||
"resourceRef": "/networkInterfaces/97c69782-f173-4793-a408-64074e601dd1/ipConfigurations/1b94ce74-b012-49a7-8e93-9315252c6ab2"
|
||||
},
|
||||
{
|
||||
"resourceRef": "/networkInterfaces/e5ea0c14-ce85-4eb7-909a-993f0477f5ac/ipConfigurations/45af7ff3-555f-43b0-ae74-7fcce88c5197"
|
||||
}
|
||||
],
|
||||
"outboundNatRules": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/outboundNatRules/49053c15-2d0f-45a2-8148-be8615282160"
|
||||
}
|
||||
],
|
||||
"loadBalancingRules": []
|
||||
}
|
||||
}
|
||||
],
|
||||
"nextLink": ""
|
||||
}
|
80
hnv/tests/fake/response/frontend_ip_configurations.json
Normal file
80
hnv/tests/fake/response/frontend_ip_configurations.json
Normal file
@ -0,0 +1,80 @@
|
||||
{
|
||||
"value": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/frontendIPConfigurations/5187779d-c61c-44d2-87be-fa69ac2d9d57",
|
||||
"resourceId": "5187779d-c61c-44d2-87be-fa69ac2d9d57",
|
||||
"etag": "W/\"fb318cf6-9102-4e34-a684-5e25aee8d3f4\"",
|
||||
"instanceId": "3902a530-9639-4759-9bbf-9bab6675593a",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"privateIPAddress": "22.0.0.22",
|
||||
"privateIPAllocationMethod": "Static",
|
||||
"subnet": {
|
||||
"resourceRef": "/logicalnetworks/ccb732ec-a3b5-4755-99ff-fddb91d50884/subnets/262b479f-0952-49b9-ad20-3d6732729389"
|
||||
},
|
||||
"loadBalancingRules": [],
|
||||
"inboundNatRules": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/inboundNatRules/fc44af15-be82-46c5-b75a-3e89ccd792a9"
|
||||
}
|
||||
],
|
||||
"outboundNatRules": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/outboundNatRules/49053c15-2d0f-45a2-8148-be8615282160"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/frontendIPConfigurations/94c568d8-d839-431a-aed4-a5c178356018",
|
||||
"resourceId": "94c568d8-d839-431a-aed4-a5c178356018",
|
||||
"etag": "W/\"fb318cf6-9102-4e34-a684-5e25aee8d3f4\"",
|
||||
"instanceId": "d896da12-37f2-4e36-b229-7278a672a0ac",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"privateIPAddress": "22.0.0.23",
|
||||
"privateIPAllocationMethod": "Static",
|
||||
"subnet": {
|
||||
"resourceRef": "/logicalnetworks/ccb732ec-a3b5-4755-99ff-fddb91d50884/subnets/262b479f-0952-49b9-ad20-3d6732729389"
|
||||
},
|
||||
"loadBalancingRules": [],
|
||||
"inboundNatRules": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/inboundNatRules/0e5ed8cf-60fb-40f4-b02a-90932d4de000"
|
||||
}
|
||||
],
|
||||
"outboundNatRules": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/outboundNatRules/49053c15-2d0f-45a2-8148-be8615282160"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/frontendIPConfigurations/94c568d8-d839-431a-aed4-a5c178356018",
|
||||
"resourceId": "94c568d8-d839-431a-aed4-a5c178356018",
|
||||
"etag": "W/\"fb318cf6-9102-4e34-a684-5e25aee8d3f4\"",
|
||||
"instanceId": "d896da12-37f2-4e36-b229-7278a672a0ac",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"privateIPAddress": "22.0.0.23",
|
||||
"privateIPAllocationMethod": "Static",
|
||||
"subnet": {
|
||||
"resourceRef": "/logicalnetworks/ccb732ec-a3b5-4755-99ff-fddb91d50884/subnets/262b479f-0952-49b9-ad20-3d6732729389"
|
||||
},
|
||||
"loadBalancingRules": [],
|
||||
"inboundNatRules": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/inboundNatRules/0e5ed8cf-60fb-40f4-b02a-90932d4de000"
|
||||
}
|
||||
],
|
||||
"outboundNatRules": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/outboundNatRules/49053c15-2d0f-45a2-8148-be8615282160"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"nextLink": ""
|
||||
}
|
85
hnv/tests/fake/response/inbound_nat_rules.json
Normal file
85
hnv/tests/fake/response/inbound_nat_rules.json
Normal file
@ -0,0 +1,85 @@
|
||||
{
|
||||
"value": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/inboundNatRules/fc44af15-be82-46c5-b75a-3e89ccd792a9",
|
||||
"resourceId": "fc44af15-be82-46c5-b75a-3e89ccd792a9",
|
||||
"etag": "W/\"fb318cf6-9102-4e34-a684-5e25aee8d3f4\"",
|
||||
"instanceId": "a748c5db-e2fd-4335-8c89-280b78d2511c",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"frontendIPConfigurations": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/frontendIPConfigurations/5187779d-c61c-44d2-87be-fa69ac2d9d57"
|
||||
}
|
||||
],
|
||||
"protocol": "Tcp",
|
||||
"frontendPort": 2003,
|
||||
"backendPort": 2003,
|
||||
"backendIPConfiguration": {
|
||||
"resourceRef": "/networkInterfaces/e5ea0c14-ce85-4eb7-909a-993f0477f5ac/ipConfigurations/45af7ff3-555f-43b0-ae74-7fcce88c5197"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/inboundNatRules/0e5ed8cf-60fb-40f4-b02a-90932d4de000",
|
||||
"resourceId": "0e5ed8cf-60fb-40f4-b02a-90932d4de000",
|
||||
"etag": "W/\"fb318cf6-9102-4e34-a684-5e25aee8d3f4\"",
|
||||
"instanceId": "e8c59538-e641-4796-968d-50c4e11225e7",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"frontendIPConfigurations": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/frontendIPConfigurations/94c568d8-d839-431a-aed4-a5c178356018"
|
||||
}
|
||||
],
|
||||
"protocol": "Tcp",
|
||||
"frontendPort": 2003,
|
||||
"backendPort": 2003,
|
||||
"backendIPConfiguration": {
|
||||
"resourceRef": "/networkInterfaces/97c69782-f173-4793-a408-64074e601dd1/ipConfigurations/1b94ce74-b012-49a7-8e93-9315252c6ab2"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/inboundNatRules/fc44af15-be82-46c5-b75a-3e89ccd792a9",
|
||||
"resourceId": "fc44af15-be82-46c5-b75a-3e89ccd792a9",
|
||||
"etag": "W/\"fb318cf6-9102-4e34-a684-5e25aee8d3f4\"",
|
||||
"instanceId": "a748c5db-e2fd-4335-8c89-280b78d2511c",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"frontendIPConfigurations": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/frontendIPConfigurations/5187779d-c61c-44d2-87be-fa69ac2d9d57"
|
||||
}
|
||||
],
|
||||
"protocol": "Tcp",
|
||||
"frontendPort": 2003,
|
||||
"backendPort": 2003,
|
||||
"backendIPConfiguration": {
|
||||
"resourceRef": "/networkInterfaces/e5ea0c14-ce85-4eb7-909a-993f0477f5ac/ipConfigurations/45af7ff3-555f-43b0-ae74-7fcce88c5197"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/inboundNatRules/fc44af15-be82-46c5-b75a-3e89ccd792a9",
|
||||
"resourceId": "fc44af15-be82-46c5-b75a-3e89ccd792a9",
|
||||
"etag": "W/\"fb318cf6-9102-4e34-a684-5e25aee8d3f4\"",
|
||||
"instanceId": "a748c5db-e2fd-4335-8c89-280b78d2511c",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"frontendIPConfigurations": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/frontendIPConfigurations/5187779d-c61c-44d2-87be-fa69ac2d9d57"
|
||||
}
|
||||
],
|
||||
"protocol": "Tcp",
|
||||
"frontendPort": 2003,
|
||||
"backendPort": 2003,
|
||||
"backendIPConfiguration": {
|
||||
"resourceRef": "/networkInterfaces/e5ea0c14-ce85-4eb7-909a-993f0477f5ac/ipConfigurations/45af7ff3-555f-43b0-ae74-7fcce88c5197"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"nextLink": ""
|
||||
}
|
347
hnv/tests/fake/response/load_balancers.json
Normal file
347
hnv/tests/fake/response/load_balancers.json
Normal file
@ -0,0 +1,347 @@
|
||||
{
|
||||
"value": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098",
|
||||
"resourceId": "0cac5f8a-9d5c-455a-a971-2682d597e098",
|
||||
"etag": "W/\"fb318cf6-9102-4e34-a684-5e25aee8d3f4\"",
|
||||
"instanceId": "d91f4951-faf7-4a15-a84a-8a9f6dffaff8",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"frontendIPConfigurations": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/frontendIPConfigurations/5187779d-c61c-44d2-87be-fa69ac2d9d57",
|
||||
"resourceId": "5187779d-c61c-44d2-87be-fa69ac2d9d57",
|
||||
"etag": "W/\"fb318cf6-9102-4e34-a684-5e25aee8d3f4\"",
|
||||
"instanceId": "3902a530-9639-4759-9bbf-9bab6675593a",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"privateIPAddress": "22.0.0.22",
|
||||
"privateIPAllocationMethod": "Static",
|
||||
"subnet": {
|
||||
"resourceRef": "/logicalnetworks/ccb732ec-a3b5-4755-99ff-fddb91d50884/subnets/262b479f-0952-49b9-ad20-3d6732729389"
|
||||
},
|
||||
"loadBalancingRules": [],
|
||||
"inboundNatRules": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/inboundNatRules/fc44af15-be82-46c5-b75a-3e89ccd792a9"
|
||||
}
|
||||
],
|
||||
"outboundNatRules": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/outboundNatRules/49053c15-2d0f-45a2-8148-be8615282160"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/frontendIPConfigurations/94c568d8-d839-431a-aed4-a5c178356018",
|
||||
"resourceId": "94c568d8-d839-431a-aed4-a5c178356018",
|
||||
"etag": "W/\"fb318cf6-9102-4e34-a684-5e25aee8d3f4\"",
|
||||
"instanceId": "d896da12-37f2-4e36-b229-7278a672a0ac",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"privateIPAddress": "22.0.0.23",
|
||||
"privateIPAllocationMethod": "Static",
|
||||
"subnet": {
|
||||
"resourceRef": "/logicalnetworks/ccb732ec-a3b5-4755-99ff-fddb91d50884/subnets/262b479f-0952-49b9-ad20-3d6732729389"
|
||||
},
|
||||
"loadBalancingRules": [],
|
||||
"inboundNatRules": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/inboundNatRules/0e5ed8cf-60fb-40f4-b02a-90932d4de000"
|
||||
}
|
||||
],
|
||||
"outboundNatRules": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/outboundNatRules/49053c15-2d0f-45a2-8148-be8615282160"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"backendAddressPools": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/backendAddressPools/b32b5ef0-5332-49a8-b383-f91090135f71",
|
||||
"resourceId": "b32b5ef0-5332-49a8-b383-f91090135f71",
|
||||
"etag": "W/\"fb318cf6-9102-4e34-a684-5e25aee8d3f4\"",
|
||||
"instanceId": "f980604c-258c-4d60-8be4-559edd085384",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"backendIPConfigurations": [
|
||||
{
|
||||
"resourceRef": "/networkInterfaces/97c69782-f173-4793-a408-64074e601dd1/ipConfigurations/1b94ce74-b012-49a7-8e93-9315252c6ab2"
|
||||
},
|
||||
{
|
||||
"resourceRef": "/networkInterfaces/e5ea0c14-ce85-4eb7-909a-993f0477f5ac/ipConfigurations/45af7ff3-555f-43b0-ae74-7fcce88c5197"
|
||||
}
|
||||
],
|
||||
"outboundNatRules": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/outboundNatRules/49053c15-2d0f-45a2-8148-be8615282160"
|
||||
}
|
||||
],
|
||||
"loadBalancingRules": []
|
||||
}
|
||||
}
|
||||
],
|
||||
"probes": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/probes/9f940e29-1d25-44fc-88d3-c81151a0344e",
|
||||
"resourceId": "9f940e29-1d25-44fc-88d3-c81151a0344e",
|
||||
"etag": "W/\"fb318cf6-9102-4e34-a684-5e25aee8d3f4\"",
|
||||
"instanceId": "0da65588-247b-475b-bd1a-7ead0ba1a182",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"protocol": "Tcp",
|
||||
"port": 55555,
|
||||
"intervalInSeconds": 30,
|
||||
"numberOfProbes": 1,
|
||||
"loadBalancingRules": []
|
||||
}
|
||||
}
|
||||
],
|
||||
"inboundNatRules": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/inboundNatRules/fc44af15-be82-46c5-b75a-3e89ccd792a9",
|
||||
"resourceId": "fc44af15-be82-46c5-b75a-3e89ccd792a9",
|
||||
"etag": "W/\"fb318cf6-9102-4e34-a684-5e25aee8d3f4\"",
|
||||
"instanceId": "a748c5db-e2fd-4335-8c89-280b78d2511c",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"frontendIPConfigurations": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/frontendIPConfigurations/5187779d-c61c-44d2-87be-fa69ac2d9d57"
|
||||
}
|
||||
],
|
||||
"protocol": "Tcp",
|
||||
"frontendPort": 2003,
|
||||
"backendPort": 2003,
|
||||
"enableFloatingIP": false,
|
||||
"idleTimeoutInMinutes": 4,
|
||||
"backendIPConfiguration": {
|
||||
"resourceRef": "/networkInterfaces/e5ea0c14-ce85-4eb7-909a-993f0477f5ac/ipConfigurations/45af7ff3-555f-43b0-ae74-7fcce88c5197"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/inboundNatRules/0e5ed8cf-60fb-40f4-b02a-90932d4de000",
|
||||
"resourceId": "0e5ed8cf-60fb-40f4-b02a-90932d4de000",
|
||||
"etag": "W/\"fb318cf6-9102-4e34-a684-5e25aee8d3f4\"",
|
||||
"instanceId": "e8c59538-e641-4796-968d-50c4e11225e7",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"frontendIPConfigurations": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/frontendIPConfigurations/94c568d8-d839-431a-aed4-a5c178356018"
|
||||
}
|
||||
],
|
||||
"protocol": "Tcp",
|
||||
"frontendPort": 2003,
|
||||
"backendPort": 2003,
|
||||
"enableFloatingIP": false,
|
||||
"idleTimeoutInMinutes": 4,
|
||||
"backendIPConfiguration": {
|
||||
"resourceRef": "/networkInterfaces/97c69782-f173-4793-a408-64074e601dd1/ipConfigurations/1b94ce74-b012-49a7-8e93-9315252c6ab2"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"outboundNatRules": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/outboundNatRules/49053c15-2d0f-45a2-8148-be8615282160",
|
||||
"resourceId": "49053c15-2d0f-45a2-8148-be8615282160",
|
||||
"etag": "W/\"fb318cf6-9102-4e34-a684-5e25aee8d3f4\"",
|
||||
"instanceId": "c4000c95-7f90-4bb4-b68d-b2bc9c1dfc3e",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"frontendIPConfigurations": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/frontendIPConfigurations/5187779d-c61c-44d2-87be-fa69ac2d9d57"
|
||||
},
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/frontendIPConfigurations/94c568d8-d839-431a-aed4-a5c178356018"
|
||||
}
|
||||
],
|
||||
"protocol": "All",
|
||||
"backendAddressPool": {
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/backendAddressPools/b32b5ef0-5332-49a8-b383-f91090135f71"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"resourceRef": "/loadBalancers/d2251a0d-32d2-457e-b3aa-e0fe1f42cce1",
|
||||
"resourceId": "d2251a0d-32d2-457e-b3aa-e0fe1f42cce1",
|
||||
"etag": "W/\"72fdfa3d-34f4-4c90-ae94-d97ed73c9cf7\"",
|
||||
"instanceId": "b32d0db3-13db-431a-a265-32185aa5a905",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"frontendIPConfigurations": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/d2251a0d-32d2-457e-b3aa-e0fe1f42cce1/frontendIPConfigurations/9f37a479-7d60-489a-aab6-d7eb2200306f",
|
||||
"resourceId": "9f37a479-7d60-489a-aab6-d7eb2200306f",
|
||||
"etag": "W/\"72fdfa3d-34f4-4c90-ae94-d97ed73c9cf7\"",
|
||||
"instanceId": "51b57d2a-80da-464a-988a-4a805bd1d875",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"privateIPAddress": "21.0.0.23",
|
||||
"privateIPAllocationMethod": "Static",
|
||||
"subnet": {
|
||||
"resourceRef": "/logicalnetworks/9c1b2b61-dec2-49e3-b573-c2ecff57893d/subnets/a4f7c90b-6056-4dff-97fb-f46211ecdc10"
|
||||
},
|
||||
"loadBalancingRules": [],
|
||||
"inboundNatRules": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/d2251a0d-32d2-457e-b3aa-e0fe1f42cce1/inboundNatRules/d076eae7-926a-457a-a60c-0a713a02977d"
|
||||
}
|
||||
],
|
||||
"outboundNatRules": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/d2251a0d-32d2-457e-b3aa-e0fe1f42cce1/outboundNatRules/f3f3291d-b26c-44d3-8d55-99b644b70388"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"resourceRef": "/loadBalancers/d2251a0d-32d2-457e-b3aa-e0fe1f42cce1/frontendIPConfigurations/ab5ccbe7-2ce9-4cdf-a0da-e4e5d81479d8",
|
||||
"resourceId": "ab5ccbe7-2ce9-4cdf-a0da-e4e5d81479d8",
|
||||
"etag": "W/\"72fdfa3d-34f4-4c90-ae94-d97ed73c9cf7\"",
|
||||
"instanceId": "fe6adbed-8b73-4fc2-82cd-191143753c4a",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"privateIPAddress": "21.0.0.24",
|
||||
"privateIPAllocationMethod": "Static",
|
||||
"subnet": {
|
||||
"resourceRef": "/logicalnetworks/9c1b2b61-dec2-49e3-b573-c2ecff57893d/subnets/a4f7c90b-6056-4dff-97fb-f46211ecdc10"
|
||||
},
|
||||
"loadBalancingRules": [],
|
||||
"inboundNatRules": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/d2251a0d-32d2-457e-b3aa-e0fe1f42cce1/inboundNatRules/425eea91-5a9e-4777-b2c3-0442dfc20344"
|
||||
}
|
||||
],
|
||||
"outboundNatRules": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/d2251a0d-32d2-457e-b3aa-e0fe1f42cce1/outboundNatRules/f3f3291d-b26c-44d3-8d55-99b644b70388"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"backendAddressPools": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/d2251a0d-32d2-457e-b3aa-e0fe1f42cce1/backendAddressPools/db1fa644-bd00-4c05-b11b-f5f07bfed86b",
|
||||
"resourceId": "db1fa644-bd00-4c05-b11b-f5f07bfed86b",
|
||||
"etag": "W/\"72fdfa3d-34f4-4c90-ae94-d97ed73c9cf7\"",
|
||||
"instanceId": "b638b320-5569-444f-9adf-78a683072269",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"backendIPConfigurations": [
|
||||
{
|
||||
"resourceRef": "/networkInterfaces/add9dac6-ddcc-4108-8543-e167c0a8d9dc/ipConfigurations/2e8a0316-66a6-4a3e-bd86-89b0e43b080f"
|
||||
},
|
||||
{
|
||||
"resourceRef": "/networkInterfaces/b3dc7295-7144-4f6e-8235-35d88b917482/ipConfigurations/581ab448-8e6f-436c-9dec-43366a9817dd"
|
||||
}
|
||||
],
|
||||
"outboundNatRules": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/d2251a0d-32d2-457e-b3aa-e0fe1f42cce1/outboundNatRules/f3f3291d-b26c-44d3-8d55-99b644b70388"
|
||||
}
|
||||
],
|
||||
"loadBalancingRules": []
|
||||
}
|
||||
}
|
||||
],
|
||||
"probes": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/d2251a0d-32d2-457e-b3aa-e0fe1f42cce1/probes/ddb4dab8-b1eb-4476-90ca-948697240317",
|
||||
"resourceId": "ddb4dab8-b1eb-4476-90ca-948697240317",
|
||||
"etag": "W/\"72fdfa3d-34f4-4c90-ae94-d97ed73c9cf7\"",
|
||||
"instanceId": "18336b2f-8b2e-4bf2-a196-99009ec8feb8",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"protocol": "Tcp",
|
||||
"port": 55555,
|
||||
"intervalInSeconds": 30,
|
||||
"numberOfProbes": 1,
|
||||
"loadBalancingRules": []
|
||||
}
|
||||
}
|
||||
],
|
||||
"inboundNatRules": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/d2251a0d-32d2-457e-b3aa-e0fe1f42cce1/inboundNatRules/d076eae7-926a-457a-a60c-0a713a02977d",
|
||||
"resourceId": "d076eae7-926a-457a-a60c-0a713a02977d",
|
||||
"etag": "W/\"72fdfa3d-34f4-4c90-ae94-d97ed73c9cf7\"",
|
||||
"instanceId": "4be2c156-cbcb-466d-a8fe-865bc9f0045d",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"frontendIPConfigurations": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/d2251a0d-32d2-457e-b3aa-e0fe1f42cce1/frontendIPConfigurations/9f37a479-7d60-489a-aab6-d7eb2200306f"
|
||||
}
|
||||
],
|
||||
"protocol": "Tcp",
|
||||
"frontendPort": 2003,
|
||||
"backendPort": 2003,
|
||||
"enableFloatingIP": false,
|
||||
"idleTimeoutInMinutes": 4,
|
||||
"backendIPConfiguration": {
|
||||
"resourceRef": "/networkInterfaces/b3dc7295-7144-4f6e-8235-35d88b917482/ipConfigurations/581ab448-8e6f-436c-9dec-43366a9817dd"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"resourceRef": "/loadBalancers/d2251a0d-32d2-457e-b3aa-e0fe1f42cce1/inboundNatRules/425eea91-5a9e-4777-b2c3-0442dfc20344",
|
||||
"resourceId": "425eea91-5a9e-4777-b2c3-0442dfc20344",
|
||||
"etag": "W/\"72fdfa3d-34f4-4c90-ae94-d97ed73c9cf7\"",
|
||||
"instanceId": "ae841775-a3b2-454e-bd69-b78a298ca7bf",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"frontendIPConfigurations": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/d2251a0d-32d2-457e-b3aa-e0fe1f42cce1/frontendIPConfigurations/ab5ccbe7-2ce9-4cdf-a0da-e4e5d81479d8"
|
||||
}
|
||||
],
|
||||
"protocol": "Tcp",
|
||||
"frontendPort": 2003,
|
||||
"backendPort": 2003,
|
||||
"enableFloatingIP": false,
|
||||
"idleTimeoutInMinutes": 4,
|
||||
"backendIPConfiguration": {
|
||||
"resourceRef": "/networkInterfaces/add9dac6-ddcc-4108-8543-e167c0a8d9dc/ipConfigurations/2e8a0316-66a6-4a3e-bd86-89b0e43b080f"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"outboundNatRules": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/d2251a0d-32d2-457e-b3aa-e0fe1f42cce1/outboundNatRules/f3f3291d-b26c-44d3-8d55-99b644b70388",
|
||||
"resourceId": "f3f3291d-b26c-44d3-8d55-99b644b70388",
|
||||
"etag": "W/\"72fdfa3d-34f4-4c90-ae94-d97ed73c9cf7\"",
|
||||
"instanceId": "f5065c75-ab45-4e5b-bb76-fb69667bf5d6",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"frontendIPConfigurations": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/d2251a0d-32d2-457e-b3aa-e0fe1f42cce1/frontendIPConfigurations/9f37a479-7d60-489a-aab6-d7eb2200306f"
|
||||
},
|
||||
{
|
||||
"resourceRef": "/loadBalancers/d2251a0d-32d2-457e-b3aa-e0fe1f42cce1/frontendIPConfigurations/ab5ccbe7-2ce9-4cdf-a0da-e4e5d81479d8"
|
||||
}
|
||||
],
|
||||
"protocol": "All",
|
||||
"backendAddressPool": {
|
||||
"resourceRef": "/loadBalancers/d2251a0d-32d2-457e-b3aa-e0fe1f42cce1/backendAddressPools/db1fa644-bd00-4c05-b11b-f5f07bfed86b"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"nextLink": ""
|
||||
}
|
74
hnv/tests/fake/response/load_balancing_rules.json
Normal file
74
hnv/tests/fake/response/load_balancing_rules.json
Normal file
@ -0,0 +1,74 @@
|
||||
{
|
||||
"value": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/d2251a0d-32d2-457e-b3aa- e0fe1f42cce1/loadBalancingRules/6339de0b-5730-4057-b2ee-37e90d3e4470",
|
||||
"resourceId": "6339de0b-5730-4057-b2ee-37e90d3e4470",
|
||||
"etag": "W/\"87c5f43a-3d37-4955-b6ba-bc3037fcfefd\"",
|
||||
"instanceId": "58b176c8-f4d1-4a5f-bfe4-623dcfe3ba2a",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"frontendIPConfigurations": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/d2251a0d-32d2-457e-b3aa- e0fe1f42cce1/frontendIPConfigurations/6bad6ea2-eca8-4143-8925-55aa497d3882"
|
||||
}
|
||||
],
|
||||
"protocol": "Tcp",
|
||||
"frontendPort": 2003,
|
||||
"backendPort": 2003,
|
||||
"enableFloatingIP": false,
|
||||
"idleTimeoutInMinutes": 4,
|
||||
"backendAddressPool": {
|
||||
"resourceRef": "/loadBalancers/d2251a0d-32d2-457e-b3aa- e0fe1f42cce1/backendAddressPools/9827f986-4606-4331-b63f-7cc39665e2c9"
|
||||
},
|
||||
"loadDistribution": "Default"
|
||||
}
|
||||
},
|
||||
{
|
||||
"resourceRef": "/loadBalancers/d2251a0d-32d2-457e-b3aa-e0fe1f42cce1/loadBalancingRules/6339de0b-5730-4057-b2ee-37e90d3e4470",
|
||||
"resourceId": "6339de0b-5730-4057-b2ee-37e90d3e4470",
|
||||
"etag": "W/\"87c5f43a-3d37-4955-b6ba-bc3037fcfefd\"",
|
||||
"instanceId": "58b176c8-f4d1-4a5f-bfe4-623dcfe3ba2a",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"frontendIPConfigurations": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/d2251a0d-32d2-457e-b3aa-e0fe1f42cce1/frontendIPConfigurations/6bad6ea2-eca8-4143-8925-55aa497d3882"
|
||||
}
|
||||
],
|
||||
"protocol": "Tcp",
|
||||
"frontendPort": 2003,
|
||||
"backendPort": 2003,
|
||||
"enableFloatingIP": false,
|
||||
"idleTimeoutInMinutes": 4,
|
||||
"backendAddressPool": {
|
||||
"resourceRef": "/loadBalancers/d2251a0d-32d2-457e-b3aa-e0fe1f42cce1/backendAddressPools/9827f986-4606-4331-b63f-7cc39665e2c9"
|
||||
},
|
||||
"loadDistribution": "Default"
|
||||
}
|
||||
},
|
||||
{
|
||||
"resourceRef": "/loadBalancers/d2251a0d-32d2-457e-b3aa-e0fe1f42cce1/loadBalancingRules/6339de0b-5730-4057-b2ee-37e90d3e4470",
|
||||
"resourceId": "6339de0b-5730-4057-b2ee-37e90d3e4470",
|
||||
"etag": "W/\"87c5f43a-3d37-4955-b6ba-bc3037fcfefd\"",
|
||||
"instanceId": "58b176c8-f4d1-4a5f-bfe4-623dcfe3ba2a",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"frontendIPConfigurations": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/d2251a0d-32d2-457e-b3aa-e0fe1f42cce1/frontendIPConfigurations/6bad6ea2-eca8-4143-8925-55aa497d3882"
|
||||
}
|
||||
],
|
||||
"protocol": "Tcp",
|
||||
"frontendPort": 2003,
|
||||
"backendPort": 2003,
|
||||
"enableFloatingIP": false,
|
||||
"idleTimeoutInMinutes": 4,
|
||||
"backendAddressPool": {
|
||||
"resourceRef": "/loadBalancers/d2251a0d-32d2-457e-b3aa-e0fe1f42cce1/backendAddressPools/9827f986-4606-4331-b63f-7cc39665e2c9"
|
||||
},
|
||||
"loadDistribution": "Default"
|
||||
}
|
||||
}
|
||||
],
|
||||
"nextLink": ""
|
||||
}
|
47
hnv/tests/fake/response/outbound_nat_rules.json
Normal file
47
hnv/tests/fake/response/outbound_nat_rules.json
Normal file
@ -0,0 +1,47 @@
|
||||
{
|
||||
"value": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/outboundNatRules/49053c15-2d0f-45a2-8148-be8615282160",
|
||||
"resourceId": "49053c15-2d0f-45a2-8148-be8615282160",
|
||||
"etag": "W/\"fb318cf6-9102-4e34-a684-5e25aee8d3f4\"",
|
||||
"instanceId": "c4000c95-7f90-4bb4-b68d-b2bc9c1dfc3e",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"frontendIPConfigurations": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/frontendIPConfigurations/5187779d-c61c-44d2-87be-fa69ac2d9d57"
|
||||
},
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/frontendIPConfigurations/94c568d8-d839-431a-aed4-a5c178356018"
|
||||
}
|
||||
],
|
||||
"protocol": "All",
|
||||
"backendAddressPool": {
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/backendAddressPools/b32b5ef0-5332-49a8-b383-f91090135f71"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/outboundNatRules/49053c15-2d0f-45a2-8148-be8615282160",
|
||||
"resourceId": "49053c15-2d0f-45a2-8148-be8615282160",
|
||||
"etag": "W/\"fb318cf6-9102-4e34-a684-5e25aee8d3f4\"",
|
||||
"instanceId": "c4000c95-7f90-4bb4-b68d-b2bc9c1dfc3e",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"frontendIPConfigurations": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/frontendIPConfigurations/5187779d-c61c-44d2-87be-fa69ac2d9d57"
|
||||
},
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/frontendIPConfigurations/94c568d8-d839-431a-aed4-a5c178356018"
|
||||
}
|
||||
],
|
||||
"protocol": "All",
|
||||
"backendAddressPool": {
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/backendAddressPools/b32b5ef0-5332-49a8-b383-f91090135f71"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"nextLink": ""
|
||||
}
|
37
hnv/tests/fake/response/probes.json
Normal file
37
hnv/tests/fake/response/probes.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"value": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/probes/9f940e29- 1d25-44fc-88d3-c81151a0344e",
|
||||
"resourceId": "9f940e29-1d25-44fc-88d3-c81151a0344e",
|
||||
"etag": "W/\"fb318cf6-9102-4e34-a684-5e25aee8d3f4\"",
|
||||
"instanceId": "0da65588-247b-475b-bd1a-7ead0ba1a182",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"protocol": "Tcp",
|
||||
"port": 55555,
|
||||
"intervalInSeconds": 30,
|
||||
"numberOfProbes": 1,
|
||||
"loadBalancingRules": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"resourceRef": "/loadBalancers/0cac5f8a-9d5c-455a-a971-2682d597e098/probes/9f940e29-1d25- 44fc-88d3-c81151a0344e",
|
||||
"resourceId": "9f940e29-1d25-44fc-88d3-c81151a0344e",
|
||||
"etag": "W/\"fb318cf6-9102-4e34-a684-5e25aee8d3f4\"",
|
||||
"instanceId": "0da65588-247b-475b-bd1a-7ead0ba1a182",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded",
|
||||
"protocol": "Tcp",
|
||||
"port": 55555,
|
||||
"intervalInSeconds": 30,
|
||||
"numberOfProbes": 1,
|
||||
"loadBalancingRules": [
|
||||
{
|
||||
"resourceRef": "/loadBalancers/ee396509-27d3-44f9-849c-f6ed28d59f66/loadBalancingRules/2ea746ea-968f-41f2-8bfa-71d2391ef752"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"nextLink": ""
|
||||
}
|
@ -153,7 +153,8 @@ class TestBaseHNVModel(unittest.TestCase):
|
||||
|
||||
mock_dump.assert_called_once_with(include_read_only=False)
|
||||
update_resource.assert_called_once_with(
|
||||
"test/hnv-client", data=mock.sentinel.request_body)
|
||||
"test/hnv-client", data=mock.sentinel.request_body,
|
||||
if_match=None)
|
||||
|
||||
if request_wait:
|
||||
self.assertEqual(get_resource.call_count, loop_count + 1)
|
||||
@ -325,3 +326,45 @@ class TestClient(unittest.TestCase):
|
||||
for raw_data in resources.get("value", []):
|
||||
self._test_get_resource(model=client.PublicIPAddresses,
|
||||
raw_data=raw_data)
|
||||
|
||||
def test_backend_address_pools(self):
|
||||
resources = self._response.backend_address_pools()
|
||||
for raw_data in resources.get("value", []):
|
||||
self._test_get_resource(model=client.BackendAddressPools,
|
||||
raw_data=raw_data)
|
||||
|
||||
def test_frontend_ip_configurations(self):
|
||||
resources = self._response.frontend_ip_configurations()
|
||||
for raw_data in resources.get("value", []):
|
||||
self._test_get_resource(model=client.FrontendIPConfigurations,
|
||||
raw_data=raw_data)
|
||||
|
||||
def test_inbound_nat_rules(self):
|
||||
resources = self._response.inbound_nat_rules()
|
||||
for raw_data in resources.get("value", []):
|
||||
self._test_get_resource(model=client.InboundNATRules,
|
||||
raw_data=raw_data)
|
||||
|
||||
def test_load_balancing_rules(self):
|
||||
resources = self._response.load_balancing_rules()
|
||||
for raw_data in resources.get("value", []):
|
||||
self._test_get_resource(model=client.LoadBalancingRules,
|
||||
raw_data=raw_data)
|
||||
|
||||
def test_outbound_nat_rules(self):
|
||||
resources = self._response.outbound_nat_rules()
|
||||
for raw_data in resources.get("value", []):
|
||||
self._test_get_resource(model=client.OutboundNATRules,
|
||||
raw_data=raw_data)
|
||||
|
||||
def test_probes(self):
|
||||
resources = self._response.probes()
|
||||
for raw_data in resources.get("value", []):
|
||||
self._test_get_resource(model=client.Probes,
|
||||
raw_data=raw_data)
|
||||
|
||||
def test_load_balancers(self):
|
||||
resources = self._response.load_balancers()
|
||||
for raw_data in resources.get("value", []):
|
||||
self._test_get_resource(model=client.LoadBalancers,
|
||||
raw_data=raw_data)
|
||||
|
Loading…
x
Reference in New Issue
Block a user