Add codepipeline.tag_resource
This commit is contained in:
parent
df951facc5
commit
b96a46b98f
@ -26,3 +26,19 @@ class ResourceNotFoundException(JsonRESTError):
|
|||||||
super(ResourceNotFoundException, self).__init__(
|
super(ResourceNotFoundException, self).__init__(
|
||||||
"ResourceNotFoundException", message
|
"ResourceNotFoundException", message
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidTagsException(JsonRESTError):
|
||||||
|
code = 400
|
||||||
|
|
||||||
|
def __init__(self, message):
|
||||||
|
super(InvalidTagsException, self).__init__("InvalidTagsException", message)
|
||||||
|
|
||||||
|
|
||||||
|
class TooManyTagsException(JsonRESTError):
|
||||||
|
code = 400
|
||||||
|
|
||||||
|
def __init__(self, arn):
|
||||||
|
super(TooManyTagsException, self).__init__(
|
||||||
|
"TooManyTagsException", "Tag limit exceeded for resource [{}].".format(arn)
|
||||||
|
)
|
||||||
|
@ -12,6 +12,8 @@ from moto.codepipeline.exceptions import (
|
|||||||
InvalidStructureException,
|
InvalidStructureException,
|
||||||
PipelineNotFoundException,
|
PipelineNotFoundException,
|
||||||
ResourceNotFoundException,
|
ResourceNotFoundException,
|
||||||
|
InvalidTagsException,
|
||||||
|
TooManyTagsException,
|
||||||
)
|
)
|
||||||
from moto.core import BaseBackend, BaseModel
|
from moto.core import BaseBackend, BaseModel
|
||||||
|
|
||||||
@ -54,6 +56,18 @@ class CodePipeline(BaseModel):
|
|||||||
|
|
||||||
return pipeline
|
return pipeline
|
||||||
|
|
||||||
|
def validate_tags(self, tags):
|
||||||
|
for tag in tags:
|
||||||
|
if tag["key"].startswith("aws:"):
|
||||||
|
raise InvalidTagsException(
|
||||||
|
"Not allowed to modify system tags. "
|
||||||
|
"System tags start with 'aws:'. "
|
||||||
|
"msg=[Caller is an end user and not allowed to mutate system tags]"
|
||||||
|
)
|
||||||
|
|
||||||
|
if (len(self.tags) + len(tags)) > 50:
|
||||||
|
raise TooManyTagsException(self._arn)
|
||||||
|
|
||||||
|
|
||||||
class CodePipelineBackend(BaseBackend):
|
class CodePipelineBackend(BaseBackend):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -93,6 +107,8 @@ class CodePipelineBackend(BaseBackend):
|
|||||||
self.pipelines[pipeline["name"]] = CodePipeline(region, pipeline)
|
self.pipelines[pipeline["name"]] = CodePipeline(region, pipeline)
|
||||||
|
|
||||||
if tags:
|
if tags:
|
||||||
|
self.pipelines[pipeline["name"]].validate_tags(tags)
|
||||||
|
|
||||||
new_tags = {tag["key"]: tag["value"] for tag in tags}
|
new_tags = {tag["key"]: tag["value"] for tag in tags}
|
||||||
self.pipelines[pipeline["name"]].tags.update(new_tags)
|
self.pipelines[pipeline["name"]].tags.update(new_tags)
|
||||||
|
|
||||||
@ -160,6 +176,22 @@ class CodePipelineBackend(BaseBackend):
|
|||||||
|
|
||||||
return tags
|
return tags
|
||||||
|
|
||||||
|
def tag_resource(self, arn, tags):
|
||||||
|
name = arn.split(":")[-1]
|
||||||
|
pipeline = self.pipelines.get(name)
|
||||||
|
|
||||||
|
if not pipeline:
|
||||||
|
raise ResourceNotFoundException(
|
||||||
|
"The account with id '{0}' does not include a pipeline with the name '{1}'".format(
|
||||||
|
ACCOUNT_ID, name
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
pipeline.validate_tags(tags)
|
||||||
|
|
||||||
|
for tag in tags:
|
||||||
|
pipeline.tags.update({tag["key"]: tag["value"]})
|
||||||
|
|
||||||
|
|
||||||
codepipeline_backends = {}
|
codepipeline_backends = {}
|
||||||
for region in Session().get_available_regions("codepipeline"):
|
for region in Session().get_available_regions("codepipeline"):
|
||||||
|
@ -46,3 +46,10 @@ class CodePipelineResponse(BaseResponse):
|
|||||||
)
|
)
|
||||||
|
|
||||||
return json.dumps({"tags": tags})
|
return json.dumps({"tags": tags})
|
||||||
|
|
||||||
|
def tag_resource(self):
|
||||||
|
self.codepipeline_backend.tag_resource(
|
||||||
|
self._get_param("resourceArn"), self._get_param("tags")
|
||||||
|
)
|
||||||
|
|
||||||
|
return ""
|
||||||
|
@ -530,6 +530,78 @@ def test_list_tags_for_resource_errors():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_codepipeline
|
||||||
|
def test_tag_resource():
|
||||||
|
client = boto3.client("codepipeline", region_name="us-east-1")
|
||||||
|
name = "test-pipeline"
|
||||||
|
create_basic_codepipeline(client, name)
|
||||||
|
|
||||||
|
client.tag_resource(
|
||||||
|
resourceArn="arn:aws:codepipeline:us-east-1:123456789012:{}".format(name),
|
||||||
|
tags=[{"key": "key-2", "value": "value-2"}],
|
||||||
|
)
|
||||||
|
|
||||||
|
response = client.list_tags_for_resource(
|
||||||
|
resourceArn="arn:aws:codepipeline:us-east-1:123456789012:{}".format(name)
|
||||||
|
)
|
||||||
|
response["tags"].should.equal(
|
||||||
|
[{"key": "key", "value": "value"}, {"key": "key-2", "value": "value-2"}]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_codepipeline
|
||||||
|
def test_tag_resource_errors():
|
||||||
|
client = boto3.client("codepipeline", region_name="us-east-1")
|
||||||
|
name = "test-pipeline"
|
||||||
|
create_basic_codepipeline(client, name)
|
||||||
|
|
||||||
|
with assert_raises(ClientError) as e:
|
||||||
|
client.tag_resource(
|
||||||
|
resourceArn="arn:aws:codepipeline:us-east-1:123456789012:not-existing",
|
||||||
|
tags=[{"key": "key-2", "value": "value-2"}],
|
||||||
|
)
|
||||||
|
ex = e.exception
|
||||||
|
ex.operation_name.should.equal("TagResource")
|
||||||
|
ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
|
||||||
|
ex.response["Error"]["Code"].should.contain("ResourceNotFoundException")
|
||||||
|
ex.response["Error"]["Message"].should.equal(
|
||||||
|
"The account with id '123456789012' does not include a pipeline with the name 'not-existing'"
|
||||||
|
)
|
||||||
|
|
||||||
|
with assert_raises(ClientError) as e:
|
||||||
|
client.tag_resource(
|
||||||
|
resourceArn="arn:aws:codepipeline:us-east-1:123456789012:{}".format(name),
|
||||||
|
tags=[{"key": "aws:key", "value": "value"}],
|
||||||
|
)
|
||||||
|
ex = e.exception
|
||||||
|
ex.operation_name.should.equal("TagResource")
|
||||||
|
ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
|
||||||
|
ex.response["Error"]["Code"].should.contain("InvalidTagsException")
|
||||||
|
ex.response["Error"]["Message"].should.equal(
|
||||||
|
"Not allowed to modify system tags. "
|
||||||
|
"System tags start with 'aws:'. "
|
||||||
|
"msg=[Caller is an end user and not allowed to mutate system tags]"
|
||||||
|
)
|
||||||
|
|
||||||
|
with assert_raises(ClientError) as e:
|
||||||
|
client.tag_resource(
|
||||||
|
resourceArn="arn:aws:codepipeline:us-east-1:123456789012:{}".format(name),
|
||||||
|
tags=[
|
||||||
|
{"key": "key-{}".format(i), "value": "value-{}".format(i)}
|
||||||
|
for i in range(50)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
ex = e.exception
|
||||||
|
ex.operation_name.should.equal("TagResource")
|
||||||
|
ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
|
||||||
|
ex.response["Error"]["Code"].should.contain("TooManyTagsException")
|
||||||
|
ex.response["Error"]["Message"].should.equal(
|
||||||
|
"Tag limit exceeded for resource [arn:aws:codepipeline:us-east-1:123456789012:{}].".format(
|
||||||
|
name
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@mock_iam
|
@mock_iam
|
||||||
def get_role_arn():
|
def get_role_arn():
|
||||||
client = boto3.client("iam", region_name="us-east-1")
|
client = boto3.client("iam", region_name="us-east-1")
|
||||||
|
Loading…
Reference in New Issue
Block a user