diff --git a/cloudcafe/networking/networks/extensions/security_groups_api/behaviors.py b/cloudcafe/networking/networks/extensions/security_groups_api/behaviors.py index 72da6fbb..2a3db5d5 100644 --- a/cloudcafe/networking/networks/extensions/security_groups_api/behaviors.py +++ b/cloudcafe/networking/networks/extensions/security_groups_api/behaviors.py @@ -21,7 +21,7 @@ from cloudcafe.networking.networks.common.behaviors \ import NetworkingBaseBehaviors, NetworkingResponse from cloudcafe.networking.networks.common.exceptions \ import ResourceBuildException, ResourceDeleteException, \ - ResourceGetException, ResourceListException + ResourceGetException, ResourceListException, ResourceUpdateException from cloudcafe.networking.networks.extensions.security_groups_api.constants \ import SecurityGroupsResponseCodes @@ -98,6 +98,70 @@ class SecurityGroupsBehaviors(NetworkingBaseBehaviors): raise ResourceBuildException(err_msg) return result + def update_security_group(self, security_group_id, name=None, + description=None, tenant_id=None, + resource_update_attempts=None, + raise_exception=False, poll_interval=None): + """ + @summary: Updates a security group + @param security_group_id: The UUID for the security group + @type security_group_id: string + @param name: A symbolic name for the security group. Not required to + be unique. + @type name: string + @param description: (optional) Description of a security group. + @type description: string + @param tenant_id: (admin use only) Owner of the security group. + @type tenant_id: string + @param resource_update_attempts: number of API retries + @type resource_update_attempts: int + @param raise_exception: flag to raise an exception if the + Security Group was not updated or to return None + @type raise_exception: bool + @param poll_interval: sleep time interval between API retries + @type poll_interval: int + @return: NetworkingResponse object with api response and failure list + @rtype: common.behaviors.NetworkingResponse + """ + poll_interval = poll_interval or self.config.api_poll_interval + resource_update_attempts = (resource_update_attempts or + self.config.api_retries) + + result = NetworkingResponse() + err_msg = 'Security Group Update failure' + for attempt in range(resource_update_attempts): + self._log.debug('Attempt {0} of {1} updating security group ' + '{2}'.format(attempt + 1, resource_update_attempts, + security_group_id)) + + resp = self.client.update_security_group( + security_group_id=security_group_id, name=name, + description=description, tenant_id=tenant_id) + + resp_check = self.check_response( + resp=resp, + status_code=SecurityGroupsResponseCodes.UPDATE_SECURITY_GROUP, + label=security_group_id, message=err_msg) + + result.response = resp + if not resp_check: + return result + + # Failures will be an empty list if the update was successful the + # first time + result.failures.append(resp_check) + time.sleep(poll_interval) + + else: + err_msg = ( + 'Unable to update {0} security group after {1} attempts: ' + '{2}').format(security_group_id, resource_update_attempts, + result.failures) + self._log.error(err_msg) + if raise_exception: + raise ResourceUpdateException(err_msg) + return result + def get_security_group(self, security_group_id, resource_get_attempts=None, raise_exception=False, poll_interval=None): """ diff --git a/cloudcafe/networking/networks/extensions/security_groups_api/client.py b/cloudcafe/networking/networks/extensions/security_groups_api/client.py index 3ceaa38e..21c558a3 100644 --- a/cloudcafe/networking/networks/extensions/security_groups_api/client.py +++ b/cloudcafe/networking/networks/extensions/security_groups_api/client.py @@ -81,6 +81,32 @@ class SecurityGroupsClient(AutoMarshallingHTTPClient): requestslib_kwargs=requestslib_kwargs) return resp + def update_security_group(self, security_group_id, name=None, + description=None, tenant_id=None, + requestslib_kwargs=None): + """ + @summary: Updates a security group + @param name: A symbolic name for the security group. Not required to + be unique. + @type name: string + @param description: (optional) Description of a security group. + @type description: string + @param tenant_id: (admin use only) Owner of the security group. + @type tenant_id: string + @return: security group update response + @rtype: Requests.response + """ + url = '{base_url}/{security_group_id}'.format( + base_url=self.security_groups_url, + security_group_id=security_group_id) + request = SecurityGroupRequest(name=name, description=description, + tenant_id=tenant_id) + resp = self.request('PUT', url, + response_entity_type=SecurityGroup, + request_entity=request, + requestslib_kwargs=requestslib_kwargs) + return resp + def get_security_group(self, security_group_id, requestslib_kwargs=None): """ @summary: Shows information for a specified security group diff --git a/cloudcafe/networking/networks/extensions/security_groups_api/config.py b/cloudcafe/networking/networks/extensions/security_groups_api/config.py index 882128df..2e6c99dd 100644 --- a/cloudcafe/networking/networks/extensions/security_groups_api/config.py +++ b/cloudcafe/networking/networks/extensions/security_groups_api/config.py @@ -48,3 +48,17 @@ class SecurityGroupsConfig(NetworkingBaseConfig): Maximum number of rules that can be assigned to a security group """ return int(self.get("max_rules_per_secgroup", 20)) + + @property + def max_rules_per_tenant(self): + """ + Maximum number of rules per tenant + """ + return int(self.get("max_rules_per_tenant", 100)) + + @property + def max_secgroups_per_tenant(self): + """ + Maximum number of security groups per tenant + """ + return int(self.get("max_secgroups_per_tenant", 10)) diff --git a/cloudcafe/networking/networks/extensions/security_groups_api/constants.py b/cloudcafe/networking/networks/extensions/security_groups_api/constants.py index 091f8925..83240fa2 100644 --- a/cloudcafe/networking/networks/extensions/security_groups_api/constants.py +++ b/cloudcafe/networking/networks/extensions/security_groups_api/constants.py @@ -23,6 +23,7 @@ class SecurityGroupsResponseCodes(NeutronResponseCodes): LIST_SECURITY_GROUPS = 200 GET_SECURITY_GROUP = 200 CREATE_SECURITY_GROUP = 201 + UPDATE_SECURITY_GROUP = 200 DELETE_SECURITY_GROUP = 204 LIST_SECURITY_GROUP_RULES = 200 GET_SECURITY_GROUP_RULE = 200 @@ -32,4 +33,11 @@ class SecurityGroupsResponseCodes(NeutronResponseCodes): class SecurityGroupsErrorTypes(NeutronErrorTypes): """Security Groups Error Types""" - pass + INVALID_INPUT = 'InvalidInput' + SECURITY_GROUP_INVALID_ICMP_VALUE = 'SecurityGroupInvalidIcmpValue' + SECURITY_GROUP_INVALID_PORT_VALUE = 'SecurityGroupInvalidPortValue' + SECURITY_GROUP_NOT_FOUND = 'SecurityGroupNotFound' + SECURITY_GROUP_PROTOCOL_REQUIRED_WITH_PORTS = ( + 'SecurityGroupProtocolRequiredWithPorts') + SECURITY_GROUP_RULE_INVALID_PROTOCOL = 'SecurityGroupRuleInvalidProtocol' + SECURITY_GROUP_RULE_NOT_FOUND = 'SecurityGroupRuleNotFound' diff --git a/cloudcafe/networking/networks/ports_api/config.py b/cloudcafe/networking/networks/ports_api/config.py index 87060b1b..1b24e2d3 100644 --- a/cloudcafe/networking/networks/ports_api/config.py +++ b/cloudcafe/networking/networks/ports_api/config.py @@ -32,20 +32,20 @@ class PortsConfig(NetworkingBaseConfig): """Test multiple ports smoke test ports number""" return int(self.get("multiple_ports", 10)) + @property + def test_ports_per_network(self): + """Flag for running the ports per network quotas tests""" + return self.get_boolean("test_ports_per_network", False) + @property def ports_per_network(self): """Ports per network quota""" return int(self.get("ports_per_network", 250)) - @property - def test_quotas(self): - """Flag for running the ports quotas tests""" - return self.get_boolean("test_quotas", False) - @property def fixed_ips_per_port(self): """Ports fixed IPs quota""" - return int(self.get("fixed_ips_per_port", 4)) + return int(self.get("fixed_ips_per_port", 5)) @property def use_over_limit_retry(self):