Added support for security group rules api

1. Create model and client
2. Added unit tests
3. Added integration tests

Change-Id: I26af15fac975a3b3266e404fab08defd49795e23
This commit is contained in:
Sumanth Nagadavalli
2013-06-11 16:08:07 +05:30
parent c482861408
commit 84ee4d4ebb
16 changed files with 569 additions and 24 deletions

View File

@@ -16,9 +16,11 @@ limitations under the License.
from cafe.engine.clients.rest import AutoMarshallingRestClient
from cloudcafe.compute.extensions.security_groups_api.models.requests \
import CreateSecurityGroup
import CreateSecurityGroup, CreateSecurityGroupRule
from cloudcafe.compute.extensions.security_groups_api.models.security_group \
import SecurityGroup, SecurityGroups
from cloudcafe.compute.extensions.security_groups_api.models.\
security_group_rule import SecurityGroupRule
class SecurityGroupsClient(AutoMarshallingRestClient):
@@ -69,3 +71,31 @@ class SecurityGroupsClient(AutoMarshallingRestClient):
resp = self.request('DELETE', url,
requestslib_kwargs=requestslib_kwargs)
return resp
class SecurityGroupRulesClient(AutoMarshallingRestClient):
def __init__(self, url, auth_token, serialize_format=None,
deserialize_format=None):
super(SecurityGroupRulesClient, self).__init__(serialize_format,
deserialize_format)
self.auth_token = auth_token
self.default_headers['X-Auth-Token'] = auth_token
ct = ''.join(['application/', self.serialize_format])
accept = ''.join(['application/', self.deserialize_format])
self.default_headers['Content-Type'] = ct
self.default_headers['Accept'] = accept
self.url = url
def create_rule(self, from_port, ip_protocol, to_port,
parent_group_id, cidr, group_id,
requestslib_kwargs=None):
url = '{base_url}/os-security-group-rules'.format(base_url=self.url)
create_sec_group_request = \
CreateSecurityGroupRule(from_port, ip_protocol, to_port,
parent_group_id, cidr, group_id)
resp = self.request('POST', url,
response_entity_type=SecurityGroupRule,
request_entity=create_sec_group_request,
requestslib_kwargs=requestslib_kwargs)
return resp

View File

@@ -15,9 +15,10 @@ limitations under the License.
"""
import json
from xml.etree import ElementTree
import xml.etree.ElementTree as ET
from cafe.engine.models.base import AutoMarshallingModel
from cloudcafe.compute.common.constants import Constants
class CreateSecurityGroup(AutoMarshallingModel):
@@ -43,3 +44,38 @@ class CreateSecurityGroup(AutoMarshallingModel):
def _obj_to_xml_ele(self):
raise NotImplemented
class CreateSecurityGroupRule(AutoMarshallingModel):
def __init__(self, from_port=None, ip_protocol=None,
to_port=None, parent_group_id=None,
cidr=None, group_id=None):
self.from_port = from_port
self.ip_protocol = ip_protocol
self.to_port = to_port
self.parent_group_id = parent_group_id
self.cidr = cidr
self.group_id = group_id
def _obj_to_json(self):
"""
@summary: Converts the object to json.
"""
ret = {'security_group_rule': self.__dict__}
print ret
return json.dumps(ret)
def _obj_to_xml(self):
"""
@summary: Converts the object to xml.
"""
xml = Constants.XML_HEADER
element = ET.Element('security_group_rule')
for key, value in self.__dict__.iteritems():
child = ET.Element(key)
child.text = str(value)
element.append(child)
xml += ET.tostring(element)
return xml

View File

@@ -18,7 +18,10 @@ import json
import xml.etree.ElementTree as ET
from cafe.engine.models.base import AutoMarshallingModel
from cloudcafe.compute.common.constants import Constants
from cloudcafe.compute.common.equality_tools import EqualityTools
from cloudcafe.compute.extensions.security_groups_api.models.\
security_group_rule import SecurityGroupRule
class SecurityGroup(AutoMarshallingModel):
@@ -39,24 +42,56 @@ class SecurityGroup(AutoMarshallingModel):
@classmethod
def _json_to_obj(cls, serialized_str):
"""
@summary: Returns an instance of a SecurityGroup
based on the json serialized_str passed in.
@param serialized_str: json serialized string.
@type serialized_str: String.
@return: SecurityGroup.
@rtype: SecurityGroup.
"""
json_dict = json.loads(serialized_str)
return cls._dict_to_obj(json_dict.get('security_group'))
@classmethod
def _dict_to_obj(cls, json_dict):
rules = []
for rule in json_dict.get('rules'):
rules.append(SecurityGroupRule._dict_to_obj(rule))
return SecurityGroup(id=json_dict.get('id'),
name=json_dict.get('name'),
description=json_dict.get('description'),
rules=json_dict.get('rules'),
rules=rules,
tenant_id=json_dict.get('tenant_id'))
@classmethod
def _xml_to_obj(cls, serialized_str):
raise NotImplemented
"""
@summary: Returns an instance of a SecurityGroup
based on the xml serialized_str passed in.
@param serialized_str: xml serialized string.
@type serialized_str: String.
@return: SecurityGroup.
@rtype: SecurityGroup.
"""
xml_ele = ET.fromstring(serialized_str)
cls._remove_xml_etree_namespace(
xml_ele, Constants.XML_API_NAMESPACE)
return cls._xml_ele_to_obj(xml_ele)
@classmethod
def _xml_ele_to_obj(cls, xml_ele):
raise NotImplemented
id = xml_ele.attrib.get('id')
tenant_id = xml_ele.attrib.get('tenant_id')
name = xml_ele.attrib.get('name')
description = xml_ele.find('description').text
rules = []
for rule in xml_ele.findall('rules'):
rules.append(SecurityGroupRule._xml_ele_to_obj(rule))
return SecurityGroup(id=id, name=name,
description=description,
rules=rules,
tenant_id=tenant_id)
def __eq__(self, other):
"""
@@ -83,13 +118,35 @@ class SecurityGroups(SecurityGroup):
@classmethod
def _xml_to_obj(cls, serialized_str):
raise NotImplemented
"""
@summary: Returns a list of a SecurityGroup
based on the xml serialized_str passed in.
@param serialized_str: xml serialized string.
@type serialized_str: String.
@return: List.
@rtype: List.
"""
xml_ele = ET.fromstring(serialized_str)
cls._remove_xml_etree_namespace(
xml_ele, Constants.XML_API_NAMESPACE)
groups = []
for group in xml_ele.findall('security_group'):
groups.append(SecurityGroup._xml_ele_to_obj(group))
return groups
@classmethod
def _json_to_obj(cls, serialized_str):
"""
@summary: Returns a list of a SecurityGroup
based on the json serialized_str passed in.
@param serialized_str: json serialized string.
@type serialized_str: String.
@return: List.
@rtype: List.
"""
ret = []
json_dict = json.loads(serialized_str)
groups = json_dict.get('security_groups')
groups = json_dict.get('security_group_rules')
for group in groups:
ret.append(SecurityGroup._dict_to_obj(group))

View File

@@ -0,0 +1,124 @@
"""
Copyright 2013 Rackspace
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
import json
import xml.etree.ElementTree as ET
from cafe.engine.models.base import AutoMarshallingModel
from cloudcafe.compute.common.constants import Constants
from cloudcafe.compute.common.equality_tools import EqualityTools
class IpRange(AutoMarshallingModel):
def __init__(self, cidr=None):
self.cidr = cidr
@classmethod
def _dict_to_obj(cls, json_dict):
return IpRange(json_dict.get('cidr'))
@classmethod
def _xml_ele_to_obj(cls, xml_ele):
cidr = xml_ele.find('cidr').text
return IpRange(cidr)
class SecurityGroupRule(AutoMarshallingModel):
def __init__(self, id=None, from_port=None, ip_protocol=None, to_port=None,
parent_group_id=None, ip_range=None):
self.id = id
self.from_port = from_port
self.ip_protocol = ip_protocol
self.to_port = to_port
self.parent_group_id = parent_group_id
self.ip_range = ip_range
@classmethod
def _json_to_obj(cls, serialized_str):
"""
@summary: Returns an instance of a SecurityGroupRule
based on the json serialized_str passed in.
@param serialized_str: json serialized string.
@type serialized_str: String.
@return: SecurityGroupRule.
@rtype: SecurityGroupRule.
"""
json_dict = json.loads(serialized_str)
return cls._dict_to_obj(json_dict.get('security_group_rule'))
@classmethod
def _dict_to_obj(cls, json_dict):
ip_range = IpRange._dict_to_obj(json_dict.get('ip_range'))
return SecurityGroupRule(id=json_dict.get('id'),
from_port=json_dict.get('from_port'),
ip_protocol=json_dict.get('ip_protocol'),
to_port=json_dict.get('to_port'),
parent_group_id=
json_dict.get('parent_group_id'),
ip_range=ip_range)
@classmethod
def _xml_to_obj(cls, serialized_str):
"""
@summary: Returns an instance of a SecurityGroupRule
based on the xml serialized_str passed in.
@param serialized_str: xml serialized string.
@type serialized_str: String.
@return: SecurityGroupRule.
@rtype: SecurityGroupRule.
"""
element = ET.fromstring(serialized_str)
cls._remove_xml_etree_namespace(
element, Constants.XML_API_NAMESPACE)
sec_group_rule = cls._xml_ele_to_obj(element)
return sec_group_rule
@classmethod
def _xml_ele_to_obj(cls, xml_ele):
id = xml_ele.attrib.get('id')
parent_group_id = xml_ele.attrib.get('parent_group_id')
ip_range = IpRange._xml_ele_to_obj(xml_ele.find('ip_range'))
from_port = xml_ele.find('from_port').text
to_port = xml_ele.find('to_port').text
ip_protocol = xml_ele.find('ip_protocol').text
return SecurityGroupRule(id=id, from_port=from_port,
ip_protocol=ip_protocol,
to_port=to_port,
parent_group_id=parent_group_id,
ip_range=ip_range)
def __eq__(self, other):
"""
@summary: Overrides the default equals
@param other: SecurityGroupRule object to compare with
@type other: SecurityGroupRule
@return: True if SecurityGroupRule objects are equal, False otherwise
@rtype: bool
"""
return EqualityTools.are_objects_equal(self, other)
def __ne__(self, other):
"""
@summary: Overrides the default not-equals
@param other: SecurityGroupRule object to compare with
@type other: SecurityGroupRule
@return: True if SecurityGroupRule objects
are not equal, False otherwise
@rtype: bool
"""
return not EqualityTools.are_objects_equal(self, other)

View File

@@ -74,4 +74,4 @@ class DefaultQuotaSetConfig(ConfigSectionInterface):
@property
def security_groups(self):
"""Default number of security groups"""
return int(self.get('security_groups'))
return int(self.get('security_group_rules'))

View File

@@ -43,13 +43,18 @@ class Quota(AutoMarshallingModel):
@classmethod
def _dict_to_obj(self, quota_dict):
return Quota(quota_dict.get('cores'), quota_dict.get('floating_ips'),
quota_dict.get('id'), quota_dict.get('injected_file_content_bytes'),
return Quota(quota_dict.get('cores'),
quota_dict.get('floating_ips'),
quota_dict.get('id'),
quota_dict.get('injected_file_content_bytes'),
quota_dict.get('injected_file_path_bytes'),
quota_dict.get('injected_files'), quota_dict.get('instances'),
quota_dict.get('key_pairs'), quota_dict.get('metadata_items'),
quota_dict.get('ram'), quota_dict.get('security_group_rules'),
quota_dict.get('security_groups'))
quota_dict.get('injected_files'),
quota_dict.get('instances'),
quota_dict.get('key_pairs'),
quota_dict.get('metadata_items'),
quota_dict.get('ram'),
quota_dict.get('security_group_rules'),
quota_dict.get('security_group_rules'))
@classmethod
def _json_to_obj(cls, serialized_str):
@@ -84,4 +89,4 @@ class Quota(AutoMarshallingModel):
"""
element = ET.fromstring(serialized_str)
quota = cls._xml_ele_to_obj(element)
return quota
return quota

View File

@@ -36,7 +36,7 @@ class QuotasMockResponse():
'"metadata_items": 128,' \
'"ram": 51200,' \
'"security_group_rules": 20,' \
'"security_groups": 10}}'
'"security_group_rules": 10}}'
def _xml_quota(self):
return '<?xml version="1.0" encoding="UTF-8"?>' \
@@ -52,4 +52,4 @@ class QuotasMockResponse():
'<metadata_items>128</metadata_items>' \
'<ram>51200</ram>' \
'<security_group_rules>20</security_group_rules>' \
'<security_groups>10</security_groups></quota_set>'
'<security_group_rules>10</security_group_rules></quota_set>'

View File

@@ -65,7 +65,7 @@ class QuotasClientTest(IntegrationTestFixture):
actual_response = self.quotas_client.\
update_quota(self.TENANT_ID, security_groups=45)
expected_request_body = '{"quota_set": {"security_groups": 45}}'
expected_request_body = '{"quota_set": {"security_group_rules": 45}}'
self._assert_default_headers_in_request(HTTPretty.last_request)
self.assertEqual(200, actual_response.status_code)
self.assertEqual(HTTPretty.last_request.body,

View File

@@ -0,0 +1,15 @@
"""
Copyright 2013 Rackspace
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""

View File

@@ -0,0 +1,50 @@
"""
Copyright 2013 Rackspace
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
class SecurityGroupRulesMockResponse():
def __init__(self, format):
self.format = format
def _get_sec_group_rule(self):
return getattr(self, '_{0}_sec_group_rule'.format(self.format))()
def _json_sec_group_rule(self):
return '{"security_group_rule":' \
' {"from_port": 80,' \
' "ip_protocol": "tcp",' \
' "to_port": 8080,' \
' "parent_group_id": 2,' \
' "ip_range": {"cidr": "0.0.0.0/0"},' \
' "id": 1' \
' "group": {}}}'
def _xml_sec_group_rule(self):
return '<?xml version=\'1.0\' encoding=\'UTF-8\'?>' \
'<security_group_rule ' \
'parent_group_id=2 id=1>' \
'<from_port>80</from_port>' \
'<ip_protocol>tcp</ip_protocol>' \
'<to_port>8080</to_port>' \
'<ip_range>' \
'<cidr>0.0.0.0/0</cidr>' \
'</ip_range>' \
'<group>' \
'<name>None</name>' \
'<tenant_id>None</tenant_id>' \
'</group>' \
'</security_group_rule>'

View File

@@ -0,0 +1,64 @@
"""
Copyright 2013 Rackspace
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
import unittest2 as unittest
from httpretty import HTTPretty
from cloudcafe.compute.extensions.security_groups_api.client\
import SecurityGroupRulesClient
from cloudcafe.compute.tests.integration.fixtures\
import IntegrationTestFixture
from cloudcafe.compute.tests.integration.\
security_group_rules.responses import SecurityGroupRulesMockResponse
class SecurityGroupRulesClientTest(IntegrationTestFixture):
@classmethod
def setUpClass(cls):
super(SecurityGroupRulesClientTest, cls).setUpClass()
cls.security_groups_client = SecurityGroupRulesClient(
url=cls.COMPUTE_API_ENDPOINT,
auth_token=cls.AUTH_TOKEN,
serialize_format=cls.FORMAT,
deserialize_format=cls.FORMAT)
cls.security_group_rules_uri = "{0}/os-security-group-rules".\
format(cls.COMPUTE_API_ENDPOINT)
cls.mock_response = SecurityGroupRulesMockResponse(cls.FORMAT)
def test_create_security_group_rule(self):
HTTPretty.register_uri(HTTPretty.POST, self.security_group_rules_uri,
body=self.mock_response._get_sec_group_rule())
expected_request_body = '{"security_group_rule":' \
' {"from_port": 80,' \
' "ip_protocol": "tcp",' \
' "to_port": 8080,' \
' "parent_group_id": 2,' \
' "cidr": "0.0.0.0/0",' \
' "group_id": 1}}'
actual_response = self.security_groups_client.\
create_rule(from_port=80, ip_protocol="tcp",
to_port=8080, parent_group_id=2,
cidr="0.0.0.0/0", group_id=1)
self._assert_default_headers_in_request(HTTPretty.last_request)
self.assertEqual(200, actual_response.status_code)
self.assertEqual(HTTPretty.last_request.body, expected_request_body)
self.assertEqual(self.mock_response._get_sec_group_rule(),
actual_response.content)
if __name__ == '__main__':
unittest.main()

View File

@@ -24,7 +24,7 @@ class QuotaRequestsTest(unittest.TestCase):
def test_serialize_host_update_request_to_json(self):
quota_obj = UpdateQuotaRequest(security_groups=45)
json_serialized_quota = quota_obj.serialize("json")
expected_json = '{"quota_set": {"security_groups": 45}}'
expected_json = '{"quota_set": {"security_group_rules": 45}}'
self.assertEqual(json_serialized_quota, expected_json)
def test_serialize_host_update_request_to_xml(self):
@@ -32,7 +32,7 @@ class QuotaRequestsTest(unittest.TestCase):
xml_serialized_quota = quota_obj.serialize("xml")
expected_xml = '<?xml version=\'1.0\' encoding=\'UTF-8\'?>' \
'<quota_set id="fake_tenant">' \
'<security_groups>45</security_groups>' \
'<security_group_rules>45</security_group_rules>' \
'</quota_set>'
self.assertEqual(xml_serialized_quota, expected_xml)

View File

@@ -52,7 +52,7 @@ class QuotaDomainJSONTest(unittest.TestCase, QuotaDomainTest):
'"metadata_items": 128,' \
'"ram": 51200,' \
'"security_group_rules": 20,' \
'"security_groups": 10}}'
'"security_group_rules": 10}}'
cls.quota = Quota.deserialize(cls.quota_json, "json")
@@ -64,15 +64,17 @@ class QuotaDomainXMLTest(unittest.TestCase, QuotaDomainTest):
'<quota_set id="fake_tenant">' \
'<cores>20</cores>' \
'<floating_ips>10</floating_ips>' \
'<injected_file_content_bytes>10240</injected_file_content_bytes>' \
'<injected_file_path_bytes>255</injected_file_path_bytes>' \
'<injected_file_content_bytes>10240' \
'</injected_file_content_bytes>' \
'<injected_file_path_bytes>255' \
'</injected_file_path_bytes>' \
'<injected_files>5</injected_files>' \
'<instances>10</instances>' \
'<key_pairs>100</key_pairs>' \
'<metadata_items>128</metadata_items>' \
'<ram>51200</ram>' \
'<security_group_rules>20</security_group_rules>' \
'<security_groups>10</security_groups>' \
'<security_group_rules>10</security_group_rules>' \
'</quota_set>'
cls.quota = Quota.deserialize(cls.quota_xml, "xml")

View File

@@ -0,0 +1,15 @@
"""
Copyright 2013 Rackspace
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""

View File

@@ -0,0 +1,63 @@
"""
Copyright 2013 Rackspace
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
import unittest2 as unittest
from cloudcafe.compute.extensions.security_groups_api.models.\
requests import CreateSecurityGroupRule
class CreateSecurityGroupRuleRequestTest(unittest.TestCase):
def test_serialize_create_security_group_rule_request_to_json(self):
create_sec_group_rule_obj = CreateSecurityGroupRule(ip_protocol="tcp",
from_port=80,
to_port=8080,
cidr="0.0.0.0/0",
group_id=1,
parent_group_id=2)
json_serialized_obj = create_sec_group_rule_obj.serialize("json")
print json_serialized_obj
expected_json = '{"security_group_rule":' \
' {"from_port": 80,' \
' "ip_protocol": "tcp",' \
' "to_port": 8080,' \
' "parent_group_id": 2,' \
' "cidr": "0.0.0.0/0",' \
' "group_id": 1}}'
self.assertEqual(json_serialized_obj, expected_json)
def test_serialize_host_update_request_to_xml(self):
create_sec_group_rule_obj = CreateSecurityGroupRule(ip_protocol="tcp",
from_port=80,
to_port=8080,
cidr="0.0.0.0/0",
group_id=1,
parent_group_id=2)
xml_serialized_obj = create_sec_group_rule_obj.serialize("xml")
expected_xml = '<?xml version=\'1.0\' encoding=\'UTF-8\'?>' \
'<security_group_rule>' \
'<from_port>80</from_port>' \
'<ip_protocol>tcp</ip_protocol>' \
'<to_port>8080</to_port>' \
'<parent_group_id>2</parent_group_id>' \
'<cidr>0.0.0.0/0</cidr>' \
'<group_id>1</group_id>' \
'</security_group_rule>'
self.assertEqual(xml_serialized_obj, expected_xml)
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,84 @@
"""
Copyright 2013 Rackspace
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
import unittest2 as unittest
from cloudcafe.compute.extensions.security_groups_api.models.\
security_group_rule import SecurityGroupRule
class SecurityGroupRuleDomainTest(object):
def test_security_group_rule_attributes(self):
self.assertEqual(str(self.sec_group_rule.from_port), '80')
self.assertEqual(str(self.sec_group_rule.to_port), '8080')
self.assertEqual(self.sec_group_rule.ip_protocol, 'tcp')
self.assertEqual(self.sec_group_rule.id,
'bf57c853-cdf2-4c99-9f9a-79b3e9dc13a8')
self.assertEqual(self.sec_group_rule.parent_group_id,
'b32c047d-5efc-42ab-8476-3ac9f3681af2')
self.assertEqual(self.sec_group_rule.ip_range.cidr, '0.0.0.0/0')
class SecurityGroupRuleDomainJSONTest(unittest.TestCase,
SecurityGroupRuleDomainTest):
@classmethod
def setUpClass(cls):
cls.sec_group_rule_json = '{"security_group_rule":' \
' {"from_port": 80,' \
'"group": {},' \
'"ip_protocol": "tcp",' \
'"to_port": 8080,' \
'"parent_group_id":' \
' "b32c047d-5efc-42ab-8476-3ac9f3681af2",' \
'"ip_range": {"cidr": "0.0.0.0/0"},' \
'"id":' \
' "bf57c853-cdf2-4c99-9f9a-79b3e9dc13a8"}}'
cls.sec_group_rule = SecurityGroupRule.\
deserialize(cls.sec_group_rule_json, "json")
class SecurityGroupRuleDomainXMLTest(unittest.TestCase,
SecurityGroupRuleDomainTest):
@classmethod
def setUpClass(cls):
cls.sec_group_rule_xml = '<?xml version="1.0" encoding="UTF-8"?>' \
'<security_group_rule ' \
'xmlns=' \
'"http://docs.openstack.org/' \
'compute/api/v1.1"' \
'parent_group_id=' \
'"b32c047d-5efc-42ab-8476-3ac9f3681af2" ' \
'id=' \
'"bf57c853-cdf2-4c99-9f9a-79b3e9dc13a8">' \
'<ip_protocol>tcp</ip_protocol>' \
'<from_port>80</from_port>' \
'<to_port>8080</to_port>' \
'<group>' \
'<name>None</name>' \
'<tenant_id>None</tenant_id>' \
'</group>' \
'<ip_range>' \
'<cidr>0.0.0.0/0</cidr>' \
'</ip_range>' \
'</security_group_rule>'
cls.sec_group_rule = SecurityGroupRule.\
deserialize(cls.sec_group_rule_xml, "xml")
if __name__ == '__main__':
unittest.main()