upsert-slr 1.0.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- upsert_slr/__init__.py +190 -0
- upsert_slr/_jsii/__init__.py +42 -0
- upsert_slr/_jsii/upsert-slr@1.0.7.jsii.tgz +0 -0
- upsert_slr/py.typed +1 -0
- upsert_slr-1.0.7.dist-info/LICENSE +19 -0
- upsert_slr-1.0.7.dist-info/METADATA +63 -0
- upsert_slr-1.0.7.dist-info/RECORD +9 -0
- upsert_slr-1.0.7.dist-info/WHEEL +5 -0
- upsert_slr-1.0.7.dist-info/top_level.txt +1 -0
upsert_slr/__init__.py
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
r'''
|
|
2
|
+
# Upsert Service-Linked Role
|
|
3
|
+
|
|
4
|
+
AWS CDK construct to create a [service-linked role (SLR)](https://docs.aws.amazon.com/IAM/latest/UserGuide/using-service-linked-roles.html) if there is no SLR for the same service, and if there is, skip the creation process.
|
|
5
|
+
|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
* Create a service-linked role. If it is already created in the same AWS account, just skip the creation.
|
|
11
|
+
* Standalone CFn template since no CDK assets are used. We use inline code for the Lambda function.
|
|
12
|
+
* Sleep some time after role creation to wait for IAM propagation.
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
npm install upsert-slr
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
import { ServiceLinkedRole } from 'upsert-slr';
|
|
22
|
+
|
|
23
|
+
new ServiceLinkedRole(this, 'ElasticsearchSlr', {
|
|
24
|
+
awsServiceName: 'es.amazonaws.com',
|
|
25
|
+
description: 'Service linked role for Elasticsearch',
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Why do we need this?
|
|
30
|
+
|
|
31
|
+
CloudFormation also supports a service-linked role ([doc](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-iam-servicelinkedrole.html)). Why do we need this?
|
|
32
|
+
|
|
33
|
+
Because the resource behaves strangely when there is already a role with the same name. All we need is to simply create a role, and skip it if it already exists. Such behavior as upsert is achieved by this construct, `upsert-slr`.
|
|
34
|
+
|
|
35
|
+
Also, even if CFn successfully creates a role, resources that depend on the role sometimes fail to be created because there is sometimes a delay before the role is actually available. See [this stack overflow](https://stackoverflow.com/questions/20156043/how-long-should-i-wait-after-applying-an-aws-iam-policy-before-it-is-valid) for more details.
|
|
36
|
+
|
|
37
|
+
To avoid the IAM propagation delay, this construct also waits for some time after a role is created.
|
|
38
|
+
'''
|
|
39
|
+
from pkgutil import extend_path
|
|
40
|
+
__path__ = extend_path(__path__, __name__)
|
|
41
|
+
|
|
42
|
+
import abc
|
|
43
|
+
import builtins
|
|
44
|
+
import datetime
|
|
45
|
+
import enum
|
|
46
|
+
import typing
|
|
47
|
+
|
|
48
|
+
import jsii
|
|
49
|
+
import publication
|
|
50
|
+
import typing_extensions
|
|
51
|
+
|
|
52
|
+
import typeguard
|
|
53
|
+
from importlib.metadata import version as _metadata_package_version
|
|
54
|
+
TYPEGUARD_MAJOR_VERSION = int(_metadata_package_version('typeguard').split('.')[0])
|
|
55
|
+
|
|
56
|
+
def check_type(argname: str, value: object, expected_type: typing.Any) -> typing.Any:
|
|
57
|
+
if TYPEGUARD_MAJOR_VERSION <= 2:
|
|
58
|
+
return typeguard.check_type(argname=argname, value=value, expected_type=expected_type) # type:ignore
|
|
59
|
+
else:
|
|
60
|
+
if isinstance(value, jsii._reference_map.InterfaceDynamicProxy): # pyright: ignore [reportAttributeAccessIssue]
|
|
61
|
+
pass
|
|
62
|
+
else:
|
|
63
|
+
if TYPEGUARD_MAJOR_VERSION == 3:
|
|
64
|
+
typeguard.config.collection_check_strategy = typeguard.CollectionCheckStrategy.ALL_ITEMS # type:ignore
|
|
65
|
+
typeguard.check_type(value=value, expected_type=expected_type) # type:ignore
|
|
66
|
+
else:
|
|
67
|
+
typeguard.check_type(value=value, expected_type=expected_type, collection_check_strategy=typeguard.CollectionCheckStrategy.ALL_ITEMS) # type:ignore
|
|
68
|
+
|
|
69
|
+
from ._jsii import *
|
|
70
|
+
|
|
71
|
+
import constructs as _constructs_77d1e7e8
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class ServiceLinkedRole(
|
|
75
|
+
_constructs_77d1e7e8.Construct,
|
|
76
|
+
metaclass=jsii.JSIIMeta,
|
|
77
|
+
jsii_type="upsert-slr.ServiceLinkedRole",
|
|
78
|
+
):
|
|
79
|
+
def __init__(
|
|
80
|
+
self,
|
|
81
|
+
scope: "_constructs_77d1e7e8.Construct",
|
|
82
|
+
id: builtins.str,
|
|
83
|
+
*,
|
|
84
|
+
aws_service_name: builtins.str,
|
|
85
|
+
description: typing.Optional[builtins.str] = None,
|
|
86
|
+
) -> None:
|
|
87
|
+
'''
|
|
88
|
+
:param scope: -
|
|
89
|
+
:param id: -
|
|
90
|
+
:param aws_service_name: The service principal for the AWS service to which this role is attached. You use a string similar to a URL but without the http:// in front. For example: elasticbeanstalk.amazonaws.com . Service principals are unique and case-sensitive. To find the exact service principal for your service-linked role, see AWS services that work with IAM in the IAM User Guide. Look for the services that have Yes in the Service-Linked Role column. Choose the Yes link to view the service-linked role documentation for that service. https://docs.aws.amazon.com/IAM/latest/UserGuide/using-service-linked-roles.html
|
|
91
|
+
:param description: The description of the role. This is only used when creating a new role. When there is an existing role for the aws service, this field is ignored. Default: no description
|
|
92
|
+
'''
|
|
93
|
+
if __debug__:
|
|
94
|
+
type_hints = typing.get_type_hints(_typecheckingstub__eaefcb6bfa6686267d9fbe8ed893ee66abd33592269a0f87588ddf3ea490fc74)
|
|
95
|
+
check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"])
|
|
96
|
+
check_type(argname="argument id", value=id, expected_type=type_hints["id"])
|
|
97
|
+
props = ServiceLinkedRoleProps(
|
|
98
|
+
aws_service_name=aws_service_name, description=description
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
jsii.create(self.__class__, self, [scope, id, props])
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@jsii.data_type(
|
|
105
|
+
jsii_type="upsert-slr.ServiceLinkedRoleProps",
|
|
106
|
+
jsii_struct_bases=[],
|
|
107
|
+
name_mapping={"aws_service_name": "awsServiceName", "description": "description"},
|
|
108
|
+
)
|
|
109
|
+
class ServiceLinkedRoleProps:
|
|
110
|
+
def __init__(
|
|
111
|
+
self,
|
|
112
|
+
*,
|
|
113
|
+
aws_service_name: builtins.str,
|
|
114
|
+
description: typing.Optional[builtins.str] = None,
|
|
115
|
+
) -> None:
|
|
116
|
+
'''
|
|
117
|
+
:param aws_service_name: The service principal for the AWS service to which this role is attached. You use a string similar to a URL but without the http:// in front. For example: elasticbeanstalk.amazonaws.com . Service principals are unique and case-sensitive. To find the exact service principal for your service-linked role, see AWS services that work with IAM in the IAM User Guide. Look for the services that have Yes in the Service-Linked Role column. Choose the Yes link to view the service-linked role documentation for that service. https://docs.aws.amazon.com/IAM/latest/UserGuide/using-service-linked-roles.html
|
|
118
|
+
:param description: The description of the role. This is only used when creating a new role. When there is an existing role for the aws service, this field is ignored. Default: no description
|
|
119
|
+
'''
|
|
120
|
+
if __debug__:
|
|
121
|
+
type_hints = typing.get_type_hints(_typecheckingstub__2b465f6bb28878e03ea2345c60b3a08d2ec8243a9fd855266499358ddd9a2940)
|
|
122
|
+
check_type(argname="argument aws_service_name", value=aws_service_name, expected_type=type_hints["aws_service_name"])
|
|
123
|
+
check_type(argname="argument description", value=description, expected_type=type_hints["description"])
|
|
124
|
+
self._values: typing.Dict[builtins.str, typing.Any] = {
|
|
125
|
+
"aws_service_name": aws_service_name,
|
|
126
|
+
}
|
|
127
|
+
if description is not None:
|
|
128
|
+
self._values["description"] = description
|
|
129
|
+
|
|
130
|
+
@builtins.property
|
|
131
|
+
def aws_service_name(self) -> builtins.str:
|
|
132
|
+
'''The service principal for the AWS service to which this role is attached.
|
|
133
|
+
|
|
134
|
+
You use a string similar to a URL but without the http:// in front. For example: elasticbeanstalk.amazonaws.com .
|
|
135
|
+
|
|
136
|
+
Service principals are unique and case-sensitive. To find the exact service principal for your service-linked role, see AWS services that work with IAM in the IAM User Guide. Look for the services that have Yes in the Service-Linked Role column. Choose the Yes link to view the service-linked role documentation for that service.
|
|
137
|
+
https://docs.aws.amazon.com/IAM/latest/UserGuide/using-service-linked-roles.html
|
|
138
|
+
'''
|
|
139
|
+
result = self._values.get("aws_service_name")
|
|
140
|
+
assert result is not None, "Required property 'aws_service_name' is missing"
|
|
141
|
+
return typing.cast(builtins.str, result)
|
|
142
|
+
|
|
143
|
+
@builtins.property
|
|
144
|
+
def description(self) -> typing.Optional[builtins.str]:
|
|
145
|
+
'''The description of the role.
|
|
146
|
+
|
|
147
|
+
This is only used when creating a new role.
|
|
148
|
+
When there is an existing role for the aws service, this field is ignored.
|
|
149
|
+
|
|
150
|
+
:default: no description
|
|
151
|
+
'''
|
|
152
|
+
result = self._values.get("description")
|
|
153
|
+
return typing.cast(typing.Optional[builtins.str], result)
|
|
154
|
+
|
|
155
|
+
def __eq__(self, rhs: typing.Any) -> builtins.bool:
|
|
156
|
+
return isinstance(rhs, self.__class__) and rhs._values == self._values
|
|
157
|
+
|
|
158
|
+
def __ne__(self, rhs: typing.Any) -> builtins.bool:
|
|
159
|
+
return not (rhs == self)
|
|
160
|
+
|
|
161
|
+
def __repr__(self) -> str:
|
|
162
|
+
return "ServiceLinkedRoleProps(%s)" % ", ".join(
|
|
163
|
+
k + "=" + repr(v) for k, v in self._values.items()
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
__all__ = [
|
|
168
|
+
"ServiceLinkedRole",
|
|
169
|
+
"ServiceLinkedRoleProps",
|
|
170
|
+
]
|
|
171
|
+
|
|
172
|
+
publication.publish()
|
|
173
|
+
|
|
174
|
+
def _typecheckingstub__eaefcb6bfa6686267d9fbe8ed893ee66abd33592269a0f87588ddf3ea490fc74(
|
|
175
|
+
scope: _constructs_77d1e7e8.Construct,
|
|
176
|
+
id: builtins.str,
|
|
177
|
+
*,
|
|
178
|
+
aws_service_name: builtins.str,
|
|
179
|
+
description: typing.Optional[builtins.str] = None,
|
|
180
|
+
) -> None:
|
|
181
|
+
"""Type checking stubs"""
|
|
182
|
+
pass
|
|
183
|
+
|
|
184
|
+
def _typecheckingstub__2b465f6bb28878e03ea2345c60b3a08d2ec8243a9fd855266499358ddd9a2940(
|
|
185
|
+
*,
|
|
186
|
+
aws_service_name: builtins.str,
|
|
187
|
+
description: typing.Optional[builtins.str] = None,
|
|
188
|
+
) -> None:
|
|
189
|
+
"""Type checking stubs"""
|
|
190
|
+
pass
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from pkgutil import extend_path
|
|
2
|
+
__path__ = extend_path(__path__, __name__)
|
|
3
|
+
|
|
4
|
+
import abc
|
|
5
|
+
import builtins
|
|
6
|
+
import datetime
|
|
7
|
+
import enum
|
|
8
|
+
import typing
|
|
9
|
+
|
|
10
|
+
import jsii
|
|
11
|
+
import publication
|
|
12
|
+
import typing_extensions
|
|
13
|
+
|
|
14
|
+
import typeguard
|
|
15
|
+
from importlib.metadata import version as _metadata_package_version
|
|
16
|
+
TYPEGUARD_MAJOR_VERSION = int(_metadata_package_version('typeguard').split('.')[0])
|
|
17
|
+
|
|
18
|
+
def check_type(argname: str, value: object, expected_type: typing.Any) -> typing.Any:
|
|
19
|
+
if TYPEGUARD_MAJOR_VERSION <= 2:
|
|
20
|
+
return typeguard.check_type(argname=argname, value=value, expected_type=expected_type) # type:ignore
|
|
21
|
+
else:
|
|
22
|
+
if isinstance(value, jsii._reference_map.InterfaceDynamicProxy): # pyright: ignore [reportAttributeAccessIssue]
|
|
23
|
+
pass
|
|
24
|
+
else:
|
|
25
|
+
if TYPEGUARD_MAJOR_VERSION == 3:
|
|
26
|
+
typeguard.config.collection_check_strategy = typeguard.CollectionCheckStrategy.ALL_ITEMS # type:ignore
|
|
27
|
+
typeguard.check_type(value=value, expected_type=expected_type) # type:ignore
|
|
28
|
+
else:
|
|
29
|
+
typeguard.check_type(value=value, expected_type=expected_type, collection_check_strategy=typeguard.CollectionCheckStrategy.ALL_ITEMS) # type:ignore
|
|
30
|
+
|
|
31
|
+
import aws_cdk._jsii
|
|
32
|
+
import constructs._jsii
|
|
33
|
+
|
|
34
|
+
__jsii_assembly__ = jsii.JSIIAssembly.load(
|
|
35
|
+
"upsert-slr", "1.0.7", __name__[0:-6], "upsert-slr@1.0.7.jsii.tgz"
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
__all__ = [
|
|
39
|
+
"__jsii_assembly__",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
publication.publish()
|
|
Binary file
|
upsert_slr/py.typed
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2026 tmokmss
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
SOFTWARE.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: upsert-slr
|
|
3
|
+
Version: 1.0.7
|
|
4
|
+
Summary: Manage AWS service-linked roles in a better way.
|
|
5
|
+
Home-page: https://github.com/tmokmss/upsert-slr.git
|
|
6
|
+
Author: tmokmss<tmokmss@users.noreply.github.com>
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Source, https://github.com/tmokmss/upsert-slr.git
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Programming Language :: JavaScript
|
|
12
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Typing :: Typed
|
|
17
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
18
|
+
Classifier: License :: OSI Approved
|
|
19
|
+
Requires-Python: ~=3.9
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: aws-cdk-lib <3.0.0,>=2.1.0
|
|
23
|
+
Requires-Dist: constructs <11.0.0,>=10.0.5
|
|
24
|
+
Requires-Dist: jsii <2.0.0,>=1.125.0
|
|
25
|
+
Requires-Dist: publication >=0.0.3
|
|
26
|
+
Requires-Dist: typeguard ==2.13.3
|
|
27
|
+
|
|
28
|
+
# Upsert Service-Linked Role
|
|
29
|
+
|
|
30
|
+
AWS CDK construct to create a [service-linked role (SLR)](https://docs.aws.amazon.com/IAM/latest/UserGuide/using-service-linked-roles.html) if there is no SLR for the same service, and if there is, skip the creation process.
|
|
31
|
+
|
|
32
|
+

|
|
33
|
+
|
|
34
|
+
## Features
|
|
35
|
+
|
|
36
|
+
* Create a service-linked role. If it is already created in the same AWS account, just skip the creation.
|
|
37
|
+
* Standalone CFn template since no CDK assets are used. We use inline code for the Lambda function.
|
|
38
|
+
* Sleep some time after role creation to wait for IAM propagation.
|
|
39
|
+
|
|
40
|
+
## Usage
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
npm install upsert-slr
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
import { ServiceLinkedRole } from 'upsert-slr';
|
|
48
|
+
|
|
49
|
+
new ServiceLinkedRole(this, 'ElasticsearchSlr', {
|
|
50
|
+
awsServiceName: 'es.amazonaws.com',
|
|
51
|
+
description: 'Service linked role for Elasticsearch',
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Why do we need this?
|
|
56
|
+
|
|
57
|
+
CloudFormation also supports a service-linked role ([doc](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-iam-servicelinkedrole.html)). Why do we need this?
|
|
58
|
+
|
|
59
|
+
Because the resource behaves strangely when there is already a role with the same name. All we need is to simply create a role, and skip it if it already exists. Such behavior as upsert is achieved by this construct, `upsert-slr`.
|
|
60
|
+
|
|
61
|
+
Also, even if CFn successfully creates a role, resources that depend on the role sometimes fail to be created because there is sometimes a delay before the role is actually available. See [this stack overflow](https://stackoverflow.com/questions/20156043/how-long-should-i-wait-after-applying-an-aws-iam-policy-before-it-is-valid) for more details.
|
|
62
|
+
|
|
63
|
+
To avoid the IAM propagation delay, this construct also waits for some time after a role is created.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
upsert_slr/__init__.py,sha256=cJIDaMfELQAEf5ekmHpg3TQPa1dDU50G3JMhMS0fNjE,9011
|
|
2
|
+
upsert_slr/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
3
|
+
upsert_slr/_jsii/__init__.py,sha256=wNq2GUOUbT-5aNRzTgbeuJafvnxxH155IvkWsL3neFI,1431
|
|
4
|
+
upsert_slr/_jsii/upsert-slr@1.0.7.jsii.tgz,sha256=KPI5kTLxeAuTZ_pXR9w-kuNEn3_UzId6defV7SfBCJE,52812
|
|
5
|
+
upsert_slr-1.0.7.dist-info/LICENSE,sha256=1YYoNgeQ6B8y9vIty3QDDD_t48nYzUoHwiLOTI5a4W4,1051
|
|
6
|
+
upsert_slr-1.0.7.dist-info/METADATA,sha256=9wZuV0PoeZfmInwvoGvYC2lH9LSf8OzNLYrUzFNHiVs,2777
|
|
7
|
+
upsert_slr-1.0.7.dist-info/WHEEL,sha256=WnJ8fYhv8N4SYVK2lLYNI6N0kVATA7b0piVUNvqIIJE,91
|
|
8
|
+
upsert_slr-1.0.7.dist-info/top_level.txt,sha256=x0hhdmxmID546u8_HGfktN_5e8MB8JI0S7zRGjdolkQ,11
|
|
9
|
+
upsert_slr-1.0.7.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
upsert_slr
|