ic-code 1.5.0__tar.gz → 1.5.3__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.5.0/src/ic_code.egg-info → ic_code-1.5.3}/PKG-INFO +3 -3
- {ic_code-1.5.0 → ic_code-1.5.3}/README.md +2 -2
- {ic_code-1.5.0 → ic_code-1.5.3}/docs/gcp/README.md +2 -2
- {ic_code-1.5.0 → ic_code-1.5.3}/docs/user_guide.md +1 -1
- {ic_code-1.5.0 → ic_code-1.5.3}/pyproject.toml +1 -1
- {ic_code-1.5.0 → ic_code-1.5.3}/src/common/gcp_utils.py +38 -30
- {ic_code-1.5.0 → ic_code-1.5.3}/src/common/log.py +7 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/__init__.py +1 -1
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/compat/common.py +18 -5
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/config/installer.py +8 -8
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/config/migration.py +28 -23
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/config/secrets.py +2 -3
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/core/logging.py +30 -32
- ic_code-1.5.3/src/ic/platforms/aws/disk/__init__.py +1 -0
- ic_code-1.5.3/src/ic/platforms/aws/disk/info.py +32 -0
- ic_code-1.5.3/src/ic/platforms/aws/ebs/__init__.py +1 -0
- ic_code-1.5.3/src/ic/platforms/aws/ebs/info.py +528 -0
- ic_code-1.5.3/src/ic/platforms/aws/ebs/mock_data.json +90 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/billing/info.py +3 -3
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/compute/info.py +50 -15
- ic_code-1.5.3/src/ic/platforms/gcp/disk/__init__.py +1 -0
- ic_code-1.5.3/src/ic/platforms/gcp/disk/info.py +566 -0
- ic_code-1.5.3/src/ic/platforms/gcp/disk/mock_data.json +96 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/firewall/info.py +219 -20
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/firewall/mock_data.json +7 -1
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/lb/info.py +329 -53
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/lb/mock_data.json +64 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/vpc/info.py +7 -6
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/ssh/__init__.py +2 -1
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/ssh/auto_ssh.py +7 -24
- ic_code-1.5.3/src/ic/platforms/ssh/policy.py +61 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/ssh/server_info.py +6 -14
- ic_code-1.5.3/src/ic/platforms/tencent/cbs/__init__.py +1 -0
- ic_code-1.5.3/src/ic/platforms/tencent/cbs/info.py +556 -0
- ic_code-1.5.3/src/ic/platforms/tencent/cbs/mock_data.json +74 -0
- ic_code-1.5.3/src/ic/platforms/tencent/disk/__init__.py +1 -0
- ic_code-1.5.3/src/ic/platforms/tencent/disk/info.py +32 -0
- {ic_code-1.5.0 → ic_code-1.5.3/src/ic_code.egg-info}/PKG-INFO +3 -3
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic_code.egg-info/SOURCES.txt +14 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/LICENSE +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/MANIFEST.in +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/SECURITY.md +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/config/default.yaml +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/docs/README.md +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/docs/aws/README.md +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/docs/cloudflare/README.md +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/docs/installation.md +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/docs/oci/README.md +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/docs/release-guide.md +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/docs/security.md +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/docs/ssh/README.md +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/docs/tencent/README.md +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/docs/troubleshooting.md +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/requirements.txt +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/scripts/bump-version.sh +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/scripts/cf_edge_nsg_make/cf_edge_nsg_make.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/scripts/ci-detect-platforms.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/scripts/ci-generate-matrix.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/scripts/ci-smoke-test.sh +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/scripts/deploy.sh +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/scripts/oracle-policy/user_policy.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/setup.cfg +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/setup.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/common/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/common/gather_env.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/common/gcp_config_validator.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/common/gcp_monitoring.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/common/progress_decorator.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/common/slack.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/common/utils.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/cli.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/commands/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/commands/config.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/commands/security.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/compat/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/compat/cli.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/config/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/config/cleanup.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/config/docs_organizer.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/config/external.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/config/manager.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/config/migration_utils.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/config/path_manager.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/config/schema.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/config/security.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/core/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/core/dependency_validator.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/core/desc_helper.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/core/interfaces/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/core/interfaces/command.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/core/interfaces/formatter.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/core/interfaces/result.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/core/platform_discovery.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/core/session.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/core/silence_logging.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/cloudfront/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/cloudfront/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/codepipeline/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/codepipeline/build.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/codepipeline/deploy.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/ec2/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/ec2/desc.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/ec2/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/ec2/list_tags.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/ec2/tag_check.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/ecs/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/ecs/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/ecs/service.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/ecs/task.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/eks/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/eks/addons.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/eks/fargate.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/eks/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/eks/nodes.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/eks/pods.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/eks/update_config.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/fargate/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/fargate/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/healthdashboard/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/healthdashboard/reboot.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/lb/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/lb/desc.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/lb/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/lb/list_tags.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/lb/tag_check.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/msk/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/msk/broker.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/msk/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/nat/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/nat/list_tags.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/nat/tag_check.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/profile/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/profile/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/rds/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/rds/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/rds/list_tags.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/rds/tag_check.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/s3/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/s3/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/s3/list_tags.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/s3/tag_check.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/sg/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/sg/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/vpc/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/vpc/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/vpc/list_tags.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/vpc/tag_check.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/vpn/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/aws/vpn/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/cloudflare/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/cloudflare/account/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/cloudflare/account/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/cloudflare/client.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/cloudflare/dns/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/cloudflare/dns/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/cloudflare/dns/list_info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/cloudflare/rules/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/cloudflare/rules/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/cloudflare/traffic/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/cloudflare/traffic/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/cloudflare/waf/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/cloudflare/waf/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/cloudflare/zone/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/cloudflare/zone/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/billing/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/billing/mock_data.json +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/compute/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/compute/desc.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/compute/mock_data.json +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/dns/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/dns/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/dns/mock_data.json +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/firewall/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/functions/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/functions/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/functions/mock_data.json +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/gke/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/gke/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/gke/mock_data.json +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/lb/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/lb/desc.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/profile/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/profile/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/profile/mock_data.json +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/project/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/project/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/project/mock_data.json +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/run/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/run/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/run/mock_data.json +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/sql/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/sql/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/sql/mock_data.json +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/storage/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/storage/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/storage/mock_data.json +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/vpc/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/gcp/vpc/mock_data.json +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/oci/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/oci/common/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/oci/common/utils.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/oci/compartment/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/oci/compartment/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/oci/cost/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/oci/cost/credit.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/oci/cost/usage.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/oci/info/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/oci/info/oci_info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/oci/lb/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/oci/lb/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/oci/nsg/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/oci/nsg/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/oci/obj/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/oci/obj/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/oci/policy/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/oci/policy/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/oci/policy/search.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/oci/vcn/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/oci/vcn/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/oci/vm/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/oci/vm/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/oci/volume/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/oci/volume/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/ssh/auto/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/ssh/auto/scan.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/ssh/server/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/ssh/server/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/tencent/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/tencent/clb/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/tencent/clb/desc.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/tencent/clb/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/tencent/clb/traffic.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/tencent/client.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/tencent/cvm/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/tencent/cvm/desc.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/tencent/cvm/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/tencent/lighthouse/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/tencent/lighthouse/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/tencent/nat/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/tencent/nat/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/tencent/profile/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/tencent/profile/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/tencent/sg/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/tencent/sg/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/tencent/tke/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/tencent/tke/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/tencent/vpc/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/platforms/tencent/vpc/info.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/security/__init__.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/security/config.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/security/detector.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/security/guidance.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/security/hooks.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/security/patterns.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic/security/scanner.py +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic_code.egg-info/dependency_links.txt +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic_code.egg-info/entry_points.txt +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/src/ic_code.egg-info/requires.txt +0 -0
- {ic_code-1.5.0 → ic_code-1.5.3}/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.5.
|
|
3
|
+
Version: 1.5.3
|
|
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
|
|
@@ -147,7 +147,7 @@ A comprehensive, production-grade Infrastructure Command Line Interface tool for
|
|
|
147
147
|
- **Networking**: VPC, Subnets, NAT Gateways, CLB (Load Balancers - listener rules, health check, target health analysis & network traffic bandwidth statistics), Security Groups (with Ingress/Egress rules & tree view)
|
|
148
148
|
- **Authentication**: Multi-account STS AssumeRole support, Profile management (`ic tencent profile info` via `~/.tencent/credentials`)
|
|
149
149
|
|
|
150
|
-
### 3. 🟩 GCP Services (Production Ready - v1.5.
|
|
150
|
+
### 3. 🟩 GCP Services (Production Ready - v1.5.3)
|
|
151
151
|
- **Compute Engine**: VM instances with status, zone, machine type (custom parsing), vCPU, memory, disks, IPs, tags, and verbose 15-column output (`ic gcp compute info -v`)
|
|
152
152
|
- **Compute Detailed Inspection (`desc`)**: Full attribute discovery, dot-notation key filtering (`-k / --keys`), schema discovery (`-l / --list-keys`) for instances
|
|
153
153
|
- **Load Balancing (LB)**: Forwarding rules, Target proxies, URL maps, Backend services, Health checks, and SSL certificates (`ic gcp lb info`)
|
|
@@ -336,7 +336,7 @@ ic tencent tke info
|
|
|
336
336
|
ic tencent profile info
|
|
337
337
|
```
|
|
338
338
|
|
|
339
|
-
### GCP Commands (v1.5.
|
|
339
|
+
### GCP Commands (v1.5.3)
|
|
340
340
|
|
|
341
341
|
```bash
|
|
342
342
|
# Compute Engine VM instances (summary & verbose 15-column output)
|
|
@@ -41,7 +41,7 @@ A comprehensive, production-grade Infrastructure Command Line Interface tool for
|
|
|
41
41
|
- **Networking**: VPC, Subnets, NAT Gateways, CLB (Load Balancers - listener rules, health check, target health analysis & network traffic bandwidth statistics), Security Groups (with Ingress/Egress rules & tree view)
|
|
42
42
|
- **Authentication**: Multi-account STS AssumeRole support, Profile management (`ic tencent profile info` via `~/.tencent/credentials`)
|
|
43
43
|
|
|
44
|
-
### 3. 🟩 GCP Services (Production Ready - v1.5.
|
|
44
|
+
### 3. 🟩 GCP Services (Production Ready - v1.5.3)
|
|
45
45
|
- **Compute Engine**: VM instances with status, zone, machine type (custom parsing), vCPU, memory, disks, IPs, tags, and verbose 15-column output (`ic gcp compute info -v`)
|
|
46
46
|
- **Compute Detailed Inspection (`desc`)**: Full attribute discovery, dot-notation key filtering (`-k / --keys`), schema discovery (`-l / --list-keys`) for instances
|
|
47
47
|
- **Load Balancing (LB)**: Forwarding rules, Target proxies, URL maps, Backend services, Health checks, and SSL certificates (`ic gcp lb info`)
|
|
@@ -230,7 +230,7 @@ ic tencent tke info
|
|
|
230
230
|
ic tencent profile info
|
|
231
231
|
```
|
|
232
232
|
|
|
233
|
-
### GCP Commands (v1.5.
|
|
233
|
+
### GCP Commands (v1.5.3)
|
|
234
234
|
|
|
235
235
|
```bash
|
|
236
236
|
# Compute Engine VM instances (summary & verbose 15-column output)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# GCP Platform Documentation
|
|
2
2
|
|
|
3
|
-
This directory contains documentation for the GCP (Google Cloud Platform) integration in IC CLI (v1.5.
|
|
3
|
+
This directory contains documentation for the GCP (Google Cloud Platform) integration in IC CLI (v1.5.3).
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -12,7 +12,7 @@ This directory contains documentation for the GCP (Google Cloud Platform) integr
|
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
|
15
|
-
## Services Supported (v1.5.
|
|
15
|
+
## Services Supported (v1.5.3)
|
|
16
16
|
|
|
17
17
|
| Service | Commands | Key Features |
|
|
18
18
|
|---|---|---|
|
|
@@ -47,7 +47,7 @@ ic config show
|
|
|
47
47
|
- **VPC / NAT / TKE**: `ic tencent vpc info` / `ic tencent nat info` / `ic tencent tke info`
|
|
48
48
|
- **자격 증명 확인**: `ic tencent profile info`
|
|
49
49
|
|
|
50
|
-
### 3. 🟩 GCP Services (v1.5.
|
|
50
|
+
### 3. 🟩 GCP Services (v1.5.3)
|
|
51
51
|
- **Compute Engine (요약 & 15개 컬럼 상세 & desc)**:
|
|
52
52
|
- `ic gcp compute info`: 기본 요약 목록
|
|
53
53
|
- `ic gcp compute info -v`: 상세 15열 뷰 (vCPU, Mem, Disks, Net/Subnet, Tags 등)
|
|
@@ -13,8 +13,9 @@ from google.cloud.resourcemanager_v3.types import SearchProjectsRequest, GetProj
|
|
|
13
13
|
from google.api_core import exceptions as gcp_exceptions
|
|
14
14
|
from google.api_core import retry
|
|
15
15
|
from ic.config.manager import ConfigManager
|
|
16
|
+
from common.progress_decorator import ManualProgress
|
|
16
17
|
|
|
17
|
-
from .log import log_info, log_info_non_console, log_error, log_exception
|
|
18
|
+
from .log import log_info, log_info_non_console, log_error, log_error_file_only, log_exception
|
|
18
19
|
|
|
19
20
|
# Import configuration validator
|
|
20
21
|
try:
|
|
@@ -327,13 +328,13 @@ class GCPProjectManager:
|
|
|
327
328
|
return project.state.name == "ACTIVE"
|
|
328
329
|
|
|
329
330
|
except gcp_exceptions.NotFound:
|
|
330
|
-
|
|
331
|
+
log_info_non_console(f"프로젝트를 찾을 수 없음: {project_id}")
|
|
331
332
|
return False
|
|
332
333
|
except gcp_exceptions.PermissionDenied:
|
|
333
|
-
|
|
334
|
+
log_info_non_console(f"프로젝트 접근 권한 없음: {project_id}")
|
|
334
335
|
return False
|
|
335
336
|
except Exception as e:
|
|
336
|
-
|
|
337
|
+
log_info_non_console(f"프로젝트 접근 검증 실패: {project_id}, Error={e}")
|
|
337
338
|
return False
|
|
338
339
|
|
|
339
340
|
def get_project_info(self, project_id: str) -> Optional[Dict[str, Any]]:
|
|
@@ -360,7 +361,7 @@ class GCPProjectManager:
|
|
|
360
361
|
}
|
|
361
362
|
|
|
362
363
|
except Exception as e:
|
|
363
|
-
|
|
364
|
+
log_info_non_console(f"프로젝트 정보 조회 실패: {project_id}, Error={e}")
|
|
364
365
|
return None
|
|
365
366
|
|
|
366
367
|
|
|
@@ -377,27 +378,34 @@ class GCPResourceCollector:
|
|
|
377
378
|
def parallel_collect(self, projects: List[str], collect_func: Callable, *args, **kwargs) -> List[Any]:
|
|
378
379
|
"""여러 프로젝트에서 병렬로 리소스를 수집합니다."""
|
|
379
380
|
results = []
|
|
381
|
+
progress_desc = kwargs.pop('progress_desc', None) or f"Collecting GCP resources across {len(projects)} project(s)"
|
|
380
382
|
|
|
381
|
-
with
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
if
|
|
395
|
-
|
|
383
|
+
with ManualProgress(progress_desc, total=len(projects)) as progress:
|
|
384
|
+
with ThreadPoolExecutor(max_workers=_get_env_int('GCP_MAX_WORKERS', 10)) as executor:
|
|
385
|
+
futures = []
|
|
386
|
+
|
|
387
|
+
for project_id in projects:
|
|
388
|
+
future = executor.submit(
|
|
389
|
+
self._safe_collect, collect_func, project_id, *args, **kwargs
|
|
390
|
+
)
|
|
391
|
+
futures.append((future, project_id))
|
|
392
|
+
|
|
393
|
+
for future, project_id in futures:
|
|
394
|
+
try:
|
|
395
|
+
result = future.result(timeout=_get_env_int('GCP_REQUEST_TIMEOUT', 30))
|
|
396
|
+
if result:
|
|
397
|
+
if isinstance(result, list):
|
|
398
|
+
results.extend(result)
|
|
399
|
+
else:
|
|
400
|
+
results.append(result)
|
|
401
|
+
item_count = len(result) if isinstance(result, list) else 1
|
|
402
|
+
progress.update(f"Processed {project_id} ({item_count} items)", advance=1)
|
|
396
403
|
else:
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
404
|
+
progress.update(f"Processed {project_id} (0 items)", advance=1)
|
|
405
|
+
except Exception as e:
|
|
406
|
+
err_msg = str(e) or type(e).__name__
|
|
407
|
+
log_info_non_console(f"프로젝트 {project_id}에서 리소스 수집 실패: {err_msg}")
|
|
408
|
+
progress.update(f"Failed {project_id} - {err_msg[:40]}", advance=1)
|
|
401
409
|
|
|
402
410
|
return results
|
|
403
411
|
|
|
@@ -406,7 +414,7 @@ class GCPResourceCollector:
|
|
|
406
414
|
try:
|
|
407
415
|
return self.handle_api_errors(lambda: collect_func(project_id, *args, **kwargs))
|
|
408
416
|
except Exception as e:
|
|
409
|
-
|
|
417
|
+
log_info_non_console(f"리소스 수집 중 오류 발생: Project={project_id}, Error={e}")
|
|
410
418
|
return None
|
|
411
419
|
|
|
412
420
|
def handle_api_errors(self, func: Callable) -> Any:
|
|
@@ -429,19 +437,19 @@ class GCPResourceCollector:
|
|
|
429
437
|
try:
|
|
430
438
|
return _retry_func()
|
|
431
439
|
except gcp_exceptions.PermissionDenied as e:
|
|
432
|
-
|
|
440
|
+
log_info_non_console(f"권한 거부: {e}")
|
|
433
441
|
raise
|
|
434
442
|
except gcp_exceptions.NotFound as e:
|
|
435
|
-
|
|
443
|
+
log_info_non_console(f"리소스를 찾을 수 없음: {e}")
|
|
436
444
|
return None
|
|
437
445
|
except gcp_exceptions.Forbidden as e:
|
|
438
|
-
|
|
446
|
+
log_info_non_console(f"API가 비활성화되었거나 접근 금지: {e}")
|
|
439
447
|
return None
|
|
440
448
|
except gcp_exceptions.TooManyRequests as e:
|
|
441
|
-
|
|
449
|
+
log_info_non_console(f"API 요청 한도 초과: {e}")
|
|
442
450
|
raise
|
|
443
451
|
except Exception as e:
|
|
444
|
-
|
|
452
|
+
log_info_non_console(f"예상치 못한 API 오류: {e}")
|
|
445
453
|
raise
|
|
446
454
|
|
|
447
455
|
def apply_filters(self, resources: List[Dict], filters: Dict[str, Any]) -> List[Dict]:
|
|
@@ -68,6 +68,13 @@ def log_info(message: str):
|
|
|
68
68
|
if os.environ.get("IC_VERBOSE") == "true":
|
|
69
69
|
console.print(f"[bold cyan]INFO:[/bold cyan] {message}")
|
|
70
70
|
|
|
71
|
+
def log_error_file_only(message: str):
|
|
72
|
+
"""ERROR 레벨 로그 출력 + 콘솔 미표시 (파일 전용)"""
|
|
73
|
+
if NEW_LOGGING_AVAILABLE and ic_logger:
|
|
74
|
+
ic_logger.log_error_file_only(message)
|
|
75
|
+
else:
|
|
76
|
+
logger.error(message)
|
|
77
|
+
|
|
71
78
|
def log_error(message: str):
|
|
72
79
|
"""ERROR 레벨 로그 출력 + 콘솔 표시"""
|
|
73
80
|
if NEW_LOGGING_AVAILABLE and ic_logger:
|
|
@@ -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.5.
|
|
7
|
+
__version__ = "1.5.3"
|
|
8
8
|
__author__ = "SangYun"
|
|
9
9
|
__email__ = "cruiser594@gmail.com"
|
|
10
10
|
|
|
@@ -36,6 +36,18 @@ def log_error(message: str, **kwargs) -> None:
|
|
|
36
36
|
logger.log_error(message)
|
|
37
37
|
|
|
38
38
|
|
|
39
|
+
def log_error_file_only(message: str, **kwargs) -> None:
|
|
40
|
+
"""
|
|
41
|
+
Backward compatibility function for log_error_file_only.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
message: Error message to log to file
|
|
45
|
+
**kwargs: Additional keyword arguments (ignored for compatibility)
|
|
46
|
+
"""
|
|
47
|
+
logger = get_logger()
|
|
48
|
+
logger.log_error_file_only(message)
|
|
49
|
+
|
|
50
|
+
|
|
39
51
|
def log_env_short(env_dict=None, **kwargs) -> None:
|
|
40
52
|
"""
|
|
41
53
|
Backward compatibility function for log_env_short.
|
|
@@ -72,7 +84,7 @@ def log_args_short(args: Any) -> None:
|
|
|
72
84
|
logger.log_args(args)
|
|
73
85
|
|
|
74
86
|
|
|
75
|
-
def gather_env_for_command(platform: str, service: str = None, command: str = None) -> Dict[str, Any]:
|
|
87
|
+
def gather_env_for_command(platform: str, service: Optional[str] = None, command: Optional[str] = None) -> Dict[str, Any]:
|
|
76
88
|
"""
|
|
77
89
|
Backward compatibility function for gather_env_for_command.
|
|
78
90
|
|
|
@@ -124,7 +136,7 @@ class GatherEnvCompat:
|
|
|
124
136
|
"""Compatibility class for common.gather_env module."""
|
|
125
137
|
|
|
126
138
|
@staticmethod
|
|
127
|
-
def gather_env_for_command(platform: str, service: str = None, command: str = None) -> Dict[str, Any]:
|
|
139
|
+
def gather_env_for_command(platform: str, service: Optional[str] = None, command: Optional[str] = None) -> Dict[str, Any]:
|
|
128
140
|
"""Gather environment for command."""
|
|
129
141
|
return gather_env_for_command(platform, service, command)
|
|
130
142
|
|
|
@@ -135,7 +147,7 @@ gather_env_compat = GatherEnvCompat()
|
|
|
135
147
|
|
|
136
148
|
|
|
137
149
|
# Utility functions for AWS session compatibility
|
|
138
|
-
def get_aws_session_compat(account_id: str, region: str = None):
|
|
150
|
+
def get_aws_session_compat(account_id: str, region: Optional[str] = None):
|
|
139
151
|
"""
|
|
140
152
|
Backward compatibility function for AWS session creation.
|
|
141
153
|
|
|
@@ -199,8 +211,8 @@ def get_gcp_client_compat(service_type: str):
|
|
|
199
211
|
|
|
200
212
|
# Import GCP utilities if available
|
|
201
213
|
try:
|
|
202
|
-
from common.gcp_utils import
|
|
203
|
-
return
|
|
214
|
+
from common.gcp_utils import create_gcp_client
|
|
215
|
+
return create_gcp_client(service_type)
|
|
204
216
|
except ImportError:
|
|
205
217
|
raise ImportError("GCP utilities not available. Please install google-cloud dependencies.")
|
|
206
218
|
|
|
@@ -208,6 +220,7 @@ def get_gcp_client_compat(service_type: str):
|
|
|
208
220
|
# Export compatibility functions
|
|
209
221
|
__all__ = [
|
|
210
222
|
'log_error',
|
|
223
|
+
'log_error_file_only',
|
|
211
224
|
'log_env_short',
|
|
212
225
|
'log_args_short',
|
|
213
226
|
'gather_env_for_command',
|
|
@@ -104,15 +104,15 @@ class ConfigInstaller:
|
|
|
104
104
|
|
|
105
105
|
def _install_secrets_example(self, target_path: Path) -> None:
|
|
106
106
|
"""Install secrets.yaml.example file."""
|
|
107
|
-
|
|
108
|
-
|
|
107
|
+
template_file_content = self.config_generator.generate_secrets_example()
|
|
108
|
+
example_file_path = target_path / 'secrets.yaml.example'
|
|
109
109
|
|
|
110
|
-
with open(
|
|
111
|
-
f.write(
|
|
110
|
+
with open(example_file_path, 'w') as f:
|
|
111
|
+
f.write(template_file_content)
|
|
112
112
|
|
|
113
113
|
# Set file permissions
|
|
114
114
|
if os.name != 'nt': # Not Windows
|
|
115
|
-
os.chmod(
|
|
115
|
+
os.chmod(example_file_path, 0o644)
|
|
116
116
|
|
|
117
117
|
|
|
118
118
|
class DefaultConfigGenerator:
|
|
@@ -181,7 +181,7 @@ class DefaultConfigGenerator:
|
|
|
181
181
|
Returns:
|
|
182
182
|
Example secrets configuration as YAML string
|
|
183
183
|
"""
|
|
184
|
-
|
|
184
|
+
template_config = {
|
|
185
185
|
'aws': {
|
|
186
186
|
'profile': 'your-aws-profile-name',
|
|
187
187
|
'access_key_id': 'AKIA...',
|
|
@@ -209,9 +209,9 @@ class DefaultConfigGenerator:
|
|
|
209
209
|
}
|
|
210
210
|
|
|
211
211
|
# Add comprehensive comments for secrets
|
|
212
|
-
|
|
212
|
+
yaml_file_content = self._add_secrets_comments()
|
|
213
213
|
|
|
214
|
-
return
|
|
214
|
+
return yaml_file_content
|
|
215
215
|
|
|
216
216
|
def _add_yaml_comments(self) -> str:
|
|
217
217
|
"""Add comprehensive comments to default YAML configuration."""
|
|
@@ -50,9 +50,9 @@ class MigrationManager:
|
|
|
50
50
|
# Check if YAML files already exist
|
|
51
51
|
config_dir = Path("config")
|
|
52
52
|
default_yaml = config_dir / "default.yaml"
|
|
53
|
-
|
|
53
|
+
secrets_file_path = config_dir / "secrets.yaml"
|
|
54
54
|
|
|
55
|
-
if not force and (default_yaml.exists() or
|
|
55
|
+
if not force and (default_yaml.exists() or secrets_file_path.exists()):
|
|
56
56
|
logger.warning("YAML configuration files already exist. Use force=True to overwrite.")
|
|
57
57
|
return False
|
|
58
58
|
|
|
@@ -69,8 +69,8 @@ class MigrationManager:
|
|
|
69
69
|
# Backup existing files if they exist
|
|
70
70
|
if default_yaml.exists():
|
|
71
71
|
self._backup_file(default_yaml)
|
|
72
|
-
if
|
|
73
|
-
self._backup_file(
|
|
72
|
+
if secrets_file_path.exists():
|
|
73
|
+
self._backup_file(secrets_file_path)
|
|
74
74
|
|
|
75
75
|
# Save configurations
|
|
76
76
|
success = True
|
|
@@ -81,11 +81,11 @@ class MigrationManager:
|
|
|
81
81
|
|
|
82
82
|
# Save secrets configuration
|
|
83
83
|
if secrets_config:
|
|
84
|
-
success &= self._save_yaml_config(
|
|
84
|
+
success &= self._save_yaml_config(secrets_file_path, secrets_config)
|
|
85
85
|
|
|
86
86
|
# Set restrictive permissions on secrets file
|
|
87
87
|
try:
|
|
88
|
-
|
|
88
|
+
secrets_file_path.chmod(0o600)
|
|
89
89
|
except Exception as e:
|
|
90
90
|
logger.warning(f"Failed to set restrictive permissions on secrets file: {e}")
|
|
91
91
|
|
|
@@ -94,7 +94,7 @@ class MigrationManager:
|
|
|
94
94
|
self._backup_file(env_path)
|
|
95
95
|
|
|
96
96
|
# Record migration
|
|
97
|
-
self._record_migration(env_path, default_yaml,
|
|
97
|
+
self._record_migration(env_path, default_yaml, secrets_file_path)
|
|
98
98
|
|
|
99
99
|
logger.info("Successfully migrated .env file to YAML configuration")
|
|
100
100
|
return True
|
|
@@ -388,11 +388,11 @@ class MigrationManager:
|
|
|
388
388
|
yaml.dump(config, f, default_flow_style=False, indent=2,
|
|
389
389
|
allow_unicode=True, sort_keys=False)
|
|
390
390
|
|
|
391
|
-
logger.info(
|
|
391
|
+
logger.info("Saved configuration to %s", file_path.name)
|
|
392
392
|
return True
|
|
393
393
|
|
|
394
394
|
except Exception as e:
|
|
395
|
-
logger.error(
|
|
395
|
+
logger.error("Failed to save configuration to %s: %s", file_path.name, e)
|
|
396
396
|
return False
|
|
397
397
|
|
|
398
398
|
def _backup_file(self, file_path: Path) -> Optional[Path]:
|
|
@@ -418,20 +418,20 @@ class MigrationManager:
|
|
|
418
418
|
|
|
419
419
|
try:
|
|
420
420
|
shutil.copy2(file_path, backup_path)
|
|
421
|
-
logger.info(
|
|
421
|
+
logger.info("Backed up %s to %s", file_path.name, backup_path.name)
|
|
422
422
|
return backup_path
|
|
423
423
|
except Exception as e:
|
|
424
|
-
logger.error(
|
|
424
|
+
logger.error("Failed to backup %s: %s", file_path.name, e)
|
|
425
425
|
return None
|
|
426
426
|
|
|
427
|
-
def _record_migration(self, env_path: Path, default_yaml: Path,
|
|
427
|
+
def _record_migration(self, env_path: Path, default_yaml: Path, secrets_file_path: Path):
|
|
428
428
|
"""Record migration details for history."""
|
|
429
429
|
migration_record = {
|
|
430
430
|
"timestamp": datetime.now().isoformat(),
|
|
431
431
|
"source_file": str(env_path),
|
|
432
432
|
"target_files": {
|
|
433
|
-
"
|
|
434
|
-
"
|
|
433
|
+
"default_config_path": str(default_yaml),
|
|
434
|
+
"secrets_config_path": str(secrets_file_path) if secrets_file_path.exists() else None
|
|
435
435
|
},
|
|
436
436
|
"backup_location": str(self.backup_dir)
|
|
437
437
|
}
|
|
@@ -446,17 +446,17 @@ class MigrationManager:
|
|
|
446
446
|
True if document was created successfully
|
|
447
447
|
"""
|
|
448
448
|
try:
|
|
449
|
-
|
|
449
|
+
history_file_content = self._generate_migration_history_content()
|
|
450
450
|
|
|
451
|
-
|
|
452
|
-
with open(
|
|
453
|
-
f.write(
|
|
451
|
+
history_file_path = self.backup_dir / "migration_history.md"
|
|
452
|
+
with open(history_file_path, 'w', encoding='utf-8') as f:
|
|
453
|
+
f.write(history_file_content)
|
|
454
454
|
|
|
455
|
-
logger.info(
|
|
455
|
+
logger.info("Created migration history document at %s", history_file_path.name)
|
|
456
456
|
return True
|
|
457
457
|
|
|
458
458
|
except Exception as e:
|
|
459
|
-
logger.error(
|
|
459
|
+
logger.error("Failed to create migration history document: %s", e)
|
|
460
460
|
return False
|
|
461
461
|
|
|
462
462
|
def _generate_migration_history_content(self) -> str:
|
|
@@ -507,10 +507,15 @@ backup/
|
|
|
507
507
|
content += f"### Migration {i}\n\n"
|
|
508
508
|
content += f"- **Date**: {record['timestamp']}\n"
|
|
509
509
|
content += f"- **Source**: {record['source_file']}\n"
|
|
510
|
-
content += f"- **Default Config**: {record['target_files']['default_config']}\n"
|
|
511
510
|
|
|
512
|
-
|
|
513
|
-
|
|
511
|
+
target_files = record.get('target_files', {})
|
|
512
|
+
default_file_path = target_files.get('default_config_path')
|
|
513
|
+
if default_file_path:
|
|
514
|
+
content += f"- **Default Config**: {default_file_path}\n"
|
|
515
|
+
|
|
516
|
+
secrets_file_path = target_files.get('secrets_config_path')
|
|
517
|
+
if secrets_file_path:
|
|
518
|
+
content += f"- **Secrets Config**: {secrets_file_path}\n"
|
|
514
519
|
|
|
515
520
|
content += f"- **Backup Location**: {record['backup_location']}\n\n"
|
|
516
521
|
else:
|
|
@@ -80,11 +80,10 @@ class SecretsManager:
|
|
|
80
80
|
secrets = self._merge_secrets(secrets, env_secrets)
|
|
81
81
|
logger.debug("Merged secrets from environment variables")
|
|
82
82
|
|
|
83
|
-
# Validate that secrets are properly separated (log
|
|
83
|
+
# Validate that secrets are properly separated (log summary only, no cleartext secret keys)
|
|
84
84
|
validation_warnings = self.validate_secrets_separation(secrets)
|
|
85
85
|
if validation_warnings:
|
|
86
|
-
|
|
87
|
-
logger.debug(f"Secrets validation: {warning}") # Changed to debug level
|
|
86
|
+
logger.debug("Secrets validation completed with %d checks", len(validation_warnings))
|
|
88
87
|
|
|
89
88
|
self.secrets_data = secrets
|
|
90
89
|
return secrets
|
|
@@ -123,8 +123,10 @@ class ICLogger:
|
|
|
123
123
|
console_formatter = logging.Formatter('%(message)s')
|
|
124
124
|
console_handler.setFormatter(console_formatter)
|
|
125
125
|
|
|
126
|
-
# Add filter to suppress non-ERROR messages on console
|
|
126
|
+
# Add filter to suppress non-ERROR messages and file-only messages on console
|
|
127
127
|
def error_only_filter(record):
|
|
128
|
+
if getattr(record, "file_only", False):
|
|
129
|
+
return False
|
|
128
130
|
return record.levelno >= logging.ERROR
|
|
129
131
|
|
|
130
132
|
console_handler.addFilter(error_only_filter)
|
|
@@ -138,7 +140,9 @@ class ICLogger:
|
|
|
138
140
|
encoding='utf-8'
|
|
139
141
|
)
|
|
140
142
|
file_handler.setLevel(self.file_level)
|
|
141
|
-
file_formatter = logging.Formatter(
|
|
143
|
+
file_formatter = logging.Formatter(
|
|
144
|
+
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
|
145
|
+
)
|
|
142
146
|
file_handler.setFormatter(file_formatter)
|
|
143
147
|
logger.addHandler(file_handler)
|
|
144
148
|
|
|
@@ -152,31 +156,27 @@ class ICLogger:
|
|
|
152
156
|
# Use security manager to mask sensitive data
|
|
153
157
|
return self.security_manager.mask_sensitive_in_text(message)
|
|
154
158
|
|
|
155
|
-
def log_args(self, args:
|
|
159
|
+
def log_args(self, args: Any) -> None:
|
|
156
160
|
"""
|
|
157
|
-
|
|
161
|
+
Log command arguments with sensitive data masking.
|
|
162
|
+
Only logs to file, never to console.
|
|
158
163
|
|
|
159
164
|
Args:
|
|
160
|
-
args:
|
|
165
|
+
args: Command line arguments namespace or dict
|
|
161
166
|
"""
|
|
162
|
-
|
|
167
|
+
if not args:
|
|
168
|
+
return
|
|
169
|
+
|
|
170
|
+
args_dict = {}
|
|
163
171
|
if hasattr(args, '__dict__'):
|
|
164
|
-
args_dict = {k: v for k, v in vars(args).items()
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
pretty_args = {k: (v if v is not None else "default")
|
|
171
|
-
for k, v in args_dict.items()}
|
|
172
|
+
args_dict = {k: v for k, v in vars(args).items() if not k.startswith('_') and k != 'func'}
|
|
173
|
+
elif isinstance(args, dict):
|
|
174
|
+
args_dict = {k: v for k, v in args.items() if not k.startswith('_')}
|
|
175
|
+
|
|
176
|
+
# Format arguments nicely
|
|
177
|
+
pretty_args = {k: (v if v is not None else "default") for k, v in args_dict.items()}
|
|
172
178
|
args_str = ", ".join(f"{k}={v}" for k, v in pretty_args.items())
|
|
173
179
|
|
|
174
|
-
# Console output for args (always shown regardless of log level)
|
|
175
|
-
if self.console and RICH_AVAILABLE:
|
|
176
|
-
self.console.print(f"[bold cyan]Args:[/bold cyan] {args_str}")
|
|
177
|
-
else:
|
|
178
|
-
print(f"Args: {args_str}")
|
|
179
|
-
|
|
180
180
|
# File logging with masking
|
|
181
181
|
masked_args_str = self._mask_message(f"Args: {args_str}")
|
|
182
182
|
self.logger.info(masked_args_str)
|
|
@@ -191,6 +191,16 @@ class ICLogger:
|
|
|
191
191
|
masked_message = self._mask_message(message)
|
|
192
192
|
self.logger.info(masked_message)
|
|
193
193
|
|
|
194
|
+
def log_error_file_only(self, message: str) -> None:
|
|
195
|
+
"""
|
|
196
|
+
Log ERROR message to file only (not console).
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
message: Error message to log to file
|
|
200
|
+
"""
|
|
201
|
+
masked_message = self._mask_message(message)
|
|
202
|
+
self.logger.error(masked_message, extra={"file_only": True})
|
|
203
|
+
|
|
194
204
|
def log_error(self, message: str) -> None:
|
|
195
205
|
"""
|
|
196
206
|
Log ERROR message to both console and file.
|
|
@@ -200,12 +210,6 @@ class ICLogger:
|
|
|
200
210
|
"""
|
|
201
211
|
masked_message = self._mask_message(message)
|
|
202
212
|
self.logger.error(masked_message)
|
|
203
|
-
|
|
204
|
-
# Also display on console with Rich formatting if available
|
|
205
|
-
if self.console and RICH_AVAILABLE:
|
|
206
|
-
self.console.print(f"[bold red]ERROR:[/bold red] {message}")
|
|
207
|
-
else:
|
|
208
|
-
print(f"ERROR: {message}")
|
|
209
213
|
|
|
210
214
|
def log_critical(self, message: str) -> None:
|
|
211
215
|
"""
|
|
@@ -216,12 +220,6 @@ class ICLogger:
|
|
|
216
220
|
"""
|
|
217
221
|
masked_message = self._mask_message(message)
|
|
218
222
|
self.logger.critical(masked_message)
|
|
219
|
-
|
|
220
|
-
# Also display on console with Rich formatting if available
|
|
221
|
-
if self.console and RICH_AVAILABLE:
|
|
222
|
-
self.console.print(f"[bold red]CRITICAL:[/bold red] {message}")
|
|
223
|
-
else:
|
|
224
|
-
print(f"CRITICAL: {message}")
|
|
225
223
|
|
|
226
224
|
def log_warning(self, message: str) -> None:
|
|
227
225
|
"""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""AWS Disk (EBS alias) module for IC CLI."""
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
AWS Disk Info Command (Alias to AWS EBS Info Command).
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
from typing import Any, Optional
|
|
8
|
+
from ic.platforms.aws.ebs.info import (
|
|
9
|
+
EbsInfoCommand,
|
|
10
|
+
main as ebs_main,
|
|
11
|
+
add_arguments as ebs_add_arguments,
|
|
12
|
+
format_table_output,
|
|
13
|
+
format_tree_output,
|
|
14
|
+
print_paste_format
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class AwsDiskInfoCommand(EbsInfoCommand):
|
|
19
|
+
"""AWS Disk (EBS) 볼륨 정보 조회 커맨드 (Alias)"""
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def main(args: Optional[argparse.Namespace] = None, config: Any = None) -> None:
|
|
24
|
+
ebs_main(args, config)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def add_arguments(parser: argparse.ArgumentParser) -> None:
|
|
28
|
+
ebs_add_arguments(parser)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
if __name__ == "__main__":
|
|
32
|
+
main()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""AWS EBS (Elastic Block Store) module for IC CLI."""
|