regscale-cli 6.21.2.0__py3-none-any.whl → 6.28.2.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.
- regscale/_version.py +1 -1
- regscale/airflow/hierarchy.py +2 -2
- regscale/core/app/api.py +5 -2
- regscale/core/app/application.py +36 -6
- regscale/core/app/internal/control_editor.py +73 -21
- regscale/core/app/internal/evidence.py +727 -204
- regscale/core/app/internal/login.py +4 -2
- regscale/core/app/internal/model_editor.py +219 -64
- regscale/core/app/utils/app_utils.py +86 -12
- regscale/core/app/utils/catalog_utils/common.py +1 -1
- regscale/core/login.py +21 -4
- regscale/core/utils/async_graphql_client.py +363 -0
- regscale/core/utils/date.py +77 -1
- regscale/dev/cli.py +26 -0
- regscale/dev/code_gen.py +109 -24
- regscale/dev/version.py +72 -0
- regscale/integrations/commercial/__init__.py +30 -2
- regscale/integrations/commercial/aws/audit_manager_compliance.py +3908 -0
- regscale/integrations/commercial/aws/cli.py +3107 -54
- regscale/integrations/commercial/aws/cloudtrail_control_mappings.py +333 -0
- regscale/integrations/commercial/aws/cloudtrail_evidence.py +501 -0
- regscale/integrations/commercial/aws/cloudwatch_control_mappings.py +357 -0
- regscale/integrations/commercial/aws/cloudwatch_evidence.py +490 -0
- regscale/integrations/commercial/{amazon → aws}/common.py +71 -19
- regscale/integrations/commercial/aws/config_compliance.py +914 -0
- regscale/integrations/commercial/aws/conformance_pack_mappings.py +198 -0
- regscale/integrations/commercial/aws/control_compliance_analyzer.py +439 -0
- regscale/integrations/commercial/aws/evidence_generator.py +283 -0
- regscale/integrations/commercial/aws/guardduty_control_mappings.py +340 -0
- regscale/integrations/commercial/aws/guardduty_evidence.py +1053 -0
- regscale/integrations/commercial/aws/iam_control_mappings.py +368 -0
- regscale/integrations/commercial/aws/iam_evidence.py +574 -0
- regscale/integrations/commercial/aws/inventory/__init__.py +338 -22
- regscale/integrations/commercial/aws/inventory/base.py +107 -5
- regscale/integrations/commercial/aws/inventory/resources/analytics.py +390 -0
- regscale/integrations/commercial/aws/inventory/resources/applications.py +234 -0
- regscale/integrations/commercial/aws/inventory/resources/audit_manager.py +513 -0
- regscale/integrations/commercial/aws/inventory/resources/cloudtrail.py +315 -0
- regscale/integrations/commercial/aws/inventory/resources/cloudtrail_logs_metadata.py +476 -0
- regscale/integrations/commercial/aws/inventory/resources/cloudwatch.py +191 -0
- regscale/integrations/commercial/aws/inventory/resources/compute.py +328 -9
- regscale/integrations/commercial/aws/inventory/resources/config.py +464 -0
- regscale/integrations/commercial/aws/inventory/resources/containers.py +74 -9
- regscale/integrations/commercial/aws/inventory/resources/database.py +481 -31
- regscale/integrations/commercial/aws/inventory/resources/developer_tools.py +253 -0
- regscale/integrations/commercial/aws/inventory/resources/guardduty.py +286 -0
- regscale/integrations/commercial/aws/inventory/resources/iam.py +470 -0
- regscale/integrations/commercial/aws/inventory/resources/inspector.py +476 -0
- regscale/integrations/commercial/aws/inventory/resources/integration.py +175 -61
- regscale/integrations/commercial/aws/inventory/resources/kms.py +447 -0
- regscale/integrations/commercial/aws/inventory/resources/machine_learning.py +358 -0
- regscale/integrations/commercial/aws/inventory/resources/networking.py +390 -67
- regscale/integrations/commercial/aws/inventory/resources/s3.py +394 -0
- regscale/integrations/commercial/aws/inventory/resources/security.py +268 -72
- regscale/integrations/commercial/aws/inventory/resources/securityhub.py +473 -0
- regscale/integrations/commercial/aws/inventory/resources/storage.py +288 -29
- regscale/integrations/commercial/aws/inventory/resources/systems_manager.py +657 -0
- regscale/integrations/commercial/aws/inventory/resources/vpc.py +655 -0
- regscale/integrations/commercial/aws/kms_control_mappings.py +288 -0
- regscale/integrations/commercial/aws/kms_evidence.py +879 -0
- regscale/integrations/commercial/aws/ocsf/__init__.py +7 -0
- regscale/integrations/commercial/aws/ocsf/constants.py +115 -0
- regscale/integrations/commercial/aws/ocsf/mapper.py +435 -0
- regscale/integrations/commercial/aws/org_control_mappings.py +286 -0
- regscale/integrations/commercial/aws/org_evidence.py +666 -0
- regscale/integrations/commercial/aws/s3_control_mappings.py +356 -0
- regscale/integrations/commercial/aws/s3_evidence.py +632 -0
- regscale/integrations/commercial/aws/scanner.py +1072 -205
- regscale/integrations/commercial/aws/security_hub.py +319 -0
- regscale/integrations/commercial/aws/session_manager.py +282 -0
- regscale/integrations/commercial/aws/ssm_control_mappings.py +291 -0
- regscale/integrations/commercial/aws/ssm_evidence.py +492 -0
- regscale/integrations/commercial/jira.py +489 -153
- regscale/integrations/commercial/microsoft_defender/defender.py +326 -5
- regscale/integrations/commercial/microsoft_defender/defender_api.py +348 -14
- regscale/integrations/commercial/microsoft_defender/defender_constants.py +157 -0
- regscale/integrations/commercial/qualys/__init__.py +167 -68
- regscale/integrations/commercial/qualys/scanner.py +305 -39
- regscale/integrations/commercial/sarif/sairf_importer.py +432 -0
- regscale/integrations/commercial/sarif/sarif_converter.py +67 -0
- regscale/integrations/commercial/sicura/api.py +79 -42
- regscale/integrations/commercial/sicura/commands.py +8 -2
- regscale/integrations/commercial/sicura/scanner.py +83 -44
- regscale/integrations/commercial/stigv2/ckl_parser.py +5 -5
- regscale/integrations/commercial/synqly/assets.py +133 -16
- regscale/integrations/commercial/synqly/edr.py +2 -8
- regscale/integrations/commercial/synqly/query_builder.py +536 -0
- regscale/integrations/commercial/synqly/ticketing.py +27 -0
- regscale/integrations/commercial/synqly/vulnerabilities.py +165 -28
- regscale/integrations/commercial/tenablev2/cis_parsers.py +453 -0
- regscale/integrations/commercial/tenablev2/cis_scanner.py +447 -0
- regscale/integrations/commercial/tenablev2/commands.py +146 -5
- regscale/integrations/commercial/tenablev2/scanner.py +1 -3
- regscale/integrations/commercial/tenablev2/stig_parsers.py +113 -57
- regscale/integrations/commercial/wizv2/WizDataMixin.py +1 -1
- regscale/integrations/commercial/wizv2/click.py +191 -76
- regscale/integrations/commercial/wizv2/compliance/__init__.py +15 -0
- regscale/integrations/commercial/wizv2/{policy_compliance_helpers.py → compliance/helpers.py} +78 -60
- regscale/integrations/commercial/wizv2/compliance_report.py +1592 -0
- regscale/integrations/commercial/wizv2/core/__init__.py +133 -0
- regscale/integrations/commercial/wizv2/{async_client.py → core/client.py} +7 -3
- regscale/integrations/commercial/wizv2/{constants.py → core/constants.py} +92 -89
- regscale/integrations/commercial/wizv2/core/file_operations.py +237 -0
- regscale/integrations/commercial/wizv2/fetchers/__init__.py +11 -0
- regscale/integrations/commercial/wizv2/{data_fetcher.py → fetchers/policy_assessment.py} +66 -9
- regscale/integrations/commercial/wizv2/file_cleanup.py +104 -0
- regscale/integrations/commercial/wizv2/issue.py +776 -28
- regscale/integrations/commercial/wizv2/models/__init__.py +0 -0
- regscale/integrations/commercial/wizv2/parsers/__init__.py +34 -0
- regscale/integrations/commercial/wizv2/{parsers.py → parsers/main.py} +1 -1
- regscale/integrations/commercial/wizv2/processors/__init__.py +11 -0
- regscale/integrations/commercial/wizv2/{finding_processor.py → processors/finding.py} +1 -1
- regscale/integrations/commercial/wizv2/reports.py +243 -0
- regscale/integrations/commercial/wizv2/sbom.py +1 -1
- regscale/integrations/commercial/wizv2/scanner.py +1031 -441
- regscale/integrations/commercial/wizv2/utils/__init__.py +48 -0
- regscale/integrations/commercial/wizv2/{utils.py → utils/main.py} +116 -61
- regscale/integrations/commercial/wizv2/variables.py +89 -3
- regscale/integrations/compliance_integration.py +1036 -151
- regscale/integrations/control_matcher.py +432 -0
- regscale/integrations/due_date_handler.py +333 -0
- regscale/integrations/milestone_manager.py +291 -0
- regscale/integrations/public/__init__.py +14 -0
- regscale/integrations/public/cci_importer.py +834 -0
- regscale/integrations/public/csam/__init__.py +0 -0
- regscale/integrations/public/csam/csam.py +938 -0
- regscale/integrations/public/csam/csam_agency_defined.py +179 -0
- regscale/integrations/public/csam/csam_common.py +154 -0
- regscale/integrations/public/csam/csam_controls.py +432 -0
- regscale/integrations/public/csam/csam_poam.py +124 -0
- regscale/integrations/public/fedramp/click.py +77 -6
- regscale/integrations/public/fedramp/docx_parser.py +10 -1
- regscale/integrations/public/fedramp/fedramp_cis_crm.py +675 -289
- regscale/integrations/public/fedramp/fedramp_five.py +1 -1
- regscale/integrations/public/fedramp/poam/scanner.py +75 -7
- regscale/integrations/public/fedramp/poam_export_v5.py +888 -0
- regscale/integrations/scanner_integration.py +1961 -430
- regscale/models/integration_models/CCI_List.xml +1 -0
- regscale/models/integration_models/aqua.py +2 -2
- regscale/models/integration_models/cisa_kev_data.json +805 -11
- regscale/models/integration_models/flat_file_importer/__init__.py +5 -8
- regscale/models/integration_models/nexpose.py +36 -10
- regscale/models/integration_models/qualys.py +3 -4
- regscale/models/integration_models/synqly_models/capabilities.json +1 -1
- regscale/models/integration_models/synqly_models/connectors/vulnerabilities.py +87 -18
- regscale/models/integration_models/synqly_models/filter_parser.py +332 -0
- regscale/models/integration_models/synqly_models/ocsf_mapper.py +124 -25
- regscale/models/integration_models/synqly_models/synqly_model.py +89 -16
- regscale/models/locking.py +12 -8
- regscale/models/platform.py +4 -2
- regscale/models/regscale_models/__init__.py +7 -0
- regscale/models/regscale_models/assessment.py +2 -1
- regscale/models/regscale_models/catalog.py +1 -1
- regscale/models/regscale_models/compliance_settings.py +251 -1
- regscale/models/regscale_models/component.py +1 -0
- regscale/models/regscale_models/control_implementation.py +236 -41
- regscale/models/regscale_models/control_objective.py +74 -5
- regscale/models/regscale_models/file.py +2 -0
- regscale/models/regscale_models/form_field_value.py +5 -3
- regscale/models/regscale_models/inheritance.py +44 -0
- regscale/models/regscale_models/issue.py +301 -102
- regscale/models/regscale_models/milestone.py +33 -14
- regscale/models/regscale_models/organization.py +3 -0
- regscale/models/regscale_models/regscale_model.py +310 -73
- regscale/models/regscale_models/security_plan.py +4 -2
- regscale/models/regscale_models/vulnerability.py +3 -3
- regscale/regscale.py +25 -4
- regscale/templates/__init__.py +0 -0
- regscale/utils/threading/threadhandler.py +20 -15
- regscale/validation/record.py +23 -1
- {regscale_cli-6.21.2.0.dist-info → regscale_cli-6.28.2.1.dist-info}/METADATA +17 -33
- {regscale_cli-6.21.2.0.dist-info → regscale_cli-6.28.2.1.dist-info}/RECORD +310 -111
- tests/core/__init__.py +0 -0
- tests/core/utils/__init__.py +0 -0
- tests/core/utils/test_async_graphql_client.py +472 -0
- tests/fixtures/test_fixture.py +13 -8
- tests/regscale/core/test_login.py +171 -4
- tests/regscale/integrations/commercial/__init__.py +0 -0
- tests/regscale/integrations/commercial/aws/__init__.py +0 -0
- tests/regscale/integrations/commercial/aws/test_audit_manager_compliance.py +1304 -0
- tests/regscale/integrations/commercial/aws/test_audit_manager_evidence_aggregation.py +341 -0
- tests/regscale/integrations/commercial/aws/test_aws_analytics_collector.py +260 -0
- tests/regscale/integrations/commercial/aws/test_aws_applications_collector.py +242 -0
- tests/regscale/integrations/commercial/aws/test_aws_audit_manager_collector.py +1155 -0
- tests/regscale/integrations/commercial/aws/test_aws_cloudtrail_collector.py +534 -0
- tests/regscale/integrations/commercial/aws/test_aws_config_collector.py +400 -0
- tests/regscale/integrations/commercial/aws/test_aws_developer_tools_collector.py +203 -0
- tests/regscale/integrations/commercial/aws/test_aws_guardduty_collector.py +315 -0
- tests/regscale/integrations/commercial/aws/test_aws_iam_collector.py +458 -0
- tests/regscale/integrations/commercial/aws/test_aws_inspector_collector.py +353 -0
- tests/regscale/integrations/commercial/aws/test_aws_inventory_integration.py +530 -0
- tests/regscale/integrations/commercial/aws/test_aws_kms_collector.py +919 -0
- tests/regscale/integrations/commercial/aws/test_aws_machine_learning_collector.py +237 -0
- tests/regscale/integrations/commercial/aws/test_aws_s3_collector.py +722 -0
- tests/regscale/integrations/commercial/aws/test_aws_scanner_integration.py +722 -0
- tests/regscale/integrations/commercial/aws/test_aws_securityhub_collector.py +792 -0
- tests/regscale/integrations/commercial/aws/test_aws_systems_manager_collector.py +918 -0
- tests/regscale/integrations/commercial/aws/test_aws_vpc_collector.py +996 -0
- tests/regscale/integrations/commercial/aws/test_cli_evidence.py +431 -0
- tests/regscale/integrations/commercial/aws/test_cloudtrail_control_mappings.py +452 -0
- tests/regscale/integrations/commercial/aws/test_cloudtrail_evidence.py +788 -0
- tests/regscale/integrations/commercial/aws/test_config_compliance.py +298 -0
- tests/regscale/integrations/commercial/aws/test_conformance_pack_mappings.py +200 -0
- tests/regscale/integrations/commercial/aws/test_control_compliance_analyzer.py +375 -0
- tests/regscale/integrations/commercial/aws/test_datetime_parsing.py +223 -0
- tests/regscale/integrations/commercial/aws/test_evidence_generator.py +386 -0
- tests/regscale/integrations/commercial/aws/test_guardduty_control_mappings.py +564 -0
- tests/regscale/integrations/commercial/aws/test_guardduty_evidence.py +1041 -0
- tests/regscale/integrations/commercial/aws/test_iam_control_mappings.py +718 -0
- tests/regscale/integrations/commercial/aws/test_iam_evidence.py +1375 -0
- tests/regscale/integrations/commercial/aws/test_kms_control_mappings.py +656 -0
- tests/regscale/integrations/commercial/aws/test_kms_evidence.py +1163 -0
- tests/regscale/integrations/commercial/aws/test_ocsf_mapper.py +370 -0
- tests/regscale/integrations/commercial/aws/test_org_control_mappings.py +546 -0
- tests/regscale/integrations/commercial/aws/test_org_evidence.py +1240 -0
- tests/regscale/integrations/commercial/aws/test_s3_control_mappings.py +672 -0
- tests/regscale/integrations/commercial/aws/test_s3_evidence.py +987 -0
- tests/regscale/integrations/commercial/aws/test_scanner_evidence.py +373 -0
- tests/regscale/integrations/commercial/aws/test_security_hub_config_filtering.py +539 -0
- tests/regscale/integrations/commercial/aws/test_session_manager.py +516 -0
- tests/regscale/integrations/commercial/aws/test_ssm_control_mappings.py +588 -0
- tests/regscale/integrations/commercial/aws/test_ssm_evidence.py +735 -0
- tests/regscale/integrations/commercial/conftest.py +28 -0
- tests/regscale/integrations/commercial/microsoft_defender/__init__.py +1 -0
- tests/regscale/integrations/commercial/microsoft_defender/test_defender.py +1517 -0
- tests/regscale/integrations/commercial/microsoft_defender/test_defender_api.py +1748 -0
- tests/regscale/integrations/commercial/microsoft_defender/test_defender_constants.py +327 -0
- tests/regscale/integrations/commercial/microsoft_defender/test_defender_scanner.py +487 -0
- tests/regscale/integrations/commercial/test_aws.py +3742 -0
- tests/regscale/integrations/commercial/test_burp.py +48 -0
- tests/regscale/integrations/commercial/test_crowdstrike.py +49 -0
- tests/regscale/integrations/commercial/test_dependabot.py +341 -0
- tests/regscale/integrations/commercial/test_gcp.py +1543 -0
- tests/regscale/integrations/commercial/test_gitlab.py +549 -0
- tests/regscale/integrations/commercial/test_ip_mac_address_length.py +84 -0
- tests/regscale/integrations/commercial/test_jira.py +2204 -0
- tests/regscale/integrations/commercial/test_npm_audit.py +42 -0
- tests/regscale/integrations/commercial/test_okta.py +1228 -0
- tests/regscale/integrations/commercial/test_sarif_converter.py +251 -0
- tests/regscale/integrations/commercial/test_sicura.py +349 -0
- tests/regscale/integrations/commercial/test_snow.py +423 -0
- tests/regscale/integrations/commercial/test_sonarcloud.py +394 -0
- tests/regscale/integrations/commercial/test_sqlserver.py +186 -0
- tests/regscale/integrations/commercial/test_stig.py +33 -0
- tests/regscale/integrations/commercial/test_stig_mapper.py +153 -0
- tests/regscale/integrations/commercial/test_stigv2.py +406 -0
- tests/regscale/integrations/commercial/test_wiz.py +1365 -0
- tests/regscale/integrations/commercial/test_wiz_inventory.py +256 -0
- tests/regscale/integrations/commercial/wizv2/__init__.py +339 -0
- tests/regscale/integrations/commercial/wizv2/compliance/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/compliance/test_helpers.py +903 -0
- tests/regscale/integrations/commercial/wizv2/core/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/core/test_auth.py +701 -0
- tests/regscale/integrations/commercial/wizv2/core/test_client.py +1037 -0
- tests/regscale/integrations/commercial/wizv2/core/test_file_operations.py +989 -0
- tests/regscale/integrations/commercial/wizv2/fetchers/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/fetchers/test_policy_assessment.py +805 -0
- tests/regscale/integrations/commercial/wizv2/parsers/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/parsers/test_main.py +1153 -0
- tests/regscale/integrations/commercial/wizv2/processors/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/processors/test_finding.py +671 -0
- tests/regscale/integrations/commercial/wizv2/test_WizDataMixin.py +537 -0
- tests/regscale/integrations/commercial/wizv2/test_click_comprehensive.py +851 -0
- tests/regscale/integrations/commercial/wizv2/test_compliance_report_comprehensive.py +910 -0
- tests/regscale/integrations/commercial/wizv2/test_compliance_report_normalization.py +138 -0
- tests/regscale/integrations/commercial/wizv2/test_file_cleanup.py +283 -0
- tests/regscale/integrations/commercial/wizv2/test_file_operations.py +260 -0
- tests/regscale/integrations/commercial/wizv2/test_issue.py +343 -0
- tests/regscale/integrations/commercial/wizv2/test_issue_comprehensive.py +1203 -0
- tests/regscale/integrations/commercial/wizv2/test_reports.py +497 -0
- tests/regscale/integrations/commercial/wizv2/test_sbom.py +643 -0
- tests/regscale/integrations/commercial/wizv2/test_scanner_comprehensive.py +805 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_click_client_id.py +165 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_compliance_report.py +1394 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_compliance_unit.py +341 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_control_normalization.py +138 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_findings_comprehensive.py +364 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_inventory_comprehensive.py +644 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_status_mapping.py +149 -0
- tests/regscale/integrations/commercial/wizv2/test_wizv2.py +1218 -0
- tests/regscale/integrations/commercial/wizv2/test_wizv2_utils.py +519 -0
- tests/regscale/integrations/commercial/wizv2/utils/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/utils/test_main.py +1523 -0
- tests/regscale/integrations/public/__init__.py +0 -0
- tests/regscale/integrations/public/fedramp/__init__.py +1 -0
- tests/regscale/integrations/public/fedramp/test_gen_asset_list.py +150 -0
- tests/regscale/integrations/public/fedramp/test_poam_export_v5.py +1293 -0
- tests/regscale/integrations/public/test_alienvault.py +220 -0
- tests/regscale/integrations/public/test_cci.py +1053 -0
- tests/regscale/integrations/public/test_cisa.py +1021 -0
- tests/regscale/integrations/public/test_emass.py +518 -0
- tests/regscale/integrations/public/test_fedramp.py +1152 -0
- tests/regscale/integrations/public/test_fedramp_cis_crm.py +3661 -0
- tests/regscale/integrations/public/test_file_uploads.py +506 -0
- tests/regscale/integrations/public/test_oscal.py +453 -0
- tests/regscale/integrations/test_compliance_status_mapping.py +406 -0
- tests/regscale/integrations/test_control_matcher.py +1421 -0
- tests/regscale/integrations/test_control_matching.py +155 -0
- tests/regscale/integrations/test_milestone_manager.py +408 -0
- tests/regscale/models/test_control_implementation.py +118 -3
- tests/regscale/models/test_form_field_value_integration.py +304 -0
- tests/regscale/models/test_issue.py +378 -1
- tests/regscale/models/test_module_integration.py +582 -0
- tests/regscale/models/test_tenable_integrations.py +811 -105
- regscale/integrations/commercial/wizv2/policy_compliance.py +0 -3057
- regscale/integrations/public/fedramp/mappings/fedramp_r4_parts.json +0 -7388
- regscale/integrations/public/fedramp/mappings/fedramp_r5_parts.json +0 -9605
- regscale/integrations/public/fedramp/parts_mapper.py +0 -107
- /regscale/integrations/commercial/{amazon → sarif}/__init__.py +0 -0
- /regscale/integrations/commercial/wizv2/{wiz_auth.py → core/auth.py} +0 -0
- {regscale_cli-6.21.2.0.dist-info → regscale_cli-6.28.2.1.dist-info}/LICENSE +0 -0
- {regscale_cli-6.21.2.0.dist-info → regscale_cli-6.28.2.1.dist-info}/WHEEL +0 -0
- {regscale_cli-6.21.2.0.dist-info → regscale_cli-6.28.2.1.dist-info}/entry_points.txt +0 -0
- {regscale_cli-6.21.2.0.dist-info → regscale_cli-6.28.2.1.dist-info}/top_level.txt +0 -0
|
@@ -1,16 +1,36 @@
|
|
|
1
1
|
"""AWS database resource collectors."""
|
|
2
2
|
|
|
3
|
-
from typing import Dict, List, Any
|
|
3
|
+
from typing import Dict, List, Any, Optional
|
|
4
4
|
|
|
5
5
|
from ..base import BaseCollector
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class DatabaseCollector(BaseCollector):
|
|
9
|
-
"""Collector for AWS database resources."""
|
|
9
|
+
"""Collector for AWS database resources with filtering support."""
|
|
10
|
+
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
session: Any,
|
|
14
|
+
region: str,
|
|
15
|
+
account_id: Optional[str] = None,
|
|
16
|
+
tags: Optional[Dict[str, str]] = None,
|
|
17
|
+
enabled_services: Optional[Dict[str, bool]] = None,
|
|
18
|
+
):
|
|
19
|
+
"""
|
|
20
|
+
Initialize database collector with filtering support.
|
|
21
|
+
|
|
22
|
+
:param session: AWS session to use for API calls
|
|
23
|
+
:param str region: AWS region to collect from
|
|
24
|
+
:param str account_id: Optional AWS account ID to filter resources
|
|
25
|
+
:param dict tags: Optional tag filters (AND logic)
|
|
26
|
+
:param dict enabled_services: Optional dict of service names to boolean flags for enabling/disabling collection
|
|
27
|
+
"""
|
|
28
|
+
super().__init__(session, region, account_id, tags)
|
|
29
|
+
self.enabled_services = enabled_services or {}
|
|
10
30
|
|
|
11
31
|
def get_rds_instances(self) -> List[Dict[str, Any]]:
|
|
12
32
|
"""
|
|
13
|
-
Get information about RDS instances.
|
|
33
|
+
Get information about RDS instances with filtering.
|
|
14
34
|
|
|
15
35
|
:return: List of RDS instance information
|
|
16
36
|
:rtype: List[Dict[str, Any]]
|
|
@@ -22,10 +42,20 @@ class DatabaseCollector(BaseCollector):
|
|
|
22
42
|
|
|
23
43
|
for page in paginator.paginate():
|
|
24
44
|
for instance in page.get("DBInstances", []):
|
|
45
|
+
# Apply tag filtering
|
|
46
|
+
if self.tags and not self._matches_tags(instance.get("TagList", [])):
|
|
47
|
+
continue
|
|
48
|
+
|
|
49
|
+
# Apply account filtering using DBInstanceArn
|
|
50
|
+
instance_arn = instance.get("DBInstanceArn", "")
|
|
51
|
+
if not self._matches_account(instance_arn):
|
|
52
|
+
continue
|
|
53
|
+
|
|
25
54
|
instances.append(
|
|
26
55
|
{
|
|
27
56
|
"Region": self.region,
|
|
28
57
|
"DBInstanceIdentifier": instance.get("DBInstanceIdentifier"),
|
|
58
|
+
"DBInstanceArn": instance.get("DBInstanceArn"),
|
|
29
59
|
"DBInstanceClass": instance.get("DBInstanceClass"),
|
|
30
60
|
"Engine": instance.get("Engine"),
|
|
31
61
|
"EngineVersion": instance.get("EngineVersion"),
|
|
@@ -34,6 +64,7 @@ class DatabaseCollector(BaseCollector):
|
|
|
34
64
|
"AllocatedStorage": instance.get("AllocatedStorage"),
|
|
35
65
|
"InstanceCreateTime": str(instance.get("InstanceCreateTime")),
|
|
36
66
|
"VpcId": instance.get("DBSubnetGroup", {}).get("VpcId"),
|
|
67
|
+
"AvailabilityZone": instance.get("AvailabilityZone"),
|
|
37
68
|
"MultiAZ": instance.get("MultiAZ"),
|
|
38
69
|
"PubliclyAccessible": instance.get("PubliclyAccessible"),
|
|
39
70
|
"StorageEncrypted": instance.get("StorageEncrypted"),
|
|
@@ -45,9 +76,60 @@ class DatabaseCollector(BaseCollector):
|
|
|
45
76
|
self._handle_error(e, "RDS instances")
|
|
46
77
|
return instances
|
|
47
78
|
|
|
79
|
+
def _should_include_table(self, dynamodb, table_arn: str, table_name: str) -> bool:
|
|
80
|
+
"""
|
|
81
|
+
Check if table should be included based on account and tag filters.
|
|
82
|
+
|
|
83
|
+
:param dynamodb: DynamoDB client
|
|
84
|
+
:param str table_arn: Table ARN
|
|
85
|
+
:param str table_name: Table name
|
|
86
|
+
:return: True if table should be included, False otherwise
|
|
87
|
+
:rtype: bool
|
|
88
|
+
"""
|
|
89
|
+
if not self._matches_account(table_arn):
|
|
90
|
+
return False
|
|
91
|
+
|
|
92
|
+
if self.tags:
|
|
93
|
+
try:
|
|
94
|
+
tags_response = dynamodb.list_tags_of_resource(ResourceArn=table_arn)
|
|
95
|
+
table_tags = tags_response.get("Tags", [])
|
|
96
|
+
return self._matches_tags(table_tags)
|
|
97
|
+
except Exception as e:
|
|
98
|
+
self._handle_error(e, f"DynamoDB table tags for {table_name}")
|
|
99
|
+
return False
|
|
100
|
+
|
|
101
|
+
return True
|
|
102
|
+
|
|
103
|
+
def _build_table_data(self, table: Dict[str, Any]) -> Dict[str, Any]:
|
|
104
|
+
"""
|
|
105
|
+
Build table data dictionary.
|
|
106
|
+
|
|
107
|
+
:param table: Raw table data
|
|
108
|
+
:return: Processed table data
|
|
109
|
+
:rtype: Dict[str, Any]
|
|
110
|
+
"""
|
|
111
|
+
return {
|
|
112
|
+
"Region": self.region,
|
|
113
|
+
"TableName": table.get("TableName"),
|
|
114
|
+
"TableStatus": table.get("TableStatus"),
|
|
115
|
+
"CreationDateTime": str(table.get("CreationDateTime")),
|
|
116
|
+
"TableSizeBytes": table.get("TableSizeBytes"),
|
|
117
|
+
"ItemCount": table.get("ItemCount"),
|
|
118
|
+
"TableArn": table.get("TableArn"),
|
|
119
|
+
"ProvisionedThroughput": {
|
|
120
|
+
"ReadCapacityUnits": table.get("ProvisionedThroughput", {}).get("ReadCapacityUnits"),
|
|
121
|
+
"WriteCapacityUnits": table.get("ProvisionedThroughput", {}).get("WriteCapacityUnits"),
|
|
122
|
+
},
|
|
123
|
+
"BillingModeSummary": table.get("BillingModeSummary", {}),
|
|
124
|
+
"GlobalSecondaryIndexes": table.get("GlobalSecondaryIndexes", []),
|
|
125
|
+
"LocalSecondaryIndexes": table.get("LocalSecondaryIndexes", []),
|
|
126
|
+
"StreamSpecification": table.get("StreamSpecification", {}),
|
|
127
|
+
"SSEDescription": table.get("SSEDescription", {}),
|
|
128
|
+
}
|
|
129
|
+
|
|
48
130
|
def get_dynamodb_tables(self) -> List[Dict[str, Any]]:
|
|
49
131
|
"""
|
|
50
|
-
Get information about DynamoDB tables.
|
|
132
|
+
Get information about DynamoDB tables with filtering.
|
|
51
133
|
|
|
52
134
|
:return: List of DynamoDB table information
|
|
53
135
|
:rtype: List[Dict[str, Any]]
|
|
@@ -61,41 +143,409 @@ class DatabaseCollector(BaseCollector):
|
|
|
61
143
|
for table_name in page.get("TableNames", []):
|
|
62
144
|
try:
|
|
63
145
|
table = dynamodb.describe_table(TableName=table_name)["Table"]
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
"ItemCount": table.get("ItemCount"),
|
|
72
|
-
"TableArn": table.get("TableArn"),
|
|
73
|
-
"ProvisionedThroughput": {
|
|
74
|
-
"ReadCapacityUnits": table.get("ProvisionedThroughput", {}).get(
|
|
75
|
-
"ReadCapacityUnits"
|
|
76
|
-
),
|
|
77
|
-
"WriteCapacityUnits": table.get("ProvisionedThroughput", {}).get(
|
|
78
|
-
"WriteCapacityUnits"
|
|
79
|
-
),
|
|
80
|
-
},
|
|
81
|
-
"BillingModeSummary": table.get("BillingModeSummary", {}),
|
|
82
|
-
"GlobalSecondaryIndexes": table.get("GlobalSecondaryIndexes", []),
|
|
83
|
-
"LocalSecondaryIndexes": table.get("LocalSecondaryIndexes", []),
|
|
84
|
-
"StreamSpecification": table.get("StreamSpecification", {}),
|
|
85
|
-
"SSEDescription": table.get("SSEDescription", {}),
|
|
86
|
-
}
|
|
87
|
-
)
|
|
146
|
+
table_arn = table.get("TableArn", "")
|
|
147
|
+
|
|
148
|
+
if not self._should_include_table(dynamodb, table_arn, table_name):
|
|
149
|
+
continue
|
|
150
|
+
|
|
151
|
+
table_data = self._build_table_data(table)
|
|
152
|
+
tables.append(table_data)
|
|
88
153
|
except Exception as e:
|
|
89
154
|
self._handle_error(e, f"DynamoDB table {table_name}")
|
|
90
155
|
except Exception as e:
|
|
91
156
|
self._handle_error(e, "DynamoDB tables")
|
|
92
157
|
return tables
|
|
93
158
|
|
|
159
|
+
def get_elasticache_clusters(self) -> List[Dict[str, Any]]:
|
|
160
|
+
"""
|
|
161
|
+
Get information about ElastiCache clusters (Redis and Memcached).
|
|
162
|
+
|
|
163
|
+
:return: List of ElastiCache cluster information
|
|
164
|
+
:rtype: List[Dict[str, Any]]
|
|
165
|
+
"""
|
|
166
|
+
clusters = []
|
|
167
|
+
try:
|
|
168
|
+
elasticache = self._get_client("elasticache")
|
|
169
|
+
paginator = elasticache.get_paginator("describe_cache_clusters")
|
|
170
|
+
|
|
171
|
+
for page in paginator.paginate(ShowCacheNodeInfo=True):
|
|
172
|
+
for cluster in page.get("CacheClusters", []):
|
|
173
|
+
cluster_arn = cluster.get("ARN", "")
|
|
174
|
+
|
|
175
|
+
if not self._matches_account(cluster_arn):
|
|
176
|
+
continue
|
|
177
|
+
|
|
178
|
+
if not self._matches_tags(cluster.get("Tags", [])):
|
|
179
|
+
continue
|
|
180
|
+
|
|
181
|
+
clusters.append(
|
|
182
|
+
{
|
|
183
|
+
"Region": self.region,
|
|
184
|
+
"CacheClusterId": cluster.get("CacheClusterId"),
|
|
185
|
+
"CacheClusterArn": cluster_arn,
|
|
186
|
+
"Engine": cluster.get("Engine"),
|
|
187
|
+
"EngineVersion": cluster.get("EngineVersion"),
|
|
188
|
+
"CacheClusterStatus": cluster.get("CacheClusterStatus"),
|
|
189
|
+
"CacheNodeType": cluster.get("CacheNodeType"),
|
|
190
|
+
"NumCacheNodes": cluster.get("NumCacheNodes"),
|
|
191
|
+
"PreferredAvailabilityZone": cluster.get("PreferredAvailabilityZone"),
|
|
192
|
+
"CacheClusterCreateTime": cluster.get("CacheClusterCreateTime"),
|
|
193
|
+
"Tags": cluster.get("Tags", []),
|
|
194
|
+
}
|
|
195
|
+
)
|
|
196
|
+
except Exception as e:
|
|
197
|
+
self._handle_error(e, "ElastiCache clusters")
|
|
198
|
+
return clusters
|
|
199
|
+
|
|
200
|
+
def get_neptune_clusters(self) -> List[Dict[str, Any]]:
|
|
201
|
+
"""
|
|
202
|
+
Get information about Neptune graph database clusters.
|
|
203
|
+
|
|
204
|
+
:return: List of Neptune cluster information
|
|
205
|
+
:rtype: List[Dict[str, Any]]
|
|
206
|
+
"""
|
|
207
|
+
clusters = []
|
|
208
|
+
try:
|
|
209
|
+
neptune = self._get_client("neptune")
|
|
210
|
+
paginator = neptune.get_paginator("describe_db_clusters")
|
|
211
|
+
|
|
212
|
+
for page in paginator.paginate():
|
|
213
|
+
for cluster in page.get("DBClusters", []):
|
|
214
|
+
cluster_arn = cluster.get("DBClusterArn", "")
|
|
215
|
+
|
|
216
|
+
if not self._matches_account(cluster_arn):
|
|
217
|
+
continue
|
|
218
|
+
|
|
219
|
+
if not self._matches_tags(cluster.get("TagList", [])):
|
|
220
|
+
continue
|
|
221
|
+
|
|
222
|
+
clusters.append(
|
|
223
|
+
{
|
|
224
|
+
"Region": self.region,
|
|
225
|
+
"DBClusterIdentifier": cluster.get("DBClusterIdentifier"),
|
|
226
|
+
"DBClusterArn": cluster_arn,
|
|
227
|
+
"Engine": cluster.get("Engine"),
|
|
228
|
+
"EngineVersion": cluster.get("EngineVersion"),
|
|
229
|
+
"Status": cluster.get("Status"),
|
|
230
|
+
"Endpoint": cluster.get("Endpoint"),
|
|
231
|
+
"ReaderEndpoint": cluster.get("ReaderEndpoint"),
|
|
232
|
+
"MultiAZ": cluster.get("MultiAZ"),
|
|
233
|
+
"StorageEncrypted": cluster.get("StorageEncrypted"),
|
|
234
|
+
"KmsKeyId": cluster.get("KmsKeyId"),
|
|
235
|
+
"Tags": cluster.get("TagList", []),
|
|
236
|
+
}
|
|
237
|
+
)
|
|
238
|
+
except Exception as e:
|
|
239
|
+
self._handle_error(e, "Neptune clusters")
|
|
240
|
+
return clusters
|
|
241
|
+
|
|
242
|
+
def get_docdb_clusters(self) -> List[Dict[str, Any]]:
|
|
243
|
+
"""
|
|
244
|
+
Get information about DocumentDB clusters.
|
|
245
|
+
|
|
246
|
+
:return: List of DocumentDB cluster information
|
|
247
|
+
:rtype: List[Dict[str, Any]]
|
|
248
|
+
"""
|
|
249
|
+
clusters = []
|
|
250
|
+
try:
|
|
251
|
+
docdb = self._get_client("docdb")
|
|
252
|
+
paginator = docdb.get_paginator("describe_db_clusters")
|
|
253
|
+
|
|
254
|
+
for page in paginator.paginate():
|
|
255
|
+
for cluster in page.get("DBClusters", []):
|
|
256
|
+
cluster_arn = cluster.get("DBClusterArn", "")
|
|
257
|
+
|
|
258
|
+
if not self._matches_account(cluster_arn):
|
|
259
|
+
continue
|
|
260
|
+
|
|
261
|
+
if not self._matches_tags(cluster.get("TagList", [])):
|
|
262
|
+
continue
|
|
263
|
+
|
|
264
|
+
clusters.append(
|
|
265
|
+
{
|
|
266
|
+
"Region": self.region,
|
|
267
|
+
"DBClusterIdentifier": cluster.get("DBClusterIdentifier"),
|
|
268
|
+
"DBClusterArn": cluster_arn,
|
|
269
|
+
"Engine": cluster.get("Engine"),
|
|
270
|
+
"EngineVersion": cluster.get("EngineVersion"),
|
|
271
|
+
"Status": cluster.get("Status"),
|
|
272
|
+
"Endpoint": cluster.get("Endpoint"),
|
|
273
|
+
"ReaderEndpoint": cluster.get("ReaderEndpoint"),
|
|
274
|
+
"MultiAZ": cluster.get("MultiAZ"),
|
|
275
|
+
"StorageEncrypted": cluster.get("StorageEncrypted"),
|
|
276
|
+
"KmsKeyId": cluster.get("KmsKeyId"),
|
|
277
|
+
"Tags": cluster.get("TagList", []),
|
|
278
|
+
}
|
|
279
|
+
)
|
|
280
|
+
except Exception as e:
|
|
281
|
+
self._handle_error(e, "DocumentDB clusters")
|
|
282
|
+
return clusters
|
|
283
|
+
|
|
284
|
+
def get_redshift_clusters(self) -> List[Dict[str, Any]]:
|
|
285
|
+
"""
|
|
286
|
+
Get information about Redshift data warehouse clusters.
|
|
287
|
+
|
|
288
|
+
:return: List of Redshift cluster information
|
|
289
|
+
:rtype: List[Dict[str, Any]]
|
|
290
|
+
"""
|
|
291
|
+
clusters = []
|
|
292
|
+
try:
|
|
293
|
+
redshift = self._get_client("redshift")
|
|
294
|
+
paginator = redshift.get_paginator("describe_clusters")
|
|
295
|
+
|
|
296
|
+
for page in paginator.paginate():
|
|
297
|
+
for cluster in page.get("Clusters", []):
|
|
298
|
+
cluster_arn = (
|
|
299
|
+
f"arn:aws:redshift:{self.region}:{cluster.get('ClusterNamespaceArn', '').split(':')[4]}:"
|
|
300
|
+
f"cluster:{cluster.get('ClusterIdentifier')}"
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
if not self._matches_account(cluster_arn):
|
|
304
|
+
continue
|
|
305
|
+
|
|
306
|
+
if not self._matches_tags(cluster.get("Tags", [])):
|
|
307
|
+
continue
|
|
308
|
+
|
|
309
|
+
clusters.append(
|
|
310
|
+
{
|
|
311
|
+
"Region": self.region,
|
|
312
|
+
"ClusterIdentifier": cluster.get("ClusterIdentifier"),
|
|
313
|
+
"ClusterStatus": cluster.get("ClusterStatus"),
|
|
314
|
+
"NodeType": cluster.get("NodeType"),
|
|
315
|
+
"NumberOfNodes": cluster.get("NumberOfNodes"),
|
|
316
|
+
"DBName": cluster.get("DBName"),
|
|
317
|
+
"Endpoint": cluster.get("Endpoint"),
|
|
318
|
+
"ClusterCreateTime": cluster.get("ClusterCreateTime"),
|
|
319
|
+
"Encrypted": cluster.get("Encrypted"),
|
|
320
|
+
"KmsKeyId": cluster.get("KmsKeyId"),
|
|
321
|
+
"VpcId": cluster.get("VpcId"),
|
|
322
|
+
"PubliclyAccessible": cluster.get("PubliclyAccessible"),
|
|
323
|
+
"Tags": cluster.get("Tags", []),
|
|
324
|
+
}
|
|
325
|
+
)
|
|
326
|
+
except Exception as e:
|
|
327
|
+
self._handle_error(e, "Redshift clusters")
|
|
328
|
+
return clusters
|
|
329
|
+
|
|
330
|
+
def get_keyspaces(self) -> List[Dict[str, Any]]:
|
|
331
|
+
"""
|
|
332
|
+
Get information about Keyspaces (Apache Cassandra) keyspaces and tables.
|
|
333
|
+
|
|
334
|
+
:return: List of Keyspaces keyspace information
|
|
335
|
+
:rtype: List[Dict[str, Any]]
|
|
336
|
+
"""
|
|
337
|
+
keyspaces = []
|
|
338
|
+
try:
|
|
339
|
+
keyspaces_client = self._get_client("keyspaces")
|
|
340
|
+
paginator = keyspaces_client.get_paginator("list_keyspaces")
|
|
341
|
+
|
|
342
|
+
for page in paginator.paginate():
|
|
343
|
+
for keyspace in page.get("keyspaces", []):
|
|
344
|
+
keyspace_name = keyspace.get("keyspaceName")
|
|
345
|
+
keyspace_arn = keyspace.get("resourceArn", "")
|
|
346
|
+
|
|
347
|
+
if not self._matches_account(keyspace_arn):
|
|
348
|
+
continue
|
|
349
|
+
|
|
350
|
+
try:
|
|
351
|
+
tags_response = keyspaces_client.list_tags_for_resource(resourceArn=keyspace_arn)
|
|
352
|
+
keyspace_tags = tags_response.get("tags", [])
|
|
353
|
+
|
|
354
|
+
if not self._matches_tags(keyspace_tags):
|
|
355
|
+
continue
|
|
356
|
+
|
|
357
|
+
keyspaces.append(
|
|
358
|
+
{
|
|
359
|
+
"Region": self.region,
|
|
360
|
+
"KeyspaceName": keyspace_name,
|
|
361
|
+
"KeyspaceArn": keyspace_arn,
|
|
362
|
+
"Tags": keyspace_tags,
|
|
363
|
+
}
|
|
364
|
+
)
|
|
365
|
+
except Exception as tag_error:
|
|
366
|
+
self._handle_error(tag_error, f"Keyspaces tags for {keyspace_name}")
|
|
367
|
+
continue
|
|
368
|
+
|
|
369
|
+
except Exception as e:
|
|
370
|
+
self._handle_error(e, "Keyspaces")
|
|
371
|
+
return keyspaces
|
|
372
|
+
|
|
373
|
+
def _process_timestream_database(self, timestream: Any, database: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
|
374
|
+
"""
|
|
375
|
+
Process a single Timestream database.
|
|
376
|
+
|
|
377
|
+
:param timestream: Timestream client
|
|
378
|
+
:param dict database: Database information
|
|
379
|
+
:return: Database information or None if filtered out
|
|
380
|
+
:rtype: Optional[Dict[str, Any]]
|
|
381
|
+
"""
|
|
382
|
+
database_arn = database.get("Arn", "")
|
|
383
|
+
|
|
384
|
+
if not self._matches_account(database_arn):
|
|
385
|
+
return None
|
|
386
|
+
|
|
387
|
+
try:
|
|
388
|
+
tags_response = timestream.list_tags_for_resource(ResourceARN=database_arn)
|
|
389
|
+
db_tags = tags_response.get("Tags", [])
|
|
390
|
+
|
|
391
|
+
if not self._matches_tags(db_tags):
|
|
392
|
+
return None
|
|
393
|
+
|
|
394
|
+
return {
|
|
395
|
+
"Region": self.region,
|
|
396
|
+
"DatabaseName": database.get("DatabaseName"),
|
|
397
|
+
"DatabaseArn": database_arn,
|
|
398
|
+
"TableCount": database.get("TableCount"),
|
|
399
|
+
"KmsKeyId": database.get("KmsKeyId"),
|
|
400
|
+
"CreationTime": database.get("CreationTime"),
|
|
401
|
+
"Tags": db_tags,
|
|
402
|
+
}
|
|
403
|
+
except Exception as tag_error:
|
|
404
|
+
self._handle_error(tag_error, f"Timestream database tags for {database_arn}")
|
|
405
|
+
return None
|
|
406
|
+
|
|
407
|
+
def get_timestream_databases(self) -> List[Dict[str, Any]]:
|
|
408
|
+
"""
|
|
409
|
+
Get information about Timestream databases.
|
|
410
|
+
|
|
411
|
+
:return: List of Timestream database information
|
|
412
|
+
:rtype: List[Dict[str, Any]]
|
|
413
|
+
"""
|
|
414
|
+
databases = []
|
|
415
|
+
try:
|
|
416
|
+
timestream = self._get_client("timestream-write")
|
|
417
|
+
next_token = None
|
|
418
|
+
|
|
419
|
+
while True:
|
|
420
|
+
if next_token:
|
|
421
|
+
response = timestream.list_databases(NextToken=next_token)
|
|
422
|
+
else:
|
|
423
|
+
response = timestream.list_databases()
|
|
424
|
+
|
|
425
|
+
for database in response.get("Databases", []):
|
|
426
|
+
db_info = self._process_timestream_database(timestream, database)
|
|
427
|
+
if db_info:
|
|
428
|
+
databases.append(db_info)
|
|
429
|
+
|
|
430
|
+
next_token = response.get("NextToken")
|
|
431
|
+
if not next_token:
|
|
432
|
+
break
|
|
433
|
+
|
|
434
|
+
except Exception as e:
|
|
435
|
+
self._handle_error(e, "Timestream databases")
|
|
436
|
+
return databases
|
|
437
|
+
|
|
438
|
+
def _process_qldb_ledger(self, qldb: Any, ledger_name: str) -> Optional[Dict[str, Any]]:
|
|
439
|
+
"""
|
|
440
|
+
Process a single QLDB ledger.
|
|
441
|
+
|
|
442
|
+
:param qldb: QLDB client
|
|
443
|
+
:param str ledger_name: Ledger name
|
|
444
|
+
:return: Ledger information or None if filtered out
|
|
445
|
+
:rtype: Optional[Dict[str, Any]]
|
|
446
|
+
"""
|
|
447
|
+
try:
|
|
448
|
+
ledger_details = qldb.describe_ledger(Name=ledger_name)
|
|
449
|
+
ledger_arn = ledger_details.get("Arn", "")
|
|
450
|
+
|
|
451
|
+
if not self._matches_account(ledger_arn):
|
|
452
|
+
return None
|
|
453
|
+
|
|
454
|
+
tags_response = qldb.list_tags_for_resource(ResourceArn=ledger_arn)
|
|
455
|
+
ledger_tags = tags_response.get("Tags", {})
|
|
456
|
+
|
|
457
|
+
if not self._matches_tags(ledger_tags):
|
|
458
|
+
return None
|
|
459
|
+
|
|
460
|
+
return {
|
|
461
|
+
"Region": self.region,
|
|
462
|
+
"Name": ledger_name,
|
|
463
|
+
"Arn": ledger_arn,
|
|
464
|
+
"State": ledger_details.get("State"),
|
|
465
|
+
"CreationDateTime": ledger_details.get("CreationDateTime"),
|
|
466
|
+
"PermissionsMode": ledger_details.get("PermissionsMode"),
|
|
467
|
+
"DeletionProtection": ledger_details.get("DeletionProtection"),
|
|
468
|
+
"Tags": ledger_tags,
|
|
469
|
+
}
|
|
470
|
+
except Exception as ledger_error:
|
|
471
|
+
self._handle_error(ledger_error, f"QLDB ledger details for {ledger_name}")
|
|
472
|
+
return None
|
|
473
|
+
|
|
474
|
+
def get_qldb_ledgers(self) -> List[Dict[str, Any]]:
|
|
475
|
+
"""
|
|
476
|
+
Get information about QLDB (Quantum Ledger Database) ledgers.
|
|
477
|
+
|
|
478
|
+
:return: List of QLDB ledger information
|
|
479
|
+
:rtype: List[Dict[str, Any]]
|
|
480
|
+
"""
|
|
481
|
+
ledgers = []
|
|
482
|
+
try:
|
|
483
|
+
qldb = self._get_client("qldb")
|
|
484
|
+
next_token = None
|
|
485
|
+
|
|
486
|
+
while True:
|
|
487
|
+
if next_token:
|
|
488
|
+
response = qldb.list_ledgers(NextToken=next_token)
|
|
489
|
+
else:
|
|
490
|
+
response = qldb.list_ledgers()
|
|
491
|
+
|
|
492
|
+
for ledger in response.get("Ledgers", []):
|
|
493
|
+
ledger_name = ledger.get("Name")
|
|
494
|
+
ledger_info = self._process_qldb_ledger(qldb, ledger_name)
|
|
495
|
+
if ledger_info:
|
|
496
|
+
ledgers.append(ledger_info)
|
|
497
|
+
|
|
498
|
+
next_token = response.get("NextToken")
|
|
499
|
+
if not next_token:
|
|
500
|
+
break
|
|
501
|
+
|
|
502
|
+
except Exception as e:
|
|
503
|
+
self._handle_error(e, "QLDB ledgers")
|
|
504
|
+
return ledgers
|
|
505
|
+
|
|
94
506
|
def collect(self) -> Dict[str, Any]:
|
|
95
507
|
"""
|
|
96
|
-
Collect
|
|
508
|
+
Collect database resources based on enabled_services configuration.
|
|
97
509
|
|
|
98
|
-
:return: Dictionary containing
|
|
510
|
+
:return: Dictionary containing enabled database resource information
|
|
99
511
|
:rtype: Dict[str, Any]
|
|
100
512
|
"""
|
|
101
|
-
|
|
513
|
+
result = {}
|
|
514
|
+
|
|
515
|
+
# RDS Instances
|
|
516
|
+
if self.enabled_services.get("rds", True):
|
|
517
|
+
result["RDSInstances"] = self.get_rds_instances()
|
|
518
|
+
|
|
519
|
+
# DynamoDB Tables
|
|
520
|
+
if self.enabled_services.get("dynamodb", True):
|
|
521
|
+
result["DynamoDBTables"] = self.get_dynamodb_tables()
|
|
522
|
+
|
|
523
|
+
# ElastiCache Clusters
|
|
524
|
+
if self.enabled_services.get("elasticache", True):
|
|
525
|
+
result["ElastiCacheClusters"] = self.get_elasticache_clusters()
|
|
526
|
+
|
|
527
|
+
# Neptune Clusters
|
|
528
|
+
if self.enabled_services.get("neptune", True):
|
|
529
|
+
result["NeptuneClusters"] = self.get_neptune_clusters()
|
|
530
|
+
|
|
531
|
+
# DocumentDB Clusters
|
|
532
|
+
if self.enabled_services.get("docdb", True):
|
|
533
|
+
result["DocumentDBClusters"] = self.get_docdb_clusters()
|
|
534
|
+
|
|
535
|
+
# Redshift Clusters
|
|
536
|
+
if self.enabled_services.get("redshift", True):
|
|
537
|
+
result["RedshiftClusters"] = self.get_redshift_clusters()
|
|
538
|
+
|
|
539
|
+
# Keyspaces
|
|
540
|
+
if self.enabled_services.get("keyspaces", True):
|
|
541
|
+
result["Keyspaces"] = self.get_keyspaces()
|
|
542
|
+
|
|
543
|
+
# Timestream Databases
|
|
544
|
+
if self.enabled_services.get("timestream", True):
|
|
545
|
+
result["TimestreamDatabases"] = self.get_timestream_databases()
|
|
546
|
+
|
|
547
|
+
# QLDB Ledgers
|
|
548
|
+
if self.enabled_services.get("qldb", True):
|
|
549
|
+
result["QLDBLedgers"] = self.get_qldb_ledgers()
|
|
550
|
+
|
|
551
|
+
return result
|