Implement DescribeAccountAttributes action
Change-Id: I2e67e88f5e804fc400109c762ca9b9be1a8f930e
This commit is contained in:
parent
c754004c21
commit
7377e3f7d9
@ -16,6 +16,7 @@ from oslo.config import cfg
|
||||
|
||||
from ec2api.api import clients
|
||||
from ec2api.api import common
|
||||
from ec2api import exception
|
||||
from ec2api.openstack.common import log as logging
|
||||
from ec2api import utils
|
||||
|
||||
@ -49,13 +50,23 @@ CONF = cfg.CONF
|
||||
CONF.register_opts(availability_zone_opts)
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
"""Availability zones and regions related API implementation
|
||||
"""Availability zones, regions, account attributes related API implementation
|
||||
"""
|
||||
# TODO(ft): implement messages, regionName AvailabilityZone properties
|
||||
# TODO(ft): implement vpc-max-security-groups-per-interface, max-elastic-ips,
|
||||
# vpc-max-elastic-ips Account Attributes
|
||||
|
||||
|
||||
Validator = common.Validator
|
||||
|
||||
|
||||
def get_account_attribute_engine():
|
||||
if CONF.full_vpc_support:
|
||||
return AccountAttributeEngineNeutron()
|
||||
else:
|
||||
return AccountAttributeEngineNova()
|
||||
|
||||
|
||||
class AvailabilityZoneDescriber(common.UniversalDescriber):
|
||||
|
||||
KIND = 'az'
|
||||
@ -120,6 +131,29 @@ def describe_regions(context, region_name=None, filter=None):
|
||||
return {'regionInfo': regions}
|
||||
|
||||
|
||||
def describe_account_attributes(context, attribute_name=None):
|
||||
def get_max_instances():
|
||||
nova = clients.nova(context)
|
||||
quotas = nova.quotas.get(context.project_id, context.user_id)
|
||||
return quotas.instances
|
||||
|
||||
attribute_getters = {
|
||||
'supported-platforms': (
|
||||
account_attribute_engine.get_supported_platforms),
|
||||
'default-vpc': account_attribute_engine.get_default_vpc,
|
||||
'max-instances': get_max_instances,
|
||||
}
|
||||
|
||||
formatted_attributes = []
|
||||
for attribute in (attribute_name or attribute_getters):
|
||||
if attribute not in attribute_getters:
|
||||
raise exception.InvalidParameter(name=attribute)
|
||||
formatted_attributes.append(
|
||||
_format_account_attribute(attribute,
|
||||
attribute_getters[attribute]()))
|
||||
return {'accountAttributeSet': formatted_attributes}
|
||||
|
||||
|
||||
def _format_availability_zone(zone):
|
||||
return {'zoneName': zone.zoneName,
|
||||
'zoneState': ('available'
|
||||
@ -128,6 +162,13 @@ def _format_availability_zone(zone):
|
||||
}
|
||||
|
||||
|
||||
def _format_account_attribute(attribute, value):
|
||||
if not isinstance(value, list):
|
||||
value = [value]
|
||||
return {'attributeName': attribute,
|
||||
'attributeValueSet': [{'attributeValue': val} for val in value]}
|
||||
|
||||
|
||||
# NOTE(Alex): Openstack extension, AWS-incompability
|
||||
# The whole function and its result is incompatible with AWS.
|
||||
|
||||
@ -152,3 +193,24 @@ def _describe_verbose(context):
|
||||
values['updated_at']))})
|
||||
|
||||
return {'availabilityZoneInfo': formatted_availability_zones}
|
||||
|
||||
|
||||
class AccountAttributeEngineNeutron(object):
|
||||
|
||||
def get_supported_platforms(self):
|
||||
return ['EC2', 'VPC']
|
||||
|
||||
def get_default_vpc(self):
|
||||
return 'none'
|
||||
|
||||
|
||||
class AccountAttributeEngineNova(object):
|
||||
|
||||
def get_supported_platforms(self):
|
||||
return ['EC2']
|
||||
|
||||
def get_default_vpc(self):
|
||||
return 'none'
|
||||
|
||||
|
||||
account_attribute_engine = get_account_attribute_engine()
|
||||
|
@ -320,7 +320,7 @@ class CloudController(object):
|
||||
@module_and_param_types(security_group, 'sg_id',
|
||||
'security_group_str', 'dummy')
|
||||
def revoke_security_group_ingress(self, context, group_id=None,
|
||||
group_name=None, ip_permissions=None):
|
||||
group_name=None, ip_permissions=None):
|
||||
"""Removes one or more ingress rules from a security group.
|
||||
|
||||
Args:
|
||||
@ -357,7 +357,7 @@ class CloudController(object):
|
||||
|
||||
@module_and_param_types(security_group, 'sg_id', 'dummy')
|
||||
def revoke_security_group_egress(self, context, group_id,
|
||||
ip_permissions=None):
|
||||
ip_permissions=None):
|
||||
"""Removes one or more egress rules from a security group for EC2-VPC.
|
||||
|
||||
Args:
|
||||
@ -676,6 +676,23 @@ class CloudController(object):
|
||||
Specified regions.
|
||||
"""
|
||||
|
||||
@module_and_param_types(availability_zone, 'strs')
|
||||
def describe_account_attributes(self, context, attribute_name=None):
|
||||
"""Describes attributes of your EC2 account.
|
||||
|
||||
Args:
|
||||
context (RequestContext): The request context.
|
||||
attribute_name (list of str): One or more account attribute names.
|
||||
The following are the supported account attributes:
|
||||
supported-platforms | default-vpc | max-instances |
|
||||
vpc-max-security-groups-per-interface (unsupported now) |
|
||||
max-elastic-ips (unsupported now) |
|
||||
vpc-max-elastic-ips (unsupported now)
|
||||
|
||||
Returns:
|
||||
Information about one or more account attributes.
|
||||
"""
|
||||
|
||||
@module_and_param_types(instance, 'i_id')
|
||||
def get_password_data(self, context, instance_id):
|
||||
"""Retrieves the encrypted administrator password for Windows instance.
|
||||
@ -1606,8 +1623,8 @@ class VpcCloudController(CloudController):
|
||||
Returns:
|
||||
A list of network interfaces.
|
||||
"""
|
||||
return network_interface.describe_network_interfaces(context,
|
||||
network_interface_id, filter)
|
||||
return network_interface.describe_network_interfaces(
|
||||
context, network_interface_id, filter)
|
||||
|
||||
@module_and_param_types(network_interface, 'eni_id',
|
||||
'str')
|
||||
@ -1635,10 +1652,10 @@ class VpcCloudController(CloudController):
|
||||
'bool',
|
||||
'sg_ids')
|
||||
def modify_network_interface_attribute(self, context,
|
||||
network_interface_id,
|
||||
description=None,
|
||||
source_dest_check=None,
|
||||
security_group_id=None):
|
||||
network_interface_id,
|
||||
description=None,
|
||||
source_dest_check=None,
|
||||
security_group_id=None):
|
||||
"""Modifies the specified attribute of the specified network interface.
|
||||
|
||||
|
||||
@ -1661,8 +1678,8 @@ class VpcCloudController(CloudController):
|
||||
@module_and_param_types(network_interface, 'eni_id',
|
||||
'str')
|
||||
def reset_network_interface_attribute(self, context,
|
||||
network_interface_id,
|
||||
attribute):
|
||||
network_interface_id,
|
||||
attribute):
|
||||
"""Resets the specified attribute of the specified network interface.
|
||||
|
||||
|
||||
|
@ -288,6 +288,10 @@ class MissingParameter(Invalid):
|
||||
msg_fmt = _("The required parameter '%(param)s' is missing")
|
||||
|
||||
|
||||
class InvalidParameter(Invalid):
|
||||
msg_fmt = _("The property '%(name)s' is not valid")
|
||||
|
||||
|
||||
class InvalidParameterValue(Invalid):
|
||||
msg_fmt = _("Value (%(value)s) for parameter %(parameter)s is invalid. "
|
||||
"%(reason)s")
|
||||
|
@ -53,6 +53,7 @@ class ApiTestCase(test_base.BaseTestCase):
|
||||
self.nova_security_group_rules = (
|
||||
nova_mock.return_value.security_group_rules)
|
||||
self.nova_volumes = nova_mock.return_value.volumes
|
||||
self.nova_quotas = nova_mock.return_value.quotas
|
||||
self.addCleanup(nova_patcher.stop)
|
||||
|
||||
glance_patcher = mock.patch('glanceclient.client.Client')
|
||||
|
@ -12,6 +12,9 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import mock
|
||||
|
||||
from ec2api.api import availability_zone
|
||||
from ec2api.tests.unit import base
|
||||
from ec2api.tests.unit import fakes
|
||||
from ec2api.tests.unit import matchers
|
||||
@ -50,3 +53,62 @@ class AvailabilityZoneCase(base.ApiTestCase):
|
||||
self.assertEqual(resp['regionInfo'][0]['regionName'], 'nova')
|
||||
self.assertTrue(resp['regionInfo'][0].get('regionEndpoint')
|
||||
is not None)
|
||||
|
||||
def test_describe_account_attributes(self):
|
||||
self.nova_quotas.get.return_value = mock.Mock(instances=77)
|
||||
|
||||
availability_zone.account_attribute_engine = (
|
||||
availability_zone.AccountAttributeEngineNeutron())
|
||||
resp = self.execute('DescribeAccountAttributes', {})
|
||||
self.assertEqual(200, resp['http_status_code'])
|
||||
self.assertThat(resp['accountAttributeSet'],
|
||||
matchers.ListMatches(
|
||||
[{'attributeName': 'supported-platforms',
|
||||
'attributeValueSet': [
|
||||
{'attributeValue': 'EC2'},
|
||||
{'attributeValue': 'VPC'}]},
|
||||
{'attributeName': 'default-vpc',
|
||||
'attributeValueSet': [
|
||||
{'attributeValue': 'none'}]},
|
||||
{'attributeName': 'max-instances',
|
||||
'attributeValueSet': [
|
||||
{'attributeValue': 77}]}],
|
||||
orderless_lists=True))
|
||||
self.nova_quotas.get.assert_called_once_with(
|
||||
fakes.ID_OS_PROJECT, fakes.ID_OS_USER)
|
||||
|
||||
availability_zone.account_attribute_engine = (
|
||||
availability_zone.AccountAttributeEngineNova())
|
||||
resp = self.execute('DescribeAccountAttributes', {})
|
||||
self.assertEqual(200, resp['http_status_code'])
|
||||
self.assertThat(resp['accountAttributeSet'],
|
||||
matchers.ListMatches(
|
||||
[{'attributeName': 'supported-platforms',
|
||||
'attributeValueSet': [
|
||||
{'attributeValue': 'EC2'}]},
|
||||
{'attributeName': 'default-vpc',
|
||||
'attributeValueSet': [
|
||||
{'attributeValue': 'none'}]},
|
||||
{'attributeName': 'max-instances',
|
||||
'attributeValueSet': [
|
||||
{'attributeValue': 77}]}],
|
||||
orderless_lists=True))
|
||||
|
||||
resp = self.execute('DescribeAccountAttributes',
|
||||
{'AttributeName.1': 'default-vpc',
|
||||
'AttributeName.2': 'max-instances'})
|
||||
self.assertEqual(200, resp['http_status_code'])
|
||||
self.assertThat(resp['accountAttributeSet'],
|
||||
matchers.ListMatches(
|
||||
[{'attributeName': 'default-vpc',
|
||||
'attributeValueSet': [
|
||||
{'attributeValue': 'none'}]},
|
||||
{'attributeName': 'max-instances',
|
||||
'attributeValueSet': [
|
||||
{'attributeValue': 77}]}],
|
||||
orderless_lists=True))
|
||||
|
||||
resp = self.execute('DescribeAccountAttributes',
|
||||
{'AttributeName.1': 'fake'})
|
||||
self.assertEqual(400, resp['http_status_code'])
|
||||
self.assertEqual('InvalidParameter', resp['Error']['Code'])
|
||||
|
Loading…
Reference in New Issue
Block a user