File: models.py

package info (click to toggle)
python-moto 5.1.18-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 116,520 kB
  • sloc: python: 636,725; javascript: 181; makefile: 39; sh: 3
file content (173 lines) | stat: -rw-r--r-- 6,265 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
"""AppRegistryBackend class with methods for supported APIs."""

import datetime
import re
from typing import Any

from moto.core.base_backend import BackendDict, BaseBackend
from moto.core.common_models import BaseModel
from moto.moto_api._internal import mock_random
from moto.resourcegroups.models import FakeResourceGroup
from moto.servicecatalogappregistry.exceptions import (
    ResourceNotFoundException,
    ValidationException,
)
from moto.utilities.tagging_service import TaggingService
from moto.utilities.utils import get_partition


class Application(BaseModel):
    def __init__(
        self,
        name: str,
        description: str,
        region: str,
        account_id: str,
    ):
        self.id = mock_random.get_random_string(
            length=27, include_digits=True, lower_case=True
        )
        self.arn = f"arn:{get_partition(region)}:servicecatalog:{region}:{account_id}:applications/{self.id}"
        self.name = name
        self.description = description
        self.creationTime = datetime.datetime.now()
        self.lastUpdateTime = self.creationTime
        self.tags: dict[str, str] = {}
        self.applicationTag: dict[str, str] = {"awsApplication": self.arn}

        self.associated_resources: dict[str, AssociatedResource] = {}

    def to_json(self) -> dict[str, Any]:
        return {
            "id": self.id,
            "arn": self.arn,
            "name": self.name,
            "description": self.description,
            "creationTime": str(self.creationTime),
            "lastUpdateTime": str(self.lastUpdateTime),
            "tags": self.tags,
            "applicationTag": self.applicationTag,
        }


class AssociatedResource(BaseBackend):
    def __init__(
        self,
        resource_type: str,
        resource: str,
        options: list[str],
        application: Application,
        account_id: str,
        region_name: str,
    ):
        if resource_type == "CFN_STACK":
            from moto.cloudformation.exceptions import ValidationError
            from moto.cloudformation.models import cloudformation_backends

            self.resource = resource
            match = re.search(
                r"^arn:aws:cloudformation:(us(-gov)?|ap|ca|cn|eu|sa)-(central|(north|south)?(east|west)?)-\d:\d{12}:stack/\w[a-zA-Z0-9\-]{0,127}/[a-f0-9]{8}(-[a-f0-9]{4}){3}-[a-f0-9]{12}$",
                resource,
            )
            if match is not None:
                self.name = resource.split("/")[1]
            else:
                self.name = resource
            cf_backend = cloudformation_backends[account_id][region_name]
            try:
                cf_backend.get_stack(self.name)
            except ValidationError:
                raise ResourceNotFoundException(
                    f"No CloudFormation stack called '{self.name}' found"
                )
        elif resource_type == "RESOURCE_TAG_VALUE":
            tags = {
                "EnableAWSServiceCatalogAppRegistry": "true",
                "aws:servicecatalog:applicationName": application.name,
                "aws:servicecatalog:applicationId": application.id,
                "aws:servicecatalog:applicationArn": application.arn,
            }
            new_resource_group = FakeResourceGroup(
                account_id,
                region_name,
                f"AWS_AppRegistry_AppTag_{account_id}-{application.name}",
                {"Type": "TAG_FILTERS_1_0", "Query": resource},
                None,
                tags,
            )
            self.resource = new_resource_group.arn
            self.name = new_resource_group._name
            self.query = resource
        else:
            raise ValidationException
        self.resource_type = resource_type
        self.options = options

    def to_json(self) -> dict[str, Any]:
        return_dict = {
            "name": self.name,
            "arn": self.resource,
            "resourceType": self.resource_type,
            "options": self.options,
        }
        if self.resource_type == "RESOURCE_TAG_VALUE":
            return_dict["resourceDetails"] = {"tagValue": self.query}  # type: ignore
        return return_dict


class AppRegistryBackend(BaseBackend):
    """Implementation of AppRegistry APIs."""

    def __init__(self, region_name: str, account_id: str):
        super().__init__(region_name, account_id)
        self.applications: dict[str, Application] = {}
        self.tagger = TaggingService()
        self.configuration: dict[str, Any] = {"tagQueryConfiguration": {}}

    def create_application(
        self, name: str, description: str, tags: dict[str, str], client_token: str
    ) -> Application:
        app = Application(
            name,
            description,
            region=self.region_name,
            account_id=self.account_id,
        )
        self.applications[app.arn] = app
        self._tag_resource(app.arn, tags)
        return app

    def list_applications(self) -> list[Application]:
        return list(self.applications.values())

    def associate_resource(
        self, application: str, resource_type: str, resource: str, options: list[str]
    ) -> dict[str, Any]:
        app = self.applications[application]
        new_resource = AssociatedResource(
            resource_type, resource, options, app, self.account_id, self.region_name
        )
        app.associated_resources[new_resource.resource] = new_resource
        return {"applicationArn": app.arn, "resourceArn": resource, "options": options}

    def _list_tags_for_resource(self, arn: str) -> dict[str, str]:
        return self.tagger.get_tag_dict_for_resource(arn)

    def _tag_resource(self, arn: str, tags: dict[str, str]) -> None:
        self.tagger.tag_resource(arn, TaggingService.convert_dict_to_tags_input(tags))

    def _untag_resource(self, arn: str, tag_keys: list[str]) -> None:
        self.tagger.untag_resource_using_names(arn, tag_keys)

    def put_configuration(self, configuration: dict[str, Any]) -> None:
        self.configuration = configuration

    def get_configuration(
        self,
    ) -> dict[str, Any]:
        return self.configuration


servicecatalogappregistry_backends = BackendDict(
    AppRegistryBackend, "servicecatalog-appregistry"
)