Fix the refresh_model method

For the moment the refresh_model method doesn't recreate the
initial structure of the model and some submodels are not
created anymore.

In order to avoid this scenario all the submodels will be
created in process_raw_data insted of the from_raw_data
method.

This patch also add some debug messages in order to ease
the debuging process.
This commit is contained in:
Alexandru Coman 2017-02-16 12:22:50 +02:00
parent 20c7fec75e
commit 9622714668
No known key found for this signature in database
GPG Key ID: A7B6A9021F704507
5 changed files with 149 additions and 103 deletions

View File

@ -373,7 +373,7 @@ max-args=15
ignored-argument-names=_.* ignored-argument-names=_.*
# Maximum number of locals for function / method body # Maximum number of locals for function / method body
max-locals=15 max-locals=20
# Maximum number of return / yield for function / method body # Maximum number of return / yield for function / method body
max-returns=6 max-returns=6

View File

@ -119,6 +119,22 @@ class _BaseHNVModel(model.Model):
# Lock the current model # Lock the current model
self._provision_done = True self._provision_done = True
def is_ready(self):
"""Check if the current model is ready to be used."""
if not self.provisioning_state:
raise exception.ServiceException("The object doesn't contain "
"`provisioningState`.")
elif self.provisioning_state == constant.FAILED:
raise exception.ServiceException(
"Failed to complete the required operation.")
elif self.provisioning_state == constant.SUCCEEDED:
LOG.debug("The model %s: %s was successfully updated "
"(or created).",
self.__class__.__name__, self.resource_id)
return True
return False
@staticmethod @staticmethod
def _get_client(): def _get_client():
"""Create a new client for the HNV REST API.""" """Create a new client for the HNV REST API."""
@ -212,8 +228,13 @@ class _BaseHNVModel(model.Model):
elapsed_time = 0 elapsed_time = 0
while wait: while wait:
try: try:
client.get_resource(endpoint) resource = cls._get(resource_id=resource_id,
parent_id=parent_id,
grandparent_id=grandparent_id)
resource.is_ready()
LOG.debug("The resource is still available. %r", resource)
except exception.NotFound: except exception.NotFound:
LOG.debug("The resource was successfully removed.")
break break
elapsed_time += CONFIG.HNV.retry_interval elapsed_time += CONFIG.HNV.retry_interval
@ -248,9 +269,12 @@ class _BaseHNVModel(model.Model):
in that case). in that case).
""" """
if not self._changes: if not self._changes:
LOG.debug("No changes available for %s: %s",
self.__class__.__name__, self.resource_id)
return return
super(_BaseHNVModel, self).commit(wait=wait, timeout=timeout) LOG.debug("Apply all the changes on the current %s: %s",
self.__class__.__name__, self.resource_id)
client = self._get_client() client = self._get_client()
endpoint = self._endpoint.format( endpoint = self._endpoint.format(
resource_id=self.resource_id or "", resource_id=self.resource_id or "",
@ -263,15 +287,8 @@ class _BaseHNVModel(model.Model):
elapsed_time = 0 elapsed_time = 0
while wait: while wait:
self.refresh() # Update the representation of the current model self.refresh() # Update the representation of the current model
if not self.provisioning_state: if self.is_ready():
raise exception.ServiceException("The object doesn't contain "
"`provisioningState`.")
elif self.provisioning_state == constant.FAILED:
raise exception.ServiceException(
"Failed to complete the required operation.")
elif self.provisioning_state == constant.SUCCEEDED:
break break
elapsed_time += CONFIG.HNV.retry_interval elapsed_time += CONFIG.HNV.retry_interval
if timeout and elapsed_time > timeout: if timeout and elapsed_time > timeout:
raise exception.TimeOut("The request timed out.") raise exception.TimeOut("The request timed out.")
@ -286,7 +303,7 @@ class _BaseHNVModel(model.Model):
return self return self
@classmethod @classmethod
def from_raw_data(cls, raw_data): def process_raw_data(cls, raw_data):
"""Create a new model using raw API response.""" """Create a new model using raw API response."""
properties = raw_data.get("properties", {}) properties = raw_data.get("properties", {})
@ -300,7 +317,7 @@ class _BaseHNVModel(model.Model):
configuration = ConfigurationState.from_raw_data(raw_state) configuration = ConfigurationState.from_raw_data(raw_state)
properties["configurationState"] = configuration properties["configurationState"] = configuration
return super(_BaseHNVModel, cls).from_raw_data(raw_data) return super(_BaseHNVModel, cls).process_raw_data(raw_data)
def _set_fields(self, fields): def _set_fields(self, fields):
"""Set or update the fields value.""" """Set or update the fields value."""
@ -522,7 +539,7 @@ class LogicalSubnetworks(_BaseHNVModel):
administrator portal.""" administrator portal."""
@classmethod @classmethod
def from_raw_data(cls, raw_data): def process_raw_data(cls, raw_data):
"""Create a new model using raw API response.""" """Create a new model using raw API response."""
properties = raw_data["properties"] properties = raw_data["properties"]
@ -545,7 +562,7 @@ class LogicalSubnetworks(_BaseHNVModel):
network_interfaces.append(resource) network_interfaces.append(resource)
properties["networkInterfaces"] = network_interfaces properties["networkInterfaces"] = network_interfaces
return super(LogicalSubnetworks, cls).from_raw_data(raw_data) return super(LogicalSubnetworks, cls).process_raw_data(raw_data)
class LogicalNetworks(_BaseHNVModel): class LogicalNetworks(_BaseHNVModel):
@ -577,7 +594,7 @@ class LogicalNetworks(_BaseHNVModel):
the network.""" the network."""
@classmethod @classmethod
def from_raw_data(cls, raw_data): def process_raw_data(cls, raw_data):
"""Create a new model using raw API response.""" """Create a new model using raw API response."""
properties = raw_data["properties"] properties = raw_data["properties"]
@ -592,7 +609,7 @@ class LogicalNetworks(_BaseHNVModel):
virtual_networks.append(Resource.from_raw_data(raw_network)) virtual_networks.append(Resource.from_raw_data(raw_network))
properties["virtualNetworks"] = virtual_networks properties["virtualNetworks"] = virtual_networks
return super(LogicalNetworks, cls).from_raw_data(raw_data) return super(LogicalNetworks, cls).process_raw_data(raw_data)
class IPConfiguration(_BaseHNVModel): class IPConfiguration(_BaseHNVModel):
@ -659,7 +676,7 @@ class IPConfiguration(_BaseHNVModel):
is connected to.""" is connected to."""
@classmethod @classmethod
def from_raw_data(cls, raw_data): def process_raw_data(cls, raw_data):
"""Create a new model using raw API response.""" """Create a new model using raw API response."""
properties = raw_data["properties"] properties = raw_data["properties"]
@ -690,7 +707,7 @@ class IPConfiguration(_BaseHNVModel):
resource = Resource.from_raw_data(raw_content) resource = Resource.from_raw_data(raw_content)
properties["subnet"] = resource properties["subnet"] = resource
return super(IPConfiguration, cls).from_raw_data(raw_data) return super(IPConfiguration, cls).process_raw_data(raw_data)
class DNSSettings(model.Model): class DNSSettings(model.Model):
@ -791,12 +808,12 @@ class PortSettings(model.Model):
is_required=False, is_property=False) is_required=False, is_property=False)
@classmethod @classmethod
def from_raw_data(cls, raw_data): def process_raw_data(cls, raw_data):
"""Create a new model using raw API response.""" """Create a new model using raw API response."""
raw_settings = raw_data.get("qosSettings", {}) raw_settings = raw_data.get("qosSettings", {})
qos_settings = QosSettings.from_raw_data(raw_settings) qos_settings = QosSettings.from_raw_data(raw_settings)
raw_data["qosSettings"] = qos_settings raw_data["qosSettings"] = qos_settings
return super(PortSettings, cls).from_raw_data(raw_data) return super(PortSettings, cls).process_raw_data(raw_data)
class ConfigurationState(model.Model): class ConfigurationState(model.Model):
@ -883,7 +900,7 @@ class NetworkInterfaces(_BaseHNVModel):
this networkInterfaces resource is part of.""" this networkInterfaces resource is part of."""
@classmethod @classmethod
def from_raw_data(cls, raw_data): def process_raw_data(cls, raw_data):
"""Create a new model using raw API response.""" """Create a new model using raw API response."""
properties = raw_data["properties"] properties = raw_data["properties"]
@ -903,7 +920,7 @@ class NetworkInterfaces(_BaseHNVModel):
port_settings = PortSettings.from_raw_data(raw_settings) port_settings = PortSettings.from_raw_data(raw_settings)
properties["portSettings"] = port_settings properties["portSettings"] = port_settings
return super(NetworkInterfaces, cls).from_raw_data(raw_data) return super(NetworkInterfaces, cls).process_raw_data(raw_data)
class SubNetworks(_BaseHNVModel): class SubNetworks(_BaseHNVModel):
@ -959,7 +976,7 @@ class SubNetworks(_BaseHNVModel):
are connected to the subnet.""" are connected to the subnet."""
@classmethod @classmethod
def from_raw_data(cls, raw_data): def process_raw_data(cls, raw_data):
"""Create a new model using raw API response.""" """Create a new model using raw API response."""
properties = raw_data["properties"] properties = raw_data["properties"]
@ -984,7 +1001,7 @@ class SubNetworks(_BaseHNVModel):
ip_configurations.append(Resource.from_raw_data(raw_config)) ip_configurations.append(Resource.from_raw_data(raw_config))
properties["ipConfigurations"] = ip_configurations properties["ipConfigurations"] = ip_configurations
return super(SubNetworks, cls).from_raw_data(raw_data) return super(SubNetworks, cls).process_raw_data(raw_data)
class DHCPOptions(model.Model): class DHCPOptions(model.Model):
@ -1051,7 +1068,7 @@ class VirtualNetworks(_BaseHNVModel):
underlay network which the virtual network runs on.""" underlay network which the virtual network runs on."""
@classmethod @classmethod
def from_raw_data(cls, raw_data): def process_raw_data(cls, raw_data):
"""Create a new model using raw API response.""" """Create a new model using raw API response."""
properties = raw_data["properties"] properties = raw_data["properties"]
@ -1075,7 +1092,7 @@ class VirtualNetworks(_BaseHNVModel):
subnetworks.append(SubNetworks.from_raw_data(raw_subnet)) subnetworks.append(SubNetworks.from_raw_data(raw_subnet))
properties["subnets"] = subnetworks properties["subnets"] = subnetworks
return super(VirtualNetworks, cls).from_raw_data(raw_data) return super(VirtualNetworks, cls).process_raw_data(raw_data)
class ACLRules(_BaseHNVModel): class ACLRules(_BaseHNVModel):
@ -1198,10 +1215,16 @@ class AccessControlLists(_BaseHNVModel):
control list is associated with.""" control list is associated with."""
@classmethod @classmethod
def from_raw_data(cls, raw_data): def process_raw_data(cls, raw_data):
"""Create a new model using raw API response.""" """Create a new model using raw API response."""
properties = raw_data["properties"] properties = raw_data["properties"]
ip_configurations = []
for raw_content in properties.get("ipConfigurations", []):
resource = Resource.from_raw_data(raw_content)
ip_configurations.append(resource)
properties["ipConfigurations"] = ip_configurations
subnetworks = [] subnetworks = []
for raw_subnet in properties.get("subnets", []): for raw_subnet in properties.get("subnets", []):
subnetworks.append(Resource.from_raw_data(raw_subnet)) subnetworks.append(Resource.from_raw_data(raw_subnet))
@ -1213,7 +1236,7 @@ class AccessControlLists(_BaseHNVModel):
acl_rules.append(ACLRules.from_raw_data(raw_rule)) acl_rules.append(ACLRules.from_raw_data(raw_rule))
properties["aclRules"] = acl_rules properties["aclRules"] = acl_rules
return super(AccessControlLists, cls).from_raw_data(raw_data) return super(AccessControlLists, cls).process_raw_data(raw_data)
class VirtualSwtichQosSettings(model.Model): class VirtualSwtichQosSettings(model.Model):
@ -1284,13 +1307,13 @@ class VirtualSwitchManager(_BaseHNVModel):
return cls._get(resource_id, parent_id, grandparent_id) return cls._get(resource_id, parent_id, grandparent_id)
@classmethod @classmethod
def from_raw_data(cls, raw_data): def process_raw_data(cls, raw_data):
"""Create a new model using raw API response.""" """Create a new model using raw API response."""
properties = raw_data["properties"] properties = raw_data["properties"]
qos_settings = properties.get("qosSettings", {}) qos_settings = properties.get("qosSettings", {})
properties["qosSettings"] = VirtualSwtichQosSettings.from_raw_data( properties["qosSettings"] = VirtualSwtichQosSettings.from_raw_data(
raw_data=qos_settings) raw_data=qos_settings)
return super(VirtualSwitchManager, cls).from_raw_data(raw_data) return super(VirtualSwitchManager, cls).process_raw_data(raw_data)
@classmethod @classmethod
def remove(cls, resource_id, parent_id=None, grandparent_id=None, def remove(cls, resource_id, parent_id=None, grandparent_id=None,
@ -1369,7 +1392,7 @@ class RouteTables(_BaseHNVModel):
table is associated with.""" table is associated with."""
@classmethod @classmethod
def from_raw_data(cls, raw_data): def process_raw_data(cls, raw_data):
"""Create a new model using raw API response.""" """Create a new model using raw API response."""
properties = raw_data["properties"] properties = raw_data["properties"]
@ -1386,7 +1409,7 @@ class RouteTables(_BaseHNVModel):
subnets.append(Resource.from_raw_data(raw_subnet)) subnets.append(Resource.from_raw_data(raw_subnet))
properties["subnets"] = subnets properties["subnets"] = subnets
return super(RouteTables, cls).from_raw_data(raw_data) return super(RouteTables, cls).process_raw_data(raw_data)
class MainMode(model.Model): class MainMode(model.Model):
@ -1566,7 +1589,7 @@ class IPSecConfiguration(model.Model):
"""Indicates collection of IPsec TrafficSelectors on the tenant side.""" """Indicates collection of IPsec TrafficSelectors on the tenant side."""
@classmethod @classmethod
def from_raw_data(cls, raw_data): def process_raw_data(cls, raw_data):
"""Create a new model using raw API response.""" """Create a new model using raw API response."""
raw_main = raw_data.get("mainMode", None) raw_main = raw_data.get("mainMode", None)
if raw_main is not None: if raw_main is not None:
@ -1590,7 +1613,7 @@ class IPSecConfiguration(model.Model):
raw_remote_vpn)) raw_remote_vpn))
raw_data["remoteVpnTrafficSelector"] = remote_vpn_ts raw_data["remoteVpnTrafficSelector"] = remote_vpn_ts
return super(IPSecConfiguration, cls).from_raw_data(raw_data) return super(IPSecConfiguration, cls).process_raw_data(raw_data)
class IPAddress(model.Model): class IPAddress(model.Model):
@ -1836,7 +1859,7 @@ class NetworkConnections(_BaseHNVModel):
is_required=False, is_read_only=False) is_required=False, is_read_only=False)
@classmethod @classmethod
def from_raw_data(cls, raw_data): def process_raw_data(cls, raw_data):
"""Create a new model using raw API response.""" """Create a new model using raw API response."""
properties = raw_data.get("properties", {}) properties = raw_data.get("properties", {})
@ -1876,7 +1899,7 @@ class NetworkConnections(_BaseHNVModel):
gateway = Resource.from_raw_data(raw_content) gateway = Resource.from_raw_data(raw_content)
properties["gateway"] = gateway properties["gateway"] = gateway
return super(NetworkConnections, cls).from_raw_data(raw_data) return super(NetworkConnections, cls).process_raw_data(raw_data)
class PublicIPAddresses(_BaseHNVModel): class PublicIPAddresses(_BaseHNVModel):
@ -1938,7 +1961,7 @@ class PublicIPAddresses(_BaseHNVModel):
""" """
@classmethod @classmethod
def from_raw_data(cls, raw_data): def process_raw_data(cls, raw_data):
"""Create a new model using raw API response.""" """Create a new model using raw API response."""
properties = raw_data.get("properties", {}) properties = raw_data.get("properties", {})
@ -1947,7 +1970,7 @@ class PublicIPAddresses(_BaseHNVModel):
resource = Resource.from_raw_data(raw_content) resource = Resource.from_raw_data(raw_content)
properties["ipConfiguration"] = resource properties["ipConfiguration"] = resource
return super(PublicIPAddresses, cls).from_raw_data(raw_data) return super(PublicIPAddresses, cls).process_raw_data(raw_data)
class BackendAddressPools(_BaseHNVModel): class BackendAddressPools(_BaseHNVModel):
@ -1997,7 +2020,7 @@ class BackendAddressPools(_BaseHNVModel):
resources that use this backend address pool.""" resources that use this backend address pool."""
@classmethod @classmethod
def from_raw_data(cls, raw_data): def process_raw_data(cls, raw_data):
"""Create a new model using raw API response.""" """Create a new model using raw API response."""
properties = raw_data.get("properties", {}) properties = raw_data.get("properties", {})
@ -2019,7 +2042,7 @@ class BackendAddressPools(_BaseHNVModel):
outbound_nat_rules.append(resource) outbound_nat_rules.append(resource)
properties["outboundNatRules"] = outbound_nat_rules properties["outboundNatRules"] = outbound_nat_rules
return super(BackendAddressPools, cls).from_raw_data(raw_data) return super(BackendAddressPools, cls).process_raw_data(raw_data)
class FrontendIPConfigurations(_BaseHNVModel): class FrontendIPConfigurations(_BaseHNVModel):
@ -2104,7 +2127,7 @@ class FrontendIPConfigurations(_BaseHNVModel):
""" """
@classmethod @classmethod
def from_raw_data(cls, raw_data): def process_raw_data(cls, raw_data):
"""Create a new model using raw API response.""" """Create a new model using raw API response."""
properties = raw_data.get("properties", {}) properties = raw_data.get("properties", {})
@ -2131,7 +2154,7 @@ class FrontendIPConfigurations(_BaseHNVModel):
resource = Resource.from_raw_data(raw_content) resource = Resource.from_raw_data(raw_content)
properties["subnet"] = resource properties["subnet"] = resource
return super(FrontendIPConfigurations, cls).from_raw_data(raw_data) return super(FrontendIPConfigurations, cls).process_raw_data(raw_data)
class InboundNATRules(_BaseHNVModel): class InboundNATRules(_BaseHNVModel):
@ -2218,7 +2241,7 @@ class InboundNATRules(_BaseHNVModel):
""" """
@classmethod @classmethod
def from_raw_data(cls, raw_data): def process_raw_data(cls, raw_data):
"""Create a new model using raw API response.""" """Create a new model using raw API response."""
properties = raw_data.get("properties", {}) properties = raw_data.get("properties", {})
@ -2236,7 +2259,7 @@ class InboundNATRules(_BaseHNVModel):
frontend_ip_configurations.append(resource) frontend_ip_configurations.append(resource)
properties["frontendIPConfigurations"] = frontend_ip_configurations properties["frontendIPConfigurations"] = frontend_ip_configurations
return super(InboundNATRules, cls).from_raw_data(raw_data) return super(InboundNATRules, cls).process_raw_data(raw_data)
class LoadBalancingRules(_BaseHNVModel): class LoadBalancingRules(_BaseHNVModel):
@ -2359,7 +2382,7 @@ class LoadBalancingRules(_BaseHNVModel):
""" """
@classmethod @classmethod
def from_raw_data(cls, raw_data): def process_raw_data(cls, raw_data):
"""Create a new model using raw API response.""" """Create a new model using raw API response."""
properties = raw_data.get("properties", {}) properties = raw_data.get("properties", {})
@ -2379,7 +2402,7 @@ class LoadBalancingRules(_BaseHNVModel):
resource = Resource.from_raw_data(raw_content) resource = Resource.from_raw_data(raw_content)
properties["probe"] = resource properties["probe"] = resource
return super(LoadBalancingRules, cls).from_raw_data(raw_data) return super(LoadBalancingRules, cls).process_raw_data(raw_data)
class OutboundNATRules(_BaseHNVModel): class OutboundNATRules(_BaseHNVModel):
@ -2426,7 +2449,7 @@ class OutboundNATRules(_BaseHNVModel):
""" """
@classmethod @classmethod
def from_raw_data(cls, raw_data): def process_raw_data(cls, raw_data):
"""Create a new model using raw API response.""" """Create a new model using raw API response."""
properties = raw_data.get("properties", {}) properties = raw_data.get("properties", {})
@ -2441,7 +2464,7 @@ class OutboundNATRules(_BaseHNVModel):
resource = Resource.from_raw_data(raw_content) resource = Resource.from_raw_data(raw_content)
properties["backendAddressPool"] = resource properties["backendAddressPool"] = resource
return super(OutboundNATRules, cls).from_raw_data(raw_data) return super(OutboundNATRules, cls).process_raw_data(raw_data)
class Probes(_BaseHNVModel): class Probes(_BaseHNVModel):
@ -2510,7 +2533,7 @@ class Probes(_BaseHNVModel):
""" """
@classmethod @classmethod
def from_raw_data(cls, raw_data): def process_raw_data(cls, raw_data):
"""Create a new model using raw API response.""" """Create a new model using raw API response."""
properties = raw_data.get("properties", {}) properties = raw_data.get("properties", {})
@ -2520,7 +2543,7 @@ class Probes(_BaseHNVModel):
load_balancing_rules.append(resource) load_balancing_rules.append(resource)
properties["loadBalancingRules"] = load_balancing_rules properties["loadBalancingRules"] = load_balancing_rules
return super(Probes, cls).from_raw_data(raw_data) return super(Probes, cls).process_raw_data(raw_data)
class LoadBalancers(_BaseHNVModel): class LoadBalancers(_BaseHNVModel):
@ -2580,7 +2603,7 @@ class LoadBalancers(_BaseHNVModel):
""" """
@classmethod @classmethod
def from_raw_data(cls, raw_data): def process_raw_data(cls, raw_data):
properties = raw_data.get("properties", {}) properties = raw_data.get("properties", {})
backend_address_pools = [] backend_address_pools = []
@ -2608,8 +2631,8 @@ class LoadBalancers(_BaseHNVModel):
outbound_nat_rules = [] outbound_nat_rules = []
for raw_content in properties.get("outboundNatRules", []): for raw_content in properties.get("outboundNatRules", []):
raw_content["parentResourceID"] = raw_data["resourceId"] raw_content["parentResourceID"] = raw_data["resourceId"]
inbound_nat_rule = OutboundNATRules.from_raw_data(raw_content) outbound_nat_rule = OutboundNATRules.from_raw_data(raw_content)
outbound_nat_rules.append(inbound_nat_rule) outbound_nat_rules.append(outbound_nat_rule)
properties["outboundNatRules"] = outbound_nat_rules properties["outboundNatRules"] = outbound_nat_rules
load_balancing_rules = [] load_balancing_rules = []
@ -2626,7 +2649,7 @@ class LoadBalancers(_BaseHNVModel):
probes.append(probe) probes.append(probe)
properties["probes"] = probes properties["probes"] = probes
return super(LoadBalancers, cls).from_raw_data(raw_data) return super(LoadBalancers, cls).process_raw_data(raw_data)
class _BGPPeersStatistics(model.Model): class _BGPPeersStatistics(model.Model):
@ -2783,7 +2806,7 @@ class BGPPeersStatistics(model.Model):
"""Time stamp when the stats were last updated.""" """Time stamp when the stats were last updated."""
@classmethod @classmethod
def from_raw_data(cls, raw_data): def process_raw_data(cls, raw_data):
"""Create a new model using raw API response.""" """Create a new model using raw API response."""
# pylint: disable=redefined-variable-type # pylint: disable=redefined-variable-type
@ -2825,7 +2848,7 @@ class BGPPeersStatistics(model.Model):
statistics = IPV6Route.from_raw_data(raw_content) statistics = IPV6Route.from_raw_data(raw_content)
raw_data["ipv6Route"] = statistics raw_data["ipv6Route"] = statistics
return super(BGPPeersStatistics, cls).from_raw_data(raw_data) return super(BGPPeersStatistics, cls).process_raw_data(raw_data)
class BGPPeers(_BaseHNVModel): class BGPPeers(_BaseHNVModel):
@ -2894,7 +2917,7 @@ class BGPPeers(_BaseHNVModel):
"""This flag is set to `True` for iBGP peers.""" """This flag is set to `True` for iBGP peers."""
@classmethod @classmethod
def from_raw_data(cls, raw_data): def process_raw_data(cls, raw_data):
"""Create a new model using raw API response.""" """Create a new model using raw API response."""
properties = raw_data.get("properties", {}) properties = raw_data.get("properties", {})
@ -2903,7 +2926,7 @@ class BGPPeers(_BaseHNVModel):
statistics = BGPPeersStatistics.from_raw_data(raw_content) statistics = BGPPeersStatistics.from_raw_data(raw_content)
properties["statistics"] = statistics properties["statistics"] = statistics
super(BGPPeers, cls).from_raw_data(raw_data) return super(BGPPeers, cls).process_raw_data(raw_data)
class BGPRouters(_BaseHNVModel): class BGPRouters(_BaseHNVModel):
@ -2957,7 +2980,7 @@ class BGPRouters(_BaseHNVModel):
"""Collection of BGP peers associated with the BGP Routers resource.""" """Collection of BGP peers associated with the BGP Routers resource."""
@classmethod @classmethod
def from_raw_data(cls, raw_data): def process_raw_data(cls, raw_data):
"""Create a new model using raw API response.""" """Create a new model using raw API response."""
properties = raw_data.get("properties", {}) properties = raw_data.get("properties", {})
@ -2968,7 +2991,7 @@ class BGPRouters(_BaseHNVModel):
bgp_peers.append(BGPPeers.from_raw_data(raw_content)) bgp_peers.append(BGPPeers.from_raw_data(raw_content))
properties["bgpPeers"] = bgp_peers properties["bgpPeers"] = bgp_peers
return super(BGPRouters, cls).from_raw_data(raw_data) return super(BGPRouters, cls).process_raw_data(raw_data)
class LoadBalancerManager(_BaseHNVModel): class LoadBalancerManager(_BaseHNVModel):
@ -3012,7 +3035,7 @@ class LoadBalancerManager(_BaseHNVModel):
return cls._get(resource_id, parent_id, grandparent_id) return cls._get(resource_id, parent_id, grandparent_id)
@classmethod @classmethod
def from_raw_data(cls, raw_data): def process_raw_data(cls, raw_data):
"""Create a new model using raw API response.""" """Create a new model using raw API response."""
properties = raw_data.get("properties", {}) properties = raw_data.get("properties", {})
@ -3022,4 +3045,4 @@ class LoadBalancerManager(_BaseHNVModel):
vip_ip_pools.append(resource) vip_ip_pools.append(resource)
properties["vipIpPools"] = vip_ip_pools properties["vipIpPools"] = vip_ip_pools
return super(LoadBalancerManager, cls).from_raw_data(raw_data) return super(LoadBalancerManager, cls).process_raw_data(raw_data)

View File

@ -105,7 +105,7 @@ class _HNVClient(object):
return not self._https_allow_insecure return not self._https_allow_insecure
def _http_request(self, resource, method=constant.GET, body=None, def _http_request(self, resource, method=constant.GET, body=None,
if_match=None): if_match=False):
if not resource.startswith("http"): if not resource.startswith("http"):
url = requests.compat.urljoin(self._base_url, resource) url = requests.compat.urljoin(self._base_url, resource)
else: else:
@ -113,10 +113,10 @@ class _HNVClient(object):
headers = self._get_headers() headers = self._get_headers()
if method in (constant.PUT, constant.PATCH): if method in (constant.PUT, constant.PATCH):
if not isinstance(if_match, six.string_types): if if_match:
if_match = (body or {}).get("etag", None) etag = (body or {}).get("etag", None)
if if_match is not None: if etag is not None:
headers["If-Match"] = if_match headers["If-Match"] = etag
attemts = 0 attemts = 0
while True: while True:
@ -127,7 +127,8 @@ class _HNVClient(object):
timeout=CONFIG.HNV.http_request_timeout timeout=CONFIG.HNV.http_request_timeout
) )
break break
except requests.ConnectionError as exc: except (requests.ConnectionError,
requests.RequestException) as exc:
attemts += 1 attemts += 1
self._http_session = None self._http_session = None
LOG.debug("Request failed: %s", exc) LOG.debug("Request failed: %s", exc)

View File

@ -79,7 +79,7 @@ class TestHNVClient(unittest.TestCase):
@mock.patch("hnv.common.utils._HNVClient._get_headers") @mock.patch("hnv.common.utils._HNVClient._get_headers")
def _test_http_request(self, mock_headers, mock_session, mock_join, def _test_http_request(self, mock_headers, mock_session, mock_join,
mock_dump, mock_sleep, mock_dump, mock_sleep,
method, body, response, status_code): method, body, response, status_code, if_match):
output = [] output = []
headers = mock_headers.return_value = {} headers = mock_headers.return_value = {}
mock_join.return_value = mock.sentinel.url mock_join.return_value = mock.sentinel.url
@ -105,35 +105,38 @@ class TestHNVClient(unittest.TestCase):
if isinstance(expected_response, requests.exceptions.SSLError): if isinstance(expected_response, requests.exceptions.SSLError):
self.assertRaises(exception.CertificateVerifyFailed, self.assertRaises(exception.CertificateVerifyFailed,
client._http_request, client._http_request,
"/fake/resource", method, body) "/fake/resource", method, body, if_match)
return return
elif isinstance(expected_response, requests.ConnectionError): elif isinstance(expected_response, requests.ConnectionError):
self.assertRaises(requests.ConnectionError, self.assertRaises(requests.ConnectionError,
client._http_request, client._http_request,
"/fake/resource", method, body) "/fake/resource", method, body, if_match)
return return
elif status_code == 400: elif status_code == 400:
self.assertRaises(exception.ServiceException, self.assertRaises(exception.ServiceException,
client._http_request, client._http_request,
"/fake/resource", method, body) "/fake/resource", method, body, if_match)
elif status_code == 404: elif status_code == 404:
self.assertRaises(exception.NotFound, self.assertRaises(exception.NotFound,
client._http_request, client._http_request,
"/fake/resource", method, body) "/fake/resource", method, body, if_match)
elif status_code != 200: elif status_code != 200:
self.assertRaises(requests.HTTPError, self.assertRaises(requests.HTTPError,
client._http_request, client._http_request,
"/fake/resource", method, body) "/fake/resource", method, body, if_match)
else: else:
client_response = client._http_request("/fake/resource", client_response = client._http_request("/fake/resource",
method, body) method, body, if_match)
mock_join.assert_called_once_with(mock.sentinel.url, mock_join.assert_called_once_with(mock.sentinel.url,
"/fake/resource") "/fake/resource")
mock_headers.assert_called_once_with() mock_headers.assert_called_once_with()
if not method == constant.GET: if not method == constant.GET and if_match:
etag = (body or {}).get("etag", None) etag = (body or {}).get("etag", None)
self.assertEqual(headers["If-Match"], etag) if etag is None:
self.assertNotIn("If-Match", headers)
else:
self.assertEqual(headers["If-Match"], etag)
if len(response) == 1: if len(response) == 1:
session_request.assert_called_once_with( session_request.assert_called_once_with(
@ -154,14 +157,16 @@ class TestHNVClient(unittest.TestCase):
self._test_http_request(method=constant.GET, self._test_http_request(method=constant.GET,
body=mock.sentinel.body, body=mock.sentinel.body,
response=response, response=response,
status_code=200) status_code=200,
if_match=False)
def test_http_request_put(self): def test_http_request_put(self):
response = [mock.MagicMock()] response = [mock.MagicMock()]
self._test_http_request(method=constant.PUT, self._test_http_request(method=constant.PUT,
body={"etag": mock.sentinel.etag}, body={"etag": mock.sentinel.etag},
response=response, response=response,
status_code=200) status_code=200,
if_match=True)
def test_http_request_with_connection_error(self): def test_http_request_with_connection_error(self):
response = [requests.ConnectionError(), mock.MagicMock()] response = [requests.ConnectionError(), mock.MagicMock()]
@ -169,7 +174,8 @@ class TestHNVClient(unittest.TestCase):
self._test_http_request(method=constant.GET, self._test_http_request(method=constant.GET,
body=mock.sentinel.body, body=mock.sentinel.body,
response=response, response=response,
status_code=200) status_code=200,
if_match=False)
def test_http_request_connection_error(self): def test_http_request_connection_error(self):
response = [requests.ConnectionError(), requests.ConnectionError()] response = [requests.ConnectionError(), requests.ConnectionError()]
@ -177,7 +183,8 @@ class TestHNVClient(unittest.TestCase):
self._test_http_request(method=constant.GET, self._test_http_request(method=constant.GET,
body=mock.sentinel.body, body=mock.sentinel.body,
response=response, response=response,
status_code=200) status_code=200,
if_match=False)
def test_http_request_ssl_error(self): def test_http_request_ssl_error(self):
response = [requests.exceptions.SSLError(), response = [requests.exceptions.SSLError(),
@ -186,28 +193,32 @@ class TestHNVClient(unittest.TestCase):
self._test_http_request(method=constant.GET, self._test_http_request(method=constant.GET,
body=mock.sentinel.body, body=mock.sentinel.body,
response=response, response=response,
status_code=200) status_code=200,
if_match=False)
def test_http_request_not_found(self): def test_http_request_not_found(self):
response = [mock.MagicMock()] response = [mock.MagicMock()]
self._test_http_request(method=constant.GET, self._test_http_request(method=constant.GET,
body=mock.sentinel.body, body=mock.sentinel.body,
response=response, response=response,
status_code=404) status_code=404,
if_match=False)
def test_http_request_bad_request(self): def test_http_request_bad_request(self):
response = [mock.MagicMock()] response = [mock.MagicMock()]
self._test_http_request(method=constant.GET, self._test_http_request(method=constant.GET,
body=mock.sentinel.body, body=mock.sentinel.body,
response=response, response=response,
status_code=400) status_code=400,
if_match=False)
def test_http_request_server_error(self): def test_http_request_server_error(self):
response = [mock.MagicMock()] response = [mock.MagicMock()]
self._test_http_request(method=constant.GET, self._test_http_request(method=constant.GET,
body=mock.sentinel.body, body=mock.sentinel.body,
response=response, response=response,
status_code=500) status_code=500,
if_match=False)
@mock.patch("hnv.common.utils._HNVClient._http_request") @mock.patch("hnv.common.utils._HNVClient._http_request")
def test_get_resource(self, mock_http_request): def test_get_resource(self, mock_http_request):

View File

@ -22,7 +22,6 @@ except ImportError:
import mock import mock
from hnv import client from hnv import client
from hnv.common import constant
from hnv.common import exception from hnv.common import exception
from hnv import config as hnv_config from hnv import config as hnv_config
from hnv.tests.fake import fake_response from hnv.tests.fake import fake_response
@ -77,15 +76,23 @@ class TestBaseHNVModel(unittest.TestCase):
self.assertEqual(resources, [{} for _ in range(10)]) self.assertEqual(resources, [{} for _ in range(10)])
@mock.patch("time.sleep") @mock.patch("time.sleep")
@mock.patch("hnv.client._BaseHNVModel._get")
@mock.patch("hnv.client._BaseHNVModel._get_client") @mock.patch("hnv.client._BaseHNVModel._get_client")
def _test_remove(self, mock_get_client, mock_sleep, def _test_remove(self, mock_get_client, mock_get, mock_sleep,
loop_count, timeout): loop_count, timeout):
resource = mock.Mock()
is_ready = resource.is_ready = mock.Mock()
http_client = mock_get_client.return_value = mock.Mock() http_client = mock_get_client.return_value = mock.Mock()
remove_resource = http_client.remove_resource = mock.Mock() remove_resource = http_client.remove_resource = mock.Mock()
get_resource = http_client.get_resource = mock.Mock()
side_effect = [None for _ in range(loop_count)] side_effect = [resource for _ in range(loop_count)]
side_effect.append(exception.NotFound if not timeout else None) side_effect.append(exception.NotFound if not timeout else resource)
get_resource.side_effect = side_effect mock_get.side_effect = side_effect
side_effect = [False for _ in range(loop_count)]
side_effect.append(True if not timeout else False)
is_ready.side_effect = side_effect
request_timeout = CONFIG.HNV.retry_interval * loop_count request_timeout = CONFIG.HNV.retry_interval * loop_count
request_wait = True if loop_count > 0 else False request_wait = True if loop_count > 0 else False
@ -115,27 +122,29 @@ class TestBaseHNVModel(unittest.TestCase):
return {"properties": {"provisioningState": provisioning_state}} return {"properties": {"provisioningState": provisioning_state}}
@mock.patch("time.sleep") @mock.patch("time.sleep")
@mock.patch("hnv.client._BaseHNVModel._reset_model")
@mock.patch("hnv.client._BaseHNVModel.is_ready")
@mock.patch("hnv.client._BaseHNVModel.refresh")
@mock.patch("hnv.client._BaseHNVModel.dump") @mock.patch("hnv.client._BaseHNVModel.dump")
@mock.patch("hnv.client._BaseHNVModel._get_client") @mock.patch("hnv.client._BaseHNVModel._get_client")
def _test_commit(self, mock_get_client, mock_dump, def _test_commit(self, mock_get_client, mock_dump, mock_refresh,
mock_sleep, mock_is_ready, mock_reset_model, mock_sleep,
loop_count, timeout, failed, invalid_response): loop_count, timeout, failed, invalid_response):
http_client = mock_get_client.return_value = mock.Mock() http_client = mock_get_client.return_value = mock.Mock()
update_resource = http_client.update_resource = mock.Mock() update_resource = http_client.update_resource = mock.Mock()
update_resource.return_value = mock.sentinel.response
mock_dump.return_value = mock.sentinel.request_body mock_dump.return_value = mock.sentinel.request_body
get_resource = http_client.get_resource = mock.Mock() side_effect = [False for _ in range(loop_count)]
side_effect = [self._get_provisioning(constant.UPDATING)
for _ in range(loop_count)]
if timeout: if timeout:
side_effect.append(self._get_provisioning(constant.UPDATING)) side_effect.append(False)
elif failed: elif failed:
side_effect.append(self._get_provisioning(constant.FAILED)) side_effect.append(exception.ServiceException)
elif invalid_response: elif invalid_response:
side_effect.append(self._get_provisioning(None)) side_effect.append(False)
else: else:
side_effect.append(self._get_provisioning(constant.SUCCEEDED)) side_effect.append(True)
get_resource.side_effect = side_effect mock_is_ready.side_effect = side_effect
request_timeout = CONFIG.HNV.retry_interval * loop_count request_timeout = CONFIG.HNV.retry_interval * loop_count
request_wait = True if loop_count > 0 else False request_wait = True if loop_count > 0 else False
@ -158,7 +167,9 @@ class TestBaseHNVModel(unittest.TestCase):
if_match=None) if_match=None)
if request_wait: if request_wait:
self.assertEqual(get_resource.call_count, loop_count + 1) self.assertEqual(mock_refresh.call_count, loop_count + 1)
else:
mock_reset_model.assert_called_once_with(mock.sentinel.response)
def test_commit(self): def test_commit(self):
self._test_commit(loop_count=0, timeout=False, self._test_commit(loop_count=0, timeout=False,