[issue #1720] Add support for AWS Organizations
added exception handling in class OrganizationsBackend
This commit is contained in:
parent
40e422b74d
commit
05928b1497
@ -3147,7 +3147,7 @@
|
||||
- [ ] update_server
|
||||
- [ ] update_server_engine_attributes
|
||||
|
||||
## organizations - 28% implemented
|
||||
## organizations - 30% implemented
|
||||
- [ ] accept_handshake
|
||||
- [ ] attach_policy
|
||||
- [ ] cancel_handshake
|
||||
@ -3176,7 +3176,7 @@
|
||||
- [X] list_accounts
|
||||
- [X] list_accounts_for_parent
|
||||
- [ ] list_aws_service_access_for_organization
|
||||
- [ ] list_children
|
||||
- [X] list_children
|
||||
- [ ] list_create_account_status
|
||||
- [ ] list_handshakes_for_account
|
||||
- [ ] list_handshakes_for_organization
|
||||
|
@ -112,7 +112,7 @@ It gets even better! Moto isn't just for Python code and it isn't just for S3. L
|
||||
|------------------------------------------------------------------------------|
|
||||
| KMS | @mock_kms | basic endpoints done |
|
||||
|------------------------------------------------------------------------------|
|
||||
| Organizations | @mock_organizations | some endpoints done |
|
||||
| Organizations | @mock_organizations | some core endpoints done |
|
||||
|------------------------------------------------------------------------------|
|
||||
| Polly | @mock_polly | all endpoints done |
|
||||
|------------------------------------------------------------------------------|
|
||||
|
@ -4,6 +4,7 @@ import datetime
|
||||
import re
|
||||
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
from moto.core.exceptions import RESTError
|
||||
from moto.core.utils import unix_time
|
||||
from moto.organizations import utils
|
||||
|
||||
@ -168,13 +169,31 @@ class OrganizationsBackend(BaseBackend):
|
||||
self.ou.append(new_ou)
|
||||
return new_ou.describe()
|
||||
|
||||
def get_organizational_unit_by_id(self, ou_id):
|
||||
ou = next((ou for ou in self.ou if ou.id == ou_id), None)
|
||||
if ou is None:
|
||||
raise RESTError(
|
||||
'OrganizationalUnitNotFoundException',
|
||||
"You specified an organizational unit that doesn't exist."
|
||||
)
|
||||
return ou
|
||||
|
||||
def validate_parent_id(self, parent_id):
|
||||
try:
|
||||
self.get_organizational_unit_by_id(parent_id)
|
||||
except RESTError as e:
|
||||
raise RESTError(
|
||||
'ParentNotFoundException',
|
||||
"You specified parent that doesn't exist."
|
||||
)
|
||||
return parent_id
|
||||
|
||||
def describe_organizational_unit(self, **kwargs):
|
||||
ou = [
|
||||
ou for ou in self.ou if ou.id == kwargs['OrganizationalUnitId']
|
||||
].pop(0)
|
||||
ou = self.get_organizational_unit_by_id(kwargs['OrganizationalUnitId'])
|
||||
return ou.describe()
|
||||
|
||||
def list_organizational_units_for_parent(self, **kwargs):
|
||||
parent_id = self.validate_parent_id(kwargs['ParentId'])
|
||||
return dict(
|
||||
OrganizationalUnits=[
|
||||
{
|
||||
@ -183,7 +202,7 @@ class OrganizationsBackend(BaseBackend):
|
||||
'Name': ou.name,
|
||||
}
|
||||
for ou in self.ou
|
||||
if ou.parent_id == kwargs['ParentId']
|
||||
if ou.parent_id == parent_id
|
||||
]
|
||||
)
|
||||
|
||||
@ -192,11 +211,20 @@ class OrganizationsBackend(BaseBackend):
|
||||
self.accounts.append(new_account)
|
||||
return new_account.create_account_status
|
||||
|
||||
def describe_account(self, **kwargs):
|
||||
account = [
|
||||
def get_account_by_id(self, account_id):
|
||||
account = next((
|
||||
account for account in self.accounts
|
||||
if account.id == kwargs['AccountId']
|
||||
].pop(0)
|
||||
if account.id == account_id
|
||||
), None)
|
||||
if account is None:
|
||||
raise RESTError(
|
||||
'AccountNotFoundException',
|
||||
"You specified an account that doesn't exist."
|
||||
)
|
||||
return account
|
||||
|
||||
def describe_account(self, **kwargs):
|
||||
account = self.get_account_by_id(kwargs['AccountId'])
|
||||
return account.describe()
|
||||
|
||||
def list_accounts(self):
|
||||
@ -205,35 +233,27 @@ class OrganizationsBackend(BaseBackend):
|
||||
)
|
||||
|
||||
def list_accounts_for_parent(self, **kwargs):
|
||||
parent_id = self.validate_parent_id(kwargs['ParentId'])
|
||||
return dict(
|
||||
Accounts=[
|
||||
account.describe()['Account']
|
||||
for account in self.accounts
|
||||
if account.parent_id == kwargs['ParentId']
|
||||
if account.parent_id == parent_id
|
||||
]
|
||||
)
|
||||
|
||||
def move_account(self, **kwargs):
|
||||
new_parent_id = kwargs['DestinationParentId']
|
||||
all_parent_id = [parent.id for parent in self.ou]
|
||||
account = [
|
||||
account for account in self.accounts
|
||||
if account.id == kwargs['AccountId']
|
||||
].pop(0)
|
||||
assert new_parent_id in all_parent_id
|
||||
assert account.parent_id == kwargs['SourceParentId']
|
||||
new_parent_id = self.validate_parent_id(kwargs['DestinationParentId'])
|
||||
self.validate_parent_id(kwargs['SourceParentId'])
|
||||
account = self.get_account_by_id(kwargs['AccountId'])
|
||||
index = self.accounts.index(account)
|
||||
self.accounts[index].parent_id = new_parent_id
|
||||
|
||||
def list_parents(self, **kwargs):
|
||||
if re.compile(r'[0-9]{12}').match(kwargs['ChildId']):
|
||||
obj_list = self.accounts
|
||||
child_object = self.get_account_by_id(kwargs['ChildId'])
|
||||
else:
|
||||
obj_list = self.ou
|
||||
parent_id = [
|
||||
obj.parent_id for obj in obj_list
|
||||
if obj.id == kwargs['ChildId']
|
||||
].pop(0)
|
||||
child_object = self.get_organizational_unit_by_id(kwargs['ChildId'])
|
||||
return dict(
|
||||
Parents=[
|
||||
{
|
||||
@ -241,17 +261,21 @@ class OrganizationsBackend(BaseBackend):
|
||||
'Type': ou.type,
|
||||
}
|
||||
for ou in self.ou
|
||||
if ou.id == parent_id
|
||||
if ou.id == child_object.parent_id
|
||||
]
|
||||
)
|
||||
|
||||
def list_children(self, **kwargs):
|
||||
parent_id = self.validate_parent_id(kwargs['ParentId'])
|
||||
if kwargs['ChildType'] == 'ACCOUNT':
|
||||
obj_list = self.accounts
|
||||
elif kwargs['ChildType'] == 'ORGANIZATIONAL_UNIT':
|
||||
obj_list = self.ou
|
||||
else:
|
||||
raise ValueError
|
||||
raise RESTError(
|
||||
'InvalidInputException',
|
||||
'You specified an invalid value.'
|
||||
)
|
||||
return dict(
|
||||
Children=[
|
||||
{
|
||||
@ -259,7 +283,7 @@ class OrganizationsBackend(BaseBackend):
|
||||
'Type': kwargs['ChildType'],
|
||||
}
|
||||
for obj in obj_list
|
||||
if obj.parent_id == kwargs['ParentId']
|
||||
if obj.parent_id == parent_id
|
||||
]
|
||||
)
|
||||
|
||||
|
@ -2,9 +2,11 @@ from __future__ import unicode_literals
|
||||
|
||||
import boto3
|
||||
import sure # noqa
|
||||
import yaml
|
||||
from botocore.exceptions import ClientError
|
||||
from nose.tools import assert_raises
|
||||
|
||||
from moto import mock_organizations
|
||||
from moto.organizations import utils
|
||||
from .organizations_test_utils import (
|
||||
validate_organization,
|
||||
validate_roots,
|
||||
@ -67,6 +69,20 @@ def test_describe_organizational_unit():
|
||||
validate_organizational_unit(org, response)
|
||||
|
||||
|
||||
@mock_organizations
|
||||
def test_describe_organizational_unit_exception():
|
||||
client = boto3.client('organizations', region_name='us-east-1')
|
||||
org = client.create_organization(FeatureSet='ALL')['Organization']
|
||||
with assert_raises(ClientError) as e:
|
||||
response = client.describe_organizational_unit(
|
||||
OrganizationalUnitId=utils.make_random_root_id()
|
||||
)
|
||||
ex = e.exception
|
||||
ex.operation_name.should.equal('DescribeOrganizationalUnit')
|
||||
ex.response['Error']['Code'].should.equal('400')
|
||||
ex.response['Error']['Message'].should.contain('OrganizationalUnitNotFoundException')
|
||||
|
||||
|
||||
@mock_organizations
|
||||
def test_list_organizational_units_for_parent():
|
||||
client = boto3.client('organizations', region_name='us-east-1')
|
||||
@ -81,6 +97,19 @@ def test_list_organizational_units_for_parent():
|
||||
validate_organizational_unit(org, dict(OrganizationalUnit=ou))
|
||||
|
||||
|
||||
@mock_organizations
|
||||
def test_list_organizational_units_for_parent_exception():
|
||||
client = boto3.client('organizations', region_name='us-east-1')
|
||||
with assert_raises(ClientError) as e:
|
||||
response = client.list_organizational_units_for_parent(
|
||||
ParentId=utils.make_random_root_id()
|
||||
)
|
||||
ex = e.exception
|
||||
ex.operation_name.should.equal('ListOrganizationalUnitsForParent')
|
||||
ex.response['Error']['Code'].should.equal('400')
|
||||
ex.response['Error']['Message'].should.contain('ParentNotFoundException')
|
||||
|
||||
|
||||
# Accounts
|
||||
mockname = 'mock-account'
|
||||
mockdomain = 'moto-example.org'
|
||||
@ -111,6 +140,17 @@ def test_describe_account():
|
||||
response['Account']['Email'].should.equal(mockemail)
|
||||
|
||||
|
||||
@mock_organizations
|
||||
def test_describe_account_exception():
|
||||
client = boto3.client('organizations', region_name='us-east-1')
|
||||
with assert_raises(ClientError) as e:
|
||||
response = client.describe_account(AccountId=utils.make_random_account_id())
|
||||
ex = e.exception
|
||||
ex.operation_name.should.equal('DescribeAccount')
|
||||
ex.response['Error']['Code'].should.equal('400')
|
||||
ex.response['Error']['Message'].should.contain('AccountNotFoundException')
|
||||
|
||||
|
||||
@mock_organizations
|
||||
def test_list_accounts():
|
||||
client = boto3.client('organizations', region_name='us-east-1')
|
||||
@ -211,7 +251,7 @@ def test_list_parents_for_accounts():
|
||||
|
||||
|
||||
@mock_organizations
|
||||
def test_list_chidlren():
|
||||
def test_list_children():
|
||||
client = boto3.client('organizations', region_name='us-east-1')
|
||||
org = client.create_organization(FeatureSet='ALL')['Organization']
|
||||
root_id = client.list_roots()['Roots'][0]['Id']
|
||||
@ -244,3 +284,28 @@ def test_list_chidlren():
|
||||
response03['Children'][0]['Type'].should.equal('ACCOUNT')
|
||||
response04['Children'][0]['Id'].should.equal(ou02_id)
|
||||
response04['Children'][0]['Type'].should.equal('ORGANIZATIONAL_UNIT')
|
||||
|
||||
|
||||
@mock_organizations
|
||||
def test_list_children_exception():
|
||||
client = boto3.client('organizations', region_name='us-east-1')
|
||||
org = client.create_organization(FeatureSet='ALL')['Organization']
|
||||
root_id = client.list_roots()['Roots'][0]['Id']
|
||||
with assert_raises(ClientError) as e:
|
||||
response = client.list_children(
|
||||
ParentId=utils.make_random_root_id(),
|
||||
ChildType='ACCOUNT'
|
||||
)
|
||||
ex = e.exception
|
||||
ex.operation_name.should.equal('ListChildren')
|
||||
ex.response['Error']['Code'].should.equal('400')
|
||||
ex.response['Error']['Message'].should.contain('ParentNotFoundException')
|
||||
with assert_raises(ClientError) as e:
|
||||
response = client.list_children(
|
||||
ParentId=root_id,
|
||||
ChildType='BLEE'
|
||||
)
|
||||
ex = e.exception
|
||||
ex.operation_name.should.equal('ListChildren')
|
||||
ex.response['Error']['Code'].should.equal('400')
|
||||
ex.response['Error']['Message'].should.contain('InvalidInputException')
|
||||
|
Loading…
Reference in New Issue
Block a user