Greengrass Implement Deployments APIs (#5281)
This commit is contained in:
parent
2c544fe498
commit
c1bdd764c7
@ -27,3 +27,15 @@ class InvalidInputException(GreengrassClientError):
|
|||||||
def __init__(self, msg):
|
def __init__(self, msg):
|
||||||
self.code = 400
|
self.code = 400
|
||||||
super().__init__("InvalidInputException", msg)
|
super().__init__("InvalidInputException", msg)
|
||||||
|
|
||||||
|
|
||||||
|
class MissingCoreException(GreengrassClientError):
|
||||||
|
def __init__(self, msg):
|
||||||
|
self.code = 400
|
||||||
|
super().__init__("MissingCoreException", msg)
|
||||||
|
|
||||||
|
|
||||||
|
class ResourceNotFoundException(GreengrassClientError):
|
||||||
|
def __init__(self, msg):
|
||||||
|
self.code = 404
|
||||||
|
super().__init__("ResourceNotFoundException", msg)
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import json
|
||||||
import uuid
|
import uuid
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
@ -10,6 +11,8 @@ from .exceptions import (
|
|||||||
IdNotFoundException,
|
IdNotFoundException,
|
||||||
InvalidInputException,
|
InvalidInputException,
|
||||||
InvalidContainerDefinitionException,
|
InvalidContainerDefinitionException,
|
||||||
|
MissingCoreException,
|
||||||
|
ResourceNotFoundException,
|
||||||
VersionNotFoundException,
|
VersionNotFoundException,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -361,6 +364,31 @@ class FakeGroupVersion(BaseModel):
|
|||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
|
||||||
|
class FakeDeployment(BaseModel):
|
||||||
|
def __init__(self, region_name, group_id, group_arn, deployment_type):
|
||||||
|
self.region_name = region_name
|
||||||
|
self.id = str(uuid.uuid4())
|
||||||
|
self.group_id = group_id
|
||||||
|
self.group_arn = group_arn
|
||||||
|
self.created_at_datetime = datetime.utcnow()
|
||||||
|
self.update_at_datetime = datetime.utcnow()
|
||||||
|
self.deployment_status = "InProgress"
|
||||||
|
self.deployment_type = deployment_type
|
||||||
|
self.arn = f"arn:aws:greengrass:{self.region_name}:{get_account_id()}:/greengrass/groups/{self.group_id}/deployments/{self.id}"
|
||||||
|
|
||||||
|
def to_dict(self, include_detail=False):
|
||||||
|
obj = {"DeploymentId": self.id, "DeploymentArn": self.arn}
|
||||||
|
|
||||||
|
if include_detail:
|
||||||
|
obj["CreatedAt"] = iso_8601_datetime_with_milliseconds(
|
||||||
|
self.created_at_datetime
|
||||||
|
)
|
||||||
|
obj["DeploymentType"] = self.deployment_type
|
||||||
|
obj["GroupArn"] = self.group_arn
|
||||||
|
|
||||||
|
return obj
|
||||||
|
|
||||||
|
|
||||||
class FakeAssociatedRole(BaseModel):
|
class FakeAssociatedRole(BaseModel):
|
||||||
def __init__(self, role_arn):
|
def __init__(self, role_arn):
|
||||||
self.role_arn = role_arn
|
self.role_arn = role_arn
|
||||||
@ -375,6 +403,20 @@ class FakeAssociatedRole(BaseModel):
|
|||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
|
||||||
|
class FakeDeploymentStatus(BaseModel):
|
||||||
|
def __init__(self, deployment_type, updated_at, deployment_status="InProgress"):
|
||||||
|
self.deployment_type = deployment_type
|
||||||
|
self.update_at_datetime = updated_at
|
||||||
|
self.deployment_status = deployment_status
|
||||||
|
|
||||||
|
def to_dict(self):
|
||||||
|
return {
|
||||||
|
"DeploymentStatus": self.deployment_status,
|
||||||
|
"DeploymentType": self.deployment_type,
|
||||||
|
"UpdatedAt": iso_8601_datetime_with_milliseconds(self.update_at_datetime),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class GreengrassBackend(BaseBackend):
|
class GreengrassBackend(BaseBackend):
|
||||||
def __init__(self, region_name, account_id):
|
def __init__(self, region_name, account_id):
|
||||||
super().__init__(region_name, account_id)
|
super().__init__(region_name, account_id)
|
||||||
@ -1081,6 +1123,109 @@ class GreengrassBackend(BaseBackend):
|
|||||||
|
|
||||||
return self.group_versions[group_id][group_version_id]
|
return self.group_versions[group_id][group_version_id]
|
||||||
|
|
||||||
|
def create_deployment(
|
||||||
|
self, group_id, group_version_id, deployment_type, deployment_id=None
|
||||||
|
):
|
||||||
|
|
||||||
|
deployment_types = (
|
||||||
|
"NewDeployment",
|
||||||
|
"Redeployment",
|
||||||
|
"ResetDeployment",
|
||||||
|
"ForceResetDeployment",
|
||||||
|
)
|
||||||
|
if deployment_type not in deployment_types:
|
||||||
|
raise InvalidInputException(
|
||||||
|
f"That deployment type is not valid. Please specify one of the following types: {{{','.join(deployment_types)}}}."
|
||||||
|
)
|
||||||
|
if deployment_type == "Redeployment":
|
||||||
|
if deployment_id is None:
|
||||||
|
raise InvalidInputException(
|
||||||
|
"Your request is missing the following required parameter(s): {DeploymentId}."
|
||||||
|
)
|
||||||
|
if deployment_id not in self.deployments:
|
||||||
|
raise InvalidInputException(
|
||||||
|
f"Deployment ID '{deployment_id}' is invalid."
|
||||||
|
)
|
||||||
|
|
||||||
|
if group_id not in self.groups:
|
||||||
|
raise ResourceNotFoundException("That group definition does not exist.")
|
||||||
|
|
||||||
|
if group_version_id not in self.group_versions[group_id]:
|
||||||
|
raise ResourceNotFoundException(
|
||||||
|
f"Version {group_version_id} of Group Definition {group_id} does not exist."
|
||||||
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
self.group_versions[group_id][group_version_id].core_definition_version_arn
|
||||||
|
is None
|
||||||
|
):
|
||||||
|
|
||||||
|
err = {
|
||||||
|
"ErrorDetails": [
|
||||||
|
{
|
||||||
|
"DetailedErrorCode": "GG-303",
|
||||||
|
"DetailedErrorMessage": "You need a Greengrass Core in this Group before you can deploy.",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
raise MissingCoreException(json.dumps(err))
|
||||||
|
group_version_arn = self.group_versions[group_id][group_version_id].arn
|
||||||
|
deployment = FakeDeployment(
|
||||||
|
self.region_name, group_id, group_version_arn, deployment_type
|
||||||
|
)
|
||||||
|
self.deployments[deployment.id] = deployment
|
||||||
|
return deployment
|
||||||
|
|
||||||
|
def list_deployments(self, group_id):
|
||||||
|
|
||||||
|
# ListDeployments API does not check specified group is exists
|
||||||
|
return [
|
||||||
|
deployment
|
||||||
|
for deployment in self.deployments.values()
|
||||||
|
if deployment.group_id == group_id
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_deployment_status(self, group_id, deployment_id):
|
||||||
|
|
||||||
|
if deployment_id not in self.deployments:
|
||||||
|
raise InvalidInputException(f"Deployment '{deployment_id}' does not exist.")
|
||||||
|
|
||||||
|
deployment = self.deployments[deployment_id]
|
||||||
|
|
||||||
|
if deployment.group_id != group_id:
|
||||||
|
raise InvalidInputException(f"Deployment '{deployment_id}' does not exist.")
|
||||||
|
|
||||||
|
return FakeDeploymentStatus(
|
||||||
|
deployment.deployment_type,
|
||||||
|
deployment.update_at_datetime,
|
||||||
|
deployment.deployment_status,
|
||||||
|
)
|
||||||
|
|
||||||
|
def reset_deployments(self, group_id, force=False):
|
||||||
|
|
||||||
|
if group_id not in self.groups:
|
||||||
|
raise ResourceNotFoundException("That Group Definition does not exist.")
|
||||||
|
|
||||||
|
deployment_type = "ForceResetDeployment"
|
||||||
|
if not force:
|
||||||
|
deployments = list(self.deployments.values())
|
||||||
|
reset_error_msg = (
|
||||||
|
f"Group id: {group_id} has not been deployed or has already been reset."
|
||||||
|
)
|
||||||
|
if not deployments:
|
||||||
|
raise ResourceNotFoundException(reset_error_msg)
|
||||||
|
if deployments[-1].deployment_type not in ["NewDeployment", "Redeployment"]:
|
||||||
|
raise ResourceNotFoundException(reset_error_msg)
|
||||||
|
deployment_type = "ResetDeployment"
|
||||||
|
|
||||||
|
group = self.groups[group_id]
|
||||||
|
deployment = FakeDeployment(
|
||||||
|
self.region_name, group_id, group.arn, deployment_type
|
||||||
|
)
|
||||||
|
self.deployments[deployment.id] = deployment
|
||||||
|
return deployment
|
||||||
|
|
||||||
def associate_role_to_group(self, group_id, role_arn):
|
def associate_role_to_group(self, group_id, role_arn):
|
||||||
|
|
||||||
# I don't know why, AssociateRoleToGroup does not check specified group is exists
|
# I don't know why, AssociateRoleToGroup does not check specified group is exists
|
||||||
|
@ -680,6 +680,76 @@ class GreengrassResponse(BaseResponse):
|
|||||||
)
|
)
|
||||||
return 200, {"status": 200}, json.dumps(res.to_dict(include_detail=True))
|
return 200, {"status": 200}, json.dumps(res.to_dict(include_detail=True))
|
||||||
|
|
||||||
|
def deployments(self, request, full_url, headers):
|
||||||
|
self.setup_class(request, full_url, headers)
|
||||||
|
|
||||||
|
if self.method == "POST":
|
||||||
|
return self.create_deployment()
|
||||||
|
|
||||||
|
if self.method == "GET":
|
||||||
|
return self.list_deployments()
|
||||||
|
|
||||||
|
def create_deployment(self):
|
||||||
|
|
||||||
|
group_id = self.path.split("/")[-2]
|
||||||
|
group_version_id = self._get_param("GroupVersionId")
|
||||||
|
deployment_type = self._get_param("DeploymentType")
|
||||||
|
deployment_id = self._get_param("DeploymentId")
|
||||||
|
|
||||||
|
res = self.greengrass_backend.create_deployment(
|
||||||
|
group_id=group_id,
|
||||||
|
group_version_id=group_version_id,
|
||||||
|
deployment_type=deployment_type,
|
||||||
|
deployment_id=deployment_id,
|
||||||
|
)
|
||||||
|
return 200, {"status": 200}, json.dumps(res.to_dict())
|
||||||
|
|
||||||
|
def list_deployments(self):
|
||||||
|
group_id = self.path.split("/")[-2]
|
||||||
|
res = self.greengrass_backend.list_deployments(group_id=group_id)
|
||||||
|
|
||||||
|
deployments = (
|
||||||
|
[]
|
||||||
|
if len(res) == 0
|
||||||
|
else [deployment.to_dict(include_detail=True) for deployment in res]
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
200,
|
||||||
|
{"status": 200},
|
||||||
|
json.dumps({"Deployments": deployments}),
|
||||||
|
)
|
||||||
|
|
||||||
|
def deployment_satus(self, request, full_url, headers):
|
||||||
|
self.setup_class(request, full_url, headers)
|
||||||
|
|
||||||
|
if self.method == "GET":
|
||||||
|
return self.get_deployment_status()
|
||||||
|
|
||||||
|
def get_deployment_status(self):
|
||||||
|
group_id = self.path.split("/")[-4]
|
||||||
|
deployment_id = self.path.split("/")[-2]
|
||||||
|
|
||||||
|
res = self.greengrass_backend.get_deployment_status(
|
||||||
|
group_id=group_id,
|
||||||
|
deployment_id=deployment_id,
|
||||||
|
)
|
||||||
|
return 200, {"status": 200}, json.dumps(res.to_dict())
|
||||||
|
|
||||||
|
def deployments_reset(self, request, full_url, headers):
|
||||||
|
self.setup_class(request, full_url, headers)
|
||||||
|
|
||||||
|
if self.method == "POST":
|
||||||
|
return self.reset_deployments()
|
||||||
|
|
||||||
|
def reset_deployments(self):
|
||||||
|
group_id = self.path.split("/")[-3]
|
||||||
|
|
||||||
|
res = self.greengrass_backend.reset_deployments(
|
||||||
|
group_id=group_id,
|
||||||
|
)
|
||||||
|
return 200, {"status": 200}, json.dumps(res.to_dict())
|
||||||
|
|
||||||
def role(self, request, full_url, headers):
|
def role(self, request, full_url, headers):
|
||||||
self.setup_class(request, full_url, headers)
|
self.setup_class(request, full_url, headers)
|
||||||
|
|
||||||
|
@ -4,10 +4,8 @@ url_bases = [
|
|||||||
r"https?://greengrass\.(.+)\.amazonaws.com",
|
r"https?://greengrass\.(.+)\.amazonaws.com",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
response = GreengrassResponse()
|
response = GreengrassResponse()
|
||||||
|
|
||||||
|
|
||||||
url_paths = {
|
url_paths = {
|
||||||
"{0}/greengrass/definition/cores$": response.core_definitions,
|
"{0}/greengrass/definition/cores$": response.core_definitions,
|
||||||
"{0}/greengrass/definition/cores/(?P<definition_id>[^/]+)/?$": response.core_definition,
|
"{0}/greengrass/definition/cores/(?P<definition_id>[^/]+)/?$": response.core_definition,
|
||||||
@ -33,5 +31,8 @@ url_paths = {
|
|||||||
"{0}/greengrass/groups/(?P<group_id>[^/]+)/?$": response.group,
|
"{0}/greengrass/groups/(?P<group_id>[^/]+)/?$": response.group,
|
||||||
"{0}/greengrass/groups/(?P<group_id>[^/]+)/role$": response.role,
|
"{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$": response.group_versions,
|
||||||
|
"{0}/greengrass/groups/(?P<group_id>[^/]+)/deployments$": response.deployments,
|
||||||
|
"{0}/greengrass/groups/(?P<group_id>[^/]+)/deployments/\\$reset$": response.deployments_reset,
|
||||||
|
"{0}/greengrass/groups/(?P<group_id>[^/]+)/deployments/(?P<group_version_id>[^/]+)/status$": response.deployment_satus,
|
||||||
"{0}/greengrass/groups/(?P<group_id>[^/]+)/versions/(?P<group_version_id>[^/]+)/?$": response.group_version,
|
"{0}/greengrass/groups/(?P<group_id>[^/]+)/versions/(?P<group_version_id>[^/]+)/?$": response.group_version,
|
||||||
}
|
}
|
||||||
|
496
tests/test_greengrass/test_greengrass_deployment.py
Normal file
496
tests/test_greengrass/test_greengrass_deployment.py
Normal file
@ -0,0 +1,496 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
|
import boto3
|
||||||
|
from botocore.client import ClientError
|
||||||
|
import freezegun
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from moto import mock_greengrass
|
||||||
|
from moto.core import get_account_id
|
||||||
|
from moto.settings import TEST_SERVER_MODE
|
||||||
|
|
||||||
|
ACCOUNT_ID = get_account_id()
|
||||||
|
|
||||||
|
|
||||||
|
@mock_greengrass
|
||||||
|
def test_create_deployment():
|
||||||
|
|
||||||
|
client = boto3.client("greengrass", region_name="ap-northeast-1")
|
||||||
|
cores = [
|
||||||
|
{
|
||||||
|
"CertificateArn": f"arn:aws:iot:ap-northeast-1:{ACCOUNT_ID}:cert/36ed61be9c6271ae8da174e29d0e033c06af149d7b21672f3800fe322044554d",
|
||||||
|
"Id": "123456789",
|
||||||
|
"ThingArn": f"arn:aws:iot:ap-northeast-1:{ACCOUNT_ID}:thing/CoreThing",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
create_core_res = client.create_core_definition(
|
||||||
|
InitialVersion={"Cores": cores}, Name="TestCore"
|
||||||
|
)
|
||||||
|
core_def_ver_arn = create_core_res["LatestVersionArn"]
|
||||||
|
|
||||||
|
create_group_res = client.create_group(
|
||||||
|
Name="TestGroup", InitialVersion={"CoreDefinitionVersionArn": core_def_ver_arn}
|
||||||
|
)
|
||||||
|
group_id = create_group_res["Id"]
|
||||||
|
latest_grp_ver = create_group_res["LatestVersion"]
|
||||||
|
|
||||||
|
res = client.create_deployment(
|
||||||
|
GroupId=group_id, GroupVersionId=latest_grp_ver, DeploymentType="NewDeployment"
|
||||||
|
)
|
||||||
|
res.should.have.key("DeploymentArn")
|
||||||
|
res.should.have.key("DeploymentId")
|
||||||
|
res["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_greengrass
|
||||||
|
def test_re_deployment_with_no_deployment_id():
|
||||||
|
|
||||||
|
client = boto3.client("greengrass", region_name="ap-northeast-1")
|
||||||
|
cores = [
|
||||||
|
{
|
||||||
|
"CertificateArn": f"arn:aws:iot:ap-northeast-1:{ACCOUNT_ID}:cert/36ed61be9c6271ae8da174e29d0e033c06af149d7b21672f3800fe322044554d",
|
||||||
|
"Id": "123456789",
|
||||||
|
"ThingArn": f"arn:aws:iot:ap-northeast-1:{ACCOUNT_ID}:thing/CoreThing",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
create_core_res = client.create_core_definition(
|
||||||
|
InitialVersion={"Cores": cores}, Name="TestCore"
|
||||||
|
)
|
||||||
|
core_def_ver_arn = create_core_res["LatestVersionArn"]
|
||||||
|
|
||||||
|
create_group_res = client.create_group(
|
||||||
|
Name="TestGroup", InitialVersion={"CoreDefinitionVersionArn": core_def_ver_arn}
|
||||||
|
)
|
||||||
|
group_id = create_group_res["Id"]
|
||||||
|
latest_grp_ver = create_group_res["LatestVersion"]
|
||||||
|
|
||||||
|
with pytest.raises(ClientError) as ex:
|
||||||
|
client.create_deployment(
|
||||||
|
GroupId=group_id,
|
||||||
|
GroupVersionId=latest_grp_ver,
|
||||||
|
DeploymentType="Redeployment",
|
||||||
|
)
|
||||||
|
ex.value.response["Error"]["Message"].should.equal(
|
||||||
|
"Your request is missing the following required parameter(s): {DeploymentId}."
|
||||||
|
)
|
||||||
|
ex.value.response["Error"]["Code"].should.equal("InvalidInputException")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_greengrass
|
||||||
|
def test_re_deployment_with_invalid_deployment_id():
|
||||||
|
|
||||||
|
client = boto3.client("greengrass", region_name="ap-northeast-1")
|
||||||
|
cores = [
|
||||||
|
{
|
||||||
|
"CertificateArn": f"arn:aws:iot:ap-northeast-1:{ACCOUNT_ID}:cert/36ed61be9c6271ae8da174e29d0e033c06af149d7b21672f3800fe322044554d",
|
||||||
|
"Id": "123456789",
|
||||||
|
"ThingArn": f"arn:aws:iot:ap-northeast-1:{ACCOUNT_ID}:thing/CoreThing",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
create_core_res = client.create_core_definition(
|
||||||
|
InitialVersion={"Cores": cores}, Name="TestCore"
|
||||||
|
)
|
||||||
|
core_def_ver_arn = create_core_res["LatestVersionArn"]
|
||||||
|
|
||||||
|
create_group_res = client.create_group(
|
||||||
|
Name="TestGroup", InitialVersion={"CoreDefinitionVersionArn": core_def_ver_arn}
|
||||||
|
)
|
||||||
|
group_id = create_group_res["Id"]
|
||||||
|
latest_grp_ver = create_group_res["LatestVersion"]
|
||||||
|
|
||||||
|
deployment_id = "7b0bdeae-54c7-47cf-9f93-561e672efd9c"
|
||||||
|
with pytest.raises(ClientError) as ex:
|
||||||
|
client.create_deployment(
|
||||||
|
GroupId=group_id,
|
||||||
|
GroupVersionId=latest_grp_ver,
|
||||||
|
DeploymentType="Redeployment",
|
||||||
|
DeploymentId=deployment_id,
|
||||||
|
)
|
||||||
|
ex.value.response["Error"]["Message"].should.equal(
|
||||||
|
f"Deployment ID '{deployment_id}' is invalid."
|
||||||
|
)
|
||||||
|
ex.value.response["Error"]["Code"].should.equal("InvalidInputException")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_greengrass
|
||||||
|
def test_create_deployment_with_no_core_group():
|
||||||
|
|
||||||
|
client = boto3.client("greengrass", region_name="ap-northeast-1")
|
||||||
|
create_group_res = client.create_group(Name="TestGroup")
|
||||||
|
group_id = create_group_res["Id"]
|
||||||
|
latest_grp_ver = create_group_res["LatestVersion"]
|
||||||
|
|
||||||
|
with pytest.raises(ClientError) as ex:
|
||||||
|
client.create_deployment(
|
||||||
|
GroupId=group_id,
|
||||||
|
GroupVersionId=latest_grp_ver,
|
||||||
|
DeploymentType="NewDeployment",
|
||||||
|
)
|
||||||
|
|
||||||
|
ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
|
||||||
|
ex.value.response["Error"]["Code"].should.equal("MissingCoreException")
|
||||||
|
err = json.loads(ex.value.response["Error"]["Message"])
|
||||||
|
err_details = err["ErrorDetails"]
|
||||||
|
|
||||||
|
err_details[0].should.have.key("DetailedErrorCode").equals("GG-303")
|
||||||
|
err_details[0].should.have.key("DetailedErrorMessage").equals(
|
||||||
|
"You need a Greengrass Core in this Group before you can deploy."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_greengrass
|
||||||
|
def test_create_deployment_with_invalid_group_id():
|
||||||
|
|
||||||
|
client = boto3.client("greengrass", region_name="ap-northeast-1")
|
||||||
|
with pytest.raises(ClientError) as ex:
|
||||||
|
client.create_deployment(
|
||||||
|
GroupId="7b0bdeae-54c7-47cf-9f93-561e672efd9c",
|
||||||
|
GroupVersionId="dfd06e54-6531-4a9b-9505-3c1036b6906a",
|
||||||
|
DeploymentType="NewDeployment",
|
||||||
|
)
|
||||||
|
|
||||||
|
ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(404)
|
||||||
|
ex.value.response["Error"]["Code"].should.equal("ResourceNotFoundException")
|
||||||
|
ex.value.response["Error"]["Message"].should.equal(
|
||||||
|
"That group definition does not exist."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_greengrass
|
||||||
|
def test_create_deployment_with_invalid_group_version_id():
|
||||||
|
|
||||||
|
client = boto3.client("greengrass", region_name="ap-northeast-1")
|
||||||
|
cores = [
|
||||||
|
{
|
||||||
|
"CertificateArn": f"arn:aws:iot:ap-northeast-1:{ACCOUNT_ID}:cert/36ed61be9c6271ae8da174e29d0e033c06af149d7b21672f3800fe322044554d",
|
||||||
|
"Id": "123456789",
|
||||||
|
"ThingArn": f"arn:aws:iot:ap-northeast-1:{ACCOUNT_ID}:thing/CoreThing",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
create_core_res = client.create_core_definition(
|
||||||
|
InitialVersion={"Cores": cores}, Name="TestCore"
|
||||||
|
)
|
||||||
|
core_def_ver_arn = create_core_res["LatestVersionArn"]
|
||||||
|
|
||||||
|
create_group_res = client.create_group(
|
||||||
|
Name="TestGroup", InitialVersion={"CoreDefinitionVersionArn": core_def_ver_arn}
|
||||||
|
)
|
||||||
|
group_id = create_group_res["Id"]
|
||||||
|
group_version_id = "dfd06e54-6531-4a9b-9505-3c1036b6906a"
|
||||||
|
|
||||||
|
with pytest.raises(ClientError) as ex:
|
||||||
|
client.create_deployment(
|
||||||
|
GroupId=group_id,
|
||||||
|
GroupVersionId=group_version_id,
|
||||||
|
DeploymentType="NewDeployment",
|
||||||
|
)
|
||||||
|
|
||||||
|
ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(404)
|
||||||
|
ex.value.response["Error"]["Code"].should.equal("ResourceNotFoundException")
|
||||||
|
ex.value.response["Error"]["Message"].should.equal(
|
||||||
|
f"Version {group_version_id} of Group Definition {group_id} does not exist."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_greengrass
|
||||||
|
def test_create_deployment_with_invalid_deployment_type():
|
||||||
|
|
||||||
|
client = boto3.client("greengrass", region_name="ap-northeast-1")
|
||||||
|
create_group_res = client.create_group(Name="TestGroup")
|
||||||
|
group_id = create_group_res["Id"]
|
||||||
|
latest_grp_ver = create_group_res["LatestVersion"]
|
||||||
|
|
||||||
|
with pytest.raises(ClientError) as ex:
|
||||||
|
client.create_deployment(
|
||||||
|
GroupId=group_id,
|
||||||
|
GroupVersionId=latest_grp_ver,
|
||||||
|
DeploymentType="InvalidDeploymentType",
|
||||||
|
)
|
||||||
|
|
||||||
|
ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
|
||||||
|
ex.value.response["Error"]["Code"].should.equal("InvalidInputException")
|
||||||
|
ex.value.response["Error"]["Message"].should.equal(
|
||||||
|
"That deployment type is not valid. Please specify one of the following types: {NewDeployment,Redeployment,ResetDeployment,ForceResetDeployment}."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@freezegun.freeze_time("2022-06-01 12:00:00")
|
||||||
|
@mock_greengrass
|
||||||
|
def test_list_deployments():
|
||||||
|
|
||||||
|
client = boto3.client("greengrass", region_name="ap-northeast-1")
|
||||||
|
cores = [
|
||||||
|
{
|
||||||
|
"CertificateArn": f"arn:aws:iot:ap-northeast-1:{ACCOUNT_ID}:cert/36ed61be9c6271ae8da174e29d0e033c06af149d7b21672f3800fe322044554d",
|
||||||
|
"Id": "123456789",
|
||||||
|
"ThingArn": f"arn:aws:iot:ap-northeast-1:{ACCOUNT_ID}:thing/CoreThing",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
create_core_res = client.create_core_definition(
|
||||||
|
InitialVersion={"Cores": cores}, Name="TestCore"
|
||||||
|
)
|
||||||
|
core_def_ver_arn = create_core_res["LatestVersionArn"]
|
||||||
|
|
||||||
|
create_group_res = client.create_group(
|
||||||
|
Name="TestGroup", InitialVersion={"CoreDefinitionVersionArn": core_def_ver_arn}
|
||||||
|
)
|
||||||
|
group_id = create_group_res["Id"]
|
||||||
|
latest_grp_ver = create_group_res["LatestVersion"]
|
||||||
|
latest_grp_ver_arn = create_group_res["LatestVersionArn"]
|
||||||
|
deployment_type = "NewDeployment"
|
||||||
|
client.create_deployment(
|
||||||
|
GroupId=group_id, GroupVersionId=latest_grp_ver, DeploymentType=deployment_type
|
||||||
|
)
|
||||||
|
|
||||||
|
res = client.list_deployments(GroupId=group_id)
|
||||||
|
res.should.have.key("Deployments")
|
||||||
|
deployments = res["Deployments"][0]
|
||||||
|
|
||||||
|
deployments.should.have.key("CreatedAt")
|
||||||
|
deployments.should.have.key("DeploymentArn")
|
||||||
|
deployments.should.have.key("DeploymentId")
|
||||||
|
deployments.should.have.key("DeploymentType").equals(deployment_type)
|
||||||
|
deployments.should.have.key("GroupArn").equals(latest_grp_ver_arn)
|
||||||
|
|
||||||
|
if not TEST_SERVER_MODE:
|
||||||
|
deployments.should.have.key("CreatedAt").equal("2022-06-01T12:00:00.000Z")
|
||||||
|
|
||||||
|
|
||||||
|
@freezegun.freeze_time("2022-06-01 12:00:00")
|
||||||
|
@mock_greengrass
|
||||||
|
def test_get_deployment_status():
|
||||||
|
|
||||||
|
client = boto3.client("greengrass", region_name="ap-northeast-1")
|
||||||
|
cores = [
|
||||||
|
{
|
||||||
|
"CertificateArn": f"arn:aws:iot:ap-northeast-1:{ACCOUNT_ID}:cert/36ed61be9c6271ae8da174e29d0e033c06af149d7b21672f3800fe322044554d",
|
||||||
|
"Id": "123456789",
|
||||||
|
"ThingArn": f"arn:aws:iot:ap-northeast-1:{ACCOUNT_ID}:thing/CoreThing",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
create_core_res = client.create_core_definition(
|
||||||
|
InitialVersion={"Cores": cores}, Name="TestCore"
|
||||||
|
)
|
||||||
|
core_def_ver_arn = create_core_res["LatestVersionArn"]
|
||||||
|
|
||||||
|
create_group_res = client.create_group(
|
||||||
|
Name="TestGroup", InitialVersion={"CoreDefinitionVersionArn": core_def_ver_arn}
|
||||||
|
)
|
||||||
|
group_id = create_group_res["Id"]
|
||||||
|
latest_grp_ver = create_group_res["LatestVersion"]
|
||||||
|
deployment_type = "NewDeployment"
|
||||||
|
create_deployment_res = client.create_deployment(
|
||||||
|
GroupId=group_id, GroupVersionId=latest_grp_ver, DeploymentType=deployment_type
|
||||||
|
)
|
||||||
|
|
||||||
|
deployment_id = create_deployment_res["DeploymentId"]
|
||||||
|
res = client.get_deployment_status(GroupId=group_id, DeploymentId=deployment_id)
|
||||||
|
|
||||||
|
res["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
|
||||||
|
res.should.have.key("DeploymentStatus").equal("InProgress")
|
||||||
|
res.should.have.key("DeploymentType").equal(deployment_type)
|
||||||
|
res.should.have.key("UpdatedAt")
|
||||||
|
|
||||||
|
if not TEST_SERVER_MODE:
|
||||||
|
res.should.have.key("UpdatedAt").equal("2022-06-01T12:00:00.000Z")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_greengrass
|
||||||
|
def test_get_deployment_status_with_invalid_deployment_id():
|
||||||
|
|
||||||
|
client = boto3.client("greengrass", region_name="ap-northeast-1")
|
||||||
|
create_group_res = client.create_group(Name="TestGroup")
|
||||||
|
group_id = create_group_res["Id"]
|
||||||
|
|
||||||
|
deployment_id = "7b0bdeae-54c7-47cf-9f93-561e672efd9c"
|
||||||
|
|
||||||
|
with pytest.raises(ClientError) as ex:
|
||||||
|
client.get_deployment_status(GroupId=group_id, DeploymentId=deployment_id)
|
||||||
|
ex.value.response["Error"]["Message"].should.equal(
|
||||||
|
f"Deployment '{deployment_id}' does not exist."
|
||||||
|
)
|
||||||
|
ex.value.response["Error"]["Code"].should.equal("InvalidInputException")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_greengrass
|
||||||
|
def test_get_deployment_status_with_invalid_group_id():
|
||||||
|
|
||||||
|
client = boto3.client("greengrass", region_name="ap-northeast-1")
|
||||||
|
cores = [
|
||||||
|
{
|
||||||
|
"CertificateArn": f"arn:aws:iot:ap-northeast-1:{ACCOUNT_ID}:cert/36ed61be9c6271ae8da174e29d0e033c06af149d7b21672f3800fe322044554d",
|
||||||
|
"Id": "123456789",
|
||||||
|
"ThingArn": f"arn:aws:iot:ap-northeast-1:{ACCOUNT_ID}:thing/CoreThing",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
create_core_res = client.create_core_definition(
|
||||||
|
InitialVersion={"Cores": cores}, Name="TestCore"
|
||||||
|
)
|
||||||
|
core_def_ver_arn = create_core_res["LatestVersionArn"]
|
||||||
|
|
||||||
|
create_group_res = client.create_group(
|
||||||
|
Name="TestGroup", InitialVersion={"CoreDefinitionVersionArn": core_def_ver_arn}
|
||||||
|
)
|
||||||
|
group_id = create_group_res["Id"]
|
||||||
|
latest_grp_ver = create_group_res["LatestVersion"]
|
||||||
|
deployment_type = "NewDeployment"
|
||||||
|
create_deployment_res = client.create_deployment(
|
||||||
|
GroupId=group_id, GroupVersionId=latest_grp_ver, DeploymentType=deployment_type
|
||||||
|
)
|
||||||
|
|
||||||
|
deployment_id = create_deployment_res["DeploymentId"]
|
||||||
|
|
||||||
|
with pytest.raises(ClientError) as ex:
|
||||||
|
client.get_deployment_status(
|
||||||
|
GroupId="7b0bdeae-54c7-47cf-9f93-561e672efd9c", DeploymentId=deployment_id
|
||||||
|
)
|
||||||
|
ex.value.response["Error"]["Message"].should.equal(
|
||||||
|
f"Deployment '{deployment_id}' does not exist."
|
||||||
|
)
|
||||||
|
ex.value.response["Error"]["Code"].should.equal("InvalidInputException")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
TEST_SERVER_MODE,
|
||||||
|
reason="Can't handle path that contains $ in server mode.So ResetGroup api can't use in server mode",
|
||||||
|
)
|
||||||
|
@freezegun.freeze_time("2022-06-01 12:00:00")
|
||||||
|
@mock_greengrass
|
||||||
|
def test_reset_deployments():
|
||||||
|
|
||||||
|
client = boto3.client("greengrass", region_name="ap-northeast-1")
|
||||||
|
cores = [
|
||||||
|
{
|
||||||
|
"CertificateArn": f"arn:aws:iot:ap-northeast-1:{ACCOUNT_ID}:cert/36ed61be9c6271ae8da174e29d0e033c06af149d7b21672f3800fe322044554d",
|
||||||
|
"Id": "123456789",
|
||||||
|
"ThingArn": f"arn:aws:iot:ap-northeast-1:{ACCOUNT_ID}:thing/CoreThing",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
create_core_res = client.create_core_definition(
|
||||||
|
InitialVersion={"Cores": cores}, Name="TestCore"
|
||||||
|
)
|
||||||
|
core_def_ver_arn = create_core_res["LatestVersionArn"]
|
||||||
|
|
||||||
|
create_group_res = client.create_group(
|
||||||
|
Name="TestGroup", InitialVersion={"CoreDefinitionVersionArn": core_def_ver_arn}
|
||||||
|
)
|
||||||
|
group_id = create_group_res["Id"]
|
||||||
|
group_arn = create_group_res["Arn"]
|
||||||
|
latest_grp_ver = create_group_res["LatestVersion"]
|
||||||
|
client.create_deployment(
|
||||||
|
GroupId=group_id, GroupVersionId=latest_grp_ver, DeploymentType="NewDeployment"
|
||||||
|
)
|
||||||
|
|
||||||
|
reset_res = client.reset_deployments(GroupId=group_id)
|
||||||
|
|
||||||
|
reset_res["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
|
||||||
|
reset_res.should.have.key("DeploymentId")
|
||||||
|
reset_res.should.have.key("DeploymentArn")
|
||||||
|
|
||||||
|
list_res = client.list_deployments(GroupId=group_id)
|
||||||
|
reset_deployment = list_res["Deployments"][1]
|
||||||
|
reset_deployment.should.have.key("CreatedAt")
|
||||||
|
reset_deployment.should.have.key("DeploymentArn")
|
||||||
|
reset_deployment.should.have.key("DeploymentId")
|
||||||
|
reset_deployment.should.have.key("DeploymentType").should.equal("ResetDeployment")
|
||||||
|
reset_deployment.should.have.key("GroupArn").should.equal(group_arn)
|
||||||
|
|
||||||
|
if not TEST_SERVER_MODE:
|
||||||
|
reset_deployment["CreatedAt"].should.equal("2022-06-01T12:00:00.000Z")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
TEST_SERVER_MODE,
|
||||||
|
reason="Can't handle path that contains $ in server mode.So ResetGroup api can't use in server mode",
|
||||||
|
)
|
||||||
|
@mock_greengrass
|
||||||
|
def test_reset_deployments_with_invalid_group_id():
|
||||||
|
|
||||||
|
client = boto3.client("greengrass", region_name="ap-northeast-1")
|
||||||
|
|
||||||
|
with pytest.raises(ClientError) as ex:
|
||||||
|
client.reset_deployments(GroupId="7b0bdeae-54c7-47cf-9f93-561e672efd9c")
|
||||||
|
ex.value.response["Error"]["Message"].should.equal(
|
||||||
|
"That Group Definition does not exist."
|
||||||
|
)
|
||||||
|
ex.value.response["Error"]["Code"].should.equal("ResourceNotFoundException")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
TEST_SERVER_MODE,
|
||||||
|
reason="Can't handle path that contains $ in server mode.So ResetGroup api can't use in server mode",
|
||||||
|
)
|
||||||
|
@mock_greengrass
|
||||||
|
def test_reset_deployments_with_never_deployed_group():
|
||||||
|
|
||||||
|
client = boto3.client("greengrass", region_name="ap-northeast-1")
|
||||||
|
cores = [
|
||||||
|
{
|
||||||
|
"CertificateArn": f"arn:aws:iot:ap-northeast-1:{ACCOUNT_ID}:cert/36ed61be9c6271ae8da174e29d0e033c06af149d7b21672f3800fe322044554d",
|
||||||
|
"Id": "123456789",
|
||||||
|
"ThingArn": f"arn:aws:iot:ap-northeast-1:{ACCOUNT_ID}:thing/CoreThing",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
create_core_res = client.create_core_definition(
|
||||||
|
InitialVersion={"Cores": cores}, Name="TestCore"
|
||||||
|
)
|
||||||
|
core_def_ver_arn = create_core_res["LatestVersionArn"]
|
||||||
|
create_group_res = client.create_group(
|
||||||
|
Name="TestGroup", InitialVersion={"CoreDefinitionVersionArn": core_def_ver_arn}
|
||||||
|
)
|
||||||
|
group_id = create_group_res["Id"]
|
||||||
|
|
||||||
|
with pytest.raises(ClientError) as ex:
|
||||||
|
client.reset_deployments(GroupId=group_id)
|
||||||
|
ex.value.response["Error"]["Message"].should.equal(
|
||||||
|
f"Group id: {group_id} has not been deployed or has already been reset."
|
||||||
|
)
|
||||||
|
ex.value.response["Error"]["Code"].should.equal("ResourceNotFoundException")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
TEST_SERVER_MODE,
|
||||||
|
reason="Can't handle path that contains $ in server mode.So ResetGroup api can't use in server mode",
|
||||||
|
)
|
||||||
|
@mock_greengrass
|
||||||
|
def test_reset_deployments_with_already_reset_group():
|
||||||
|
|
||||||
|
client = boto3.client("greengrass", region_name="ap-northeast-1")
|
||||||
|
cores = [
|
||||||
|
{
|
||||||
|
"CertificateArn": f"arn:aws:iot:ap-northeast-1:{ACCOUNT_ID}:cert/36ed61be9c6271ae8da174e29d0e033c06af149d7b21672f3800fe322044554d",
|
||||||
|
"Id": "123456789",
|
||||||
|
"ThingArn": f"arn:aws:iot:ap-northeast-1:{ACCOUNT_ID}:thing/CoreThing",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
create_core_res = client.create_core_definition(
|
||||||
|
InitialVersion={"Cores": cores}, Name="TestCore"
|
||||||
|
)
|
||||||
|
core_def_ver_arn = create_core_res["LatestVersionArn"]
|
||||||
|
create_group_res = client.create_group(
|
||||||
|
Name="TestGroup", InitialVersion={"CoreDefinitionVersionArn": core_def_ver_arn}
|
||||||
|
)
|
||||||
|
group_id = create_group_res["Id"]
|
||||||
|
latest_grp_ver = create_group_res["LatestVersion"]
|
||||||
|
|
||||||
|
client.create_deployment(
|
||||||
|
GroupId=group_id, GroupVersionId=latest_grp_ver, DeploymentType="NewDeployment"
|
||||||
|
)
|
||||||
|
client.reset_deployments(GroupId=group_id)
|
||||||
|
|
||||||
|
with pytest.raises(ClientError) as ex:
|
||||||
|
client.reset_deployments(GroupId=group_id)
|
||||||
|
ex.value.response["Error"]["Message"].should.equal(
|
||||||
|
f"Group id: {group_id} has not been deployed or has already been reset."
|
||||||
|
)
|
||||||
|
ex.value.response["Error"]["Code"].should.equal("ResourceNotFoundException")
|
Loading…
Reference in New Issue
Block a user