Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,32 @@ def enable_organization_policies(self, policy_type='SERVICE_CONTROL_POLICY'): #
def trim_policy_path(policy):
return policy[2:] if policy.startswith('//') else policy

@staticmethod
def is_ou_id(ou_id):
return ou_id[0] in ['r','o']

def get_organization_map(self, org_structure, counter=0):
for name, ou_id in org_structure.copy().items():
# Skip accounts - accounts can't have children
if not Organizations.is_ou_id(ou_id):
continue
# List OUs
for organization_id in [organization_id['Id'] for organization_id in paginator(self.client.list_children, **{"ParentId":ou_id, "ChildType":"ORGANIZATIONAL_UNIT"})]:
if organization_id in org_structure.values() and counter != 0:
continue
ou_name = self.describe_ou_name(organization_id)
trimmed_path = Organizations.trim_policy_path("{0}/{1}".format(name, ou_name))
org_structure[trimmed_path] = organization_id
# List accounts
for account_id in [account_id['Id'] for account_id in paginator(self.client.list_children, **{"ParentId":ou_id, "ChildType":"ACCOUNT"})]:
if account_id in org_structure.values() and counter != 0:
continue
account_name = self.describe_account_name(account_id)
trimmed_path = Organizations.trim_policy_path("{0}/{1}".format(name, account_name))
org_structure[trimmed_path] = account_id
counter = counter + 1
# Counter is greater than 4 here is the conditional as organizations cannot have more than 5 levels of nested OUs
return org_structure if counter > 4 else self.get_organization_map(org_structure, counter)
# Counter is greater than 5 here is the conditional as organizations cannot have more than 5 levels of nested OUs + 1 accounts "level"
return org_structure if counter > 5 else self.get_organization_map(org_structure, counter)

def update_policy(self, content, policy_id):
self.client.update_policy(
Expand Down Expand Up @@ -162,6 +177,16 @@ def describe_ou_name(self, ou_id):
except ClientError as error:
raise RootOUIDError("OU is the Root of the Organization") from error

def describe_account_name(self, account_id):
try:
response = self.client.describe_account(
AccountId=account_id
)
return response['Account']['Name']
except ClientError as error:
LOGGER.error('Failed to retrieve account name for account ID %s', account_id)
raise error

@staticmethod
def determine_ou_path(ou_path, ou_child_name):
return '{0}/{1}'.format(ou_path,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,16 @@
'Name': 'some_ou_name'
}
}

describe_account = {
'Account': {
'Id': 'some_account_id',
'Arn': 'string',
'Email': 'some_account_email',
'Name': 'some_account_name',
'Status': 'ACTIVE',
'JoinedMethod': 'INVITED'
# Excluding JoinedTimestamp to avoid
# adding dependency on datetime
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ def test_describe_ou_name(cls):
assert cls.describe_ou_name('some_ou_id') == 'some_ou_name'


def test_describe_account_name(cls):
cls.client = Mock()
cls.client.describe_account.return_value = stub_organizations.describe_account
assert cls.describe_account_name('some_account_id') == 'some_account_name'


def test_determine_ou_path(cls):
assert cls.determine_ou_path(
'some_path', 'some_ou_name'
Expand Down