ic-code 1.2.9__tar.gz → 1.3.1__tar.gz
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.
- {ic_code-1.2.9/src/ic_code.egg-info → ic_code-1.3.1}/PKG-INFO +3 -2
- {ic_code-1.2.9 → ic_code-1.3.1}/README.md +2 -1
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/cloudflare_configuration_example.md +1 -1
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/user_guide.md +1 -1
- {ic_code-1.2.9 → ic_code-1.3.1}/pyproject.toml +1 -1
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/__init__.py +1 -1
- ic_code-1.3.1/src/ic/platforms/aws/healthdashboard/__init__.py +1 -0
- ic_code-1.3.1/src/ic/platforms/aws/healthdashboard/reboot.py +350 -0
- {ic_code-1.2.9 → ic_code-1.3.1/src/ic_code.egg-info}/PKG-INFO +3 -2
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic_code.egg-info/SOURCES.txt +2 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/LICENSE +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/MANIFEST.in +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/SECURITY.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/config/default.yaml +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/README.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/_templates/configuration.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/_templates/installation.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/_templates/troubleshooting.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/_templates/usage.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/aws/README.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/aws/aws_cli_prd.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/aws/installation.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/ci-workflow-guide.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/config_migration.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/deployment.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/development/README.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/development/cleanup_summary.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/development/development_guide.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/development/import_patterns.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/development/migration_guide.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/gcp/GCP_CONFIGURATION_GUIDE.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/gcp/GCP_SECURITY_BEST_PRACTICES.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/gcp/README.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/general/configuration.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/installation.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/migration.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/migration_guide.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/oci/README.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/oci/installation.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/release-guide.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/security.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/ssh/configuration.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/docs/troubleshooting.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/requirements.txt +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/scripts/analysis_summary.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/scripts/bump-version.sh +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/scripts/cf_edge_nsg_make/cf_edge_nsg_make.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/scripts/ci-detect-platforms.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/scripts/ci-generate-matrix.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/scripts/cli_usage_analysis.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/scripts/dependency_mapper.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/scripts/deploy.sh +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/scripts/final_validation_and_documentation.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/scripts/fix_consolidated_imports.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/scripts/migration_execution_and_validation.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/scripts/oracle-policy/user_policy.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/scripts/performance_optimization.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/scripts/setup_venv.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/scripts/test-ci-detection.sh +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/scripts/unset_env.sh +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/scripts/validate_config.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/scripts/validate_dependencies.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/setup.cfg +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/setup.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/common/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/common/gather_env.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/common/gcp_config_validator.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/common/gcp_monitoring.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/common/gcp_utils.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/common/log.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/common/progress_decorator.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/common/slack.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/common/utils.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/cli.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/commands/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/commands/config.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/commands/security.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/compat/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/compat/cli.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/compat/common.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/config/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/config/cleanup.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/config/docs_organizer.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/config/external.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/config/installer.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/config/manager.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/config/migration.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/config/migration_utils.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/config/path_manager.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/config/schema.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/config/secrets.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/config/security.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/core/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/core/dependency_validator.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/core/logging.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/core/platform_discovery.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/core/session.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/core/silence_logging.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/cloudfront/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/cloudfront/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/codepipeline/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/codepipeline/build.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/codepipeline/deploy.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/ec2/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/ec2/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/ec2/list_tags.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/ec2/tag_check.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/ecs/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/ecs/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/ecs/service.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/ecs/task.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/eks/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/eks/addons.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/eks/fargate.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/eks/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/eks/nodes.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/eks/pods.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/eks/update_config.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/fargate/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/fargate/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/lb/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/lb/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/lb/list_tags.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/lb/tag_check.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/msk/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/msk/broker.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/msk/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/nat/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/nat/list_tags.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/nat/tag_check.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/profile/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/profile/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/rds/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/rds/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/rds/list_tags.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/rds/tag_check.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/s3/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/s3/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/s3/list_tags.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/s3/tag_check.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/sg/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/sg/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/vpc/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/vpc/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/vpc/list_tags.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/vpc/tag_check.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/vpn/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/aws/vpn/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/cloudflare/README.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/cloudflare/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/cloudflare/account/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/cloudflare/account/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/cloudflare/client.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/cloudflare/dns/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/cloudflare/dns/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/cloudflare/dns/list_info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/cloudflare/rules/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/cloudflare/rules/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/cloudflare/traffic/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/cloudflare/traffic/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/cloudflare/waf/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/cloudflare/waf/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/cloudflare/zone/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/cloudflare/zone/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/gcp/README.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/gcp/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/gcp/billing/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/gcp/billing/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/gcp/billing/mock_data.json +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/gcp/compute/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/gcp/compute/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/gcp/compute/mock_data.json +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/gcp/firewall/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/gcp/firewall/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/gcp/functions/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/gcp/functions/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/gcp/gke/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/gcp/gke/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/gcp/gke/mock_data.json +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/gcp/lb/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/gcp/lb/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/gcp/run/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/gcp/run/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/gcp/sql/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/gcp/sql/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/gcp/storage/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/gcp/storage/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/gcp/vpc/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/gcp/vpc/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/gcp/vpc/mock_data.json +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/oci/README.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/oci/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/oci/common/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/oci/common/utils.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/oci/compartment/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/oci/compartment/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/oci/cost/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/oci/cost/credit.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/oci/cost/usage.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/oci/info/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/oci/info/oci_info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/oci/lb/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/oci/lb/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/oci/nsg/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/oci/nsg/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/oci/obj/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/oci/obj/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/oci/policy/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/oci/policy/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/oci/policy/search.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/oci/vcn/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/oci/vcn/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/oci/vm/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/oci/vm/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/oci/volume/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/oci/volume/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/ssh/README.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/ssh/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/ssh/auto/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/ssh/auto/scan.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/ssh/auto_ssh.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/ssh/server/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/ssh/server/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/ssh/server_info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/tencent/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/tencent/clb/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/tencent/clb/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/tencent/client.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/tencent/cvm/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/tencent/cvm/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/tencent/lighthouse/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/tencent/lighthouse/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/tencent/nat/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/tencent/nat/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/tencent/profile/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/tencent/profile/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/tencent/sg/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/tencent/sg/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/tencent/tke/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/tencent/tke/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/tencent/vpc/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/platforms/tencent/vpc/info.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/security/README.md +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/security/__init__.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/security/config.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/security/detector.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/security/guidance.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/security/hooks.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/security/patterns.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic/security/scanner.py +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic_code.egg-info/dependency_links.txt +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic_code.egg-info/entry_points.txt +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic_code.egg-info/requires.txt +0 -0
- {ic_code-1.2.9 → ic_code-1.3.1}/src/ic_code.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ic-code
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.1
|
|
4
4
|
Summary: Infrastructure CLI tool for managing AWS, GCP, OCI, CloudFlare, SSH, and more
|
|
5
5
|
Home-page: https://github.com/dgr009/ic
|
|
6
6
|
Author: SangYun Kim
|
|
@@ -104,6 +104,7 @@ A comprehensive, production-grade Infrastructure Command Line Interface tool for
|
|
|
104
104
|
- **Compute**: EC2 instances, ECS services/tasks, EKS clusters/nodes/pods, Fargate profiles
|
|
105
105
|
- **Storage & DB**: S3 buckets (with tagging compliance checks), RDS instances & clusters
|
|
106
106
|
- **Networking**: VPC, Subnets, Gateways, Load Balancers (ALB/NLB with listener rules, health check path & target health analysis), Security Groups (with Ingress & Egress rule analysis & tree view), VPN connections
|
|
107
|
+
- **Health & Maintenance**: AWS Health Dashboard EC2 scheduled reboot maintenance check (`ic aws healthdashboard reboot`)
|
|
107
108
|
- **Integrations**: CloudFront distributions, MSK Kafka brokers, CodePipeline build/deploy status, Profile management
|
|
108
109
|
|
|
109
110
|
### 2. 🟦 Tencent Cloud Services (Production Ready)
|
|
@@ -138,7 +139,7 @@ A comprehensive, production-grade Infrastructure Command Line Interface tool for
|
|
|
138
139
|
### From PyPI (Recommended)
|
|
139
140
|
|
|
140
141
|
```bash
|
|
141
|
-
# Install the latest stable version (v1.
|
|
142
|
+
# Install the latest stable version (v1.3.1+)
|
|
142
143
|
pip install ic-code
|
|
143
144
|
|
|
144
145
|
# Verify installation
|
|
@@ -26,6 +26,7 @@ A comprehensive, production-grade Infrastructure Command Line Interface tool for
|
|
|
26
26
|
- **Compute**: EC2 instances, ECS services/tasks, EKS clusters/nodes/pods, Fargate profiles
|
|
27
27
|
- **Storage & DB**: S3 buckets (with tagging compliance checks), RDS instances & clusters
|
|
28
28
|
- **Networking**: VPC, Subnets, Gateways, Load Balancers (ALB/NLB with listener rules, health check path & target health analysis), Security Groups (with Ingress & Egress rule analysis & tree view), VPN connections
|
|
29
|
+
- **Health & Maintenance**: AWS Health Dashboard EC2 scheduled reboot maintenance check (`ic aws healthdashboard reboot`)
|
|
29
30
|
- **Integrations**: CloudFront distributions, MSK Kafka brokers, CodePipeline build/deploy status, Profile management
|
|
30
31
|
|
|
31
32
|
### 2. 🟦 Tencent Cloud Services (Production Ready)
|
|
@@ -60,7 +61,7 @@ A comprehensive, production-grade Infrastructure Command Line Interface tool for
|
|
|
60
61
|
### From PyPI (Recommended)
|
|
61
62
|
|
|
62
63
|
```bash
|
|
63
|
-
# Install the latest stable version (v1.
|
|
64
|
+
# Install the latest stable version (v1.3.1+)
|
|
64
65
|
pip install ic-code
|
|
65
66
|
|
|
66
67
|
# Verify installation
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
IC는 통합 클라우드 인프라 관리 CLI 도구로, **AWS**, **GCP**, **OCI**, **CloudFlare**, **SSH** 등 다양한 멀티 클라우드 및 서버 리소스를 단일 CLI 환경에서 손쉽게 조회하고 관리할 수 있습니다.
|
|
6
6
|
|
|
7
|
-
## 주요 특징 (v1.
|
|
7
|
+
## 주요 특징 (v1.3.1+)
|
|
8
8
|
|
|
9
9
|
- **YAML 기반 보안 설정 시스템**: 민감한 자격 증명(`secrets.yaml`)과 일반 설정(`default.yaml`)의 명확한 분리
|
|
10
10
|
- **실시간 프로그레스 바**: 리전 및 계정별 리소스 수집 진행 상황 시각화
|
|
@@ -4,7 +4,7 @@ IC (Infra Resource Management CLI) - A comprehensive tool for managing cloud inf
|
|
|
4
4
|
This package provides CLI tools and libraries for managing AWS, GCP, OCI, CloudFlare, and SSH resources.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
__version__ = "1.
|
|
7
|
+
__version__ = "1.3.1"
|
|
8
8
|
__author__ = "SangYun"
|
|
9
9
|
__email__ = "cruiser594@gmail.com"
|
|
10
10
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# AWS Health Dashboard Service Package
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
AWS Health Dashboard EC2 Reboot Maintenance Schedule Command
|
|
4
|
+
`ic aws healthdashboard reboot`
|
|
5
|
+
|
|
6
|
+
AWS Health API를 사용하여 EC2 인스턴스의 예정된 재부팅 유지보수 일정
|
|
7
|
+
("EC2 instance reboot maintenance scheduled")을 조회합니다.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import sys
|
|
11
|
+
import argparse
|
|
12
|
+
from datetime import datetime, timezone
|
|
13
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
14
|
+
|
|
15
|
+
import boto3
|
|
16
|
+
from botocore.exceptions import BotoCoreError, ClientError
|
|
17
|
+
from rich.console import Console
|
|
18
|
+
from rich.table import Table
|
|
19
|
+
from rich.panel import Panel
|
|
20
|
+
from rich.text import Text
|
|
21
|
+
from rich import box
|
|
22
|
+
|
|
23
|
+
from common.log import log_info_non_console
|
|
24
|
+
from common.progress_decorator import ManualProgress
|
|
25
|
+
from common.utils import get_valid_accounts, get_profiles, DEFINED_REGIONS
|
|
26
|
+
|
|
27
|
+
console = Console()
|
|
28
|
+
|
|
29
|
+
# 대상 타겟 이벤트 코드 정의 (EC2 인스턴스 예정된 재부팅 유지보수)
|
|
30
|
+
TARGET_EVENT_CODES = [
|
|
31
|
+
"AWS_EC2_INSTANCE_REBOOT_MAINTENANCE_SCHEDULED",
|
|
32
|
+
"AWS_EC2_PERSISTENT_INSTANCE_REBOOT_SCHEDULED",
|
|
33
|
+
"AWS_EC2_SCHEDULED_REBOOT"
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
TARGET_DESCRIPTION_KEYWORD = "ec2 instance reboot maintenance scheduled"
|
|
37
|
+
|
|
38
|
+
def format_datetime_short(dt):
|
|
39
|
+
"""datetime 객체를 YY-MM-DD HH:MM UTC 형태로 압축하여 표 가로폭을 최적화합니다."""
|
|
40
|
+
if not dt:
|
|
41
|
+
return "-"
|
|
42
|
+
if isinstance(dt, str):
|
|
43
|
+
return dt
|
|
44
|
+
if dt.tzinfo is None:
|
|
45
|
+
dt = dt.replace(tzinfo=timezone.utc)
|
|
46
|
+
|
|
47
|
+
try:
|
|
48
|
+
return dt.strftime("%Y-%m-%d %H:%M UTC")
|
|
49
|
+
except Exception:
|
|
50
|
+
return str(dt)
|
|
51
|
+
|
|
52
|
+
def get_instance_details(session, instance_id, region):
|
|
53
|
+
"""
|
|
54
|
+
EC2 API를 호출하여 인스턴스의 Name 태그, 현재 상태(State), 실제 리전을 조회합니다.
|
|
55
|
+
"""
|
|
56
|
+
if not instance_id or not instance_id.startswith("i-"):
|
|
57
|
+
return "-", "unknown", region
|
|
58
|
+
|
|
59
|
+
regions_to_try = [region] if region and region != "global" else DEFINED_REGIONS
|
|
60
|
+
|
|
61
|
+
for reg in regions_to_try:
|
|
62
|
+
try:
|
|
63
|
+
ec2_client = session.client("ec2", region_name=reg)
|
|
64
|
+
response = ec2_client.describe_instances(InstanceIds=[instance_id])
|
|
65
|
+
for reservation in response.get("Reservations", []):
|
|
66
|
+
for instance in reservation.get("Instances", []):
|
|
67
|
+
state = instance.get("State", {}).get("Name", "unknown")
|
|
68
|
+
name = "-"
|
|
69
|
+
for tag in instance.get("Tags", []):
|
|
70
|
+
if tag.get("Key") == "Name":
|
|
71
|
+
name = tag.get("Value", "-")
|
|
72
|
+
break
|
|
73
|
+
return name, state, reg
|
|
74
|
+
except ClientError:
|
|
75
|
+
continue
|
|
76
|
+
except Exception as e:
|
|
77
|
+
log_info_non_console(f"EC2 인스턴스 세부 정보 조회 오류 ({instance_id}/{reg}): {e}")
|
|
78
|
+
continue
|
|
79
|
+
|
|
80
|
+
return "-", "unknown", region
|
|
81
|
+
|
|
82
|
+
def parse_region_from_arn_or_event(event, entity):
|
|
83
|
+
"""이벤트 또는 엔티티 ARN에서 AWS Region 정보를 추출합니다."""
|
|
84
|
+
event_region = event.get("region")
|
|
85
|
+
if event_region and event_region != "global":
|
|
86
|
+
return event_region
|
|
87
|
+
|
|
88
|
+
entity_arn = entity.get("entityArn", "")
|
|
89
|
+
if entity_arn and entity_arn.startswith("arn:aws:"):
|
|
90
|
+
parts = entity_arn.split(":")
|
|
91
|
+
if len(parts) >= 4 and parts[3]:
|
|
92
|
+
return parts[3]
|
|
93
|
+
|
|
94
|
+
return "global"
|
|
95
|
+
|
|
96
|
+
def fetch_reboot_events_for_account(account_id, profile_name, include_closed=False):
|
|
97
|
+
"""단일 계정에 대해 AWS Health API(us-east-1)를 사용하여 EC2 재부팅 유지보수 이벤트를 수집합니다."""
|
|
98
|
+
log_info_non_console(f"AWS Health API 조회 시작: Account={account_id}, Profile={profile_name}")
|
|
99
|
+
|
|
100
|
+
events_found = []
|
|
101
|
+
error_message = None
|
|
102
|
+
|
|
103
|
+
try:
|
|
104
|
+
session = boto3.Session(profile_name=profile_name, region_name="us-east-1")
|
|
105
|
+
health_client = session.client("health", region_name="us-east-1")
|
|
106
|
+
|
|
107
|
+
status_codes = ["open", "upcoming"]
|
|
108
|
+
if include_closed:
|
|
109
|
+
status_codes.append("closed")
|
|
110
|
+
|
|
111
|
+
filter_params = {
|
|
112
|
+
"services": ["EC2"],
|
|
113
|
+
"eventStatusCodes": status_codes
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
paginator = health_client.get_paginator("describe_events")
|
|
117
|
+
raw_events = []
|
|
118
|
+
for page in paginator.paginate(filter=filter_params):
|
|
119
|
+
for event in page.get("events", []):
|
|
120
|
+
raw_events.append(event)
|
|
121
|
+
|
|
122
|
+
if not raw_events:
|
|
123
|
+
return account_id, profile_name, [], None
|
|
124
|
+
|
|
125
|
+
for event in raw_events:
|
|
126
|
+
event_arn = event.get("arn")
|
|
127
|
+
event_code = event.get("eventTypeCode", "")
|
|
128
|
+
event_status = event.get("statusCode", "unknown")
|
|
129
|
+
start_time = format_datetime_short(event.get("startTime"))
|
|
130
|
+
end_time = format_datetime_short(event.get("endTime"))
|
|
131
|
+
event_region = event.get("region", "global")
|
|
132
|
+
|
|
133
|
+
# 이벤트 설명 상세 조회
|
|
134
|
+
description_text = ""
|
|
135
|
+
try:
|
|
136
|
+
details_res = health_client.describe_event_details(eventArns=[event_arn])
|
|
137
|
+
successful_set = details_res.get("successfulSet", [])
|
|
138
|
+
if successful_set:
|
|
139
|
+
event_desc_obj = successful_set[0].get("eventDescription", {})
|
|
140
|
+
description_text = event_desc_obj.get("latestDescription", "")
|
|
141
|
+
except Exception as de:
|
|
142
|
+
log_info_non_console(f"이벤트 상세 정보 조회 실패 ({event_arn}): {de}")
|
|
143
|
+
|
|
144
|
+
# 정확한 EC2 인스턴스 재부팅 유지보수 일정 필터링
|
|
145
|
+
is_target_code = event_code in TARGET_EVENT_CODES
|
|
146
|
+
is_target_desc = TARGET_DESCRIPTION_KEYWORD in description_text.lower()
|
|
147
|
+
|
|
148
|
+
if not (is_target_code or is_target_desc):
|
|
149
|
+
continue
|
|
150
|
+
|
|
151
|
+
# 영향받는 엔티티(인스턴스) 수집
|
|
152
|
+
affected_entities = []
|
|
153
|
+
try:
|
|
154
|
+
ent_paginator = health_client.get_paginator("describe_affected_entities")
|
|
155
|
+
for ent_page in ent_paginator.paginate(filter={"eventArns": [event_arn]}):
|
|
156
|
+
for entity in ent_page.get("entities", []):
|
|
157
|
+
affected_entities.append(entity)
|
|
158
|
+
except Exception as ee:
|
|
159
|
+
log_info_non_console(f"영향받는 엔티티 조회 실패 ({event_arn}): {ee}")
|
|
160
|
+
|
|
161
|
+
if affected_entities:
|
|
162
|
+
for entity in affected_entities:
|
|
163
|
+
entity_value = entity.get("entityValue", "-") # 인스턴스 ID
|
|
164
|
+
entity_status = entity.get("statusCode", "UNKNOWN") # IMPAIRED, RESOLVED 등
|
|
165
|
+
|
|
166
|
+
parsed_region = parse_region_from_arn_or_event(event, entity)
|
|
167
|
+
inst_name, inst_state, final_region = get_instance_details(session, entity_value, parsed_region)
|
|
168
|
+
|
|
169
|
+
events_found.append({
|
|
170
|
+
"account_id": account_id,
|
|
171
|
+
"profile_name": profile_name,
|
|
172
|
+
"event_code": event_code,
|
|
173
|
+
"event_status": event_status,
|
|
174
|
+
"entity_status": entity_status,
|
|
175
|
+
"start_time": start_time,
|
|
176
|
+
"end_time": end_time,
|
|
177
|
+
"instance_id": entity_value,
|
|
178
|
+
"instance_name": inst_name,
|
|
179
|
+
"instance_state": inst_state,
|
|
180
|
+
"region": final_region,
|
|
181
|
+
"description": description_text
|
|
182
|
+
})
|
|
183
|
+
else:
|
|
184
|
+
events_found.append({
|
|
185
|
+
"account_id": account_id,
|
|
186
|
+
"profile_name": profile_name,
|
|
187
|
+
"event_code": event_code,
|
|
188
|
+
"event_status": event_status,
|
|
189
|
+
"entity_status": "-",
|
|
190
|
+
"start_time": start_time,
|
|
191
|
+
"end_time": end_time,
|
|
192
|
+
"instance_id": "-",
|
|
193
|
+
"instance_name": "-",
|
|
194
|
+
"instance_state": "-",
|
|
195
|
+
"region": event_region,
|
|
196
|
+
"description": description_text
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
except ClientError as e:
|
|
200
|
+
error_code = e.response.get("Error", {}).get("Code", "")
|
|
201
|
+
if error_code == "SubscriptionRequiredException":
|
|
202
|
+
error_message = "AWS Business 또는 Enterprise Support 플랜이 필요합니다."
|
|
203
|
+
elif error_code == "AccessDeniedException":
|
|
204
|
+
error_message = "AWS Health API 접근 권한(health:DescribeEvents 등)이 부족합니다."
|
|
205
|
+
else:
|
|
206
|
+
error_message = f"AWS Health API 오류: {e.response.get('Error', {}).get('Message', str(e))}"
|
|
207
|
+
log_info_non_console(f"Account {account_id} Health API ClientError: {e}")
|
|
208
|
+
except Exception as e:
|
|
209
|
+
error_message = f"오류 발생: {e}"
|
|
210
|
+
log_info_non_console(f"Account {account_id} Health API 예외: {e}")
|
|
211
|
+
|
|
212
|
+
return account_id, profile_name, events_found, error_message
|
|
213
|
+
|
|
214
|
+
def print_results(all_events, account_errors, verbose=False):
|
|
215
|
+
"""결과 데이터를 rich 표 및 안내 패널로 출력합니다."""
|
|
216
|
+
console.print()
|
|
217
|
+
|
|
218
|
+
if verbose and account_errors:
|
|
219
|
+
for acct, prof, err in account_errors:
|
|
220
|
+
console.print(f"[bold yellow]⚠️ [{prof} ({acct})][/bold yellow] {err}")
|
|
221
|
+
console.print()
|
|
222
|
+
|
|
223
|
+
if not all_events:
|
|
224
|
+
panel_content = Text()
|
|
225
|
+
panel_content.append("✅ 예정된 EC2 인스턴스 재부팅 일정이 없습니다.\n", style="bold green")
|
|
226
|
+
panel_content.append(" (EC2 instance reboot maintenance scheduled)", style="dim")
|
|
227
|
+
console.print(Panel(panel_content, title="AWS Health Dashboard", border_style="green", box=box.ROUNDED))
|
|
228
|
+
console.print()
|
|
229
|
+
return
|
|
230
|
+
|
|
231
|
+
table = Table(
|
|
232
|
+
title="🚨 EC2 Instance Reboot Maintenance Schedule",
|
|
233
|
+
box=box.ROUNDED,
|
|
234
|
+
header_style="bold cyan",
|
|
235
|
+
show_lines=True,
|
|
236
|
+
expand=True
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
table.add_column("Account", style="cyan", min_width=15, ratio=2)
|
|
240
|
+
table.add_column("Region", style="magenta", min_width=12, ratio=1)
|
|
241
|
+
table.add_column("Instance ID", style="bold yellow", min_width=19, ratio=2)
|
|
242
|
+
table.add_column("Instance Name", style="bold white", min_width=20, ratio=3)
|
|
243
|
+
table.add_column("EC2 State", style="green", min_width=8, ratio=1)
|
|
244
|
+
table.add_column("Entity Status", style="bold white", min_width=10, ratio=1)
|
|
245
|
+
table.add_column("Event Status", style="dim", min_width=9, ratio=1)
|
|
246
|
+
table.add_column("Scheduled Start", style="yellow", min_width=16, ratio=2)
|
|
247
|
+
table.add_column("Scheduled End", style="dim", min_width=16, ratio=2)
|
|
248
|
+
|
|
249
|
+
for item in all_events:
|
|
250
|
+
event_status_display = item["event_status"]
|
|
251
|
+
if item["event_status"].lower() in ["open", "upcoming"]:
|
|
252
|
+
event_status_display = f"[yellow]{item['event_status']}[/yellow]"
|
|
253
|
+
elif item["event_status"].lower() == "closed":
|
|
254
|
+
event_status_display = f"[dim]{item['event_status']}[/dim]"
|
|
255
|
+
|
|
256
|
+
entity_status_str = str(item["entity_status"]).upper()
|
|
257
|
+
if entity_status_str == "RESOLVED":
|
|
258
|
+
entity_status_display = "[bold green]RESOLVED[/bold green]"
|
|
259
|
+
elif entity_status_str in ["IMPAIRED", "IMPACTED"]:
|
|
260
|
+
entity_status_display = "[bold red]IMPAIRED[/bold red]"
|
|
261
|
+
else:
|
|
262
|
+
entity_status_display = entity_status_str
|
|
263
|
+
|
|
264
|
+
state_str = str(item["instance_state"]).lower()
|
|
265
|
+
if state_str == "running":
|
|
266
|
+
state_display = f"[bold green]{item['instance_state']}[/bold green]"
|
|
267
|
+
elif state_str in ["stopped", "stopping"]:
|
|
268
|
+
state_display = f"[bold yellow]{item['instance_state']}[/bold yellow]"
|
|
269
|
+
elif state_str == "terminated":
|
|
270
|
+
state_display = f"[bold red]{item['instance_state']}[/bold red]"
|
|
271
|
+
else:
|
|
272
|
+
state_display = item["instance_state"]
|
|
273
|
+
|
|
274
|
+
table.add_row(
|
|
275
|
+
f"{item['profile_name']}\n({item['account_id']})",
|
|
276
|
+
item["region"],
|
|
277
|
+
item["instance_id"],
|
|
278
|
+
item["instance_name"],
|
|
279
|
+
state_display,
|
|
280
|
+
entity_status_display,
|
|
281
|
+
event_status_display,
|
|
282
|
+
item["start_time"],
|
|
283
|
+
item["end_time"]
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
console.print(table)
|
|
287
|
+
console.print(f"\n총 [bold yellow]{len(all_events)}[/bold yellow]건의 유지보수 일정이 확인되었습니다.")
|
|
288
|
+
console.print()
|
|
289
|
+
|
|
290
|
+
def main(args, config=None):
|
|
291
|
+
"""ic aws healthdashboard reboot 실행 엔트리 포인트"""
|
|
292
|
+
all_accounts_flag = getattr(args, 'all_accounts', False)
|
|
293
|
+
account_input = args.account if hasattr(args, 'account') and args.account else None
|
|
294
|
+
|
|
295
|
+
# --all-accounts 플래그가 지정되었거나 계정이 지정되지 않은 경우, 로컬 AWS 프로파일 전체 수집
|
|
296
|
+
if all_accounts_flag or not account_input:
|
|
297
|
+
profiles_dict = get_profiles()
|
|
298
|
+
valid_accounts = []
|
|
299
|
+
if profiles_dict:
|
|
300
|
+
for acct_id, prof_name in profiles_dict.items():
|
|
301
|
+
# 'default' 제외하고 추가하거나 default도 활성화된 프로필이면 유지
|
|
302
|
+
valid_accounts.append((acct_id, prof_name))
|
|
303
|
+
else:
|
|
304
|
+
valid_accounts = get_valid_accounts(None)
|
|
305
|
+
else:
|
|
306
|
+
valid_accounts = get_valid_accounts(account_input)
|
|
307
|
+
|
|
308
|
+
if not valid_accounts:
|
|
309
|
+
console.print("❌ 조회를 진행할 AWS 계정을 찾을 수 없습니다. (.env 또는 AWS 프로파일 설정을 확인하세요)")
|
|
310
|
+
sys.exit(1)
|
|
311
|
+
|
|
312
|
+
include_closed = getattr(args, 'all_status', False)
|
|
313
|
+
all_events = []
|
|
314
|
+
account_errors = []
|
|
315
|
+
|
|
316
|
+
total_ops = len(valid_accounts)
|
|
317
|
+
with ManualProgress("Checking AWS Health Dashboard for EC2 reboot schedules across all profiles...", total=total_ops) as progress:
|
|
318
|
+
with ThreadPoolExecutor(max_workers=min(len(valid_accounts), 15)) as executor:
|
|
319
|
+
futures = {
|
|
320
|
+
executor.submit(fetch_reboot_events_for_account, acct, prof, include_closed): (acct, prof)
|
|
321
|
+
for acct, prof in valid_accounts
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
for future in as_completed(futures):
|
|
325
|
+
acct, prof = futures[future]
|
|
326
|
+
try:
|
|
327
|
+
acct_id, prof_name, events, error_msg = future.result()
|
|
328
|
+
if error_msg:
|
|
329
|
+
account_errors.append((acct_id, prof_name, error_msg))
|
|
330
|
+
if events:
|
|
331
|
+
all_events.extend(events)
|
|
332
|
+
progress.update(f"Completed {prof_name} ({acct_id})", advance=1)
|
|
333
|
+
except Exception as e:
|
|
334
|
+
account_errors.append((acct, prof, f"조회 중 예외 발생: {e}"))
|
|
335
|
+
progress.update(f"Failed {prof} ({acct})", advance=1)
|
|
336
|
+
|
|
337
|
+
print_results(all_events, account_errors, verbose=getattr(args, 'verbose', False))
|
|
338
|
+
|
|
339
|
+
def add_arguments(parser):
|
|
340
|
+
"""Command line arguments definition"""
|
|
341
|
+
parser.add_argument('-a', '--account', help='특정 AWS 계정 ID 또는 프로파일 지정 (구분자: ,)')
|
|
342
|
+
parser.add_argument('-A', '--all-accounts', '--all-profiles', action='store_true', help='로컬 AWS 프로필에 등록된 모든 계정 전체 조회')
|
|
343
|
+
parser.add_argument('--all-status', action='store_true', help='이미 종료된(closed) 과거 일정까지 포함하여 조회')
|
|
344
|
+
parser.add_argument('-v', '--verbose', action='store_true', help='상세 에러 로그 및 정보 출력')
|
|
345
|
+
|
|
346
|
+
if __name__ == "__main__":
|
|
347
|
+
parser = argparse.ArgumentParser(description="AWS Health Dashboard EC2 Reboot Schedule Check")
|
|
348
|
+
add_arguments(parser)
|
|
349
|
+
args = parser.parse_args()
|
|
350
|
+
main(args)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ic-code
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.1
|
|
4
4
|
Summary: Infrastructure CLI tool for managing AWS, GCP, OCI, CloudFlare, SSH, and more
|
|
5
5
|
Home-page: https://github.com/dgr009/ic
|
|
6
6
|
Author: SangYun Kim
|
|
@@ -104,6 +104,7 @@ A comprehensive, production-grade Infrastructure Command Line Interface tool for
|
|
|
104
104
|
- **Compute**: EC2 instances, ECS services/tasks, EKS clusters/nodes/pods, Fargate profiles
|
|
105
105
|
- **Storage & DB**: S3 buckets (with tagging compliance checks), RDS instances & clusters
|
|
106
106
|
- **Networking**: VPC, Subnets, Gateways, Load Balancers (ALB/NLB with listener rules, health check path & target health analysis), Security Groups (with Ingress & Egress rule analysis & tree view), VPN connections
|
|
107
|
+
- **Health & Maintenance**: AWS Health Dashboard EC2 scheduled reboot maintenance check (`ic aws healthdashboard reboot`)
|
|
107
108
|
- **Integrations**: CloudFront distributions, MSK Kafka brokers, CodePipeline build/deploy status, Profile management
|
|
108
109
|
|
|
109
110
|
### 2. 🟦 Tencent Cloud Services (Production Ready)
|
|
@@ -138,7 +139,7 @@ A comprehensive, production-grade Infrastructure Command Line Interface tool for
|
|
|
138
139
|
### From PyPI (Recommended)
|
|
139
140
|
|
|
140
141
|
```bash
|
|
141
|
-
# Install the latest stable version (v1.
|
|
142
|
+
# Install the latest stable version (v1.3.1+)
|
|
142
143
|
pip install ic-code
|
|
143
144
|
|
|
144
145
|
# Verify installation
|
|
@@ -114,6 +114,8 @@ src/ic/platforms/aws/eks/pods.py
|
|
|
114
114
|
src/ic/platforms/aws/eks/update_config.py
|
|
115
115
|
src/ic/platforms/aws/fargate/__init__.py
|
|
116
116
|
src/ic/platforms/aws/fargate/info.py
|
|
117
|
+
src/ic/platforms/aws/healthdashboard/__init__.py
|
|
118
|
+
src/ic/platforms/aws/healthdashboard/reboot.py
|
|
117
119
|
src/ic/platforms/aws/lb/__init__.py
|
|
118
120
|
src/ic/platforms/aws/lb/info.py
|
|
119
121
|
src/ic/platforms/aws/lb/list_tags.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|