disallow organization deletion when accounts are members, allow removal of accounts from organization (#4773)
This commit is contained in:
parent
3f534119f4
commit
ebe74d2eb0
@ -71,7 +71,7 @@ organizations
|
||||
- [X] list_targets_for_policy
|
||||
- [X] move_account
|
||||
- [X] register_delegated_administrator
|
||||
- [ ] remove_account_from_organization
|
||||
- [X] remove_account_from_organization
|
||||
- [X] tag_resource
|
||||
- [X] untag_resource
|
||||
- [X] update_organizational_unit
|
||||
|
@ -381,6 +381,11 @@ class OrganizationsBackend(BaseBackend):
|
||||
return self.org.describe()
|
||||
|
||||
def delete_organization(self, **kwargs):
|
||||
if [account for account in self.accounts if account.name != "master"]:
|
||||
raise RESTError(
|
||||
"OrganizationNotEmptyException",
|
||||
"To delete an organization you must first remove all member accounts (except the master).",
|
||||
)
|
||||
self._reset()
|
||||
return {}
|
||||
|
||||
@ -885,5 +890,11 @@ class OrganizationsBackend(BaseBackend):
|
||||
else:
|
||||
raise InvalidInputException("You specified an invalid value.")
|
||||
|
||||
def remove_account_from_organization(self, **kwargs):
|
||||
account = self.get_account_by_id(kwargs["AccountId"])
|
||||
for policy in account.attached_policies:
|
||||
policy.attachments.remove(account)
|
||||
self.accounts.remove(account)
|
||||
|
||||
|
||||
organizations_backend = OrganizationsBackend()
|
||||
|
@ -215,3 +215,10 @@ class OrganizationsResponse(BaseResponse):
|
||||
return json.dumps(
|
||||
self.organizations_backend.detach_policy(**self.request_params)
|
||||
)
|
||||
|
||||
def remove_account_from_organization(self):
|
||||
return json.dumps(
|
||||
self.organizations_backend.remove_account_from_organization(
|
||||
**self.request_params
|
||||
)
|
||||
)
|
||||
|
@ -420,6 +420,49 @@ def test_get_paginated_list_create_account_status():
|
||||
validate_create_account_status(createAccountStatus)
|
||||
|
||||
|
||||
@mock_organizations
|
||||
def test_remove_account_from_organization():
|
||||
client = boto3.client("organizations", region_name="us-east-1")
|
||||
client.create_organization(FeatureSet="ALL")["Organization"]
|
||||
create_account_status = client.create_account(
|
||||
AccountName=mockname, Email=mockemail
|
||||
)["CreateAccountStatus"]
|
||||
account_id = create_account_status["AccountId"]
|
||||
|
||||
def created_account_exists(accounts):
|
||||
return any(
|
||||
account
|
||||
for account in accounts
|
||||
if account["Name"] == mockname and account["Email"] == mockemail
|
||||
)
|
||||
|
||||
accounts = client.list_accounts()["Accounts"]
|
||||
assert len(accounts) == 2
|
||||
assert created_account_exists(accounts)
|
||||
client.remove_account_from_organization(AccountId=account_id)
|
||||
accounts = client.list_accounts()["Accounts"]
|
||||
assert len(accounts) == 1
|
||||
assert not created_account_exists(accounts)
|
||||
|
||||
|
||||
@mock_organizations
|
||||
def test_delete_organization_with_existing_account():
|
||||
client = boto3.client("organizations", region_name="us-east-1")
|
||||
client.create_organization(FeatureSet="ALL")
|
||||
create_account_status = client.create_account(
|
||||
Email=mockemail, AccountName=mockname
|
||||
)["CreateAccountStatus"]
|
||||
account_id = create_account_status["AccountId"]
|
||||
with pytest.raises(ClientError) as e:
|
||||
client.delete_organization()
|
||||
e.match("OrganizationNotEmptyException")
|
||||
client.remove_account_from_organization(AccountId=account_id)
|
||||
client.delete_organization()
|
||||
with pytest.raises(ClientError) as e:
|
||||
client.describe_organization()
|
||||
e.match("AWSOrganizationsNotInUseException")
|
||||
|
||||
|
||||
# Service Control Policies
|
||||
policy_doc01 = dict(
|
||||
Version="2012-10-17",
|
||||
|
Loading…
Reference in New Issue
Block a user