runbooks 0.2.5__py3-none-any.whl → 0.7.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.
Files changed (249) hide show
  1. conftest.py +26 -0
  2. jupyter-agent/.env +2 -0
  3. jupyter-agent/.env.template +2 -0
  4. jupyter-agent/.gitattributes +35 -0
  5. jupyter-agent/.gradio/certificate.pem +31 -0
  6. jupyter-agent/README.md +16 -0
  7. jupyter-agent/__main__.log +8 -0
  8. jupyter-agent/app.py +256 -0
  9. jupyter-agent/cloudops-agent.png +0 -0
  10. jupyter-agent/ds-system-prompt.txt +154 -0
  11. jupyter-agent/jupyter-agent.png +0 -0
  12. jupyter-agent/llama3_template.jinja +123 -0
  13. jupyter-agent/requirements.txt +9 -0
  14. jupyter-agent/tmp/4ojbs8a02ir/jupyter-agent.ipynb +68 -0
  15. jupyter-agent/tmp/cm5iasgpm3p/jupyter-agent.ipynb +91 -0
  16. jupyter-agent/tmp/crqbsseag5/jupyter-agent.ipynb +91 -0
  17. jupyter-agent/tmp/hohanq1u097/jupyter-agent.ipynb +57 -0
  18. jupyter-agent/tmp/jns1sam29wm/jupyter-agent.ipynb +53 -0
  19. jupyter-agent/tmp/jupyter-agent.ipynb +27 -0
  20. jupyter-agent/utils.py +409 -0
  21. runbooks/__init__.py +71 -3
  22. runbooks/__main__.py +13 -0
  23. runbooks/aws/ec2_describe_instances.py +1 -1
  24. runbooks/aws/ec2_run_instances.py +8 -2
  25. runbooks/aws/ec2_start_stop_instances.py +17 -4
  26. runbooks/aws/ec2_unused_volumes.py +5 -1
  27. runbooks/aws/s3_create_bucket.py +4 -2
  28. runbooks/aws/s3_list_objects.py +6 -1
  29. runbooks/aws/tagging_lambda_handler.py +13 -2
  30. runbooks/aws/tags.json +12 -0
  31. runbooks/base.py +353 -0
  32. runbooks/cfat/README.md +49 -0
  33. runbooks/cfat/__init__.py +74 -0
  34. runbooks/cfat/app.ts +644 -0
  35. runbooks/cfat/assessment/__init__.py +40 -0
  36. runbooks/cfat/assessment/asana-import.csv +39 -0
  37. runbooks/cfat/assessment/cfat-checks.csv +31 -0
  38. runbooks/cfat/assessment/cfat.txt +520 -0
  39. runbooks/cfat/assessment/collectors.py +200 -0
  40. runbooks/cfat/assessment/jira-import.csv +39 -0
  41. runbooks/cfat/assessment/runner.py +387 -0
  42. runbooks/cfat/assessment/validators.py +290 -0
  43. runbooks/cfat/cli.py +103 -0
  44. runbooks/cfat/docs/asana-import.csv +24 -0
  45. runbooks/cfat/docs/cfat-checks.csv +31 -0
  46. runbooks/cfat/docs/cfat.txt +335 -0
  47. runbooks/cfat/docs/checks-output.png +0 -0
  48. runbooks/cfat/docs/cloudshell-console-run.png +0 -0
  49. runbooks/cfat/docs/cloudshell-download.png +0 -0
  50. runbooks/cfat/docs/cloudshell-output.png +0 -0
  51. runbooks/cfat/docs/downloadfile.png +0 -0
  52. runbooks/cfat/docs/jira-import.csv +24 -0
  53. runbooks/cfat/docs/open-cloudshell.png +0 -0
  54. runbooks/cfat/docs/report-header.png +0 -0
  55. runbooks/cfat/models.py +1026 -0
  56. runbooks/cfat/package-lock.json +5116 -0
  57. runbooks/cfat/package.json +38 -0
  58. runbooks/cfat/report.py +496 -0
  59. runbooks/cfat/reporting/__init__.py +46 -0
  60. runbooks/cfat/reporting/exporters.py +337 -0
  61. runbooks/cfat/reporting/formatters.py +496 -0
  62. runbooks/cfat/reporting/templates.py +135 -0
  63. runbooks/cfat/run-assessment.sh +23 -0
  64. runbooks/cfat/runner.py +69 -0
  65. runbooks/cfat/src/actions/check-cloudtrail-existence.ts +43 -0
  66. runbooks/cfat/src/actions/check-config-existence.ts +37 -0
  67. runbooks/cfat/src/actions/check-control-tower.ts +37 -0
  68. runbooks/cfat/src/actions/check-ec2-existence.ts +46 -0
  69. runbooks/cfat/src/actions/check-iam-users.ts +50 -0
  70. runbooks/cfat/src/actions/check-legacy-cur.ts +30 -0
  71. runbooks/cfat/src/actions/check-org-cloudformation.ts +30 -0
  72. runbooks/cfat/src/actions/check-vpc-existence.ts +43 -0
  73. runbooks/cfat/src/actions/create-asanaimport.ts +14 -0
  74. runbooks/cfat/src/actions/create-backlog.ts +372 -0
  75. runbooks/cfat/src/actions/create-jiraimport.ts +15 -0
  76. runbooks/cfat/src/actions/create-report.ts +616 -0
  77. runbooks/cfat/src/actions/define-account-type.ts +51 -0
  78. runbooks/cfat/src/actions/get-enabled-org-policy-types.ts +40 -0
  79. runbooks/cfat/src/actions/get-enabled-org-services.ts +26 -0
  80. runbooks/cfat/src/actions/get-idc-info.ts +34 -0
  81. runbooks/cfat/src/actions/get-org-da-accounts.ts +34 -0
  82. runbooks/cfat/src/actions/get-org-details.ts +35 -0
  83. runbooks/cfat/src/actions/get-org-member-accounts.ts +44 -0
  84. runbooks/cfat/src/actions/get-org-ous.ts +35 -0
  85. runbooks/cfat/src/actions/get-regions.ts +22 -0
  86. runbooks/cfat/src/actions/zip-assessment.ts +27 -0
  87. runbooks/cfat/src/types/index.d.ts +147 -0
  88. runbooks/cfat/tests/__init__.py +141 -0
  89. runbooks/cfat/tests/test_cli.py +340 -0
  90. runbooks/cfat/tests/test_integration.py +290 -0
  91. runbooks/cfat/tests/test_models.py +505 -0
  92. runbooks/cfat/tests/test_reporting.py +354 -0
  93. runbooks/cfat/tsconfig.json +16 -0
  94. runbooks/cfat/webpack.config.cjs +27 -0
  95. runbooks/config.py +260 -0
  96. runbooks/finops/README.md +337 -0
  97. runbooks/finops/__init__.py +86 -0
  98. runbooks/finops/aws_client.py +245 -0
  99. runbooks/finops/cli.py +151 -0
  100. runbooks/finops/cost_processor.py +410 -0
  101. runbooks/finops/dashboard_runner.py +448 -0
  102. runbooks/finops/helpers.py +355 -0
  103. runbooks/finops/main.py +14 -0
  104. runbooks/finops/profile_processor.py +174 -0
  105. runbooks/finops/types.py +66 -0
  106. runbooks/finops/visualisations.py +80 -0
  107. runbooks/inventory/.gitignore +354 -0
  108. runbooks/inventory/ArgumentsClass.py +261 -0
  109. runbooks/inventory/FAILED_SCRIPTS_TROUBLESHOOTING.md +619 -0
  110. runbooks/inventory/Inventory_Modules.py +6130 -0
  111. runbooks/inventory/LandingZone/delete_lz.py +1075 -0
  112. runbooks/inventory/PASSED_SCRIPTS_GUIDE.md +738 -0
  113. runbooks/inventory/README.md +1320 -0
  114. runbooks/inventory/__init__.py +62 -0
  115. runbooks/inventory/account_class.py +532 -0
  116. runbooks/inventory/all_my_instances_wrapper.py +123 -0
  117. runbooks/inventory/aws_decorators.py +201 -0
  118. runbooks/inventory/aws_organization.png +0 -0
  119. runbooks/inventory/cfn_move_stack_instances.py +1526 -0
  120. runbooks/inventory/check_cloudtrail_compliance.py +614 -0
  121. runbooks/inventory/check_controltower_readiness.py +1107 -0
  122. runbooks/inventory/check_landingzone_readiness.py +711 -0
  123. runbooks/inventory/cloudtrail.md +727 -0
  124. runbooks/inventory/collectors/__init__.py +20 -0
  125. runbooks/inventory/collectors/aws_compute.py +518 -0
  126. runbooks/inventory/collectors/aws_networking.py +275 -0
  127. runbooks/inventory/collectors/base.py +222 -0
  128. runbooks/inventory/core/__init__.py +19 -0
  129. runbooks/inventory/core/collector.py +303 -0
  130. runbooks/inventory/core/formatter.py +296 -0
  131. runbooks/inventory/delete_s3_buckets_objects.py +169 -0
  132. runbooks/inventory/discovery.md +81 -0
  133. runbooks/inventory/draw_org_structure.py +748 -0
  134. runbooks/inventory/ec2_vpc_utils.py +341 -0
  135. runbooks/inventory/find_cfn_drift_detection.py +272 -0
  136. runbooks/inventory/find_cfn_orphaned_stacks.py +719 -0
  137. runbooks/inventory/find_cfn_stackset_drift.py +733 -0
  138. runbooks/inventory/find_ec2_security_groups.py +669 -0
  139. runbooks/inventory/find_landingzone_versions.py +201 -0
  140. runbooks/inventory/find_vpc_flow_logs.py +1221 -0
  141. runbooks/inventory/inventory.sh +659 -0
  142. runbooks/inventory/list_cfn_stacks.py +558 -0
  143. runbooks/inventory/list_cfn_stackset_operation_results.py +252 -0
  144. runbooks/inventory/list_cfn_stackset_operations.py +734 -0
  145. runbooks/inventory/list_cfn_stacksets.py +453 -0
  146. runbooks/inventory/list_config_recorders_delivery_channels.py +681 -0
  147. runbooks/inventory/list_ds_directories.py +354 -0
  148. runbooks/inventory/list_ec2_availability_zones.py +286 -0
  149. runbooks/inventory/list_ec2_ebs_volumes.py +244 -0
  150. runbooks/inventory/list_ec2_instances.py +425 -0
  151. runbooks/inventory/list_ecs_clusters_and_tasks.py +562 -0
  152. runbooks/inventory/list_elbs_load_balancers.py +411 -0
  153. runbooks/inventory/list_enis_network_interfaces.py +526 -0
  154. runbooks/inventory/list_guardduty_detectors.py +568 -0
  155. runbooks/inventory/list_iam_policies.py +404 -0
  156. runbooks/inventory/list_iam_roles.py +518 -0
  157. runbooks/inventory/list_iam_saml_providers.py +359 -0
  158. runbooks/inventory/list_lambda_functions.py +882 -0
  159. runbooks/inventory/list_org_accounts.py +446 -0
  160. runbooks/inventory/list_org_accounts_users.py +354 -0
  161. runbooks/inventory/list_rds_db_instances.py +406 -0
  162. runbooks/inventory/list_route53_hosted_zones.py +318 -0
  163. runbooks/inventory/list_servicecatalog_provisioned_products.py +575 -0
  164. runbooks/inventory/list_sns_topics.py +360 -0
  165. runbooks/inventory/list_ssm_parameters.py +402 -0
  166. runbooks/inventory/list_vpc_subnets.py +433 -0
  167. runbooks/inventory/list_vpcs.py +422 -0
  168. runbooks/inventory/lockdown_cfn_stackset_role.py +224 -0
  169. runbooks/inventory/models/__init__.py +24 -0
  170. runbooks/inventory/models/account.py +192 -0
  171. runbooks/inventory/models/inventory.py +309 -0
  172. runbooks/inventory/models/resource.py +247 -0
  173. runbooks/inventory/recover_cfn_stack_ids.py +205 -0
  174. runbooks/inventory/requirements.txt +12 -0
  175. runbooks/inventory/run_on_multi_accounts.py +211 -0
  176. runbooks/inventory/tests/common_test_data.py +3661 -0
  177. runbooks/inventory/tests/common_test_functions.py +204 -0
  178. runbooks/inventory/tests/setup.py +24 -0
  179. runbooks/inventory/tests/src.py +18 -0
  180. runbooks/inventory/tests/test_cfn_describe_stacks.py +208 -0
  181. runbooks/inventory/tests/test_ec2_describe_instances.py +162 -0
  182. runbooks/inventory/tests/test_inventory_modules.py +55 -0
  183. runbooks/inventory/tests/test_lambda_list_functions.py +86 -0
  184. runbooks/inventory/tests/test_moto_integration_example.py +273 -0
  185. runbooks/inventory/tests/test_org_list_accounts.py +49 -0
  186. runbooks/inventory/update_aws_actions.py +173 -0
  187. runbooks/inventory/update_cfn_stacksets.py +1215 -0
  188. runbooks/inventory/update_cloudwatch_logs_retention_policy.py +294 -0
  189. runbooks/inventory/update_iam_roles_cross_accounts.py +478 -0
  190. runbooks/inventory/update_s3_public_access_block.py +539 -0
  191. runbooks/inventory/utils/__init__.py +23 -0
  192. runbooks/inventory/utils/aws_helpers.py +510 -0
  193. runbooks/inventory/utils/threading_utils.py +493 -0
  194. runbooks/inventory/utils/validation.py +682 -0
  195. runbooks/inventory/verify_ec2_security_groups.py +1430 -0
  196. runbooks/main.py +1004 -0
  197. runbooks/organizations/__init__.py +12 -0
  198. runbooks/organizations/manager.py +374 -0
  199. runbooks/security/README.md +447 -0
  200. runbooks/security/__init__.py +71 -0
  201. runbooks/{security_baseline → security}/checklist/alternate_contacts.py +8 -1
  202. runbooks/{security_baseline → security}/checklist/bucket_public_access.py +4 -1
  203. runbooks/{security_baseline → security}/checklist/cloudwatch_alarm_configuration.py +9 -2
  204. runbooks/{security_baseline → security}/checklist/guardduty_enabled.py +9 -2
  205. runbooks/{security_baseline → security}/checklist/multi_region_instance_usage.py +5 -1
  206. runbooks/{security_baseline → security}/checklist/root_access_key.py +6 -1
  207. runbooks/{security_baseline → security}/config-origin.json +1 -1
  208. runbooks/{security_baseline → security}/config.json +1 -1
  209. runbooks/{security_baseline → security}/permission.json +1 -1
  210. runbooks/{security_baseline → security}/report_generator.py +10 -2
  211. runbooks/{security_baseline → security}/report_template_en.html +7 -7
  212. runbooks/{security_baseline → security}/report_template_jp.html +7 -7
  213. runbooks/{security_baseline → security}/report_template_kr.html +12 -12
  214. runbooks/{security_baseline → security}/report_template_vn.html +7 -7
  215. runbooks/{security_baseline → security}/run_script.py +8 -2
  216. runbooks/{security_baseline → security}/security_baseline_tester.py +12 -4
  217. runbooks/{security_baseline → security}/utils/common.py +5 -1
  218. runbooks/utils/__init__.py +204 -0
  219. runbooks-0.7.0.dist-info/METADATA +375 -0
  220. runbooks-0.7.0.dist-info/RECORD +249 -0
  221. {runbooks-0.2.5.dist-info → runbooks-0.7.0.dist-info}/WHEEL +1 -1
  222. runbooks-0.7.0.dist-info/entry_points.txt +7 -0
  223. runbooks-0.7.0.dist-info/licenses/LICENSE +201 -0
  224. runbooks-0.7.0.dist-info/top_level.txt +3 -0
  225. runbooks/python101/calculator.py +0 -34
  226. runbooks/python101/config.py +0 -1
  227. runbooks/python101/exceptions.py +0 -16
  228. runbooks/python101/file_manager.py +0 -218
  229. runbooks/python101/toolkit.py +0 -153
  230. runbooks-0.2.5.dist-info/METADATA +0 -439
  231. runbooks-0.2.5.dist-info/RECORD +0 -61
  232. runbooks-0.2.5.dist-info/entry_points.txt +0 -3
  233. runbooks-0.2.5.dist-info/top_level.txt +0 -1
  234. /runbooks/{security_baseline/__init__.py → inventory/tests/script_test_data.py} +0 -0
  235. /runbooks/{security_baseline → security}/checklist/__init__.py +0 -0
  236. /runbooks/{security_baseline → security}/checklist/account_level_bucket_public_access.py +0 -0
  237. /runbooks/{security_baseline → security}/checklist/direct_attached_policy.py +0 -0
  238. /runbooks/{security_baseline → security}/checklist/iam_password_policy.py +0 -0
  239. /runbooks/{security_baseline → security}/checklist/iam_user_mfa.py +0 -0
  240. /runbooks/{security_baseline → security}/checklist/multi_region_trail.py +0 -0
  241. /runbooks/{security_baseline → security}/checklist/root_mfa.py +0 -0
  242. /runbooks/{security_baseline → security}/checklist/root_usage.py +0 -0
  243. /runbooks/{security_baseline → security}/checklist/trail_enabled.py +0 -0
  244. /runbooks/{security_baseline → security}/checklist/trusted_advisor.py +0 -0
  245. /runbooks/{security_baseline → security}/utils/__init__.py +0 -0
  246. /runbooks/{security_baseline → security}/utils/enums.py +0 -0
  247. /runbooks/{security_baseline → security}/utils/language.py +0 -0
  248. /runbooks/{security_baseline → security}/utils/level_const.py +0 -0
  249. /runbooks/{security_baseline → security}/utils/permission_list.py +0 -0
@@ -0,0 +1,733 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ AWS CloudFormation StackSet Drift Detection Management and Analysis Script
4
+
5
+ Comprehensive enterprise-grade tool for discovering, monitoring, and enabling drift detection
6
+ across CloudFormation StackSets in AWS Organizations environments. Designed for infrastructure
7
+ governance, compliance monitoring, and automated drift detection management with multi-threading
8
+ support for efficient large-scale StackSet operations.
9
+
10
+ Key Features:
11
+ - Multi-account CloudFormation StackSet drift detection discovery and status monitoring
12
+ - Automated drift detection enablement based on configurable time thresholds
13
+ - Fragment-based StackSet filtering for targeted drift detection management
14
+ - Multi-threaded drift detection operations for improved performance at scale
15
+ - Comprehensive status reporting with tabular output and optional file export
16
+ - Enterprise authentication with cross-account role assumption support
17
+ - Configurable time-based drift detection refresh policies
18
+
19
+ Enterprise Capabilities:
20
+ - CloudFormation StackSet lifecycle management and drift monitoring
21
+ - Organizational compliance tracking through systematic drift detection
22
+ - Automated infrastructure governance with policy-driven drift detection updates
23
+ - Multi-region StackSet drift status visibility and management
24
+ - Performance-optimized concurrent drift detection operations
25
+ - Comprehensive error handling for large-scale organizational environments
26
+
27
+ Operational Use Cases:
28
+ - Infrastructure compliance auditing across organizational StackSet deployments
29
+ - Automated drift detection enablement for StackSets exceeding age thresholds
30
+ - StackSet governance through systematic drift monitoring and reporting
31
+ - Enterprise infrastructure change tracking and compliance validation
32
+ - Organizational CloudFormation resource drift analysis and remediation planning
33
+
34
+ Output Format:
35
+ - Tabular display of StackSet drift detection status with account, region, and timing information
36
+ - Optional CSV/JSON export for integration with enterprise reporting systems
37
+ - Comprehensive operational metrics including drift detection age and status
38
+ - Color-coded terminal output for enhanced operational visibility
39
+
40
+ Authentication & Security:
41
+ - AWS Organizations cross-account access with IAM role assumption
42
+ - Multi-profile authentication support for organizational account management
43
+ - Regional validation and access control for secure StackSet operations
44
+ - Comprehensive error handling for authorization and access management
45
+
46
+ Performance & Scale:
47
+ - Multi-threaded drift detection operations for efficient large-scale processing
48
+ - Memory-efficient processing for extensive StackSet inventories
49
+ - Configurable concurrency limits for optimal AWS API usage and performance
50
+ - Progress tracking and operational timing for performance monitoring
51
+
52
+ Dependencies:
53
+ - boto3: AWS SDK for CloudFormation StackSet API operations
54
+ - Custom modules: Inventory_Modules, ArgumentsClass, account_class
55
+ - colorama: Enhanced terminal output and color formatting
56
+ - dateutil: Advanced date/time parsing and timezone handling
57
+
58
+ Authors: AWS CloudOps Team
59
+ Version: 2024.03.06
60
+ License: MIT
61
+ """
62
+
63
+ import logging
64
+ import sys
65
+ from datetime import datetime
66
+ from os.path import split
67
+ from time import time
68
+
69
+ import Inventory_Modules
70
+ from account_class import aws_acct_access
71
+ from ArgumentsClass import CommonArguments
72
+ from botocore.exceptions import ClientError
73
+ from colorama import Fore, init
74
+ from Inventory_Modules import display_results
75
+
76
+ # Initialize colorama for cross-platform colored terminal output
77
+ init()
78
+ __version__ = "2024.03.06"
79
+ begin_time = time() # Script execution timing for performance monitoring
80
+ sleep_interval = 5 # Default wait interval for drift detection operations
81
+
82
+
83
+ def parse_args(args):
84
+ """
85
+ Parse and validate command line arguments for CloudFormation StackSet drift detection operations.
86
+
87
+ Configures comprehensive CLI argument parsing with enterprise-grade options for StackSet
88
+ drift detection management, including profile authentication, regional targeting, fragment
89
+ filtering, drift detection enablement, and time-based refresh policies for organizational
90
+ infrastructure governance and compliance monitoring.
91
+
92
+ Args:
93
+ args (list): Command line arguments from sys.argv[1:] for argument parsing
94
+
95
+ Returns:
96
+ argparse.Namespace: Parsed arguments object containing:
97
+ - Profile: AWS profile name for authentication and cross-account access
98
+ - Region: Target AWS region for StackSet drift detection operations
99
+ - Fragments: StackSet name fragments for targeted filtering and discovery
100
+ - Exact: Boolean flag for exact fragment matching vs substring matching
101
+ - pstatus: StackSet status filter for 'active' vs all status types
102
+ - pEnable: Boolean flag to enable automated drift detection on eligible StackSets
103
+ - pDaysSince: Time threshold in days for drift detection refresh policy
104
+ - Filename: Optional output file path for results export and persistence
105
+ - Time: Boolean flag for execution timing and performance monitoring
106
+ - loglevel: Logging verbosity level for operational visibility
107
+
108
+ CLI Arguments:
109
+ Authentication & Targeting:
110
+ --profile (-p): AWS profile for authentication and account access
111
+ --region (-r): Target AWS region for StackSet operations
112
+
113
+ StackSet Filtering & Discovery:
114
+ --fragment (-f): StackSet name fragments for targeted search and filtering
115
+ --exact (-e): Enable exact fragment matching instead of substring search
116
+
117
+ Drift Detection Management:
118
+ --status (-s): StackSet status filter ('active' for operational StackSets only)
119
+ +enable: Automated drift detection enablement for eligible StackSets
120
+ --days_since (--ds): Age threshold in days for drift detection refresh
121
+
122
+ Output & Reporting:
123
+ --filename: Output file path for results export (CSV/JSON format)
124
+ --timing (-t): Enable execution timing and performance metrics
125
+ --loglevel (-v): Logging verbosity (DEBUG, INFO, WARNING, ERROR)
126
+
127
+ Enterprise Features:
128
+ - Multi-profile authentication for organizational account management
129
+ - Regional targeting with validation for StackSet drift detection operations
130
+ - Fragment-based filtering for targeted StackSet discovery and management
131
+ - Time-based drift detection refresh policies for compliance automation
132
+ - Flexible output options for integration with enterprise reporting systems
133
+
134
+ Validation & Error Handling:
135
+ - AWS profile validation with comprehensive error messaging
136
+ - Regional access validation preventing unauthorized operations
137
+ - Argument validation with detailed help text and usage examples
138
+ - Type checking and range validation for numeric parameters
139
+ """
140
+ # Extract script name for argument group organization and help display
141
+ script_path, script_name = split(sys.argv[0])
142
+
143
+ # Initialize common argument parser with enterprise authentication and targeting
144
+ parser = CommonArguments()
145
+ parser.singleprofile() # AWS profile for authentication and account access
146
+ parser.singleregion() # Target AWS region for StackSet operations
147
+ parser.extendedargs() # Extended arguments for account filtering and targeting
148
+ parser.fragment() # StackSet name fragment filtering for targeted discovery
149
+ parser.save_to_file() # Output file options for results export and persistence
150
+ parser.timing() # Execution timing for performance monitoring
151
+ parser.verbosity() # Logging verbosity for operational visibility
152
+ parser.version(__version__) # Script version for compatibility tracking
153
+
154
+ # Configure script-specific arguments for StackSet drift detection management
155
+ local = parser.my_parser.add_argument_group(script_name, "Parameters specific to this script")
156
+
157
+ # StackSet status filtering for operational vs all StackSet types
158
+ local.add_argument(
159
+ "-s",
160
+ "--status",
161
+ dest="pstatus",
162
+ metavar="CloudFormation status",
163
+ default="active",
164
+ help="StackSet status filter: 'active' for operational StackSets, 'all' for comprehensive discovery including deleted StackSets",
165
+ )
166
+
167
+ # Automated drift detection enablement for eligible StackSets
168
+ local.add_argument(
169
+ "+enable",
170
+ dest="pEnable",
171
+ action="store_true",
172
+ help="Enable automated drift detection on StackSets that haven't been checked within the specified time threshold",
173
+ )
174
+
175
+ # Time threshold for drift detection refresh policy and compliance automation
176
+ local.add_argument(
177
+ "--days_since",
178
+ "--ds",
179
+ dest="pDaysSince",
180
+ metavar="Number of days old",
181
+ type=int,
182
+ default=15,
183
+ help="Maximum age in days since last drift detection check before StackSet requires drift detection refresh (default: 15 days)",
184
+ )
185
+
186
+ return parser.my_parser.parse_args(args)
187
+
188
+
189
+ def setup_auth(fProfile: str) -> aws_acct_access:
190
+ """
191
+ Configure AWS authentication and validate account access for StackSet drift detection operations.
192
+
193
+ Establishes secure AWS authentication using the specified profile with comprehensive error
194
+ handling and validation. Provides operational context display including account information,
195
+ region targeting, fragment filtering, and drift detection enablement status for enterprise
196
+ StackSet management and infrastructure governance operations.
197
+
198
+ Args:
199
+ fProfile (str): AWS profile name for authentication and cross-account access
200
+ None or empty string defaults to default profile or environment credentials
201
+
202
+ Returns:
203
+ aws_acct_access: Authenticated AWS account access object containing:
204
+ - acct_number: AWS account number for operational context
205
+ - AccountType: Account type (root, member, etc.) for organizational visibility
206
+ - Region: Target AWS region for StackSet drift detection operations
207
+ - session: Authenticated boto3 session for CloudFormation API calls
208
+ - Success: Boolean indicating successful authentication and account access
209
+
210
+ Authentication Process:
211
+ 1. Initialize AWS account access object with specified profile
212
+ 2. Validate credential authenticity and account permissions
213
+ 3. Verify CloudFormation StackSet API access in target region
214
+ 4. Display comprehensive operational context for user confirmation
215
+ 5. Return authenticated account object for downstream operations
216
+
217
+ Operational Context Display:
218
+ - Account information including account number and organizational type
219
+ - Target region for StackSet drift detection operations
220
+ - Fragment filtering criteria for StackSet discovery and targeting
221
+ - Drift detection enablement status and operational mode
222
+ - User confirmation of operational parameters and scope
223
+
224
+ Error Handling:
225
+ - Connection errors with comprehensive error messaging and exit codes
226
+ - Authentication failures with detailed troubleshooting guidance
227
+ - Profile validation with specific error messaging for credential issues
228
+ - Regional access validation preventing unauthorized operations
229
+
230
+ Enterprise Security:
231
+ - Multi-profile authentication for organizational account management
232
+ - Cross-account role assumption validation for secure operations
233
+ - Regional access control ensuring authorized StackSet operations
234
+ - Comprehensive audit logging for security and compliance tracking
235
+
236
+ Raises:
237
+ SystemExit: On authentication failures or connection errors with specific exit codes:
238
+ - Exit code 8: Connection errors preventing AWS API access
239
+ - Exit code 99: Authentication failures or invalid credentials
240
+ """
241
+ try:
242
+ # Initialize AWS account access with profile-based authentication
243
+ aws_acct = aws_acct_access(fProfile)
244
+ except ConnectionError as my_Error:
245
+ # Handle connection errors with detailed logging and graceful exit
246
+ logging.error(f"Exiting due to error: {my_Error}")
247
+ sys.exit(8)
248
+
249
+ # Validate successful authentication and account access
250
+ if not aws_acct.Success:
251
+ print(f"{Fore.RED}Profile {pProfile} failed to access an account. Check credentials and try again{Fore.RESET}")
252
+ sys.exit(99)
253
+
254
+ # Display comprehensive operational context for user confirmation and audit logging
255
+ print()
256
+ print(f"You asked me to display drift detection status on stacksets that match the following:")
257
+ print(f"\t\tIn the {aws_acct.AccountType} account {aws_acct.acct_number}")
258
+ print(f"\t\tIn this Region: {pRegion}")
259
+
260
+ # Display fragment filtering criteria with exact vs substring matching context
261
+ if pExact:
262
+ print(f"\t\tFor stacksets that {Fore.RED}exactly match{Fore.RESET}: {pFragments}")
263
+ else:
264
+ print(
265
+ f"\t\tFor stacksets that contain th{'is fragment' if len(pFragments) == 1 else 'ese fragments'}: {pFragments}"
266
+ )
267
+
268
+ # Display drift detection enablement status for operational clarity
269
+ print(f"\t\tand enable drift detection on those stacksets, if they're not current") if pEnableDriftDetection else ""
270
+
271
+ print()
272
+ return aws_acct
273
+
274
+
275
+ def find_stack_sets(faws_acct: aws_acct_access, fStackSetFragmentlist: list = None, fExact: bool = False) -> dict:
276
+ """
277
+ Discover and enumerate CloudFormation StackSets with comprehensive drift detection metadata.
278
+
279
+ Performs targeted CloudFormation StackSet discovery using fragment-based filtering with
280
+ comprehensive error handling and drift detection metadata extraction. Designed for enterprise
281
+ StackSet lifecycle management, compliance monitoring, and automated drift detection operations
282
+ across organizational AWS environments.
283
+
284
+ Args:
285
+ faws_acct (aws_acct_access): Authenticated AWS account access object containing:
286
+ - session: boto3 session for CloudFormation API operations
287
+ - Region: Target AWS region for StackSet discovery operations
288
+ - acct_number: Account number for error logging and operational context
289
+ fStackSetFragmentlist (list): StackSet name fragments for targeted filtering
290
+ None defaults to ["all"] for comprehensive StackSet discovery
291
+ fExact (bool): Fragment matching mode for precision targeting
292
+ True: Exact fragment matching for specific StackSet identification
293
+ False: Substring matching for broader StackSet discovery
294
+
295
+ Returns:
296
+ dict: Comprehensive StackSet discovery results containing:
297
+ - Success: Boolean indicating successful StackSet discovery operation
298
+ - ErrorMessage: Detailed error information for troubleshooting and logging
299
+ - StackSets: Dictionary of discovered StackSets with drift detection metadata:
300
+ - StackSetName: CloudFormation StackSet identifier
301
+ - Status: Current StackSet operational status
302
+ - DriftStatus: Current drift detection status (DRIFTED, IN_SYNC, etc.)
303
+ - LastDriftCheckTimestamp: Most recent drift detection timestamp
304
+ - Stack_Instances_number: Count of StackSet instances across accounts/regions
305
+ - Additional operational metadata for governance and compliance
306
+
307
+ StackSet Discovery Features:
308
+ - Fragment-based filtering for targeted StackSet identification and management
309
+ - Comprehensive drift detection metadata extraction for compliance monitoring
310
+ - StackSet instance enumeration for organizational visibility and governance
311
+ - Status-based filtering for operational StackSet lifecycle management
312
+ - Regional StackSet discovery with cross-account instance visibility
313
+
314
+ Drift Detection Metadata:
315
+ - Current drift detection status for infrastructure change tracking
316
+ - Last drift check timestamps for compliance and policy enforcement
317
+ - Drift detection enablement status for automated governance workflows
318
+ - Instance-level drift aggregation for comprehensive compliance reporting
319
+
320
+ Error Handling & Resilience:
321
+ - AWS API authorization failure detection with detailed error logging
322
+ - CloudFormation service error handling with comprehensive error context
323
+ - Network connectivity error management with graceful degradation
324
+ - Regional access validation preventing unauthorized StackSet operations
325
+
326
+ Enterprise Integration:
327
+ - Structured result format for integration with enterprise reporting systems
328
+ - Comprehensive error messaging for operational troubleshooting and audit
329
+ - Performance-optimized discovery for large-scale StackSet inventories
330
+ - Organizational compliance tracking through systematic metadata extraction
331
+
332
+ Performance Considerations:
333
+ - Memory-efficient processing for extensive StackSet inventories
334
+ - Regional API optimization for improved discovery performance
335
+ - Concurrent-safe operations for integration with multi-threaded workflows
336
+ - Structured result caching for repeated discovery operations
337
+ """
338
+ # Configure default fragment filtering for comprehensive StackSet discovery
339
+ if fStackSetFragmentlist is None:
340
+ fStackSetFragmentlist = ["all"] # Default to all StackSets for comprehensive analysis
341
+
342
+ # Initialize StackSet discovery result structure with error tracking
343
+ StackSets = {"Success": False, "ErrorMessage": "", "StackSets": {}}
344
+
345
+ try:
346
+ # Execute comprehensive StackSet discovery with drift detection metadata extraction
347
+ StackSets = Inventory_Modules.find_stacksets3(faws_acct, faws_acct.Region, fStackSetFragmentlist, fExact, True)
348
+ except ClientError as my_Error:
349
+ # Handle AWS API client errors with specific authorization failure detection
350
+ if "AuthFailure" in str(my_Error):
351
+ error_message = f"{aws_acct.acct_number}: Authorization Failure"
352
+ logging.error(error_message)
353
+ else:
354
+ error_message = f"Error: {my_Error}"
355
+ logging.error(error_message)
356
+ StackSets["ErrorMessage"] = error_message
357
+ except Exception as my_Error:
358
+ # Handle comprehensive exceptions with detailed error logging
359
+ error_message = f"Error: {my_Error}"
360
+ logging.error(error_message)
361
+ StackSets["ErrorMessage"] = error_message
362
+
363
+ return StackSets
364
+
365
+
366
+ def enable_stack_set_drift_detection(faws_acct: aws_acct_access, fStackSets: dict = None):
367
+ """
368
+ Enable automated drift detection across multiple CloudFormation StackSets using multi-threading.
369
+
370
+ Executes comprehensive drift detection enablement operations across organizational StackSets
371
+ using multi-threaded processing for efficient large-scale operations. Monitors drift detection
372
+ operation progress with real-time status tracking and comprehensive error handling for enterprise
373
+ infrastructure governance and compliance automation.
374
+
375
+ Args:
376
+ faws_acct (aws_acct_access): Authenticated AWS account access object containing:
377
+ - session: boto3 session for CloudFormation StackSet API operations
378
+ - acct_number: Account number for operational logging and error context
379
+ - Region: Target AWS region for drift detection operations
380
+ fStackSets (dict): List of StackSets requiring drift detection enablement containing:
381
+ - StackSetName: CloudFormation StackSet identifier for drift detection
382
+ - NeedsDriftDetectionUpdate: Boolean indicating drift detection requirement
383
+ - Additional StackSet metadata for operational context and tracking
384
+
385
+ Returns:
386
+ dict: Updated StackSets dictionary with drift detection operation results containing:
387
+ - Success: Boolean indicating overall drift detection enablement success
388
+ - ErrorMessage: Detailed error information for failed operations
389
+ - Individual StackSet status updates with drift detection results
390
+
391
+ Multi-threaded Architecture:
392
+ - Queue-based worker pattern for concurrent drift detection operations
393
+ - Configurable worker thread pool with automatic scaling based on StackSet count
394
+ - Thread-safe operation monitoring with real-time progress tracking
395
+ - Graceful error handling for authorization and operational failures
396
+
397
+ Drift Detection Operation Management:
398
+ - Automated drift detection enablement on eligible StackSets
399
+ - Real-time operation status monitoring with progress indicators
400
+ - Operation completion tracking with timeout management
401
+ - Comprehensive error detection and recovery for failed operations
402
+
403
+ Progress Monitoring & Feedback:
404
+ - Real-time terminal progress display with operation status updates
405
+ - Configurable sleep intervals for optimal API usage and performance
406
+ - Operation timing tracking for performance monitoring and optimization
407
+ - Visual progress indicators for enhanced user experience
408
+
409
+ Error Handling & Resilience:
410
+ - AWS API authorization failure detection with graceful degradation
411
+ - CloudFormation service error management with detailed error logging
412
+ - Network connectivity error handling with operation retry capabilities
413
+ - Thread-safe error aggregation for comprehensive operation reporting
414
+
415
+ Enterprise Operational Features:
416
+ - Concurrent drift detection operations for improved performance at scale
417
+ - Comprehensive operational logging for audit and troubleshooting
418
+ - Resource-efficient processing for large-scale StackSet inventories
419
+ - Integration-ready result format for enterprise reporting and automation
420
+
421
+ Performance Optimization:
422
+ - Worker thread scaling based on StackSet count for optimal performance
423
+ - Memory-efficient processing with queue-based work distribution
424
+ - API rate limiting awareness with configurable sleep intervals
425
+ - Operational timing metrics for performance analysis and optimization
426
+ """
427
+ from queue import Queue
428
+ from threading import Thread
429
+ from time import sleep
430
+
431
+ class UpdateDriftDetection(Thread):
432
+ """
433
+ Multi-threaded worker class for concurrent drift detection enablement operations.
434
+
435
+ Implements thread-safe drift detection operations using queue-based work distribution
436
+ for efficient processing of CloudFormation StackSet drift detection across multiple
437
+ StackSets with comprehensive error handling and progress monitoring.
438
+ """
439
+
440
+ def __init__(self, queue):
441
+ Thread.__init__(self)
442
+ self.queue = queue
443
+
444
+ def run(self):
445
+ while True:
446
+ # Extract StackSet work item from queue for drift detection processing
447
+ c_aws_acct, c_stackset_name = self.queue.get()
448
+ logging.info(f"De-queued info for account {c_aws_acct.acct_number}")
449
+
450
+ try:
451
+ # Execute drift detection enablement with comprehensive status monitoring
452
+ logging.info(f"Attempting to run drift_detection on {c_stackset_name['StackSetName']}")
453
+ client = c_aws_acct.session.client("cloudformation")
454
+ logging.info(f"Enabling Drift Detection for {c_stackset_name['StackSetName']}")
455
+
456
+ # Initiate drift detection operation using custom inventory module
457
+ DD_Operation = Inventory_Modules.enable_drift_on_stackset3(
458
+ c_aws_acct, c_stackset_name["StackSetName"]
459
+ )
460
+
461
+ # Monitor drift detection operation progress with real-time status tracking
462
+ intervals_waited = 1
463
+ sleep(sleep_interval) # Initial wait for operation to start
464
+
465
+ # Poll drift detection operation status until completion
466
+ Status = client.describe_stack_set_operation(
467
+ StackSetName=c_stackset_name["StackSetName"], OperationId=DD_Operation["OperationId"]
468
+ )
469
+
470
+ # Continue monitoring while drift detection operation is running
471
+ while Status["StackSetOperation"]["Status"] in ["RUNNING"]:
472
+ Status = client.describe_stack_set_operation(
473
+ StackSetName=c_stackset_name["StackSetName"], OperationId=DD_Operation["OperationId"]
474
+ )
475
+ sleep(sleep_interval) # Wait between status checks to avoid API throttling
476
+
477
+ # Display real-time progress with timing information
478
+ print(
479
+ f"{ERASE_LINE}Waiting for {c_stackset_name['StackSetName']} to finish drift detection",
480
+ f"{sleep_interval * intervals_waited} seconds waited so far",
481
+ end="\r",
482
+ )
483
+ intervals_waited += 1
484
+ logging.info(f"Sleeping to allow {c_stackset_name['StackSetName']} to continue drift detection")
485
+
486
+ # Process drift detection operation completion status
487
+ if Status["Status"] in ["FAILED"]:
488
+ fStackSets["Success"] = False
489
+ fStackSets["ErrorMessage"] = Status["StackSetOperation"]["StackSetDriftDetectionDetails"]
490
+ else:
491
+ fStackSets["Success"] = True
492
+
493
+ except TypeError as my_Error:
494
+ # Handle type errors in drift detection processing with logging
495
+ logging.info(f"Error: {my_Error}")
496
+ continue
497
+ except ClientError as my_Error:
498
+ # Handle AWS API client errors with specific authorization failure detection
499
+ if "AuthFailure" in str(my_Error):
500
+ logging.error(f"Account {c_aws_acct.acct_number}: Authorization Failure")
501
+ continue
502
+ except KeyError as my_Error:
503
+ # Handle missing key errors in account access with detailed logging
504
+ logging.error(f"Account Access failed - trying to access {c_aws_acct.acct_number}")
505
+ logging.info(f"Actual Error: {my_Error}")
506
+ continue
507
+ finally:
508
+ # Mark queue item as completed for work distribution tracking
509
+ # Note: Commented metadata updates for potential future enhancement
510
+ # fStackSets[c_stackset_name]['AccountId'] = c_aws_acct.acct_number
511
+ # fStackSets[c_stackset_name]['Region'] = c_aws_acct.Region
512
+ self.queue.task_done()
513
+
514
+ # Configure optimal worker thread count based on StackSet count and system limits
515
+ WorkerThreads = min(len(fStackSets), 25)
516
+
517
+ # Initialize multi-threaded processing infrastructure for drift detection operations
518
+ checkqueue = Queue()
519
+
520
+ # Create and start worker thread pool for concurrent drift detection operations
521
+ for x in range(WorkerThreads):
522
+ worker = UpdateDriftDetection(checkqueue)
523
+ # Daemon threads allow main thread exit even if workers are still processing
524
+ worker.daemon = True
525
+ worker.start()
526
+
527
+ # Queue drift detection work items for worker thread processing
528
+ for stackset in fStackSets:
529
+ logging.info(f"Connecting to account {faws_acct.acct_number}")
530
+ try:
531
+ # Queue StackSet for drift detection processing with progress display
532
+ print(
533
+ f"{ERASE_LINE}Queuing stackset {stackset['StackSetName']} in account {faws_acct.acct_number} in region {faws_acct.Region}",
534
+ end="\r",
535
+ )
536
+ checkqueue.put((faws_acct, stackset))
537
+ except ClientError as my_Error:
538
+ # Handle authorization failures with informative error messaging
539
+ if "AuthFailure" in str(my_Error):
540
+ logging.error(
541
+ f"Authorization Failure accessing account {faws_acct.acct_number} in {faws_acct.Region} region"
542
+ )
543
+ logging.error(f"It's possible that the region {faws_acct.Region} hasn't been opted-into")
544
+ pass
545
+
546
+ # Wait for all worker threads to complete drift detection operations
547
+ checkqueue.join()
548
+ return fStackSets
549
+
550
+
551
+ def days_between_dates(fdate1: datetime, fdays_since: int):
552
+ """
553
+ Calculate time difference between drift detection timestamp and current time for compliance evaluation.
554
+
555
+ Performs comprehensive date arithmetic to determine whether CloudFormation StackSet drift detection
556
+ timestamps meet organizational compliance policies and time-based refresh requirements. Designed
557
+ for enterprise governance automation with timezone-aware date calculations and structured result
558
+ formatting for integration with automated compliance workflows.
559
+
560
+ Args:
561
+ fdate1 (datetime): Drift detection timestamp from CloudFormation StackSet metadata
562
+ None indicates drift detection has never been executed
563
+ Must be timezone-aware datetime object for accurate calculations
564
+ fdays_since (int): Maximum acceptable age in days for drift detection compliance
565
+ Organizational policy threshold for drift detection refresh requirements
566
+
567
+ Returns:
568
+ dict: Comprehensive drift detection age evaluation containing:
569
+ - Current: Boolean indicating compliance with organizational time policies
570
+ - NumberOfDays: Integer days since last drift detection for operational metrics
571
+ - ErrorMessage: Detailed error information for null or invalid timestamps
572
+
573
+ Compliance Policy Evaluation:
574
+ - Current=True: Drift detection age within acceptable organizational thresholds
575
+ - Current=False: Drift detection exceeds policy limits and requires refresh
576
+ - ErrorMessage: Indicates drift detection has never been executed (requires enablement)
577
+
578
+ Enterprise Features:
579
+ - Timezone-aware date calculations for accurate multi-region compliance evaluation
580
+ - Structured result format for integration with enterprise governance systems
581
+ - Comprehensive error handling for missing or invalid drift detection metadata
582
+ - Policy-driven compliance evaluation with configurable time thresholds
583
+
584
+ Date Calculation Logic:
585
+ 1. Validate drift detection timestamp existence and format
586
+ 2. Calculate absolute time difference between current time and drift detection timestamp
587
+ 3. Extract days component from timedelta for policy evaluation
588
+ 4. Compare against organizational policy threshold for compliance determination
589
+ 5. Return structured compliance result with operational metrics
590
+
591
+ Error Handling:
592
+ - Null timestamp handling for StackSets without drift detection history
593
+ - Type validation ensuring datetime objects for accurate calculations
594
+ - Timezone handling for consistent multi-region drift detection evaluation
595
+ - Comprehensive error messaging for troubleshooting and operational visibility
596
+
597
+ Integration Considerations:
598
+ - Structured result format for automated compliance reporting systems
599
+ - Policy threshold configurability for organizational governance flexibility
600
+ - Operational metrics inclusion for drift detection age tracking and analysis
601
+ - Error state handling for StackSets requiring initial drift detection enablement
602
+ """
603
+ from dateutil.tz import tzutc
604
+
605
+ # Validate drift detection timestamp existence for compliance evaluation
606
+ if fdate1 is None:
607
+ # Return structured error result for StackSets without drift detection history
608
+ response = {"Current": False, "ErrorMessage": "Drift Status never checked"}
609
+ return response
610
+ elif not isinstance(fdate1, datetime):
611
+ # Enforce datetime object requirement for accurate date arithmetic
612
+ raise ValueError("Date passed in should be datetime object")
613
+
614
+ # Calculate timezone-aware time difference for accurate compliance evaluation
615
+ date_difference = abs(datetime.now(tzutc()) - fdate1)
616
+
617
+ # Extract days component from timedelta for policy threshold comparison
618
+ number_of_days = date_difference.days
619
+
620
+ # Evaluate drift detection age against organizational compliance policy
621
+ if number_of_days <= fdays_since:
622
+ # Drift detection meets organizational compliance requirements
623
+ response = {"Current": True, "NumberOfDays": number_of_days}
624
+ else:
625
+ # Drift detection exceeds policy threshold and requires refresh
626
+ response = {"Current": False, "NumberOfDays": number_of_days}
627
+
628
+ return response
629
+
630
+
631
+ ##################
632
+ # Main
633
+ ##################
634
+ if __name__ == "__main__":
635
+ args = parse_args(sys.argv[1:])
636
+ pProfile = args.Profile
637
+ pRegion = args.Region
638
+ pFragments = args.Fragments
639
+ pExact = args.Exact
640
+ pDaysSince = args.pDaysSince
641
+ pstatus = args.pstatus
642
+ pFilename = args.Filename
643
+ pEnableDriftDetection = args.pEnable
644
+ pTiming = args.Time
645
+ AccountsToSkip = args.SkipAccounts
646
+ ProfilesToSkip = args.SkipProfiles
647
+ pAccounts = args.Accounts
648
+ pSaveFilename = args.Filename
649
+ verbose = args.loglevel
650
+
651
+ # Set Log Level
652
+ logging.basicConfig(level=verbose, format="[%(filename)s:%(lineno)s - %(funcName)20s() ] %(message)s")
653
+ logging.getLogger("boto3").setLevel(logging.CRITICAL)
654
+ logging.getLogger("botocore").setLevel(logging.CRITICAL)
655
+ logging.getLogger("s3transfer").setLevel(logging.CRITICAL)
656
+ logging.getLogger("urllib3").setLevel(logging.CRITICAL)
657
+ """
658
+ We should eventually create an argument here that would check on the status of the drift-detection using
659
+ "describe_stack_drift_detection_status", but we haven't created that function yet...
660
+ https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cloudformation.html#CloudFormation.Client.describe_stack_drift_detection_status
661
+ """
662
+
663
+ ##########################
664
+ ERASE_LINE = "\x1b[2K"
665
+
666
+ # Setup the aws_acct object, and the list of Regions
667
+ aws_acct = setup_auth(pProfile)
668
+
669
+ display_dict_stacksets = {
670
+ "AccountNumber": {"DisplayOrder": 1, "Heading": "Acct Number"},
671
+ "Region": {"DisplayOrder": 2, "Heading": "Region"},
672
+ "StackSetName": {"DisplayOrder": 3, "Heading": "Stack Set Name"},
673
+ "Status": {"DisplayOrder": 4, "Heading": "Stack Status"},
674
+ "Stack_Instances_number": {"DisplayOrder": 5, "Heading": "# of Instances"},
675
+ "DriftStatus": {"DisplayOrder": 6, "Heading": "Drift Status"},
676
+ "LastDriftCheckTimestamp": {"DisplayOrder": 7, "Heading": "Date Drift Checked"},
677
+ "NeedsDriftDetectionUpdate": {"DisplayOrder": 8, "Heading": "Needs update", "Condition": [True]},
678
+ }
679
+
680
+ # RegionList = Inventory_Modules.get_service_regions('cloudformation', pRegionList)
681
+
682
+ # Find StackSets to operate on and get the last detection status
683
+ StackSets = find_stack_sets(aws_acct, pFragments, pExact)
684
+ StackSetsList = [item for key, item in StackSets["StackSets"].items()]
685
+ for item in StackSetsList:
686
+ item["AccountNumber"] = aws_acct.acct_number
687
+ item["Region"] = aws_acct.Region
688
+ sorted_all_stacksets = sorted(StackSetsList, key=lambda x: (x["StackSetName"]))
689
+ for item in sorted_all_stacksets:
690
+ if (
691
+ "LastDriftCheckTimestamp" not in item.keys()
692
+ or not days_between_dates(item["LastDriftCheckTimestamp"], pDaysSince)["Current"]
693
+ ) and item.get("Stack_Instances_number", 0) > 0:
694
+ item["NeedsDriftDetectionUpdate"] = True
695
+ else:
696
+ item["NeedsDriftDetectionUpdate"] = False
697
+ display_results(sorted_all_stacksets, display_dict_stacksets, None, pSaveFilename)
698
+ # Enable drift_detection on those stacksets
699
+ DriftDetectionNeededStacksets = [item for item in StackSetsList if item["NeedsDriftDetectionUpdate"]]
700
+ if len(DriftDetectionNeededStacksets) == 0:
701
+ print()
702
+ print(f"The stacksets found all fall within current guidelines. No additional drift detection is necessary.")
703
+ print()
704
+ ReallyDetectDrift = False
705
+ else:
706
+ StackSetNamesThatNeededDriftDetection = [item["StackSetName"] for item in DriftDetectionNeededStacksets]
707
+ if verbose == logging.INFO:
708
+ print(
709
+ f"The following stacksets haven't been updated in at least {pDaysSince} days, and therefore need to be updated:"
710
+ )
711
+ for stackname in StackSetNamesThatNeededDriftDetection:
712
+ print(f"\t{stackname}")
713
+ ReallyDetectDrift = input(
714
+ f"Do you want to enable drift detection on th{'is' if len(DriftDetectionNeededStacksets) == 1 else 'ese'} {len(DriftDetectionNeededStacksets)} stackset{' that is not' if len(DriftDetectionNeededStacksets) == 1 else 's that are not'} current? (y/n)"
715
+ ) in ["Y", "y"]
716
+ if ReallyDetectDrift:
717
+ Drift_Status = enable_stack_set_drift_detection(aws_acct, DriftDetectionNeededStacksets)
718
+ StackSets = find_stack_sets(aws_acct, StackSetNamesThatNeededDriftDetection, True)
719
+ # Determine whether we want to update this status or not -
720
+ StackSetsList = [item for key, item in StackSets["StackSets"].items()]
721
+ sorted_all_stacksets = sorted(StackSetsList, key=lambda x: (x["StackSetName"]))
722
+ # Display results
723
+ display_results(sorted_all_stacksets, display_dict_stacksets, None, pSaveFilename)
724
+
725
+ print(ERASE_LINE)
726
+ print(f"{Fore.RED}Looked through {len(sorted_all_stacksets)} StackSets across the {pRegion} region{Fore.RESET}")
727
+ print()
728
+
729
+ if pTiming:
730
+ print(ERASE_LINE)
731
+ print(f"{Fore.GREEN}This script took {time() - begin_time:.3f} seconds{Fore.RESET}")
732
+ print("Thanks for using this script...")
733
+ print()