Greengrass Implement group and role associate APIs (#5278)

This commit is contained in:
cm-iwata 2022-07-01 20:18:57 +09:00 committed by GitHub
parent 6282e5124d
commit 01d0141da8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 173 additions and 0 deletions

View File

@ -361,10 +361,25 @@ class FakeGroupVersion(BaseModel):
return obj
class FakeAssociatedRole(BaseModel):
def __init__(self, role_arn):
self.role_arn = role_arn
self.associated_at = datetime.utcnow()
def to_dict(self, include_detail=False):
obj = {"AssociatedAt": iso_8601_datetime_with_milliseconds(self.associated_at)}
if include_detail:
obj["RoleArn"] = self.role_arn
return obj
class GreengrassBackend(BaseBackend):
def __init__(self, region_name, account_id):
super().__init__(region_name, account_id)
self.groups = OrderedDict()
self.group_role_associations = OrderedDict()
self.group_versions = OrderedDict()
self.core_definitions = OrderedDict()
self.core_definition_versions = OrderedDict()
@ -1066,5 +1081,28 @@ class GreengrassBackend(BaseBackend):
return self.group_versions[group_id][group_version_id]
def associate_role_to_group(self, group_id, role_arn):
# I don't know why, AssociateRoleToGroup does not check specified group is exists
# So, this API allows any group id such as "a"
associated_role = FakeAssociatedRole(role_arn)
self.group_role_associations[group_id] = associated_role
return associated_role
def get_associated_role(self, group_id):
if group_id not in self.group_role_associations:
raise GreengrassClientError(
"404", "You need to attach an IAM role to this deployment group."
)
return self.group_role_associations[group_id]
def disassociate_role_from_group(self, group_id):
if group_id not in self.group_role_associations:
return
del self.group_role_associations[group_id]
greengrass_backends = BackendDict(GreengrassBackend, "greengrass")

View File

@ -1,5 +1,7 @@
from datetime import datetime
import json
from moto.core.utils import iso_8601_datetime_with_milliseconds
from moto.core.responses import BaseResponse
from .models import greengrass_backends
@ -677,3 +679,50 @@ class GreengrassResponse(BaseResponse):
group_version_id=group_version_id,
)
return 200, {"status": 200}, json.dumps(res.to_dict(include_detail=True))
def role(self, request, full_url, headers):
self.setup_class(request, full_url, headers)
if self.method == "PUT":
return self.associate_role_to_group()
if self.method == "GET":
return self.get_associated_role()
if self.method == "DELETE":
return self.disassociate_role_from_group()
def associate_role_to_group(self):
group_id = self.path.split("/")[-2]
role_arn = self._get_param("RoleArn")
res = self.greengrass_backend.associate_role_to_group(
group_id=group_id,
role_arn=role_arn,
)
return 200, {"status": 200}, json.dumps(res.to_dict())
def get_associated_role(self):
group_id = self.path.split("/")[-2]
res = self.greengrass_backend.get_associated_role(
group_id=group_id,
)
return 200, {"status": 200}, json.dumps(res.to_dict(include_detail=True))
def disassociate_role_from_group(self):
group_id = self.path.split("/")[-2]
self.greengrass_backend.disassociate_role_from_group(
group_id=group_id,
)
return (
200,
{"status": 200},
json.dumps(
{
"DisassociatedAt": iso_8601_datetime_with_milliseconds(
datetime.utcnow()
)
}
),
)

View File

@ -31,6 +31,7 @@ url_paths = {
"{0}/greengrass/definition/resources/(?P<definition_id>[^/]+)/versions/(?P<definition_version_id>[^/]+)/?$": response.resource_definition_version,
"{0}/greengrass/groups$": response.groups,
"{0}/greengrass/groups/(?P<group_id>[^/]+)/?$": response.group,
"{0}/greengrass/groups/(?P<group_id>[^/]+)/role$": response.role,
"{0}/greengrass/groups/(?P<group_id>[^/]+)/versions$": response.group_versions,
"{0}/greengrass/groups/(?P<group_id>[^/]+)/versions/(?P<group_version_id>[^/]+)/?$": response.group_version,
}

View File

@ -473,3 +473,88 @@ def test_get_group_version_with_invalid_version_id():
f"Version {invalid_group_ver_id} of Group Definition {group_id} does not exist."
)
ex.value.response["Error"]["Code"].should.equal("VersionNotFoundException")
@freezegun.freeze_time("2022-06-01 12:00:00")
@mock_greengrass
def test_associate_role_to_group():
client = boto3.client("greengrass", region_name="ap-northeast-1")
res = client.associate_role_to_group(
GroupId="abc002c8-1093-485e-9324-3baadf38e582",
RoleArn=f"arn:aws:iam::{ACCOUNT_ID}:role/greengrass-role",
)
res.should.have.key("AssociatedAt")
res["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
@freezegun.freeze_time("2022-06-01 12:00:00")
@mock_greengrass
def test_get_associated_role():
client = boto3.client("greengrass", region_name="ap-northeast-1")
group_id = "abc002c8-1093-485e-9324-3baadf38e582"
role_arn = f"arn:aws:iam::{ACCOUNT_ID}:role/greengrass-role"
client.associate_role_to_group(GroupId=group_id, RoleArn=role_arn)
res = client.get_associated_role(GroupId=group_id)
res.should.have.key("AssociatedAt")
res.should.have.key("RoleArn").should.equal(role_arn)
res["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
if not TEST_SERVER_MODE:
res["AssociatedAt"].should.equal("2022-06-01T12:00:00.000Z")
@mock_greengrass
def test_get_associated_role_with_invalid_id():
client = boto3.client("greengrass", region_name="ap-northeast-1")
with pytest.raises(ClientError) as ex:
client.get_associated_role(GroupId="abc002c8-1093-485e-9324-3baadf38e582")
ex.value.response["Error"]["Message"].should.equal(
"You need to attach an IAM role to this deployment group."
)
ex.value.response["Error"]["Code"].should.equal("404")
@freezegun.freeze_time("2022-06-01 12:00:00")
@mock_greengrass
def test_disassociate_role_from_group():
client = boto3.client("greengrass", region_name="ap-northeast-1")
group_id = "abc002c8-1093-485e-9324-3baadf38e582"
role_arn = f"arn:aws:iam::{ACCOUNT_ID}:role/greengrass-role"
client.associate_role_to_group(GroupId=group_id, RoleArn=role_arn)
client.get_associated_role(GroupId=group_id)
res = client.disassociate_role_from_group(GroupId=group_id)
res.should.have.key("DisassociatedAt")
res["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
if not TEST_SERVER_MODE:
res["DisassociatedAt"].should.equal("2022-06-01T12:00:00.000Z")
with pytest.raises(ClientError) as ex:
client.get_associated_role(GroupId=group_id)
ex.value.response["Error"]["Message"].should.equal(
"You need to attach an IAM role to this deployment group."
)
ex.value.response["Error"]["Code"].should.equal("404")
@freezegun.freeze_time("2022-06-01 12:00:00")
@mock_greengrass
def test_disassociate_role_from_group_with_none_exists_group_id():
client = boto3.client("greengrass", region_name="ap-northeast-1")
group_id = "abc002c8-1093-485e-9324-3baadf38e582"
res = client.disassociate_role_from_group(GroupId=group_id)
res.should.have.key("DisassociatedAt")
res["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
if not TEST_SERVER_MODE:
res["DisassociatedAt"].should.equal("2022-06-01T12:00:00.000Z")