ic-code 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
ic/cli.py ADDED
@@ -0,0 +1,769 @@
1
+ #!/usr/bin/env python3
2
+
3
+ import argparse
4
+ import sys
5
+ import warnings
6
+
7
+ # Silence all logging except ERROR messages
8
+ from .core.silence_logging import silence_all_logging
9
+ silence_all_logging()
10
+
11
+ # Set up compatibility layer first
12
+ from .compat.cli import setup_cli_compatibility, wrap_command_function, ensure_env_compatibility
13
+ from .compat.common import log_error, log_env_short, log_args_short, gather_env_for_command
14
+
15
+ # Initialize compatibility layer
16
+ setup_cli_compatibility()
17
+
18
+ # Initialize new configuration system
19
+ from .config.manager import ConfigManager
20
+ from .config.security import SecurityManager
21
+ from .core.logging import init_logger
22
+
23
+ # Global configuration manager instance
24
+ _config_manager = None
25
+ _ic_logger = None
26
+
27
+ def get_config_manager():
28
+ """Get or create global configuration manager."""
29
+ global _config_manager, _ic_logger
30
+ if _config_manager is None:
31
+ # Suppress all logging during initialization
32
+ import logging
33
+ logging.getLogger().setLevel(logging.CRITICAL)
34
+
35
+ security_manager = SecurityManager()
36
+ _config_manager = ConfigManager(security_manager)
37
+
38
+ # Load all configurations
39
+ config = _config_manager.load_all_configs()
40
+
41
+ # Initialize logging with new configuration
42
+ _ic_logger = init_logger(config)
43
+
44
+ # Log .env file usage to file only (no console output)
45
+ from pathlib import Path
46
+ if Path('.env').exists() and _ic_logger:
47
+ _ic_logger.log_info_file_only("Using .env file for configuration. Consider migrating to YAML configuration with 'ic config migrate'")
48
+
49
+ return _config_manager
50
+
51
+ # Legacy dotenv support (silent loading)
52
+ try:
53
+ from dotenv import load_dotenv
54
+ from pathlib import Path
55
+ if Path('.env').exists():
56
+ load_dotenv()
57
+ except ImportError:
58
+ pass
59
+ from aws.ec2 import list_tags as ec2_list_tags
60
+ from aws.ec2 import tag_check as ec2_tag_check
61
+ from aws.ec2 import info as ec2_info
62
+ from aws.lb import list_tags as lb_list_tags
63
+ from aws.lb import tag_check as lb_tag_check
64
+ from aws.vpc import tag_check as vpc_tag_check
65
+ from aws.vpc import list_tags as vpc_list_tags
66
+ from aws.rds import list_tags as rds_list_tags
67
+ from aws.rds import tag_check as rds_tag_check
68
+ from aws.s3 import list_tags as s3_list_tags
69
+ from aws.s3 import tag_check as s3_tag_check
70
+ from aws.sg import info as sg_info
71
+ from aws.eks import info as eks_info
72
+ from aws.eks import nodes as eks_nodes
73
+ from aws.eks import pods as eks_pods
74
+ from aws.eks import fargate as eks_fargate
75
+ from aws.eks import addons as eks_addons
76
+ from aws.eks import update_config as eks_update_config
77
+ from aws.fargate import info as fargate_info
78
+ from aws.codepipeline import build as codepipeline_build
79
+ from aws.codepipeline import deploy as codepipeline_deploy
80
+ from aws.ecs import info as ecs_info
81
+ from aws.ecs import service as ecs_service
82
+ from aws.ecs import task as ecs_task
83
+ from aws.msk import info as msk_info
84
+ from aws.msk import broker as msk_broker
85
+ from cf.dns import list_info as dns_info
86
+ from oci_module.info import oci_info as oci_info # Deprecated. 통합 oci info
87
+ from oci_module.vm import add_arguments as vm_add_args, main as vm_main
88
+ from oci_module.lb import add_arguments as lb_add_args, main as lb_main
89
+ from oci_module.nsg import add_arguments as nsg_add_args, main as nsg_main
90
+ from oci_module.volume import add_arguments as volume_add_args, main as volume_main
91
+ from oci_module.policy import add_arguments as policy_add_args, main as policy_main
92
+ from oci_module.policy import search as oci_policy_search
93
+ from oci_module.obj import add_arguments as obj_add_args, main as obj_main
94
+ from oci_module.cost import usage_add_arguments as cost_usage_add_args, usage_main as cost_usage_main
95
+ from oci_module.cost import credit_add_arguments as cost_credit_add_args, credit_main as cost_credit_main
96
+ from oci_module.vcn import info as vcn_info
97
+ from ssh import auto_ssh, server_info
98
+ import concurrent.futures
99
+ from threading import Lock
100
+
101
+ load_dotenv()
102
+
103
+ # Global lock for thread-safe output formatting
104
+ output_lock = Lock()
105
+
106
+ def oci_info_deprecated(args):
107
+ from rich.console import Console
108
+ console = Console()
109
+ console.print("\n[bold yellow]⚠️ 'ic oci info' 명령어는 더 이상 사용되지 않습니다.[/bold yellow]")
110
+ console.print("대신 각 서비스별 `info` 명령어를 사용해주세요. 예시:\n")
111
+ console.print(" - `ic oci vm info`")
112
+ console.print(" - `ic oci lb info`")
113
+ console.print(" - `ic oci nsg info`")
114
+ console.print(" - `ic oci volume info`")
115
+ console.print(" - `ic oci obj info`")
116
+ console.print(" - `ic oci policy info`\n")
117
+ console.print(" - 여러 서비스 : `ic oci vm,lb,nsg,volume,obj,policy info`\n")
118
+ console.print("전체 OCI 명령어는 `ic oci --help`로 확인하실 수 있습니다.")
119
+
120
+ def execute_gcp_multi_service(services, command_and_options, parser):
121
+ """GCP 다중 서비스 명령을 병렬로 실행합니다."""
122
+ from rich.console import Console
123
+ console = Console()
124
+
125
+ def execute_service(service):
126
+ """단일 GCP 서비스를 실행하고 결과를 반환합니다."""
127
+ try:
128
+ current_argv = ['gcp', service] + command_and_options
129
+ args = parser.parse_args(current_argv)
130
+
131
+ # Capture output for thread-safe display
132
+ import io
133
+ import contextlib
134
+
135
+ output_buffer = io.StringIO()
136
+ with contextlib.redirect_stdout(output_buffer):
137
+ execute_single_command(args)
138
+
139
+ return {
140
+ 'service': service,
141
+ 'success': True,
142
+ 'output': output_buffer.getvalue(),
143
+ 'error': None
144
+ }
145
+ except SystemExit as e:
146
+ # SystemExit with code 0 is normal (e.g., help command)
147
+ if e.code == 0:
148
+ return {
149
+ 'service': service,
150
+ 'success': True,
151
+ 'output': output_buffer.getvalue(),
152
+ 'error': None
153
+ }
154
+ else:
155
+ return {
156
+ 'service': service,
157
+ 'success': False,
158
+ 'output': '',
159
+ 'error': f"Command failed with exit code: {e.code}"
160
+ }
161
+ except Exception as e:
162
+ return {
163
+ 'service': service,
164
+ 'success': False,
165
+ 'output': '',
166
+ 'error': str(e)
167
+ }
168
+
169
+ # Execute services in parallel
170
+ console.print(f"\n[bold cyan]Executing GCP services in parallel: {', '.join(services)}[/bold cyan]")
171
+
172
+ with concurrent.futures.ThreadPoolExecutor(max_workers=min(len(services), 5)) as executor:
173
+ future_to_service = {executor.submit(execute_service, service): service for service in services}
174
+ results = []
175
+
176
+ for future in concurrent.futures.as_completed(future_to_service):
177
+ result = future.result()
178
+ results.append(result)
179
+
180
+ # Sort results by original service order
181
+ service_order = {service: i for i, service in enumerate(services)}
182
+ results.sort(key=lambda x: service_order[x['service']])
183
+
184
+ # Display results with thread-safe output
185
+ with output_lock:
186
+ has_error = False
187
+ for result in results:
188
+ service = result['service']
189
+ if result['success']:
190
+ console.print(f"\n[bold green]✓ GCP {service.upper()} Results:[/bold green]")
191
+ if result['output'].strip():
192
+ print(result['output'])
193
+ else:
194
+ console.print(f"[dim]No output from {service} service[/dim]")
195
+ else:
196
+ console.print(f"\n[bold red]✗ GCP {service.upper()} Failed:[/bold red]")
197
+ console.print(f"[red]Error: {result['error']}[/red]")
198
+ has_error = True
199
+
200
+ if has_error:
201
+ console.print(f"\n[bold yellow]⚠️ Some GCP services failed. Check individual service configurations.[/bold yellow]")
202
+ sys.exit(1)
203
+ else:
204
+ console.print(f"\n[bold green]✓ All GCP services completed successfully[/bold green]")
205
+
206
+ def gcp_monitor_performance_command(args):
207
+ """GCP 성능 메트릭을 표시하는 명령어"""
208
+ try:
209
+ from common.gcp_monitoring import log_gcp_performance_summary
210
+ log_gcp_performance_summary()
211
+ except ImportError:
212
+ from rich.console import Console
213
+ console = Console()
214
+ console.print("[bold red]GCP monitoring module not available[/bold red]")
215
+
216
+ def gcp_monitor_health_command(args):
217
+ """GCP 서비스 헬스 상태를 표시하는 명령어"""
218
+ try:
219
+ from common.gcp_monitoring import gcp_monitor
220
+ from rich.console import Console
221
+ from rich.panel import Panel
222
+
223
+ console = Console()
224
+ health_status = gcp_monitor.get_health_status()
225
+
226
+ health_text = f"MCP Connected: {'✓' if health_status['mcp_connected'] else '✗'}\n"
227
+ health_text += f"Uptime: {health_status['uptime_minutes']:.1f} minutes\n"
228
+ health_text += f"Total API Calls: {health_status['total_api_calls']}\n"
229
+
230
+ if health_status['service_health']:
231
+ health_text += "\nService Health:\n"
232
+ for service, is_healthy in health_status['service_health'].items():
233
+ status = '✓' if is_healthy else '✗'
234
+ health_text += f" {service}: {status}\n"
235
+ else:
236
+ health_text += "\nNo service health data available"
237
+
238
+ console.print(Panel(
239
+ health_text,
240
+ title="GCP System Health",
241
+ border_style="green" if health_status['mcp_connected'] else "yellow"
242
+ ))
243
+
244
+ except ImportError:
245
+ from rich.console import Console
246
+ console = Console()
247
+ console.print("[bold red]GCP monitoring module not available[/bold red]")
248
+
249
+ def main():
250
+ """IC CLI 엔트리 포인트"""
251
+ # Initialize configuration system early
252
+ try:
253
+ config_manager = get_config_manager()
254
+ except Exception as e:
255
+ print(f"Warning: Failed to initialize configuration system: {e}")
256
+ print("Falling back to legacy configuration...")
257
+
258
+ parser = argparse.ArgumentParser(
259
+ description="Infra CLI: Platform Resource CLI Tool",
260
+ usage="ic <platform|config> <service> <command> [options]"
261
+ )
262
+ platform_subparsers = parser.add_subparsers(
263
+ dest="platform",
264
+ required=True,
265
+ help="클라우드 플랫폼 (aws, oci, cf, ssh, azure, gcp) 또는 config 관리"
266
+ )
267
+
268
+ # Add config commands
269
+ from .commands.config import ConfigCommands
270
+ config_commands = ConfigCommands()
271
+ config_commands.add_subparsers(platform_subparsers)
272
+
273
+ aws_parser = platform_subparsers.add_parser("aws", help="AWS 관련 명령어")
274
+ oci_parser = platform_subparsers.add_parser("oci", help="OCI 관련 명령어")
275
+ azure_parser = platform_subparsers.add_parser("azure", help="Azure 관련 명령어")
276
+ gcp_parser = platform_subparsers.add_parser("gcp", help="GCP 관련 명령어")
277
+ cf_parser = platform_subparsers.add_parser("cf", help="CloudFlare 관련 명령어")
278
+ ssh_parser = platform_subparsers.add_parser("ssh", help="SSH 관련 명령어")
279
+
280
+ aws_subparsers = aws_parser.add_subparsers(dest="service",required=True,help="AWS 리소스 관리 서비스")
281
+ oci_subparsers = oci_parser.add_subparsers(dest="service",required=True,help="OCI 리소스 관리 서비스")
282
+ azure_subparsers = azure_parser.add_subparsers(dest="service", required=True, help="Azure 리소스 관리 서비스")
283
+ gcp_subparsers = gcp_parser.add_subparsers(dest="service", required=True, help="GCP 리소스 관리 서비스")
284
+ cf_subparsers = cf_parser.add_subparsers(dest="service",required=True,help="CloudFlare 리소스 관리 서비스")
285
+ ssh_subparsers = ssh_parser.add_subparsers(dest="service",required=True,help="SSH 관리 서비스")
286
+
287
+ # ---------------- AWS ----------------
288
+ ec2_parser = aws_subparsers.add_parser("ec2", help="EC2 관련 명령어")
289
+ ec2_subparsers = ec2_parser.add_subparsers(dest="command", required=True)
290
+ ec2_list_tags_parser = ec2_subparsers.add_parser("list_tags", help="EC2 인스턴스 태그 나열")
291
+ ec2_list_tags.add_arguments(ec2_list_tags_parser)
292
+ ec2_list_tags_parser.set_defaults(func=ec2_list_tags.main)
293
+ ec2_tag_check_parser = ec2_subparsers.add_parser("tag_check", help="EC2 태그 유효성 검사")
294
+ ec2_tag_check.add_arguments(ec2_tag_check_parser)
295
+ ec2_tag_check_parser.set_defaults(func=ec2_tag_check.main)
296
+ ec2_info_parser = ec2_subparsers.add_parser("info", help="EC2 인스턴스 정보 나열")
297
+ ec2_info.add_arguments(ec2_info_parser)
298
+ ec2_info_parser.set_defaults(func=ec2_info.main)
299
+
300
+ lb_parser = aws_subparsers.add_parser("lb", help="LB 관련 명령어")
301
+ lb_subparsers = lb_parser.add_subparsers(dest="command", required=True)
302
+ lb_list_parser = lb_subparsers.add_parser("list_tags", help="LB 태그 조회")
303
+ lb_list_tags.add_arguments(lb_list_parser)
304
+ lb_list_parser.set_defaults(func=lb_list_tags.main)
305
+ lb_check_parser = lb_subparsers.add_parser("tag_check", help="LB 태그 유효성 검사")
306
+ lb_tag_check.add_arguments(lb_check_parser)
307
+ lb_check_parser.set_defaults(func=lb_tag_check.main)
308
+
309
+ lb_info_parser = lb_subparsers.add_parser("info", help="LB 상세 정보 조회")
310
+ from aws.lb import info as lb_info
311
+ lb_info.add_arguments(lb_info_parser)
312
+ lb_info_parser.set_defaults(func=lb_info.main)
313
+
314
+ vpc_parser = aws_subparsers.add_parser("vpc", help="VPC + Gateway + VPN 관련 명령어")
315
+ vpc_subparsers = vpc_parser.add_subparsers(dest="command", required=True)
316
+ vpc_check_parser = vpc_subparsers.add_parser("tag_check", help="VPC + Gateway + VPN 태그 유효성 검사")
317
+ vpc_tag_check.add_arguments(vpc_check_parser)
318
+ vpc_check_parser.set_defaults(func=vpc_tag_check.main)
319
+ vpc_list_parser = vpc_subparsers.add_parser("list_tags", help="VPC + Gateway + VPN 태그 조회")
320
+ vpc_tag_check.add_arguments(vpc_list_parser)
321
+ vpc_list_parser.set_defaults(func=vpc_list_tags.main)
322
+
323
+ vpc_info_parser = vpc_subparsers.add_parser("info", help="VPC 상세 정보 조회")
324
+ from aws.vpc import info as vpc_info
325
+ vpc_info.add_arguments(vpc_info_parser)
326
+ vpc_info_parser.set_defaults(func=vpc_info.main)
327
+
328
+ vpn_parser = aws_subparsers.add_parser("vpn", help="TGW, VGW, VPN Connection, Endpoint 관련 명령어")
329
+ vpn_subparsers = vpn_parser.add_subparsers(dest="command", required=True)
330
+ vpn_info_parser = vpn_subparsers.add_parser("info", help="VPN 관련 상세 정보 조회")
331
+ from aws.vpn import info as vpn_info
332
+ vpn_info.add_arguments(vpn_info_parser)
333
+ vpn_info_parser.set_defaults(func=vpn_info.main)
334
+
335
+
336
+ rds_parser = aws_subparsers.add_parser("rds", help="RDS 관련 명령어")
337
+ rds_subparsers = rds_parser.add_subparsers(dest="command", required=True)
338
+ rds_list_cmd = rds_subparsers.add_parser("list_tags", help="RDS 태그 조회")
339
+ rds_list_tags.add_arguments(rds_list_cmd)
340
+ rds_list_cmd.set_defaults(func=rds_list_tags.main)
341
+ rds_check_cmd = rds_subparsers.add_parser("tag_check", help="RDS 태그 유효성 검사")
342
+ rds_tag_check.add_arguments(rds_check_cmd)
343
+ rds_check_cmd.set_defaults(func=rds_tag_check.main)
344
+
345
+ rds_info_parser = rds_subparsers.add_parser("info", help="RDS 상세 정보 조회")
346
+ from aws.rds import info as rds_info
347
+ rds_info.add_arguments(rds_info_parser)
348
+ rds_info_parser.set_defaults(func=rds_info.main)
349
+
350
+ s3_parser = aws_subparsers.add_parser("s3", help="S3 관련 명령어")
351
+ s3_subparsers = s3_parser.add_subparsers(dest="command", required=True)
352
+ s3_list_cmd = s3_subparsers.add_parser("list_tags", help="S3 버킷 태그 조회")
353
+ s3_list_tags.add_arguments(s3_list_cmd)
354
+ s3_list_cmd.set_defaults(func=s3_list_tags.main)
355
+ s3_check_cmd = s3_subparsers.add_parser("tag_check", help="S3 태그 유효성 검사")
356
+ s3_tag_check.add_arguments(s3_check_cmd)
357
+ s3_check_cmd.set_defaults(func=s3_tag_check.main)
358
+
359
+ s3_info_parser = s3_subparsers.add_parser("info", help="S3 상세 정보 조회")
360
+ from aws.s3 import info as s3_info
361
+ s3_info.add_arguments(s3_info_parser)
362
+ s3_info_parser.set_defaults(func=s3_info.main)
363
+
364
+ sg_parser = aws_subparsers.add_parser("sg", help="Security Group 관련 명령어")
365
+ sg_subparsers = sg_parser.add_subparsers(dest="command", required=True)
366
+ sg_info_parser = sg_subparsers.add_parser("info", help="Security Group 상세 정보 조회")
367
+ sg_info.add_arguments(sg_info_parser)
368
+ sg_info_parser.set_defaults(func=sg_info.main)
369
+
370
+ # EKS 관련 명령어
371
+ eks_parser = aws_subparsers.add_parser("eks", help="EKS 관련 명령어")
372
+ eks_subparsers = eks_parser.add_subparsers(dest="command", required=True)
373
+
374
+ eks_info_parser = eks_subparsers.add_parser("info", help="EKS 클러스터 정보 조회")
375
+ eks_info.add_arguments(eks_info_parser)
376
+ eks_info_parser.set_defaults(func=eks_info.main)
377
+
378
+ eks_nodes_parser = eks_subparsers.add_parser("nodes", help="EKS 노드 정보 조회")
379
+ eks_nodes.add_arguments(eks_nodes_parser)
380
+ eks_nodes_parser.set_defaults(func=eks_nodes.main)
381
+
382
+ eks_pods_parser = eks_subparsers.add_parser("pods", help="EKS 파드 정보 조회")
383
+ eks_pods.add_arguments(eks_pods_parser)
384
+ eks_pods_parser.set_defaults(func=eks_pods.main)
385
+
386
+ eks_fargate_parser = eks_subparsers.add_parser("fargate", help="EKS Fargate 프로파일 정보 조회")
387
+ eks_fargate.add_arguments(eks_fargate_parser)
388
+ eks_fargate_parser.set_defaults(func=eks_fargate.main)
389
+
390
+ eks_addons_parser = eks_subparsers.add_parser("addons", help="EKS 애드온 정보 조회")
391
+ eks_addons.add_arguments(eks_addons_parser)
392
+ eks_addons_parser.set_defaults(func=eks_addons.main)
393
+
394
+ eks_update_config_parser = eks_subparsers.add_parser("update-config", help="EKS kubeconfig 업데이트")
395
+ eks_update_config.add_arguments(eks_update_config_parser)
396
+ eks_update_config_parser.set_defaults(func=eks_update_config.main)
397
+
398
+ # Fargate 관련 명령어 (DEPRECATED - EKS로 완전 통합됨)
399
+ def fargate_deprecated_handler(args):
400
+ from rich.console import Console
401
+ console = Console()
402
+ console.print("\n[bold red]⚠️ 'ic aws fargate' 명령어는 더 이상 사용되지 않습니다.[/bold red]")
403
+ console.print("EKS Fargate 기능이 EKS 서비스로 완전히 통합되었습니다.\n")
404
+ console.print("[bold yellow]새로운 명령어를 사용해주세요:[/bold yellow]")
405
+ console.print(" • EKS Fargate 프로파일: [bold cyan]ic aws eks fargate[/bold cyan]")
406
+ console.print(" • EKS 파드 정보: [bold cyan]ic aws eks pods[/bold cyan]")
407
+ console.print(" • EKS 전체 정보: [bold cyan]ic aws eks --help[/bold cyan]\n")
408
+ console.print("ECS Fargate는 [bold cyan]ic aws ecs task[/bold cyan] 명령어를 사용하세요.")
409
+ return
410
+
411
+ fargate_parser = aws_subparsers.add_parser("fargate", help="[DEPRECATED] Fargate 관련 명령어 - 'ic aws eks' 사용 권장")
412
+ fargate_subparsers = fargate_parser.add_subparsers(dest="command", required=False)
413
+ fargate_parser.set_defaults(func=fargate_deprecated_handler)
414
+
415
+ # CodePipeline 관련 명령어 (code 서비스 하위)
416
+ code_parser = aws_subparsers.add_parser("code", help="CodePipeline 관련 명령어")
417
+ code_subparsers = code_parser.add_subparsers(dest="command", required=True)
418
+
419
+ code_build_parser = code_subparsers.add_parser("build", help="CodePipeline 빌드 스테이지 상태 조회")
420
+ codepipeline_build.add_arguments(code_build_parser)
421
+ code_build_parser.set_defaults(func=codepipeline_build.main)
422
+
423
+ code_deploy_parser = code_subparsers.add_parser("deploy", help="CodePipeline 배포 스테이지 상태 조회")
424
+ codepipeline_deploy.add_arguments(code_deploy_parser)
425
+ code_deploy_parser.set_defaults(func=codepipeline_deploy.main)
426
+
427
+ # ECS 관련 명령어
428
+ ecs_parser = aws_subparsers.add_parser("ecs", help="ECS 관련 명령어")
429
+ ecs_subparsers = ecs_parser.add_subparsers(dest="command", required=True)
430
+
431
+ ecs_info_parser = ecs_subparsers.add_parser("info", help="ECS 클러스터 정보 조회")
432
+ ecs_info.add_arguments(ecs_info_parser)
433
+ ecs_info_parser.set_defaults(func=ecs_info.main)
434
+
435
+ ecs_service_parser = ecs_subparsers.add_parser("service", help="ECS 서비스 정보 조회")
436
+ ecs_service.add_arguments(ecs_service_parser)
437
+ ecs_service_parser.set_defaults(func=ecs_service.main)
438
+
439
+ ecs_task_parser = ecs_subparsers.add_parser("task", help="ECS 태스크 정보 조회")
440
+ ecs_task.add_arguments(ecs_task_parser)
441
+ ecs_task_parser.set_defaults(func=ecs_task.main)
442
+
443
+ # MSK 관련 명령어
444
+ msk_parser = aws_subparsers.add_parser("msk", help="MSK (Managed Streaming for Apache Kafka) 관련 명령어")
445
+ msk_subparsers = msk_parser.add_subparsers(dest="command", required=True)
446
+
447
+ msk_info_parser = msk_subparsers.add_parser("info", help="MSK 클러스터 정보 조회")
448
+ msk_info.add_arguments(msk_info_parser)
449
+ msk_info_parser.set_defaults(func=msk_info.main)
450
+
451
+ msk_broker_parser = msk_subparsers.add_parser("broker", help="MSK 브로커 엔드포인트 정보 조회")
452
+ msk_broker.add_arguments(msk_broker_parser)
453
+ msk_broker_parser.set_defaults(func=msk_broker.main)
454
+
455
+ # ---------------- Azure ----------------
456
+ # Azure VM 관련 명령어
457
+ azure_vm_parser = azure_subparsers.add_parser("vm", help="Azure Virtual Machine 관련 명령어")
458
+ azure_vm_subparsers = azure_vm_parser.add_subparsers(dest="command", required=True)
459
+ azure_vm_info_parser = azure_vm_subparsers.add_parser("info", help="Azure VM 정보 조회")
460
+ try:
461
+ from azure_module.vm import info as azure_vm_info
462
+ azure_vm_info.add_arguments(azure_vm_info_parser)
463
+ azure_vm_info_parser.set_defaults(func=azure_vm_info.main)
464
+ except ImportError:
465
+ azure_vm_info_parser.set_defaults(func=lambda args: print("Azure 모듈이 설치되지 않았습니다. pip install azure-mgmt-compute를 실행하세요."))
466
+
467
+ # Azure VNet 관련 명령어
468
+ azure_vnet_parser = azure_subparsers.add_parser("vnet", help="Azure Virtual Network 관련 명령어")
469
+ azure_vnet_subparsers = azure_vnet_parser.add_subparsers(dest="command", required=True)
470
+ azure_vnet_info_parser = azure_vnet_subparsers.add_parser("info", help="Azure VNet 정보 조회")
471
+ try:
472
+ from azure_module.vnet import info as azure_vnet_info
473
+ azure_vnet_info.add_arguments(azure_vnet_info_parser)
474
+ azure_vnet_info_parser.set_defaults(func=azure_vnet_info.main)
475
+ except ImportError:
476
+ azure_vnet_info_parser.set_defaults(func=lambda args: print("Azure 모듈이 설치되지 않았습니다."))
477
+
478
+ # Azure AKS 관련 명령어
479
+ azure_aks_parser = azure_subparsers.add_parser("aks", help="Azure Kubernetes Service 관련 명령어")
480
+ azure_aks_subparsers = azure_aks_parser.add_subparsers(dest="command", required=True)
481
+ azure_aks_info_parser = azure_aks_subparsers.add_parser("info", help="Azure AKS 클러스터 정보 조회")
482
+ try:
483
+ from azure_module.aks import info as azure_aks_info
484
+ azure_aks_info.add_arguments(azure_aks_info_parser)
485
+ azure_aks_info_parser.set_defaults(func=azure_aks_info.main)
486
+ except ImportError:
487
+ azure_aks_info_parser.set_defaults(func=lambda args: print("Azure 모듈이 설치되지 않았습니다."))
488
+
489
+ # Azure Storage 관련 명령어
490
+ azure_storage_parser = azure_subparsers.add_parser("storage", help="Azure Storage Account 관련 명령어")
491
+ azure_storage_subparsers = azure_storage_parser.add_subparsers(dest="command", required=True)
492
+ azure_storage_info_parser = azure_storage_subparsers.add_parser("info", help="Azure Storage Account 정보 조회")
493
+ try:
494
+ from azure_module.storage import info as azure_storage_info
495
+ azure_storage_info.add_arguments(azure_storage_info_parser)
496
+ azure_storage_info_parser.set_defaults(func=azure_storage_info.main)
497
+ except ImportError:
498
+ azure_storage_info_parser.set_defaults(func=lambda args: print("Azure 모듈이 설치되지 않았습니다."))
499
+
500
+ # Azure NSG 관련 명령어
501
+ azure_nsg_parser = azure_subparsers.add_parser("nsg", help="Azure Network Security Group 관련 명령어")
502
+ azure_nsg_subparsers = azure_nsg_parser.add_subparsers(dest="command", required=True)
503
+ azure_nsg_info_parser = azure_nsg_subparsers.add_parser("info", help="Azure NSG 정보 조회")
504
+ try:
505
+ from azure_module.nsg import info as azure_nsg_info
506
+ azure_nsg_info.add_arguments(azure_nsg_info_parser)
507
+ azure_nsg_info_parser.set_defaults(func=azure_nsg_info.main)
508
+ except ImportError:
509
+ azure_nsg_info_parser.set_defaults(func=lambda args: print("Azure 모듈이 설치되지 않았습니다."))
510
+
511
+ # Azure Load Balancer 관련 명령어
512
+ azure_lb_parser = azure_subparsers.add_parser("lb", help="Azure Load Balancer 관련 명령어")
513
+ azure_lb_subparsers = azure_lb_parser.add_subparsers(dest="command", required=True)
514
+ azure_lb_info_parser = azure_lb_subparsers.add_parser("info", help="Azure Load Balancer 정보 조회")
515
+ try:
516
+ from azure_module.lb import info as azure_lb_info
517
+ azure_lb_info.add_arguments(azure_lb_info_parser)
518
+ azure_lb_info_parser.set_defaults(func=azure_lb_info.main)
519
+ except ImportError:
520
+ azure_lb_info_parser.set_defaults(func=lambda args: print("Azure 모듈이 설치되지 않았습니다."))
521
+
522
+ # Azure Container Instances 관련 명령어
523
+ azure_aci_parser = azure_subparsers.add_parser("aci", help="Azure Container Instances 관련 명령어")
524
+ azure_aci_subparsers = azure_aci_parser.add_subparsers(dest="command", required=True)
525
+ azure_aci_info_parser = azure_aci_subparsers.add_parser("info", help="Azure Container Instances 정보 조회")
526
+ try:
527
+ from azure_module.aci import info as azure_aci_info
528
+ azure_aci_info.add_arguments(azure_aci_info_parser)
529
+ azure_aci_info_parser.set_defaults(func=azure_aci_info.main)
530
+ except ImportError:
531
+ azure_aci_info_parser.set_defaults(func=lambda args: print("Azure 모듈이 설치되지 않았습니다."))
532
+
533
+ # ---------------- GCP ----------------
534
+ gcp_compute_parser = gcp_subparsers.add_parser("compute", help="GCP Compute Engine 관련 명령어")
535
+ gcp_compute_subparsers = gcp_compute_parser.add_subparsers(dest="command", required=True)
536
+ gcp_compute_info_parser = gcp_compute_subparsers.add_parser("info", help="GCP Compute Engine 정보 조회 (Mock)")
537
+ from gcp.compute import info as gcp_compute_info
538
+ gcp_compute_info.add_arguments(gcp_compute_info_parser)
539
+ gcp_compute_info_parser.set_defaults(func=gcp_compute_info.main)
540
+
541
+ gcp_vpc_parser = gcp_subparsers.add_parser("vpc", help="GCP VPC 관련 명령어")
542
+ gcp_vpc_subparsers = gcp_vpc_parser.add_subparsers(dest="command", required=True)
543
+ gcp_vpc_info_parser = gcp_vpc_subparsers.add_parser("info", help="GCP VPC 정보 조회 (Mock)")
544
+ from gcp.vpc import info as gcp_vpc_info
545
+ gcp_vpc_info.add_arguments(gcp_vpc_info_parser)
546
+ gcp_vpc_info_parser.set_defaults(func=gcp_vpc_info.main)
547
+
548
+ gcp_gke_parser = gcp_subparsers.add_parser("gke", help="GCP Google Kubernetes Engine 관련 명령어")
549
+ gcp_gke_subparsers = gcp_gke_parser.add_subparsers(dest="command", required=True)
550
+ gcp_gke_info_parser = gcp_gke_subparsers.add_parser("info", help="GCP GKE 클러스터 정보 조회")
551
+ from gcp.gke import info as gcp_gke_info
552
+ gcp_gke_info.add_arguments(gcp_gke_info_parser)
553
+ gcp_gke_info_parser.set_defaults(func=gcp_gke_info.main)
554
+
555
+ gcp_storage_parser = gcp_subparsers.add_parser("storage", help="GCP Cloud Storage 관련 명령어")
556
+ gcp_storage_subparsers = gcp_storage_parser.add_subparsers(dest="command", required=True)
557
+ gcp_storage_info_parser = gcp_storage_subparsers.add_parser("info", help="GCP Cloud Storage 버킷 정보 조회")
558
+ from gcp.storage import info as gcp_storage_info
559
+ gcp_storage_info.add_arguments(gcp_storage_info_parser)
560
+ gcp_storage_info_parser.set_defaults(func=gcp_storage_info.main)
561
+
562
+ gcp_sql_parser = gcp_subparsers.add_parser("sql", help="GCP Cloud SQL 관련 명령어")
563
+ gcp_sql_subparsers = gcp_sql_parser.add_subparsers(dest="command", required=True)
564
+ gcp_sql_info_parser = gcp_sql_subparsers.add_parser("info", help="GCP Cloud SQL 인스턴스 정보 조회")
565
+ from gcp.sql import info as gcp_sql_info
566
+ gcp_sql_info.add_arguments(gcp_sql_info_parser)
567
+ gcp_sql_info_parser.set_defaults(func=gcp_sql_info.main)
568
+
569
+ gcp_functions_parser = gcp_subparsers.add_parser("functions", help="GCP Cloud Functions 관련 명령어")
570
+ gcp_functions_subparsers = gcp_functions_parser.add_subparsers(dest="command", required=True)
571
+ gcp_functions_info_parser = gcp_functions_subparsers.add_parser("info", help="GCP Cloud Functions 정보 조회")
572
+ from gcp.functions import info as gcp_functions_info
573
+ gcp_functions_info.add_arguments(gcp_functions_info_parser)
574
+ gcp_functions_info_parser.set_defaults(func=gcp_functions_info.main)
575
+
576
+ gcp_run_parser = gcp_subparsers.add_parser("run", help="GCP Cloud Run 관련 명령어")
577
+ gcp_run_subparsers = gcp_run_parser.add_subparsers(dest="command", required=True)
578
+ gcp_run_info_parser = gcp_run_subparsers.add_parser("info", help="GCP Cloud Run 서비스 정보 조회")
579
+ from gcp.run import info as gcp_run_info
580
+ gcp_run_info.add_arguments(gcp_run_info_parser)
581
+ gcp_run_info_parser.set_defaults(func=gcp_run_info.main)
582
+
583
+ gcp_lb_parser = gcp_subparsers.add_parser("lb", help="GCP Load Balancing 관련 명령어")
584
+ gcp_lb_subparsers = gcp_lb_parser.add_subparsers(dest="command", required=True)
585
+ gcp_lb_info_parser = gcp_lb_subparsers.add_parser("info", help="GCP Load Balancer 정보 조회")
586
+ from gcp.lb import info as gcp_lb_info
587
+ gcp_lb_info.add_arguments(gcp_lb_info_parser)
588
+ gcp_lb_info_parser.set_defaults(func=gcp_lb_info.main)
589
+
590
+ gcp_firewall_parser = gcp_subparsers.add_parser("firewall", help="GCP 방화벽 규칙 관련 명령어")
591
+ gcp_firewall_subparsers = gcp_firewall_parser.add_subparsers(dest="command", required=True)
592
+ gcp_firewall_info_parser = gcp_firewall_subparsers.add_parser("info", help="GCP 방화벽 규칙 정보 조회")
593
+ from gcp.firewall import info as gcp_firewall_info
594
+ gcp_firewall_info.add_arguments(gcp_firewall_info_parser)
595
+ gcp_firewall_info_parser.set_defaults(func=gcp_firewall_info.main)
596
+
597
+ gcp_billing_parser = gcp_subparsers.add_parser("billing", help="GCP Billing 및 비용 관련 명령어")
598
+ gcp_billing_subparsers = gcp_billing_parser.add_subparsers(dest="command", required=True)
599
+ gcp_billing_info_parser = gcp_billing_subparsers.add_parser("info", help="GCP Billing 정보 및 비용 조회")
600
+ from gcp.billing import info as gcp_billing_info
601
+ gcp_billing_info.add_arguments(gcp_billing_info_parser)
602
+ gcp_billing_info_parser.set_defaults(func=gcp_billing_info.main)
603
+
604
+ # GCP 모니터링 및 성능 메트릭
605
+ gcp_monitor_parser = gcp_subparsers.add_parser("monitor", help="GCP 모니터링 및 성능 메트릭")
606
+ gcp_monitor_subparsers = gcp_monitor_parser.add_subparsers(dest="command", required=True)
607
+ gcp_monitor_perf_parser = gcp_monitor_subparsers.add_parser("performance", help="GCP 성능 메트릭 조회")
608
+ gcp_monitor_perf_parser.add_argument("--time-window", type=int, default=60,
609
+ help="메트릭 조회 시간 창 (분, 기본값: 60)")
610
+ gcp_monitor_perf_parser.set_defaults(func=gcp_monitor_performance_command)
611
+
612
+ gcp_monitor_health_parser = gcp_monitor_subparsers.add_parser("health", help="GCP 서비스 헬스 체크")
613
+ gcp_monitor_health_parser.set_defaults(func=gcp_monitor_health_command)
614
+
615
+ # ---------------- CloudFlare ----------------
616
+ cf_dns_parser = cf_subparsers.add_parser("dns", help="DNS Record 관련 명령어")
617
+ dns_subparsers = cf_dns_parser.add_subparsers(dest="command", required=True)
618
+ dns_info_cmd = dns_subparsers.add_parser("info", help="DNS Record 정보 조회")
619
+ dns_info.add_arguments(dns_info_cmd)
620
+ dns_info_cmd.set_defaults(func=dns_info.info)
621
+
622
+ # ---------------- SSH ----------------
623
+ ssh_info_parser = ssh_subparsers.add_parser("info", help="등록된 SSH 서버의 상세 정보(CPU/Mem/Disk)를 스캔합니다.")
624
+ ssh_info_parser.add_argument("--host", help="특정 호스트 문자열을 포함하는 서버만 필터링합니다.")
625
+ ssh_info_parser.add_argument("--key", help="사용할 특정 프라이빗 키 파일을 지정합니다. (config 파일 우선)")
626
+ ssh_info_parser.set_defaults(func=server_info.main)
627
+
628
+ ssh_reg_parser = ssh_subparsers.add_parser("reg", help="네트워크를 스캔하여 새로운 SSH 서버를 찾아 .ssh/config에 등록합니다.")
629
+ ssh_reg_parser.set_defaults(func=lambda args: auto_ssh.main())
630
+
631
+ # ---------------- OCI ----------------
632
+ oci_info_parser = oci_subparsers.add_parser("info", help="[DEPRECATED] OCI 리소스 통합 조회. 각 서비스별 명령어를 사용하세요.")
633
+ oci_info_parser.set_defaults(func=oci_info_deprecated)
634
+
635
+ # ---- new structured services ----
636
+ vm_parser = oci_subparsers.add_parser("vm", help="OCI VM(Instance) 관련")
637
+ vm_sub = vm_parser.add_subparsers(dest="command", required=True)
638
+ vm_info_p = vm_sub.add_parser("info", help="VM 정보 조회")
639
+ vm_add_args(vm_info_p)
640
+ vm_info_p.set_defaults(func=vm_main)
641
+
642
+ lb_parser = oci_subparsers.add_parser("lb", help="OCI LoadBalancer 관련")
643
+ lb_sub = lb_parser.add_subparsers(dest="command", required=True)
644
+ lb_info_p = lb_sub.add_parser("info", help="LB 정보 조회")
645
+ lb_add_args(lb_info_p)
646
+ lb_info_p.set_defaults(func=lb_main)
647
+
648
+ nsg_parser = oci_subparsers.add_parser("nsg", help="OCI NSG 관련")
649
+ nsg_sub = nsg_parser.add_subparsers(dest="command", required=True)
650
+ nsg_info_p = nsg_sub.add_parser("info", help="NSG 정보 조회")
651
+ nsg_add_args(nsg_info_p)
652
+ nsg_info_p.set_defaults(func=nsg_main)
653
+
654
+ vcn_parser = oci_subparsers.add_parser("vcn", help="OCI VCN 관련")
655
+ vcn_sub = vcn_parser.add_subparsers(dest="command", required=True)
656
+ vcn_info_p = vcn_sub.add_parser("info", help="VCN, Subnet, Route Table 정보 조회")
657
+ vcn_info.add_arguments(vcn_info_p)
658
+ vcn_info_p.set_defaults(func=vcn_info.main)
659
+
660
+ vol_parser = oci_subparsers.add_parser("volume", help="OCI Block/Boot Volume 관련")
661
+ vol_sub = vol_parser.add_subparsers(dest="command", required=True)
662
+ vol_info_p = vol_sub.add_parser("info", help="Volume 정보 조회")
663
+ volume_add_args(vol_info_p)
664
+ vol_info_p.set_defaults(func=volume_main)
665
+
666
+ obj_parser = oci_subparsers.add_parser("obj", help="OCI Object Storage 관련")
667
+ obj_sub = obj_parser.add_subparsers(dest="command", required=True)
668
+ obj_info_p = obj_sub.add_parser("info", help="Bucket 정보 조회")
669
+ obj_add_args(obj_info_p)
670
+ obj_info_p.set_defaults(func=obj_main)
671
+
672
+ pol_parser = oci_subparsers.add_parser("policy", help="OCI Policy 관련")
673
+ pol_sub = pol_parser.add_subparsers(dest="command", required=True)
674
+ pol_info_p = pol_sub.add_parser("info", help="Policy 목록/구문 조회")
675
+ policy_add_args(pol_info_p)
676
+ pol_info_p.set_defaults(func=policy_main)
677
+ pol_search_p = pol_sub.add_parser("search", help="Policy 구문 검색")
678
+ oci_policy_search.add_arguments(pol_search_p)
679
+ pol_search_p.set_defaults(func=oci_policy_search.main)
680
+
681
+ cost_parser = oci_subparsers.add_parser("cost", help="OCI 비용/크레딧 관련")
682
+ cost_sub = cost_parser.add_subparsers(dest="command", required=True)
683
+ cost_usage_p = cost_sub.add_parser("usage", help="비용 조회")
684
+ cost_usage_add_args(cost_usage_p)
685
+ cost_usage_p.set_defaults(func=cost_usage_main)
686
+ cost_credit_p = cost_sub.add_parser("credit", help="크레딧 사용 조회")
687
+ cost_credit_add_args(cost_credit_p)
688
+ cost_credit_p.set_defaults(func=cost_credit_main)
689
+
690
+ # 인수 처리
691
+ process_and_execute_commands(parser)
692
+
693
+ def process_and_execute_commands(parser):
694
+ """명령행 인수를 파싱하고 각 서비스에 대해 명령을 실행합니다."""
695
+ if len(sys.argv) > 2 and sys.argv[1] == 'oci' and sys.argv[2] == 'info':
696
+ oci_info_deprecated(None)
697
+ sys.exit(0)
698
+
699
+ if len(sys.argv) > 2 and ',' in sys.argv[2]:
700
+ platform = sys.argv[1]
701
+ services = [s.strip() for s in sys.argv[2].split(',')]
702
+ command_and_options = sys.argv[3:]
703
+
704
+ # For GCP multi-service commands, use parallel execution
705
+ if platform == 'gcp':
706
+ execute_gcp_multi_service(services, command_and_options, parser)
707
+ else:
708
+ # Sequential execution for other platforms
709
+ has_error = False
710
+ for service in services:
711
+ print(f"--- Executing: ic {platform} {service} {' '.join(command_and_options)} ---")
712
+ current_argv = [platform, service] + command_and_options
713
+ try:
714
+ args = parser.parse_args(current_argv)
715
+ execute_single_command(args)
716
+ except SystemExit:
717
+ print(f"--- Skipping service '{service}' due to an error or invalid arguments ---")
718
+ has_error = True
719
+ except Exception as e:
720
+ log_error(f"Error processing service '{service}': {e}")
721
+ has_error = True
722
+
723
+ if has_error:
724
+ sys.exit(1)
725
+
726
+ else:
727
+ try:
728
+ args = parser.parse_args()
729
+ execute_single_command(args)
730
+ except SystemExit:
731
+ sys.exit(0)
732
+ except Exception as e:
733
+ log_error(f"명령어 실행 중 오류 발생: {e}")
734
+ sys.exit(1)
735
+
736
+ def execute_single_command(args):
737
+ """파싱된 인수를 기반으로 실제 단일 명령을 실행합니다."""
738
+ if not hasattr(args, 'service') or not args.service:
739
+ return
740
+
741
+ if args.platform == "ssh" and args.service == "info":
742
+ args.command = "none"
743
+ elif args.platform == "oci" and args.service == "info":
744
+ args.command = "none"
745
+
746
+ log_args_short(args)
747
+ env_used = gather_env_for_command(args.platform, args.service, args.command)
748
+ if env_used:
749
+ log_env_short(env_used)
750
+
751
+ if hasattr(args, 'func'):
752
+ # Add consistent error handling for GCP services
753
+ if args.platform == 'gcp':
754
+ try:
755
+ args.func(args)
756
+ except ImportError as e:
757
+ log_error(f"GCP service '{args.service}' dependencies not available: {e}")
758
+ raise
759
+ except Exception as e:
760
+ log_error(f"GCP service '{args.service}' execution failed: {e}")
761
+ raise
762
+ else:
763
+ args.func(args)
764
+ else:
765
+ log_error(f"'{args.service}' 서비스에 대해 실행할 명령어가 지정되지 않았습니다. 'ic {args.platform} {args.service} --help'를 확인하세요.")
766
+ raise ValueError("No function to execute")
767
+
768
+ if __name__ == "__main__":
769
+ main()