reverse-diagrams 1.2.2__py3-none-any.whl → 1.3.1__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,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: reverse_diagrams
3
- Version: 1.2.2
3
+ Version: 1.3.1
4
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
5
5
  Project-URL: Homepage, https://github.com/velez94/reverse_diagrams
6
6
  Project-URL: Bug Tracker, https://github.com/velez94/reverse_diagrams/issues
@@ -26,6 +26,7 @@ Requires-Dist: boto3>=1.26.44
26
26
  Requires-Dist: colorama>=0.4.4
27
27
  Requires-Dist: diagrams>=0.23.4
28
28
  Requires-Dist: emoji>=2.2.0
29
+ Requires-Dist: inquirer>=3.1.4
29
30
  Requires-Dist: rich>=13.7.0
30
31
  Description-Content-Type: text/markdown
31
32
 
@@ -39,10 +40,12 @@ Description-Content-Type: text/markdown
39
40
  - [Use](#use)
40
41
  - [Subcommands](#subcommands)
41
42
  - [watch](#watch)
42
- - [Service supported](#service-supported)
43
- - [AWS Organizations](#aws-organizations)
44
- - [Identity and Access Manager Center (SSO)](#identity-and-access-manager-center-sso)
45
- - [Additional Commands](#additional-commands)
43
+ - [Service supported](#service-supported)
44
+ - [AWS Organizations](#aws-organizations)
45
+ - [Identity and Access Manager Center (SSO)](#identity-and-access-manager-center-sso)
46
+ - [Additional Commands](#additional-commands)
47
+ - [watch](#watch-1)
48
+ - [Options](#options)
46
49
  - [Combine the options](#combine-the-options)
47
50
  - [Extras](#extras)
48
51
  - [Enable autocomplete](#enable-autocomplete)
@@ -53,10 +56,11 @@ Description-Content-Type: text/markdown
53
56
 
54
57
  > Continuous Documentation Tool - Documentation as Code Tool
55
58
 
56
- This package create reverse diagrams based on your current state in your cloud environment.
59
+ This package create diagrams and help to audit your services from your shell.
60
+
57
61
  # Requirement
58
62
 
59
- AWS programmatic access using AWS CLI. :arrow_right: [Configuring the AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html)
63
+ AWS programmatic access using AWS CLI. [Configuring the AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html)
60
64
 
61
65
 
62
66
  # Install
@@ -169,19 +173,47 @@ Create view of diagrams in console based on kind of diagram and json file.:
169
173
  diagrams/json/account_assignments.json.jso
170
174
  ```
171
175
 
172
- ## Service supported
176
+ # Service supported
173
177
 
174
- #### AWS Organizations
178
+ ## AWS Organizations
175
179
 
176
180
  ```commandline
177
181
  reverse_diagrams -p my-profile -o -r us-east-2
178
182
  ```
179
- #### Identity and Access Manager Center (SSO)
183
+ ## Identity and Access Manager Center (SSO)
180
184
 
181
185
  ```commandline
182
186
  reverse_diagrams -p my-profile -i -r us-east-2
183
187
  ```
184
- ## Additional Commands
188
+ # Additional Commands
189
+
190
+ ## watch
191
+ You can watch the configuration and summary in your shell based on json files generated previously.
192
+
193
+ ### Options
194
+
195
+ ```commandline
196
+ $ reverse_diagrams watch -h
197
+ usage: reverse_diagrams watch [-h] [-wo WATCH_GRAPH_ORGANIZATION] [-wi WATCH_GRAPH_IDENTITY] [-wa WATCH_GRAPH_ACCOUNTS_ASSIGNMENTS]
198
+
199
+ Create view of diagrams in console based on kind of diagram and json file.
200
+
201
+ options:
202
+ -h, --help show this help message and exit
203
+
204
+ Create view of diagrams in console based on kind of diagram and json file.:
205
+ -wo WATCH_GRAPH_ORGANIZATION, --watch_graph_organization WATCH_GRAPH_ORGANIZATION
206
+ Set if you want to see graph for your organization structure summary. For example: reverse_diagrams watch watch -wo diagrams/json/organizations.json
207
+ -wi WATCH_GRAPH_IDENTITY, --watch_graph_identity WATCH_GRAPH_IDENTITY
208
+ Set if you want to see graph for your groups and users. For example: reverse_diagrams watch watch -wi diagrams/json/groups.json
209
+ -wa WATCH_GRAPH_ACCOUNTS_ASSIGNMENTS, --watch_graph_accounts_assignments WATCH_GRAPH_ACCOUNTS_ASSIGNMENTS
210
+ Set if you want to see graph for your IAM Center- Accounts assignments. For example: reverse_diagrams watch watch -wa diagrams/json/account_assignments.json
211
+
212
+ ```
213
+
214
+ For example, to watch account assignments:
215
+
216
+ ![view Acoount assigments](docs/images/show_console_view.gif)
185
217
 
186
218
  ### Combine the options
187
219
 
@@ -1,9 +1,9 @@
1
1
  src/__init__.py,sha256=lOE8TAJF_WdxgxEBxVz9t8dC3s3t2c21VWYPrzfznkE,17
2
- src/reverse_diagrams.py,sha256=qFAEVbkLhpvttslCkSjCjlDF8Hu9u6NabGYledUeyD0,4236
3
- src/version.py,sha256=IjzCpUToK2ceTC9HDaPGKdRVJBSBX5GpUi-2XqbbVsY,48
2
+ src/reverse_diagrams.py,sha256=dVkz429-8MtDAfQFxVhchuuVrH8D-IcYyTBgRnw65cA,4208
3
+ src/version.py,sha256=lyd6uObU7M31dNBuGYnxL9c0wbRwaQfFrSpXL3QGeKs,48
4
4
  src/aws/__init__.py,sha256=lOE8TAJF_WdxgxEBxVz9t8dC3s3t2c21VWYPrzfznkE,17
5
- src/aws/describe_identity_store.py,sha256=y96MJUiPImyJBZMqcL7iomLxoCuKLdW-D8k7fJ0GaEM,15289
6
- src/aws/describe_organization.py,sha256=9k0LTTI31b1jiJ8id-VfnYmCNt1WAENCVRBCVahcKO4,13828
5
+ src/aws/describe_identity_store.py,sha256=oqw7KfwQFGySnQz-qAuJDCpRoJLTpN2eiyamXiln6x0,15364
6
+ src/aws/describe_organization.py,sha256=_FEikrnsP1HaXhfglaQwHfOR1KGdDtF6gc5DAPcXsRs,13962
7
7
  src/aws/describe_sso.py,sha256=z65RnoxJDVSMPB1TRJAxi8S8-DllwmaxxXaZ4uicSzU,4915
8
8
  src/banner/__init__.py,sha256=lOE8TAJF_WdxgxEBxVz9t8dC3s3t2c21VWYPrzfznkE,17
9
9
  src/banner/banner.py,sha256=XREWjVLp1-PHVdfBSoADgw0LvRpYU5u7NPaUraL9Els,3893
@@ -11,12 +11,11 @@ src/dgms/__init__.py,sha256=lOE8TAJF_WdxgxEBxVz9t8dC3s3t2c21VWYPrzfznkE,17
11
11
  src/dgms/graph_mapper.py,sha256=xutxzxLCIGSBfHCAF-BnWXN21bjzusA43ZhKtXUir2E,7714
12
12
  src/dgms/graph_template.py,sha256=IOEmTk9A0xqEhtdNnaFrVDJlBF0ggW0WpxosW4nbcQo,1217
13
13
  src/reports/__init__.py,sha256=lOE8TAJF_WdxgxEBxVz9t8dC3s3t2c21VWYPrzfznkE,17
14
- src/reports/console_view.py,sha256=V3k2iz3ITJFv3Q1FkLavJvqOOXi_EgkuTUrWVADyF-c,3020
15
- src/reports/organizations_complete_state.json,sha256=nP30DTrwlm5aw6YZB03CiLyK9snjTgdH1ZjZRq3bXVI,2628
14
+ src/reports/console_view.py,sha256=1_ET53Bn_vKlLmqr0Sih5szP5kNFCQRH4A8tXJgip2Y,5832
16
15
  src/reports/save_results.py,sha256=g-UphsQ_tfDhvNH3QNV7j68TWWvy44vbbjaNyn4KWhU,719
17
16
  src/reports/tes.py,sha256=c6TdxhAedfHjPrqaRw0nucdCEQOM9xKsgw35IOIDdYs,17691
18
- reverse_diagrams-1.2.2.dist-info/METADATA,sha256=vCNaELVCiVz2mD5TxTYHCXYUDXX4Ze1prk22Y6bkg7s,8106
19
- reverse_diagrams-1.2.2.dist-info/WHEEL,sha256=TJPnKdtrSue7xZ_AVGkp9YXcvDrobsjBds1du3Nx6dc,87
20
- reverse_diagrams-1.2.2.dist-info/entry_points.txt,sha256=VZNkrc7qUDbddTCH3pGd83EhUT3PHTx9MzpAk6bb6qc,63
21
- reverse_diagrams-1.2.2.dist-info/licenses/LICENSE,sha256=o6nDaQ7M9xbR0L7HSJ3A-1JbBPoZro_zhVPO4-M5CAQ,571
22
- reverse_diagrams-1.2.2.dist-info/RECORD,,
17
+ reverse_diagrams-1.3.1.dist-info/METADATA,sha256=xOmutWsxQYayFL0MQOw80RD9phB-eP4sGo812soczRk,9542
18
+ reverse_diagrams-1.3.1.dist-info/WHEEL,sha256=TJPnKdtrSue7xZ_AVGkp9YXcvDrobsjBds1du3Nx6dc,87
19
+ reverse_diagrams-1.3.1.dist-info/entry_points.txt,sha256=VZNkrc7qUDbddTCH3pGd83EhUT3PHTx9MzpAk6bb6qc,63
20
+ reverse_diagrams-1.3.1.dist-info/licenses/LICENSE,sha256=o6nDaQ7M9xbR0L7HSJ3A-1JbBPoZro_zhVPO4-M5CAQ,571
21
+ reverse_diagrams-1.3.1.dist-info/RECORD,,
@@ -15,6 +15,10 @@ from ..dgms.graph_template import (
15
15
  graph_template_sso,
16
16
  graph_template_sso_complete,
17
17
  )
18
+ from ..reports.console_view import (
19
+ create_account_assignments_view,
20
+ create_group_console_view,
21
+ )
18
22
  from ..reports.save_results import save_results
19
23
  from .describe_organization import list_accounts
20
24
  from .describe_sso import (
@@ -24,7 +28,6 @@ from .describe_sso import (
24
28
  list_instances,
25
29
  list_permissions_set,
26
30
  )
27
- from ..reports.console_view import create_console_view, create_account_assignments_view
28
31
 
29
32
 
30
33
  def list_groups_pag(identity_store_id, region, next_token: str = None):
@@ -59,8 +62,7 @@ def list_groups(identity_store_id, region):
59
62
  identity_client = client("identitystore", region_name=region)
60
63
 
61
64
  groups = identity_client.list_groups(
62
- IdentityStoreId=identity_store_id,
63
- MaxResults=20
65
+ IdentityStoreId=identity_store_id, MaxResults=20
64
66
  )
65
67
 
66
68
  logging.info(groups)
@@ -278,7 +280,7 @@ def extend_account_assignments(accounts_list, permissions_sets, store_arn, regio
278
280
  for p, y in zip(
279
281
  permissions_sets,
280
282
  track(
281
- range(len(permissions_sets) ),
283
+ range(len(permissions_sets)),
282
284
  description="Getting account assignments ...",
283
285
  ),
284
286
  ):
@@ -314,7 +316,7 @@ def add_users_and_groups_assign(
314
316
  for a, y in zip(
315
317
  account_assignments_list,
316
318
  track(
317
- range(len(account_assignments_list) ),
319
+ range(len(account_assignments_list)),
318
320
  description="Create user and groups assignments ...",
319
321
  ),
320
322
  ):
@@ -483,8 +485,10 @@ def graph_identity_center(diagrams_path, region, auto):
483
485
  print(Fore.RED + "❌ Error creating diagrams")
484
486
  print(command)
485
487
 
486
- create_console_view(file_path=f"{json_path}/groups.json")
487
- create_account_assignments_view(file_path=f"{json_path}/account_assignments.json")
488
+ create_group_console_view(groups=d_groups) # (f"{json_path}/groups.json")
489
+ create_account_assignments_view(
490
+ assign=f_accounts
491
+ ) # load_json(f"{json_path}/account_assignments.json"))
488
492
  else:
489
493
  print(
490
494
  Fore.YELLOW
@@ -242,80 +242,93 @@ def search_ou_map(map_ou: dict, ou_id, level=0, tree="."):
242
242
  return None
243
243
 
244
244
 
245
- def init_org_complete(root_id, org, list_ous, ):
245
+ def init_org_complete(
246
+ root_id,
247
+ org,
248
+ list_ous,
249
+ ):
250
+ """
251
+ Init organization dictionary.
252
+
253
+ :param root_id:
254
+ :param org:
255
+ :param list_ous:
256
+ :return:
257
+ """
246
258
  organizations_complete = {
247
259
  "rootId": root_id,
248
- "masterAccountId": org['MasterAccountId'],
260
+ "masterAccountId": org["MasterAccountId"],
249
261
  "noOutAccounts": [],
250
- "organizationalUnits": {}
262
+ "organizationalUnits": {},
251
263
  }
252
-
253
264
  # Iterate in ous for getting ous tree
254
265
  for a, i in zip(list_ous, range(len(list_ous))):
255
-
256
266
  for p in a["Parents"]:
257
267
  if p["Type"] == "ROOT":
258
- organizations_complete["organizationalUnits"][a['Name']] = {
259
- "Id": a['Id'],
260
- "Name": a['Name'],
268
+ organizations_complete["organizationalUnits"][a["Name"]] = {
269
+ "Id": a["Id"],
270
+ "Name": a["Name"],
261
271
  "accounts": {},
262
- "nestedOus": {}}
272
+ "nestedOus": {},
273
+ }
263
274
  return organizations_complete
264
275
 
265
276
 
266
277
  # create organization complete map
267
- def map_organizations_complete(organizations_complete: dict,
268
- list_ous, llist_accounts,
269
- reference_outs_list,
270
- ):
278
+ def map_organizations_complete(
279
+ organizations_complete: dict,
280
+ list_ous,
281
+ llist_accounts,
282
+ reference_outs_list,
283
+ ):
271
284
  """
272
285
  Create complete mapper file.
273
286
 
274
-
275
287
  :param reference_outs_list:
276
288
  :param organizations_complete:
277
289
  :param list_ous:
278
290
  :param llist_accounts:
279
291
  :return:
280
292
  """
281
-
282
293
  # Iterate in ous for getting ous tree
283
294
  for a, i in zip(list_ous, range(len(list_ous))):
284
-
285
295
  for p in a["Parents"]:
286
-
287
296
  if p["Type"] == "ORGANIZATIONAL_UNIT":
288
-
289
- o = find_ou_name(reference_outs_list, p['Id'])
297
+ o = find_ou_name(reference_outs_list, p["Id"])
290
298
 
291
299
  if o not in organizations_complete["organizationalUnits"].keys():
292
- p = search_ou_map(organizations_complete["organizationalUnits"], ou_id=o)
300
+ p = search_ou_map(
301
+ organizations_complete["organizationalUnits"], ou_id=o
302
+ )
293
303
  o = p["Name"]
294
304
 
295
305
  organizations_complete["organizationalUnits"][o]["nestedOus"][
296
- find_ou_name(reference_outs_list, a['Id'])] = {
297
-
298
- "Id": a['Id'],
299
- "Name": a['Name'],
300
- "accounts": [],
301
- "nestedOus": {}
302
-
303
- }
306
+ find_ou_name(reference_outs_list, a["Id"])
307
+ ] = {"Id": a["Id"], "Name": a["Name"], "accounts": [], "nestedOus": {}}
304
308
  # print(organizations_complete["organizationalUnits"][o]["nestedOus"])
305
- if len(organizations_complete["organizationalUnits"][o]["nestedOus"]) > 0:
306
- new_list_ous = organizations_complete["organizationalUnits"][o]["nestedOus"]
309
+ if (
310
+ len(organizations_complete["organizationalUnits"][o]["nestedOus"])
311
+ > 0
312
+ ):
313
+ new_list_ous = organizations_complete["organizationalUnits"][o][
314
+ "nestedOus"
315
+ ]
307
316
 
308
317
  new_list_ous = plop_dict_out(ous_list=list_ous, ou=new_list_ous)
309
318
  organizations_complete = map_organizations_complete(
310
319
  organizations_complete=organizations_complete,
311
320
  list_ous=new_list_ous,
312
321
  llist_accounts=llist_accounts,
313
- reference_outs_list=reference_outs_list)
322
+ reference_outs_list=reference_outs_list,
323
+ )
314
324
 
315
325
  return organizations_complete
316
326
 
317
327
 
318
- def plop_dict_out(ous_list: list, ou, ):
328
+ def plop_dict_out(
329
+ ous_list: list,
330
+ ou,
331
+ ):
319
332
  """
320
333
  Clean list.
321
334
 
@@ -324,7 +337,6 @@ def plop_dict_out(ous_list: list, ou, ):
324
337
  :return:
325
338
  """
326
339
  for o in ou.keys():
327
-
328
340
  # for c in ou.keys():
329
341
  for unit in ous_list:
330
342
  if unit["Id"] == ou[o]["Id"]:
@@ -348,18 +360,16 @@ def set_accounts_tree(llist_accounts, organizations_complete, list_ous):
348
360
  for p in c["parents"]:
349
361
  if p["Type"] == "ROOT":
350
362
  organizations_complete["noOutAccounts"].append(
351
- {
352
- "account": c["account"],
353
- "name": c['name']
354
- }
363
+ {"account": c["account"], "name": c["name"]}
355
364
  )
356
365
 
357
366
  for o, j in zip(list_ous, range(len(list_ous))):
358
367
  if p["Id"] == o["Id"] and p["Type"] == "ORGANIZATIONAL_UNIT":
359
- organizations_complete["organizationalUnits"][find_ou_name(list_ous, o['Id'])]["accounts"][
360
- c['name']] = {
368
+ organizations_complete["organizationalUnits"][
369
+ find_ou_name(list_ous, o["Id"])
370
+ ]["accounts"][c["name"]] = {
361
371
  "account": c["account"],
362
- "name": c['name']
372
+ "name": c["name"],
363
373
  }
364
374
 
365
375
  return organizations_complete
@@ -391,8 +401,7 @@ def graph_organizations(diagrams_path, region, auto):
391
401
  logging.debug(roots)
392
402
 
393
403
  print(
394
- Fore.BLUE
395
- + emoji.emojize(":sparkle: List Organizational Units " + Fore.RESET)
404
+ Fore.BLUE + emoji.emojize(":sparkle: List Organizational Units " + Fore.RESET)
396
405
  )
397
406
  logging.debug("The Organizational Units list ")
398
407
  ous = list_organizational_units(parent_id=roots[0]["Id"], region=region)
@@ -432,12 +441,20 @@ def graph_organizations(diagrams_path, region, auto):
432
441
  file_name = "organizations_complete.json"
433
442
  # view in console
434
443
  organizations_complete_f = map_organizations_complete(
435
- organizations_complete=init_org_complete(org=organization, root_id=roots[0]["Id"],
436
- list_ous=i_ous),
437
- llist_accounts=i_accounts, list_ous=i_ous, reference_outs_list=i_ous.copy()
444
+ organizations_complete=init_org_complete(
445
+ org=organization, root_id=roots[0]["Id"], list_ous=i_ous
446
+ ),
447
+ llist_accounts=i_accounts,
448
+ list_ous=i_ous,
449
+ reference_outs_list=i_ous.copy(),
450
+ )
451
+ organizations_complete_f = (
452
+ set_accounts_tree(
453
+ llist_accounts=i_accounts,
454
+ organizations_complete=organizations_complete_f,
455
+ list_ous=i_ous,
456
+ ),
438
457
  )
439
- organizations_complete_f = set_accounts_tree(llist_accounts=i_accounts,
440
- organizations_complete=organizations_complete_f, list_ous=i_ous),
441
458
 
442
459
  save_results(results=organizations_complete_f, filename=f"{json_path}/{file_name}")
443
460
 
@@ -1,9 +1,10 @@
1
+ """Create Console View."""
1
2
  import json
2
- from rich.console import Console
3
+
4
+ import inquirer
3
5
  from rich.columns import Columns
6
+ from rich.console import Console
4
7
  from rich.panel import Panel
5
- from colorama import Fore
6
- from rich.progress import track
7
8
 
8
9
 
9
10
  # load json file from path function
@@ -14,7 +15,7 @@ def load_json(path):
14
15
  :param path:
15
16
  :return:
16
17
  """
17
- with open(path, 'r') as f:
18
+ with open(path, "r") as f:
18
19
  return json.load(f)
19
20
 
20
21
 
@@ -28,7 +29,7 @@ def get_members(group):
28
29
  members_groups = {}
29
30
  for m in group:
30
31
  members_groups[group[m]["group_name"]] = []
31
- for mm in group[m]['members']:
32
+ for mm in group[m]["members"]:
32
33
  members_groups[group[m]["group_name"]].append(mm["MemberId"]["UserName"])
33
34
 
34
35
  return members_groups
@@ -48,23 +49,56 @@ def pretty_members(members):
48
49
  return string
49
50
 
50
51
 
51
- def create_console_view(file_path="diagrams/json/groups.json"):
52
+ def create_group_console_view(groups):
52
53
  """
53
54
  Create tree.
54
55
 
55
- :param file_path:
56
+ :param groups:
56
57
  :return:
57
58
  """
58
- try:
59
- c = load_json(file_path)
60
- members = get_members(c)
61
- console = Console()
62
- c = [Panel(f"[b][green]{group}[/b]\n[yellow]{pretty_members(members[group])}", expand=True) for group in c]
63
- console.print(Columns(c))
64
- except FileNotFoundError:
59
+ members = get_members(groups)
60
+ console = Console()
61
+ c = [
62
+ Panel(
63
+ f"[b][green]{group}[/b]\n[yellow]{pretty_members(members[group])}",
64
+ expand=True,
65
+ )
66
+ for group in groups
67
+ ]
68
+ console.print(Columns(c))
69
+
70
+
71
+ def single_create_group_assignments_view(members, group_name):
72
+ """
73
+ Create tree.
74
+
75
+ :param group_name:
76
+ :param members:
77
+ :return:
78
+ """
79
+ console = Console()
80
+ c = [Panel(f"[b]{group_name}[/b]\n[blue]{pretty_members(members)}", expand=True)]
81
+ console.print(Columns(c))
82
+
65
83
 
66
- print(f"{Fore.RED}File not found. {Fore.RESET}")
67
- raise
84
+ def create_string_account_assignment(account_assignment):
85
+ """
86
+ Create string account assignment.
87
+
88
+ :param account_assignment:
89
+ :return:
90
+ """
91
+ string = ""
92
+ if (
93
+ account_assignment["PrincipalType"] == "GROUP"
94
+ and "GroupName" in account_assignment.keys()
95
+ ):
96
+ string += f"GroupName: {account_assignment['GroupName']}\n"
97
+ elif account_assignment["PrincipalType"] == "USER":
98
+ string += f"UserName: {account_assignment['UserName']}\n"
99
+ if "PermissionSetName" in account_assignment.keys():
100
+ string += f"PermissionSetName: {account_assignment['PermissionSetName']}\n\n"
101
+ return string
68
102
 
69
103
 
70
104
  # get account assignments
@@ -76,39 +110,119 @@ def pretty_account_assignments(accounts: dict):
76
110
  :return:
77
111
  """
78
112
  string = ""
113
+ if isinstance(accounts, dict):
114
+ for a in accounts.keys():
115
+ for c in accounts[a]:
116
+ string += create_string_account_assignment(account_assignment=c)
117
+ elif isinstance(accounts, list):
118
+ for c in accounts:
119
+ string += create_string_account_assignment(account_assignment=c)
120
+ return string
79
121
 
80
- for a in accounts.keys():
81
- for c in accounts[a]:
82
122
 
83
- if c['PrincipalType'] == "GROUP" and "GroupName" in c.keys():
84
- string += f"GroupName: {c['GroupName']}\n"
85
- elif c['PrincipalType'] == "USER":
86
- string += f"UserName: {c['UserName']}\n"
87
- if "PermissionSetName" in c.keys():
88
- string += f"PermissionSetName: {c['PermissionSetName']}\n\n"
123
+ def single_create_account_assignments_view(assign, account_name):
124
+ """
125
+ Create tree.
126
+
127
+ :param account_name:
128
+ :param assign:
129
+ :return:
130
+ """
131
+ console = Console()
132
+ c = [
133
+ Panel(
134
+ f"[b]{account_name}[/b]\n[blue]{pretty_account_assignments(assign)}",
135
+ expand=True,
136
+ )
137
+ ]
138
+ console.print(Columns(c))
89
139
 
90
- return string
91
140
 
141
+ def create_console_view_from_input(assign):
142
+ """
143
+ Ask print single account.
92
144
 
93
- def create_account_assignments_view(file_path="diagrams/json/account_assignments.json"):
145
+ :param assign:
146
+ :return:
147
+ """
148
+ # execute while the user decide to leave
149
+ con = "yes"
150
+ while con == "yes":
151
+ questions = [
152
+ inquirer.List(
153
+ "account",
154
+ message="Which account do you want to see?",
155
+ choices=list(assign.keys()),
156
+ ),
157
+ ]
158
+ answers = inquirer.prompt(questions)
159
+ single_create_account_assignments_view(
160
+ assign[answers["account"]], account_name=answers["account"]
161
+ )
162
+ # execute while the user decide to leave
163
+ continue_ = [
164
+ inquirer.List(
165
+ name="ans",
166
+ message="Do you want to watch another account ?",
167
+ choices=["yes", "no"],
168
+ )
169
+ ]
170
+ continue_ans = inquirer.prompt(continue_)
171
+ con = continue_ans["ans"]
172
+
173
+
174
+ def ask_control(case):
175
+ """
176
+ Ask control.
177
+
178
+ :type case: object
179
+ :param case:
180
+ :return:
181
+ """
182
+ control_ = [
183
+ inquirer.List(
184
+ name="ans",
185
+ message=f"Do you want to watch all {case}?",
186
+ choices=["all", "one-at-time"],
187
+ )
188
+ ]
189
+ control_ans = inquirer.prompt(control_)
190
+ control = control_ans["ans"]
191
+ return control
192
+
193
+
194
+ def create_account_assignments_view(assign):
94
195
  """
95
196
  Create tree.
96
197
 
97
- :param file_path:
198
+ :param assign:
98
199
  :return:
99
200
  """
100
- assign = load_json(file_path)
201
+ control = ask_control(case="account assignments or account by account")
202
+ if control == "one-at-time":
203
+ create_console_view_from_input(assign=assign)
204
+ else:
205
+ console = Console()
206
+ c = [
207
+ Panel(
208
+ f"[b]{account}[/b]\n[blue]{pretty_account_assignments(assign)}",
209
+ expand=True,
210
+ )
211
+ for account in assign
212
+ ]
213
+ console.print(Columns(c))
101
214
 
102
- console = Console()
103
- c = [Panel(f"[b]{account}[/b]\n[blue]{pretty_account_assignments(assign)}", expand=True) for account in assign]
104
- console.print(Columns(c))
105
215
 
216
+ # create console view based on user input using inquirer
106
217
 
107
218
  # pretty for organizations
108
219
 
109
- def watch_on_demand(args, ):
220
+
221
+ def watch_on_demand(
222
+ args,
223
+ ):
110
224
  """
111
- Watch on demand graphs in cosole.
225
+ Watch on demand graphs in console.
112
226
 
113
227
  :param args:
114
228
  :return:
@@ -117,8 +231,8 @@ def watch_on_demand(args, ):
117
231
  # create_console_view(file_path=f"{diagrams_path}/json/organizations.json")
118
232
  print("Not available jet")
119
233
  if args.watch_graph_accounts_assignments:
120
- create_account_assignments_view(file_path=args.watch_graph_accounts_assignments)
234
+ assign = load_json(args.watch_graph_accounts_assignments)
235
+ create_account_assignments_view(assign=assign)
121
236
  if args.watch_graph_identity:
122
- create_console_view(file_path=args.watch_graph_identity)
123
-
124
-
237
+ c = load_json(args.watch_graph_identity)
238
+ create_group_console_view(groups=c)
src/reverse_diagrams.py CHANGED
@@ -8,8 +8,8 @@ from boto3 import setup_default_session
8
8
  from .aws.describe_identity_store import graph_identity_center
9
9
  from .aws.describe_organization import graph_organizations
10
10
  from .banner.banner import get_version
11
- from .version import __version__
12
11
  from .reports.console_view import watch_on_demand
12
+ from .version import __version__
13
13
 
14
14
 
15
15
  def main() -> int:
@@ -22,7 +22,7 @@ def main() -> int:
22
22
  parser = argparse.ArgumentParser(
23
23
  prog="reverse_diagrams",
24
24
  description="Create architecture diagram, inspect and audit your AWS services from your current state.",
25
- epilog="Thanks for using %(prog)s!"
25
+ epilog="Thanks for using %(prog)s!",
26
26
  )
27
27
 
28
28
  parser.add_argument(
@@ -66,7 +66,7 @@ def main() -> int:
66
66
  name="watch",
67
67
  description="Create view of diagrams in console based on kind of diagram and json file.",
68
68
  help="Create pretty console view: \n"
69
- "For example: %(prog)s watch -wi diagrams/json/account_assignments.json ",
69
+ "For example: %(prog)s watch -wi diagrams/json/account_assignments.json ",
70
70
  )
71
71
  # Add idp options
72
72
  watch_group = watch_parser.add_argument_group(
@@ -76,22 +76,19 @@ def main() -> int:
76
76
  "-wo",
77
77
  "--watch_graph_organization",
78
78
  help="Set if you want to see graph for your organization structure summary.\n"
79
- "For example: %(prog)s watch -wo diagrams/json/organizations.json",
80
-
79
+ "For example: %(prog)s watch -wo diagrams/json/organizations.json",
81
80
  )
82
81
  watch_group.add_argument(
83
82
  "-wi",
84
83
  "--watch_graph_identity",
85
84
  help="Set if you want to see graph for your groups and users. \n"
86
- "For example: %(prog)s watch -wi diagrams/json/groups.json",
87
-
85
+ "For example: %(prog)s watch -wi diagrams/json/groups.json",
88
86
  )
89
87
  watch_group.add_argument(
90
88
  "-wa",
91
89
  "--watch_graph_accounts_assignments",
92
90
  help="Set if you want to see graph for your IAM Center- Accounts assignments. \n"
93
- "For example: %(prog)s watch -wa diagrams/json/account_assignments.json.json",
94
-
91
+ "For example: %(prog)s watch -wa diagrams/json/account_assignments.json",
95
92
  )
96
93
 
97
94
  parser.add_argument("-v", "--version", help="Show version", action="store_true")
@@ -126,7 +123,6 @@ def main() -> int:
126
123
  diagrams_path=diagrams_path, region=region, auto=args.auto_create
127
124
  )
128
125
  if args.commands == "watch":
129
-
130
126
  watch_on_demand(args=args)
131
127
 
132
128
  if args.version:
src/version.py CHANGED
@@ -1,2 +1,2 @@
1
1
  """Set version file."""
2
- __version__ = "1.2.2"
2
+ __version__ = "1.3.1"
@@ -1,93 +0,0 @@
1
- {
2
- "rootId": "r-w3ow",
3
- "masterAccountId": "029921763173",
4
- "noOutAccounts": [
5
- {
6
- "account": "029921763173",
7
- "name": "Alejandro Velez"
8
- }
9
- ],
10
- "organizationalUnits": {
11
- "Research": {
12
- "Id": "ou-w3ow-oegm0al0",
13
- "Name": "Research",
14
- "accounts": {},
15
- "nestedOus": {}
16
- },
17
- "Dev": {
18
- "Id": "ou-w3ow-k24p2opx",
19
- "Name": "Dev",
20
- "accounts": {
21
- "LabVelCT": {
22
- "account": "994261317734",
23
- "name": "LabVelCT"
24
- },
25
- "Dev": {
26
- "account": "571340586587",
27
- "name": "Dev"
28
- }
29
- },
30
- "nestedOus": {}
31
- },
32
- "Core": {
33
- "Id": "ou-w3ow-93hiq3zr",
34
- "Name": "Core",
35
- "accounts": {
36
- "Log archive": {
37
- "account": "884478634998",
38
- "name": "Log archive"
39
- },
40
- "Audit": {
41
- "account": "895882538541",
42
- "name": "Audit"
43
- }
44
- },
45
- "nestedOus": {}
46
- },
47
- "Custom": {
48
- "Id": "ou-w3ow-5qsqi8b5",
49
- "Name": "Custom",
50
- "accounts": {
51
- "Prod": {
52
- "account": "582441254763",
53
- "name": "Prod"
54
- }
55
- },
56
- "nestedOus": {
57
- "NetstedOU": {
58
- "Id": "ou-w3ow-i9xzgb9x",
59
- "Name": "NetstedOU",
60
- "accounts": [],
61
- "nestedOus": {}
62
- },
63
- "NetstedOU2": {
64
- "Id": "ou-w3ow-i9xzgxxx",
65
- "Name": "NetstedOU2",
66
- "accounts": [],
67
- "nestedOus": {}
68
- },
69
- "NetstedOU3": {
70
- "Id": "ou-w3ow-i9xzgxx3",
71
- "Name": "NetstedOU3",
72
- "accounts": [],
73
- "nestedOus": {}
74
- }
75
- }
76
- },
77
- "Shared": {
78
- "Id": "ou-w3ow-w7dzhzcz",
79
- "Name": "Shared",
80
- "accounts": {
81
- "DevSecOps": {
82
- "account": "105171185823",
83
- "name": "DevSecOps"
84
- },
85
- "SharedServices": {
86
- "account": "155794986228",
87
- "name": "SharedServices"
88
- }
89
- },
90
- "nestedOus": {}
91
- }
92
- }
93
- }