reverse-diagrams 0.2.5__py3-none-any.whl → 1.0.0__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.
@@ -1,42 +1,32 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: reverse_diagrams
3
- Version: 0.2.5
4
- Summary: Continuous Documentation Tool - Documentation as Code Tool -
5
- This package create reverse diagrams based on your current state in your cloud environment
3
+ Version: 1.0.0
4
+ Summary: Continuous Documentation Tool - Documentation as Code Tool - This package create reverse diagrams based on your current state in your cloud environment using diagrams library
6
5
  Project-URL: Homepage, https://github.com/velez94/reverse_diagrams
7
6
  Project-URL: Bug Tracker, https://github.com/velez94/reverse_diagrams/issues
8
7
  Author-email: Alejandro Velez <avelez@labvel.io>
9
- License: MIT License
8
+ License: Copyright [2024] [Alejandro Velez]
10
9
 
11
- Copyright (c) [2023] [Alejandro Velez]
10
+ Licensed under the Apache License, Version 2.0 (the "License");
11
+ you may not use this file except in compliance with the License.
12
+ You may obtain a copy of the License at
12
13
 
13
- Permission is hereby granted, free of charge, to any person obtaining a copy
14
- of this software and associated documentation files (the "Software"), to deal
15
- in the Software without restriction, including without limitation the rights
16
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
- copies of the Software, and to permit persons to whom the Software is
18
- furnished to do so, subject to the following conditions:
14
+ http://www.apache.org/licenses/LICENSE-2.0
19
15
 
20
- The above copyright notice and this permission notice shall be included in all
21
- copies or substantial portions of the Software.
22
-
23
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
- SOFTWARE.
16
+ Unless required by applicable law or agreed to in writing, software
17
+ distributed under the License is distributed on an "AS IS" BASIS,
18
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
+ See the License for the specific language governing permissions and
20
+ limitations under the License.
30
21
  License-File: LICENSE
31
- Classifier: License :: OSI Approved :: MIT License
32
22
  Classifier: Operating System :: OS Independent
33
23
  Classifier: Programming Language :: Python :: 3
34
24
  Requires-Python: >=3.8
35
25
  Requires-Dist: boto3>=1.26.44
36
26
  Requires-Dist: colorama>=0.4.4
37
- Requires-Dist: diagrams>=0.22.0
27
+ Requires-Dist: diagrams>=0.23.4
38
28
  Requires-Dist: emoji>=2.2.0
39
- Requires-Dist: jsonschema>=3.2.0
29
+ Requires-Dist: rich>=13.7.0
40
30
  Description-Content-Type: text/markdown
41
31
 
42
32
  <!-- START doctoc generated TOC please keep comment here to allow auto update -->
@@ -157,3 +147,25 @@ reverse_diagrams -c aws -p my-profile -i -r us-east-2
157
147
  reverse_diagrams -c aws -p my-profile -o -i -r us-east-2
158
148
  ```
159
149
 
150
+ ## Extras
151
+ ### Enable autocomplete
152
+ Argcomplete provides easy, extensible command line tab completion of arguments for your Python application.
153
+
154
+ It makes two assumptions:
155
+
156
+ * You’re using bash or zsh as your shell
157
+
158
+ * You’re using argparse to manage your command line arguments/options
159
+
160
+ Argcomplete is particularly useful if your program has lots of options or subparsers, and if your program can dynamically suggest completions for your argument/option values (for example, if the user is browsing resources over the network).
161
+ Run:
162
+ ```bash
163
+ activate-global-python-argcomplete
164
+ ```
165
+ and to make sure that bash knows about this script, you use
166
+ ```bash
167
+
168
+ echo 'eval "$(register-python-argcomplete reverse_diagrams)"' >> ~/.bashrc
169
+ source ~/.bashrc
170
+
171
+ ```
@@ -0,0 +1,20 @@
1
+ src/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ src/reverse_diagrams.py,sha256=xC4alfmJ4CZcgnjShXE13ZvehhSuxSkrQxhs4LX1FVU,9496
3
+ src/version.py,sha256=GdBzLFWoHZyrTuCHs8_6o2940bb1o4TwZpxxsOIS-kI,48
4
+ src/aws/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ src/aws/describe_identity_store.py,sha256=2mmniQowKhatfg7ekLdJASz424j0gkP9TJ-ArEeb8Po,8838
6
+ src/aws/describe_organization.py,sha256=S9r-lCy3NX1e1qpLw_gMl_-nbeE5RXcISLMdThDOp7w,4731
7
+ src/aws/describe_sso.py,sha256=LMejRRupMckB6r2akK8Nyu35AFzyvprwh4QnzAQvmoA,4832
8
+ src/banner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ src/banner/banner.py,sha256=aGFVaW7RVdhgMi8b3YeC6MQodhJd01MO3iTTHlQRw8s,979
10
+ src/dgms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ src/dgms/graph_mapper.py,sha256=vzBgjdFzO7nseqTXp0Z68-f5OgtZaDsThfMNy8Q7kjg,7402
12
+ src/dgms/graph_template.py,sha256=QMTsbYPt9uZkWS9r7h8UDc7NP7BKcCP1j523soeQrOQ,1176
13
+ src/export_report/export_csv.py,sha256=7j53bcuXK1x6ciGzq88psfyguhQWo36uVFYxp0y8p34,92
14
+ src/reports/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ src/reports/save_results.py,sha256=eOYGmp1-2Kfaf5k-cUZ7UIAQoBm59ta8sxlDUoZCfK4,689
16
+ reverse_diagrams-1.0.0.dist-info/METADATA,sha256=udbRPGZhORkHUAyUOYW9DLhqjb6dt6QcjPytoEaWUTQ,5528
17
+ reverse_diagrams-1.0.0.dist-info/WHEEL,sha256=TJPnKdtrSue7xZ_AVGkp9YXcvDrobsjBds1du3Nx6dc,87
18
+ reverse_diagrams-1.0.0.dist-info/entry_points.txt,sha256=VZNkrc7qUDbddTCH3pGd83EhUT3PHTx9MzpAk6bb6qc,63
19
+ reverse_diagrams-1.0.0.dist-info/licenses/LICENSE,sha256=o6nDaQ7M9xbR0L7HSJ3A-1JbBPoZro_zhVPO4-M5CAQ,571
20
+ reverse_diagrams-1.0.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.12.2
2
+ Generator: hatchling 1.21.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -0,0 +1,13 @@
1
+ Copyright [2024] [Alejandro Velez]
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
@@ -1,29 +1,29 @@
1
- import boto3
2
- from .describe_sso import list_account_assignments
3
- from colorama import Fore
4
1
  import logging
5
2
 
3
+ from colorama import Fore
4
+ from rich.progress import track
5
+
6
+ from .describe_sso import client, list_account_assignments
7
+
8
+
9
+ def list_groups_pag(identity_store_id, region, next_token: str = None):
10
+ identity_client = client("identitystore", region_name=region)
6
11
 
7
- def list_groups_pag(identity_store_id, client=boto3.client('identitystore', region_name="us-east-2"),
8
- next_token: str = None):
9
- paginator = client.get_paginator('list_groups')
12
+ paginator = identity_client.get_paginator("list_groups")
10
13
  response_iterator = paginator.paginate(
11
14
  IdentityStoreId=identity_store_id,
12
- PaginationConfig={
13
- 'MaxItems': 1000,
14
- 'PageSize': 4,
15
- 'StartingToken': next_token
16
- }
15
+ PaginationConfig={"MaxItems": 1000, "PageSize": 4, "StartingToken": next_token},
17
16
  )
18
17
  response = response_iterator.build_full_result()
19
18
  logging.info(response_iterator.build_full_result())
20
19
  return response["Groups"]
21
20
 
22
21
 
23
- def list_groups(identity_store_id, client=boto3.client('identitystore', region_name="us-east-2"), ):
24
- groups = client.list_groups(
25
- IdentityStoreId=identity_store_id,
26
- MaxResults=20
22
+ def list_groups(identity_store_id, region):
23
+ identity_client = client("identitystore", region_name=region)
24
+
25
+ groups = identity_client.list_groups(
26
+ IdentityStoreId=identity_store_id, MaxResults=20
27
27
  )
28
28
 
29
29
  logging.info(groups)
@@ -32,7 +32,11 @@ def list_groups(identity_store_id, client=boto3.client('identitystore', region_n
32
32
 
33
33
  if len(groups["Groups"]) >= 20:
34
34
  logging.info("Paginating ...")
35
- ad_groups = list_groups_pag(identity_store_id=identity_store_id, client=client, next_token=groups["NextToken"])
35
+ ad_groups = list_groups_pag(
36
+ identity_store_id=identity_store_id,
37
+ region=region,
38
+ next_token=groups["NextToken"],
39
+ )
36
40
  for ad in ad_groups:
37
41
  l_groups.append(ad)
38
42
  logging.info(f"You have {len(l_groups)} Groups")
@@ -40,33 +44,117 @@ def list_groups(identity_store_id, client=boto3.client('identitystore', region_n
40
44
  return l_groups
41
45
 
42
46
 
43
- def list_users(identity_store_id, client=boto3.client('identitystore', region_name="us-east-2"), ):
44
- response = client.list_users(
47
+ # define pagination list user function
48
+ def list_users_pag(identity_store_id, region, next_token: str = None):
49
+ identity_client = client("identitystore", region_name=region)
50
+ paginator = identity_client.get_paginator("list_users")
51
+ response_iterator = paginator.paginate(
45
52
  IdentityStoreId=identity_store_id,
53
+ PaginationConfig={"MaxItems": 1000, "PageSize": 4, "StartingToken": next_token},
54
+ )
55
+ return response_iterator["Users"]
46
56
 
57
+
58
+ def list_users(identity_store_id, region):
59
+ identity_client = client("identitystore", region_name=region)
60
+
61
+ response = identity_client.list_users(
62
+ IdentityStoreId=identity_store_id,
47
63
  )
64
+ # create pagination option
65
+ users = response["Users"]
66
+ if len(users) >= 20:
67
+ logging.info("Paginating ...")
68
+ ad_users = list_users_pag(
69
+ identity_store_id=identity_store_id,
70
+ region=region,
71
+ next_token=response["NextToken"],
72
+ )
73
+ for ad in ad_users:
74
+ users.append(ad)
75
+ logging.info(f"You have {len(users)} Users")
48
76
 
49
- return response["Users"]
77
+ return users
50
78
 
51
79
 
52
- def get_members(identity_store_id, groups, client=boto3.client('identitystore', region_name="us-east-2")):
80
+ def get_members_pag(identity_store_id, region, next_token: str = None):
81
+ identity_client = client("identitystore", region_name=region)
82
+
83
+ paginator = identity_client.get_paginator("list_group_memberships")
84
+ response_iterator = paginator.paginate(
85
+ IdentityStoreId=identity_store_id,
86
+ PaginationConfig={"MaxItems": 1000, "PageSize": 4, "StartingToken": next_token},
87
+ )
88
+ response = response_iterator.build_full_result()
89
+ logging.info(response_iterator.build_full_result())
90
+ return response["GroupMemberships"]
91
+
92
+
93
+ def get_members(identity_store_id, groups, region):
94
+ l_client = client("identitystore", region_name=region)
53
95
  group_members = []
54
- for g in groups:
55
- response = client.list_group_memberships(
96
+ for g, y in zip(
97
+ groups, track(range(len(groups) - 1), description="Getting groups members...")
98
+ ):
99
+ response = l_client.list_group_memberships(
56
100
  IdentityStoreId=identity_store_id,
57
101
  GroupId=g["GroupId"],
58
-
102
+ MaxResults=20,
59
103
  )
104
+ members = response["GroupMemberships"]
105
+ logging.info(members)
106
+
107
+ logging.info(len(members))
108
+
109
+ if len(members) >= 20:
110
+ logging.info("Paginating ...")
111
+ ad_members = get_members_pag(
112
+ identity_store_id=identity_store_id,
113
+ region=region,
114
+ next_token=response["NextToken"],
115
+ )
116
+ for ad in ad_members:
117
+ members.append(ad)
118
+ logging.info(f"You have {len(ad_members)} Members")
119
+
60
120
  group_members.append(
61
- {"group_id": g["GroupId"],
62
- "group_name": g["DisplayName"],
63
- "members": response["GroupMemberships"]
64
- }
121
+ {
122
+ "group_id": g["GroupId"],
123
+ "group_name": g["DisplayName"],
124
+ "members": members,
125
+ }
65
126
  )
66
127
 
67
128
  return group_members
68
129
 
69
130
 
131
+ def list_group_memberships(identitystore_client, group_name, pagination=True):
132
+ """
133
+ Lists memberships for a group in an AWS SSO identity store.
134
+
135
+ Args:
136
+ identitystore_client (client): Boto3 SSO identity store client
137
+ group_name (str): Name of the group to list memberships for
138
+ pagination (bool): Whether to enable result pagination (default: True)
139
+
140
+ Returns:
141
+ list: List of member objects
142
+ """
143
+
144
+ params = {"GroupName": group_name}
145
+ members = []
146
+
147
+ if pagination:
148
+ paginator = identitystore_client.get_paginator("list_group_memberships")
149
+ for page in paginator.paginate(**params):
150
+ members.extend(page["Members"])
151
+ else:
152
+ response = identitystore_client.list_group_memberships(**params)
153
+ members.extend(response["Members"])
154
+
155
+ return members
156
+
157
+
70
158
  def complete_group_members(group_members, users_list):
71
159
  for m in group_members:
72
160
  for u in m["members"]:
@@ -85,7 +173,7 @@ def l_groups_to_d_groups(l_groups: list = None):
85
173
  """
86
174
  names = []
87
175
  for a in l_groups:
88
- names.append(a['group_name'])
176
+ names.append(a["group_name"])
89
177
  logging.info(names)
90
178
 
91
179
  d_user_groups = dict(zip(names, l_groups))
@@ -93,36 +181,72 @@ def l_groups_to_d_groups(l_groups: list = None):
93
181
  return d_user_groups
94
182
 
95
183
 
96
- def extend_account_assignments(accounts_list, permissions_sets, store_arn,
97
- client_sso=boto3.client('identitystore', region_name="us-east-2")):
184
+ def extend_account_assignments(accounts_list, permissions_sets, store_arn, region):
98
185
  account_assignments = []
99
- for p in permissions_sets:
100
-
186
+ for p, y in zip(
187
+ permissions_sets,
188
+ track(
189
+ range(len(permissions_sets) - 1),
190
+ description="Getting account assignments ...",
191
+ ),
192
+ ):
101
193
  for ac in accounts_list:
102
- assign = list_account_assignments(instance_arn=store_arn, account_id=ac["Id"], client=client_sso,
103
- permission_set_arn=p)
194
+ assign = list_account_assignments(
195
+ instance_arn=store_arn,
196
+ account_id=ac["Id"],
197
+ region=region,
198
+ permission_set_arn=p,
199
+ )
104
200
  logging.debug(f"AccountAssignments {assign}")
105
201
  for a in assign:
106
202
  account_assignments.append(a)
107
203
  return account_assignments
108
204
 
109
205
 
110
- def add_users_and_groups_assign(account_assignments_list, user_and_group_list, user_list,
111
- list_permissions_set_arn_name):
112
- for a in account_assignments_list:
206
+ def add_users_and_groups_assign(
207
+ account_assignments_list,
208
+ user_and_group_list,
209
+ user_list,
210
+ list_permissions_set_arn_name,
211
+ ):
212
+ for a, y in zip(
213
+ account_assignments_list,
214
+ track(
215
+ range(len(account_assignments_list) - 1),
216
+ description="Create user and groups assignments ...",
217
+ ),
218
+ ):
113
219
  for g in user_and_group_list:
114
- if len(a) > 0 and a['PrincipalType'] == 'GROUP' and g["group_id"] == a['PrincipalId']:
115
- print(Fore.YELLOW +
116
- f"Account {a['AccountId']} assign to {a['PrincipalType']} {g['group_name']} with permission set {list_permissions_set_arn_name[a['PermissionSetArn']]} or {a['PermissionSetArn']}" + Fore.RESET)
117
-
118
- a["GroupName"] = g['group_name']
119
- a["PermissionSetName"] = list_permissions_set_arn_name[a['PermissionSetArn']]
220
+ if (
221
+ len(a) > 0
222
+ and a["PrincipalType"] == "GROUP"
223
+ and g["group_id"] == a["PrincipalId"]
224
+ ):
225
+ logging.info(
226
+ Fore.YELLOW
227
+ + f"Account {a['AccountId']} assign to {a['PrincipalType']} {g['group_name']} with permission set {list_permissions_set_arn_name[a['PermissionSetArn']]} or {a['PermissionSetArn']}"
228
+ + Fore.RESET
229
+ )
230
+
231
+ a["GroupName"] = g["group_name"]
232
+ a["PermissionSetName"] = list_permissions_set_arn_name[
233
+ a["PermissionSetArn"]
234
+ ]
120
235
  for u in user_list:
121
- if len(a) > 0 and a['PrincipalType'] == 'USER' and u["UserId"] == a['PrincipalId']:
122
- print(Fore.YELLOW +
123
- f"Account {a['AccountId']} assign to {a['PrincipalType']} {u['UserName']} with permission set {a['PermissionSetArn']} or {list_permissions_set_arn_name[a['PermissionSetArn']]}" + Fore.RESET)
124
- a["UserName"] = u['UserName']
125
- a["PermissionSetName"] = list_permissions_set_arn_name[a['PermissionSetArn']]
236
+ if (
237
+ len(a) > 0
238
+ and a["PrincipalType"] == "USER"
239
+ and u["UserId"] == a["PrincipalId"]
240
+ ):
241
+ logging.info(
242
+ Fore.YELLOW
243
+ + f"Account {a['AccountId']} assign to {a['PrincipalType']} {u['UserName']} with permission set {a['PermissionSetArn']} or {list_permissions_set_arn_name[a['PermissionSetArn']]}"
244
+ + Fore.RESET
245
+ )
246
+ a["UserName"] = u["UserName"]
247
+ a["PermissionSetName"] = list_permissions_set_arn_name[
248
+ a["PermissionSetArn"]
249
+ ]
126
250
  logging.debug(f"Account Assignments --> {account_assignments_list}")
127
251
  return account_assignments_list
128
252
 
@@ -132,7 +256,6 @@ def order_accounts_assignments_list(accounts_dict, account_assignments):
132
256
  for ac in accounts_dict:
133
257
  final_account_assignments[ac["Name"]] = []
134
258
  for a in account_assignments:
135
-
136
259
  if ac["Id"] == a["AccountId"]:
137
260
  final_account_assignments[ac["Name"]].append(a)
138
261
 
@@ -1,36 +1,79 @@
1
- import boto3
2
1
  import logging
3
2
 
3
+ from colorama import Fore
4
4
 
5
- def describe_organization(client=boto3.client('organizations')):
6
- organization = client.describe_organization()
5
+ from .describe_sso import client
6
+
7
+
8
+ def describe_organization(region):
9
+ """
10
+ Describe the organization.
11
+
12
+ :param region: AWS Region
13
+ :return:
14
+ """
15
+ print(f"{Fore.GREEN}❇️ Describe Organization {Fore.RESET}")
16
+ org_client = client("organizations", region_name=region)
17
+ organization = org_client.describe_organization()
7
18
  organization = organization["Organization"]
8
19
  return organization
9
20
 
10
21
 
11
- def list_roots(client=boto3.client('organizations')):
12
- roots = client.list_roots(
13
-
14
- )
22
+ def list_roots(region):
23
+ """
24
+ List the roots
25
+ :param region: AWS Region
26
+ :return:
27
+ """
28
+ org_client = client("organizations", region_name=region)
29
+ roots = org_client.list_roots()
15
30
  return roots["Roots"]
16
31
 
17
32
 
18
- def list_organizational_units(parent_id, client=boto3.client('organizations'), org_units=[]):
19
- ous = client.list_organizational_units_for_parent(
33
+ # def list organizational units pagination
34
+ def list_organizational_units_pag(parent_id, region, next_token=None):
35
+ org_client = client("organizations", region_name=region)
36
+ paginator = org_client.get_paginator("list_organizational_units_for_parent")
37
+ response_iterator = paginator.paginate(
20
38
  ParentId=parent_id,
39
+ PaginationConfig={"MaxItems": 1000, "PageSize": 4, "StartingToken": next_token},
40
+ )
41
+ return response_iterator["OrganizationalUnits"]
42
+
21
43
 
44
+ def list_organizational_units(parent_id, region, org_units=None):
45
+ org_client = client("organizations", region_name=region)
46
+ if org_units is None:
47
+ org_units = []
48
+ ous = org_client.list_organizational_units_for_parent(
49
+ ParentId=parent_id,
50
+ MaxResults=20,
22
51
  )
52
+ ous = ous["OrganizationalUnits"]
53
+
54
+ if len(ous) >= 20:
55
+ logging.info("Paginating ...")
56
+ add_ous = list_organizational_units_pag(
57
+ parent_id, region, next_token=ous["NextToken"]
58
+ )
59
+ for ou in add_ous:
60
+ ous.append(ou)
61
+ logging.debug(add_ous)
23
62
 
24
- for o in ous["OrganizationalUnits"]:
63
+ for o in ous:
25
64
  org_units.append(o)
26
- logging.debug("The parent Id is: ", parent_id)
65
+ logging.debug(
66
+ f"The parent Id is: {parent_id}",
67
+ )
27
68
  logging.debug(ous)
28
69
  if len(ous) > 0:
29
70
  for ou in ous["OrganizationalUnits"]:
30
71
  logging.debug(ou)
31
72
  if "Id" in ou.keys():
32
- logging.debug("Search nested for: ", ou["Name"])
33
- ous_next = list_organizational_units(ou["Id"], client=client, org_units=org_units)
73
+ logging.debug(f"Search nested for: {ou['Name']}")
74
+ ous_next = list_organizational_units(
75
+ ou["Id"], region=region, org_units=org_units
76
+ )
34
77
  logging.debug(ous_next)
35
78
  if len(ous_next) > 0:
36
79
  logging.debug("Find Netsted")
@@ -38,50 +81,61 @@ def list_organizational_units(parent_id, client=boto3.client('organizations'), o
38
81
  return org_units
39
82
 
40
83
 
41
- def list_parents(child_id, client=boto3.client('organizations')):
42
- response = client.list_parents(
43
- ChildId=child_id,
84
+ def list_parents(child_id, region):
85
+ """
86
+ List the parents of a child.
44
87
 
88
+ :param child_id:
89
+ :param region:
90
+ :return:
91
+ """
92
+ org_client = client("organizations", region_name=region)
93
+ response = org_client.list_parents(
94
+ ChildId=child_id,
45
95
  )
46
96
  return response["Parents"]
47
97
 
48
98
 
49
- def index_ous(list_ous, client=boto3.client('organizations')):
99
+ def index_ous(list_ous, region):
100
+ """
101
+ Index the parents of a child.
102
+
103
+ :param list_ous:
104
+ :param region:
105
+ :return list_ous:
106
+
107
+ """
108
+ org_client = client("organizations", region_name=region)
50
109
  for ou in list_ous:
51
110
  if "Id" in ou.keys() and len(ou) > 0:
52
- response = client.list_parents(
111
+ response = org_client.list_parents(
53
112
  ChildId=ou["Id"],
54
-
55
113
  )
56
114
  logging.debug(response["Parents"])
57
115
  ou["Parents"] = response["Parents"]
58
116
  return list_ous
59
117
 
60
118
 
61
- def list_accounts_pag(client=boto3.client('organizations'), next_token: str = None):
62
- paginator = client.get_paginator('list_accounts')
119
+ def list_accounts_pag(region, next_token: str = None):
120
+ org_client = client("organizations", region_name=region)
121
+ paginator = org_client.get_paginator("list_accounts")
63
122
  response_iterator = paginator.paginate(
64
- PaginationConfig={
65
- 'MaxItems': 1000,
66
- 'PageSize': 20,
67
- 'StartingToken': next_token
68
- }
123
+ PaginationConfig={"MaxItems": 1000, "PageSize": 20, "StartingToken": next_token}
69
124
  )
70
125
  response = response_iterator.build_full_result()
71
126
  logging.info(response_iterator.build_full_result())
72
127
  return response["Accounts"]
73
128
 
74
129
 
75
- def list_accounts(client=boto3.client('organizations')):
76
- accounts = client.list_accounts(
77
-
78
- )
130
+ def list_accounts(region):
131
+ org_client = client("organizations", region_name=region)
132
+ accounts = org_client.list_accounts()
79
133
  logging.info(accounts)
80
134
  l_account = accounts["Accounts"]
81
135
  logging.info(len(accounts["Accounts"]))
82
136
  if len(accounts["Accounts"]) >= 20:
83
137
  logging.info("Paginating ...")
84
- ad_accounts = list_accounts_pag(client=client, next_token=accounts["NextToken"])
138
+ ad_accounts = list_accounts_pag(region=region, next_token=accounts["NextToken"])
85
139
  for ad in ad_accounts:
86
140
  l_account.append(ad)
87
141
  logging.info(f"You Organizations have {len(l_account)} Accounts")
@@ -89,14 +143,15 @@ def list_accounts(client=boto3.client('organizations')):
89
143
  return l_account
90
144
 
91
145
 
92
- def index_accounts(list_account):
146
+ def index_accounts(list_account, region):
93
147
  accounts = []
94
- client = boto3.client('organizations')
148
+ org_client = client("organizations", region_name=region)
95
149
  for a in list_account:
96
- response = client.list_parents(
150
+ response = org_client.list_parents(
97
151
  ChildId=a["Id"],
98
-
99
152
  )
100
153
 
101
- accounts.append({"account": a["Id"], "name": a["Name"], "parents": response["Parents"]})
154
+ accounts.append(
155
+ {"account": a["Id"], "name": a["Name"], "parents": response["Parents"]}
156
+ )
102
157
  return accounts