mcp-openstack-ops 3.4.8__tar.gz → 3.5.0__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.
Files changed (159) hide show
  1. mcp_openstack_ops-3.5.0/.env.example +73 -0
  2. mcp_openstack_ops-3.5.0/.env.test +1 -0
  3. mcp_openstack_ops-3.5.0/.github/FUNDING.yml +3 -0
  4. mcp_openstack_ops-3.5.0/.github/copilot-instructions.md +153 -0
  5. mcp_openstack_ops-3.5.0/.github/dependabot.yml +58 -0
  6. mcp_openstack_ops-3.5.0/.github/workflows/pypi-publish.yml +73 -0
  7. mcp_openstack_ops-3.5.0/.gitignore +20 -0
  8. mcp_openstack_ops-3.5.0/.gitleaks.toml +11 -0
  9. mcp_openstack_ops-3.5.0/.pre-commit-config.yaml +5 -0
  10. mcp_openstack_ops-3.5.0/.python-version +1 -0
  11. mcp_openstack_ops-3.5.0/Dockerfile.MCP-Server +20 -0
  12. mcp_openstack_ops-3.5.0/Dockerfile.MCPO-Proxy +20 -0
  13. {mcp_openstack_ops-3.4.8/src/mcp_openstack_ops.egg-info → mcp_openstack_ops-3.5.0}/PKG-INFO +2 -1
  14. mcp_openstack_ops-3.5.0/build-mcp-server-docker-image.sh +33 -0
  15. mcp_openstack_ops-3.5.0/build-mcpo-server-docker-image.sh +33 -0
  16. mcp_openstack_ops-3.5.0/diagnose_openstack.py +138 -0
  17. mcp_openstack_ops-3.5.0/docker-compose.yml +58 -0
  18. mcp_openstack_ops-3.5.0/img/MCP-Workflow-of-Quickstart-Tutorial.png +0 -0
  19. mcp_openstack_ops-3.5.0/img/screenshot-claude-desktop.png +0 -0
  20. mcp_openstack_ops-3.5.0/img/screenshot-claude-desktop.png:Zone.Identifier +4 -0
  21. mcp_openstack_ops-3.5.0/img/screenshot-example-cluster-status.png +0 -0
  22. mcp_openstack_ops-3.5.0/img/screenshot-openstack-dashboard.png +0 -0
  23. mcp_openstack_ops-3.5.0/main.py +6 -0
  24. mcp_openstack_ops-3.5.0/mcp-config.json.http +11 -0
  25. mcp_openstack_ops-3.5.0/mcp-config.json.multi-project +82 -0
  26. mcp_openstack_ops-3.5.0/mcp-config.json.stdio +30 -0
  27. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/pyproject.toml +7 -2
  28. mcp_openstack_ops-3.5.0/scripts/mcp-server-docker-cmd.sh +40 -0
  29. mcp_openstack_ops-3.5.0/scripts/run-mcp-inspector-local.sh +25 -0
  30. mcp_openstack_ops-3.5.0/scripts/run-mcp-inspector-pypi.sh +20 -0
  31. mcp_openstack_ops-3.5.0/src/mcp_openstack_ops/prompt_template.md +898 -0
  32. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0/src/mcp_openstack_ops.egg-info}/PKG-INFO +2 -1
  33. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops.egg-info/SOURCES.txt +32 -0
  34. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops.egg-info/requires.txt +1 -0
  35. mcp_openstack_ops-3.5.0/test_compatibility.sh +36 -0
  36. mcp_openstack_ops-3.5.0/test_project_isolation.py +161 -0
  37. mcp_openstack_ops-3.5.0/uv.lock +1571 -0
  38. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/LICENSE +0 -0
  39. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/MANIFEST.in +0 -0
  40. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/README.md +0 -0
  41. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/setup.cfg +0 -0
  42. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/__init__.py +0 -0
  43. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/__main__.py +0 -0
  44. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/connection.py +0 -0
  45. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/functions.py +0 -0
  46. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/mcp_main.py +0 -0
  47. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/services/__init__.py +0 -0
  48. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/services/compute.py +0 -0
  49. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/services/core.py +0 -0
  50. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/services/identity.py +0 -0
  51. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/services/image.py +0 -0
  52. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/services/load_balancer/__init__.py +0 -0
  53. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/services/load_balancer/amphorae.py +0 -0
  54. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/services/load_balancer/core.py +0 -0
  55. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/services/load_balancer/health_monitors.py +0 -0
  56. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/services/load_balancer/l7_policies.py +0 -0
  57. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/services/load_balancer/listeners.py +0 -0
  58. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/services/load_balancer/management.py +0 -0
  59. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/services/load_balancer/pools.py +0 -0
  60. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/services/monitoring.py +0 -0
  61. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/services/network.py +0 -0
  62. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/services/orchestration.py +0 -0
  63. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/services/storage.py +0 -0
  64. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/__init__.py +0 -0
  65. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_availability_zones.py +0 -0
  66. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_floating_ip_pools.py +0 -0
  67. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_floating_ips.py +0 -0
  68. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_heat_stacks.py +0 -0
  69. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_hypervisor_details.py +0 -0
  70. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_image_detail_list.py +0 -0
  71. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_instance.py +0 -0
  72. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_instance_by_name.py +0 -0
  73. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_instance_details.py +0 -0
  74. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_instances_by_status.py +0 -0
  75. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_keypair_list.py +0 -0
  76. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_load_balancer_amphorae.py +0 -0
  77. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_load_balancer_availability_zones.py +0 -0
  78. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_load_balancer_details.py +0 -0
  79. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_load_balancer_flavors.py +0 -0
  80. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_load_balancer_health_monitors.py +0 -0
  81. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_load_balancer_l7_policies.py +0 -0
  82. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_load_balancer_l7_rules.py +0 -0
  83. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_load_balancer_list.py +0 -0
  84. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_load_balancer_listeners.py +0 -0
  85. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_load_balancer_pool_members.py +0 -0
  86. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_load_balancer_pools.py +0 -0
  87. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_load_balancer_providers.py +0 -0
  88. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_load_balancer_quotas.py +0 -0
  89. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_network_details.py +0 -0
  90. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_project_details.py +0 -0
  91. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_quota.py +0 -0
  92. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_resource_monitoring.py +0 -0
  93. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_role_assignments.py +0 -0
  94. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_routers.py +0 -0
  95. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_security_groups.py +0 -0
  96. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_server_events.py +0 -0
  97. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_server_groups.py +0 -0
  98. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_server_volumes.py +0 -0
  99. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_service_status.py +0 -0
  100. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_usage_statistics.py +0 -0
  101. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_user_list.py +0 -0
  102. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_volume_list.py +0 -0
  103. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_volume_snapshots.py +0 -0
  104. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/get_volume_types.py +0 -0
  105. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/search_instances.py +0 -0
  106. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_alarms.py +0 -0
  107. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_compute_agents.py +0 -0
  108. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_domains.py +0 -0
  109. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_flavor.py +0 -0
  110. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_floating_ip.py +0 -0
  111. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_floating_ip_port_forwarding.py +0 -0
  112. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_heat_stack.py +0 -0
  113. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_identity_groups.py +0 -0
  114. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_image.py +0 -0
  115. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_image_members.py +0 -0
  116. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_image_metadata.py +0 -0
  117. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_image_visibility.py +0 -0
  118. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_instance.py +0 -0
  119. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_keypair.py +0 -0
  120. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_load_balancer.py +0 -0
  121. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_load_balancer_amphora.py +0 -0
  122. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_load_balancer_availability_zone.py +0 -0
  123. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_load_balancer_flavor.py +0 -0
  124. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_load_balancer_health_monitor.py +0 -0
  125. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_load_balancer_l7_policy.py +0 -0
  126. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_load_balancer_l7_rule.py +0 -0
  127. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_load_balancer_listener.py +0 -0
  128. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_load_balancer_pool.py +0 -0
  129. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_load_balancer_pool_member.py +0 -0
  130. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_load_balancer_quota.py +0 -0
  131. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_metrics.py +0 -0
  132. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_network_agents.py +0 -0
  133. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_network_ports.py +0 -0
  134. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_network_qos_policies.py +0 -0
  135. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_networks.py +0 -0
  136. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_project.py +0 -0
  137. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_quota.py +0 -0
  138. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_roles.py +0 -0
  139. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_server_backup.py +0 -0
  140. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_server_dump.py +0 -0
  141. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_server_fixed_ip.py +0 -0
  142. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_server_floating_ip.py +0 -0
  143. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_server_group.py +0 -0
  144. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_server_migration.py +0 -0
  145. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_server_network.py +0 -0
  146. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_server_properties.py +0 -0
  147. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_server_security_group.py +0 -0
  148. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_server_volume.py +0 -0
  149. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_service_logs.py +0 -0
  150. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_services.py +0 -0
  151. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_snapshot.py +0 -0
  152. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_subnets.py +0 -0
  153. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_volume.py +0 -0
  154. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_volume_backups.py +0 -0
  155. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_volume_groups.py +0 -0
  156. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops/tools/set_volume_qos.py +0 -0
  157. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops.egg-info/dependency_links.txt +0 -0
  158. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops.egg-info/entry_points.txt +0 -0
  159. {mcp_openstack_ops-3.4.8 → mcp_openstack_ops-3.5.0}/src/mcp_openstack_ops.egg-info/top_level.txt +0 -0
@@ -0,0 +1,73 @@
1
+ # MCP Server Configuration Template
2
+ # Copy this file to .env and modify values as needed
3
+
4
+ # Logging level
5
+ MCP_LOG_LEVEL=INFO
6
+
7
+ # Safety Control - Allow OpenStack state modification operations
8
+ # Set to true to enable modification operations (create, delete, update)
9
+ # Set to false to allow only read-only operations (list, get, show)
10
+ ALLOW_MODIFY_OPERATIONS=false
11
+
12
+ # Python module path for Docker
13
+ PYTHONPATH=/app/src
14
+
15
+ # Transport configuration
16
+ FASTMCP_TYPE=streamable-http
17
+
18
+ # HTTP Transport settings (used only when FASTMCP_TYPE=streamable-http)
19
+ FASTMCP_HOST=0.0.0.0
20
+ FASTMCP_PORT=8000
21
+
22
+ # (Optional) Enable authentication for streamable-http mode
23
+ # Recommended for production environments
24
+ REMOTE_AUTH_ENABLE=false
25
+ REMOTE_SECRET_KEY=your-secure-secret-key-here
26
+
27
+ # OpenStack API Environment Variables Template
28
+ # PROJECT ISOLATION SECURITY: All operations are 100% scoped to specified project
29
+ # Enhanced multi-layer security prevents cross-tenant access and ensures complete isolation
30
+ OS_PROJECT_DOMAIN_NAME=Default
31
+ OS_USER_DOMAIN_NAME=Default
32
+
33
+ # CRITICAL SECURITY PARAMETER: All operations are scoped to this project only
34
+ # Enhanced project isolation with ownership validation and secure resource lookup
35
+ # For multi-project management, deploy multiple MCP servers with different OS_PROJECT_NAME values
36
+ # NEVER modify resources in other projects - complete tenant isolation guaranteed
37
+ OS_PROJECT_NAME=your_project_name
38
+ OS_TENANT_NAME=your_tenant_name
39
+ OS_USERNAME=your_username
40
+ OS_PASSWORD=your_password
41
+ OS_AUTH_HOST=your-openstack-host
42
+ OS_INTERFACE=internal
43
+ OS_ENDPOINT_TYPE=internalURL
44
+ OS_IDENTITY_API_VERSION=3
45
+ OS_REGION_NAME=RegionOne
46
+ OS_AUTH_PLUGIN=password
47
+
48
+ # OpenStack Connection Protocol (http or https)
49
+ # Use 'https' for production environments with SSL/TLS enabled
50
+ # When using https, set OS_CACERT to your CA certificate path
51
+ # If OS_CACERT is not set with https, SSL verification will be disabled (insecure)
52
+ OS_AUTH_PROTOCOL=http
53
+
54
+ # (Optional) SSL CA Certificate for HTTPS connections
55
+ # Required for secure HTTPS connections to OpenStack API
56
+ # Example: OS_CACERT=/etc/ssl/certs/openstack-ca.pem
57
+ # OS_CACERT=
58
+
59
+ # OpenStack Service Port Configuration
60
+ # These ports can be customized to match your OpenStack deployment
61
+ OS_AUTH_PORT=5000
62
+ OS_COMPUTE_PORT=8774
63
+ OS_NETWORK_PORT=9696
64
+ OS_VOLUME_PORT=8776
65
+ OS_IMAGE_PORT=9292
66
+ OS_PLACEMENT_PORT=8780
67
+ OS_HEAT_STACK_PORT=8004
68
+ OS_HEAT_STACK_CFN_PORT=8000
69
+
70
+ # Docker Port Mappings
71
+ DOCKER_EXTERNAL_PORT_OPENWEBUI=3000
72
+ DOCKER_EXTERNAL_PORT_MCP_SERVER=8000
73
+ DOCKER_EXTERNAL_PORT_MCPO_PROXY=8080
@@ -0,0 +1 @@
1
+ ALLOW_MODIFY_OPERATIONS=true
@@ -0,0 +1,3 @@
1
+ # These are supported funding model platforms
2
+
3
+ buy_me_a_coffee: call518
@@ -0,0 +1,153 @@
1
+ # GitHub Copilot Instructions
2
+
3
+ ## 🚫 CRITICAL RESTRICTIONS - ALWAYS ENFORCE
4
+
5
+ ### **Never Execute These Operations Directly:**
6
+ - **Git operations**: Never run `git add`, `git commit`, `git push`, `git pull`, `git tag`, or any Git commands
7
+ - **Docker operations**: Never run `docker build`, `docker run`, `docker-compose up/down`, `docker push`, or any Docker commands
8
+ - **Instead**: Always ask the user to execute these commands manually
9
+
10
+ ### **Python Execution Requirements:**
11
+ - **MANDATORY**: Always use `.venv/bin/python` for all Python execution
12
+ - **MANDATORY**: Always use `.venv/bin/pip` for all package management
13
+ - **NEVER use**: `python`, `python3`, `/usr/bin/python`, `pip`, `pip3`, or system Python/pip
14
+ - **Example**: Use `.venv/bin/python -m mcp_openstack_ops` instead of `python -m mcp_openstack_ops`
15
+ - **Example**: Use `.venv/bin/pip install package` instead of `pip install package`
16
+
17
+ ### **MCP Tool Safety Control Requirements:**
18
+ - **MANDATORY**: When adding new MCP tools with modify operations, always use `@conditional_tool` decorator
19
+ - **MANDATORY**: Verify that ALLOW_MODIFY_OPERATIONS=false properly hides modify tools from registration
20
+ - **NEVER use**: `@mcp.tool()` for operations that can modify/delete OpenStack resources
21
+ - **Always test**: Tool visibility with both `ALLOW_MODIFY_OPERATIONS=true` and `ALLOW_MODIFY_OPERATIONS=false`
22
+ - **Pattern**: Read-only tools use `@mcp.tool()`, modify tools use `@conditional_tool`
23
+
24
+ ---
25
+
26
+ ## Architecture Overview
27
+ This is an **MCP (Model Context Protocol) Server for OpenStack Operations** - a Python service providing real-time OpenStack cluster management through 24+ tools. The architecture follows a layered pattern:
28
+
29
+ - **`src/mcp_openstack_ops/functions.py`** (3000+ lines): Core OpenStack SDK operations with connection caching
30
+ - **`src/mcp_openstack_ops/mcp_main.py`** (1400+ lines): FastMCP tool definitions and conditional safety system
31
+ - **`src/mcp_openstack_ops/prompt_template.md`**: AI assistant behavior guide with tool patterns
32
+
33
+ ## Critical Safety System
34
+ The codebase implements a **conditional tool registration pattern** via `ALLOW_MODIFY_OPERATIONS` environment variable:
35
+
36
+ ```python
37
+ @conditional_tool # Only registers when ALLOW_MODIFY_OPERATIONS=true
38
+ async def set_instance(instance_name: str, action: str) -> str:
39
+ ```
40
+
41
+ vs.
42
+
43
+ ```python
44
+ @mcp.tool() # Always available (read-only operations)
45
+ async def get_cluster_status() -> str:
46
+ ```
47
+
48
+ **Never bypass this safety system** - it prevents destructive operations in production.
49
+
50
+ ## Environment Configuration Patterns
51
+ Connection management uses **proxy-based routing** with service-specific ports:
52
+
53
+ ```bash
54
+ # Required for OpenStack connection
55
+ OS_AUTH_HOST=192.168.35.2
56
+ OS_AUTH_PORT=5555
57
+
58
+ # Service-specific ports (Heat Stack naming convention)
59
+ OS_HEAT_STACK_PORT=8004
60
+ OS_HEAT_STACK_CFN_PORT=18888
61
+ ```
62
+
63
+ ## Key Development Workflows
64
+
65
+ ### Testing MCP Server
66
+ ```bash
67
+ # REQUIRED: Use virtual environment Python only
68
+ .venv/bin/python -m mcp_openstack_ops --stdio
69
+
70
+ # Connection validation
71
+ .venv/bin/python -c "from mcp_openstack_ops.functions import get_openstack_connection; print('OK')"
72
+
73
+ # NEVER use system Python
74
+ # ❌ python -m mcp_openstack_ops
75
+ # ❌ python3 -m mcp_openstack_ops
76
+ ```
77
+
78
+ ### Adding New OpenStack Services
79
+ 1. Add core function to `functions.py` with connection caching pattern
80
+ 2. Create MCP tool wrapper in `mcp_main.py` (use `@conditional_tool` for modify operations)
81
+ 3. Update `prompt_template.md` with tool patterns and decision flows
82
+ 4. Add environment variables for service ports if needed
83
+
84
+ ## Connection Management Pattern
85
+ Global connection caching with automatic retry:
86
+
87
+ ```python
88
+ _connection_cache = None
89
+
90
+ def get_openstack_connection():
91
+ global _connection_cache
92
+ if _connection_cache is not None:
93
+ try:
94
+ _connection_cache.identity.get_token() # Test validity
95
+ return _connection_cache
96
+ except Exception:
97
+ _connection_cache = None # Reset on failure
98
+ ```
99
+
100
+ ## Resource Monitoring Conventions
101
+ Always distinguish **physical vs. virtual resources** in monitoring results:
102
+ - `pCPU` = physical CPU cores (hypervisor hardware)
103
+ - `vCPU` = virtual CPU allocation (project quota)
104
+ - Use separate table rows, never combine in single row
105
+
106
+ ## Function Naming Conventions
107
+ - Core functions: `get_*()`, `set_*()`, `search_*()`, `monitor_*()`
108
+ - Heat-specific: `get_heat_stacks()`, `set_heat_stack()` (not generic `stack`)
109
+ - Load Balancer: `get_load_balancer_*()`, `set_load_balancer*()` (Octavia operations)
110
+ - MCP tools: Must exactly match underlying function names
111
+
112
+ ## Docker Multi-Service Architecture
113
+ The `docker-compose.yml` orchestrates three services:
114
+ - **mcp-server**: Main FastMCP server (port via `DOCKER_EXTERNAL_PORT_MCP_SERVER`)
115
+ - **mcpo-proxy**: HTTP proxy for web clients
116
+ - **open-webui**: Chat interface for testing
117
+
118
+ **Critical**: MCP server ports must align across `.env`, `docker-compose.yml`, and `mcp-config.json.http`.
119
+
120
+ ## Error Handling Pattern
121
+ All OpenStack operations use consistent error handling:
122
+
123
+ ```python
124
+ try:
125
+ conn = get_openstack_connection()
126
+ # OpenStack SDK operations
127
+ return result_data
128
+ except Exception as e:
129
+ logger.error(f"Operation failed: {e}")
130
+ return {"error": str(e), "success": False}
131
+ ```
132
+
133
+ ## Never Execute Directly
134
+ - **Git operations**: `git add`, `commit`, `push`, `pull`, `tag` - ask user to run manually
135
+ - **Docker operations**: `docker build`, `docker-compose up/down`, `docker push` - ask user to run manually
136
+ - **Package management**: `uv add`, `pip install`, `uv sync` - ask user to run manually
137
+ - **Python execution**: Only use `.venv/bin/python`, never system Python
138
+ - **Pip commands**: Only use `.venv/bin/pip`, never system pip
139
+
140
+ ## Pagination Support
141
+ Large-scale environments require pagination in data-heavy functions:
142
+
143
+ ```python
144
+ def get_instance_details(instance_names=None, limit=50, offset=0, include_all=False):
145
+ ```
146
+
147
+ Default limit: 50, max: 200, always include pagination metadata in responses.
148
+
149
+ ## Transport Modes
150
+ - **stdio**: Direct pipe communication via `mcp-config.json.stdio`
151
+ - **streamable-http**: Web API via `mcp-config.json.http` with optional authentication
152
+
153
+ Both modes share the same environment variable structure but different client configurations.
@@ -0,0 +1,58 @@
1
+ version: 2
2
+ updates:
3
+ # Python dependencies (pyproject.toml, requirements files)
4
+ - package-ecosystem: "pip"
5
+ directory: "/"
6
+ schedule:
7
+ interval: "weekly"
8
+ day: "monday"
9
+ time: "09:00"
10
+ timezone: "Asia/Seoul"
11
+ open-pull-requests-limit: 5
12
+ assignees:
13
+ - "call518"
14
+ commit-message:
15
+ prefix: "deps"
16
+ include: "scope"
17
+ labels:
18
+ - "dependencies"
19
+ - "python"
20
+ ignore:
21
+ - dependency-name: "fastmcp"
22
+ update-types: ["version-update:semver-major"]
23
+
24
+ # GitHub Actions workflow dependencies
25
+ - package-ecosystem: "github-actions"
26
+ directory: "/"
27
+ schedule:
28
+ interval: "weekly"
29
+ day: "monday"
30
+ time: "09:30"
31
+ timezone: "Asia/Seoul"
32
+ open-pull-requests-limit: 3
33
+ assignees:
34
+ - "call518"
35
+ commit-message:
36
+ prefix: "ci"
37
+ include: "scope"
38
+ labels:
39
+ - "dependencies"
40
+ - "github-actions"
41
+
42
+ # Docker dependencies (Dockerfile, docker-compose.yml)
43
+ - package-ecosystem: "docker"
44
+ directory: "/"
45
+ schedule:
46
+ interval: "weekly"
47
+ day: "monday"
48
+ time: "10:00"
49
+ timezone: "Asia/Seoul"
50
+ open-pull-requests-limit: 3
51
+ assignees:
52
+ - "call518"
53
+ commit-message:
54
+ prefix: "docker"
55
+ include: "scope"
56
+ labels:
57
+ - "dependencies"
58
+ - "docker"
@@ -0,0 +1,73 @@
1
+ # This workflow will install Python dependencies, run tests and lint with a variety of Python versions
2
+ # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
3
+
4
+ name: Publish to PyPI on tag
5
+
6
+ on:
7
+ push:
8
+ tags: ["*"]
9
+
10
+ permissions:
11
+ contents: read
12
+ id-token: write
13
+
14
+ jobs:
15
+ build:
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - uses: actions/checkout@v6
19
+ with:
20
+ persist-credentials: false
21
+ fetch-depth: 0
22
+ - uses: actions/setup-python@v6
23
+ with:
24
+ python-version: "3.12.x"
25
+ - name: Install build tool
26
+ run: pip install --upgrade build
27
+ - name: Build distributions
28
+ run: python -m build
29
+ - uses: actions/upload-artifact@v7
30
+ with:
31
+ name: dist
32
+ path: dist/
33
+
34
+ publish-to-testpypi:
35
+ name: Publish to TestPyPI
36
+ if: startsWith(github.ref, 'refs/tags/')
37
+ runs-on: ubuntu-latest
38
+ needs: build
39
+ permissions:
40
+ id-token: write
41
+ environment:
42
+ name: testpypi
43
+ url: https://test.pypi.org/project/mcp-openstack-ops
44
+ steps:
45
+ - uses: actions/download-artifact@v8
46
+ with:
47
+ name: dist
48
+ path: dist/
49
+ - name: Publish to TestPyPI
50
+ uses: pypa/gh-action-pypi-publish@release/v1
51
+ with:
52
+ repository-url: https://test.pypi.org/legacy/
53
+
54
+ publish-to-pypi:
55
+ name: Publish to PyPI
56
+ if: startsWith(github.ref, 'refs/tags/')
57
+ runs-on: ubuntu-latest
58
+ needs: build
59
+ #needs: publish-to-testpypi
60
+ permissions:
61
+ id-token: write
62
+ environment:
63
+ name: pypi
64
+ url: https://pypi.org/project/mcp-openstack-ops
65
+ steps:
66
+ - uses: actions/download-artifact@v8
67
+ with:
68
+ name: dist
69
+ path: dist/
70
+ - name: Publish to PyPI
71
+ uses: pypa/gh-action-pypi-publish@release/v1
72
+ with:
73
+ repository-url: https://upload.pypi.org/legacy/
@@ -0,0 +1,20 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+
12
+ # Environment files
13
+ .env
14
+
15
+ **/__pycache__/
16
+ **/.pytest_cache/
17
+
18
+ .vscode*
19
+ #.github/copilot-instructions.md
20
+ *.swp
@@ -0,0 +1,11 @@
1
+ title = "README REDACTED 허용 (extend)"
2
+
3
+ [extend]
4
+ useDefault = true # 기본 내장 rules 로드
5
+
6
+ [[allowlists]]
7
+ description = "README.md generic-api-key 예시"
8
+ paths = ["README\\.md"]
9
+ ruleIDs = ["generic-api-key"]
10
+ regexes = ['''REDACTED''']
11
+ regexTarget = "secret"
@@ -0,0 +1,5 @@
1
+ repos:
2
+ - repo: https://github.com/gitleaks/gitleaks
3
+ rev: v8.30.0
4
+ hooks:
5
+ - id: gitleaks
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,20 @@
1
+ FROM rockylinux:9.3
2
+
3
+ ARG PYTHON_VERSION=3.12
4
+
5
+ WORKDIR /app
6
+
7
+ RUN dnf install -y epel-release \
8
+ && dnf install -y python${PYTHON_VERSION} python${PYTHON_VERSION}-pip git procps-ng lsof telnet screen iputils nmap-ncat \
9
+ && dnf clean all \
10
+ && update-alternatives --install /usr/bin/python python /usr/bin/python${PYTHON_VERSION} 1000 --slave /usr/bin/pip pip /usr/bin/pip${PYTHON_VERSION}
11
+
12
+ RUN pip install \
13
+ 'uv>=0.8.5' \
14
+ 'mcpo>=0.0.17' \
15
+ 'fastmcp>=2.12.4' \
16
+ 'aiohttp>=3.12.0' \
17
+ 'openstacksdk>=4.1.0,<=4.9.0' \
18
+ 'python-dotenv>=1.1.1'
19
+
20
+ CMD ["/bin/bash", "/app/scripts/mcp-server-docker-cmd.sh"]
@@ -0,0 +1,20 @@
1
+ FROM rockylinux:9.3
2
+
3
+ ARG PYTHON_VERSION=3.12
4
+
5
+ RUN mkdir -p /app/config
6
+
7
+ WORKDIR /app
8
+
9
+ RUN dnf install -y epel-release \
10
+ && dnf install -y python${PYTHON_VERSION} python${PYTHON_VERSION}-pip git procps-ng lsof telnet screen iputils \
11
+ && dnf clean all \
12
+ && update-alternatives --install /usr/bin/python python /usr/bin/python${PYTHON_VERSION} 1000 --slave /usr/bin/pip pip /usr/bin/pip${PYTHON_VERSION}
13
+
14
+ RUN pip install \
15
+ 'uv>=0.8.5' \
16
+ 'mcpo>=0.0.17' \
17
+ 'fastmcp>=2.12.4' \
18
+ 'aiohttp>=3.12.0'
19
+
20
+ CMD ["mcpo", "--host", "0.0.0.0", "--port", "8000", "--config", "/app/config/mcp-config.json", "--hot-reload"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-openstack-ops
3
- Version: 3.4.8
3
+ Version: 3.5.0
4
4
  Summary: OpenStack operations automation MCP server
5
5
  Author-email: JungJungIn <call518@gmail.com>
6
6
  Requires-Python: >=3.12
@@ -9,6 +9,7 @@ License-File: LICENSE
9
9
  Requires-Dist: fastmcp>=2.12.3
10
10
  Requires-Dist: openstacksdk<=4.11.0,>=4.1.0
11
11
  Requires-Dist: python-dotenv>=1.1.1
12
+ Requires-Dist: setuptools-scm>=10.0.5
12
13
  Provides-Extra: dev
13
14
  Requires-Dist: pytest>=7.0.0; extra == "dev"
14
15
  Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
@@ -0,0 +1,33 @@
1
+ #!/bin/bash
2
+ set -eo pipefail
3
+
4
+ Dockerfile_PATH="./Dockerfile.MCP-Server"
5
+ IMAGE_NAME="call518/mcp-server-openstack-ops"
6
+
7
+ echo "=== Building Docker image Name: ${IMAGE_NAME} ==="
8
+
9
+ VERSION="1.0.3"
10
+ TAGs="latest"
11
+
12
+ # Build once with version tag
13
+ docker build -t ${IMAGE_NAME}:${VERSION} -f ${Dockerfile_PATH} .
14
+
15
+ # Tag as latest
16
+ for TAG in ${TAGs}
17
+ do
18
+ docker tag ${IMAGE_NAME}:${VERSION} ${IMAGE_NAME}:${TAG}
19
+ done
20
+
21
+ echo
22
+
23
+ read -p "Do you want to push the images to Docker Hub? (y/N): " answer
24
+ if [[ "$answer" == "y" || "$answer" == "Y" ]]; then
25
+ echo "Pushing version ${VERSION}..."
26
+ docker push ${IMAGE_NAME}:${VERSION}
27
+
28
+ echo "Pushing latest tag..."
29
+ for TAG in ${TAGs}
30
+ do
31
+ docker push ${IMAGE_NAME}:${TAG}
32
+ done
33
+ fi
@@ -0,0 +1,33 @@
1
+ #!/bin/bash
2
+ set -eo pipefail
3
+
4
+ Dockerfile_PATH="./Dockerfile.MCPO-Proxy"
5
+ IMAGE_NAME="call518/mcpo-proxy-openstack-ops"
6
+
7
+ echo "=== Building Docker image Name: ${IMAGE_NAME} ==="
8
+
9
+ VERSION="1.0.2"
10
+ TAGs="latest"
11
+
12
+ # Build once with version tag
13
+ docker build -t ${IMAGE_NAME}:${VERSION} -f ${Dockerfile_PATH} .
14
+
15
+ # Tag as latest
16
+ for TAG in ${TAGs}
17
+ do
18
+ docker tag ${IMAGE_NAME}:${VERSION} ${IMAGE_NAME}:${TAG}
19
+ done
20
+
21
+ echo
22
+
23
+ read -p "Do you want to push the images to Docker Hub? (y/N): " answer
24
+ if [[ "$answer" == "y" || "$answer" == "Y" ]]; then
25
+ echo "Pushing version ${VERSION}..."
26
+ docker push ${IMAGE_NAME}:${VERSION}
27
+
28
+ echo "Pushing latest tag..."
29
+ for TAG in ${TAGs}
30
+ do
31
+ docker push ${IMAGE_NAME}:${TAG}
32
+ done
33
+ fi
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ OpenStack 권한 및 API 접근 진단 스크립트
4
+ """
5
+ import os
6
+ from dotenv import load_dotenv
7
+ from openstack import connection
8
+ import json
9
+
10
+ def diagnose_openstack_access():
11
+ load_dotenv()
12
+
13
+ print("=== OpenStack API 접근 진단 ===")
14
+ print(f"사용자: {os.environ.get('OS_USERNAME')}")
15
+ print(f"프로젝트: {os.environ.get('OS_PROJECT_NAME')}")
16
+ print(f"인증 URL: {os.environ.get('OS_AUTH_URL')}")
17
+ print()
18
+
19
+ try:
20
+ conn = connection.Connection(
21
+ auth_url=os.environ.get('OS_AUTH_URL'),
22
+ project_name=os.environ.get('OS_PROJECT_NAME'),
23
+ username=os.environ.get('OS_USERNAME'),
24
+ password=os.environ.get('OS_PASSWORD'),
25
+ user_domain_name=os.environ.get('OS_USER_DOMAIN_NAME', 'default'),
26
+ project_domain_name=os.environ.get('OS_PROJECT_DOMAIN_NAME', 'default'),
27
+ )
28
+
29
+ print("✅ OpenStack 연결 성공")
30
+
31
+ # 1. 현재 사용자 정보
32
+ try:
33
+ token = conn.identity.get_token()
34
+ print(f"✅ 토큰 획득 성공")
35
+
36
+ # 사용자 역할 확인
37
+ user_id = conn.current_user_id
38
+ project_id = conn.current_project_id
39
+
40
+ roles = list(conn.identity.role_assignments.list(user=user_id, project=project_id))
41
+ print(f"현재 사용자 역할: {len(roles)}개")
42
+
43
+ for assignment in roles:
44
+ role_id = assignment.role['id']
45
+ role = conn.identity.get_role(role_id)
46
+ print(f" - {role.name}")
47
+
48
+ except Exception as e:
49
+ print(f"❌ 사용자 정보 조회 실패: {e}")
50
+
51
+ print()
52
+
53
+ # 2. Hypervisor 정보 (admin 권한 필요)
54
+ print("--- Hypervisor 정보 조회 (admin 권한 필요) ---")
55
+ try:
56
+ hypervisors = list(conn.compute.hypervisors(details=True))
57
+ print(f"✅ Hypervisor 조회 성공: {len(hypervisors)}개")
58
+
59
+ for hyp in hypervisors:
60
+ print(f"Hypervisor ID: {hyp.id}")
61
+ print(f" 이름: {getattr(hyp, 'hypervisor_hostname', 'N/A')}")
62
+ print(f" 상태: {getattr(hyp, 'status', 'N/A')}/{getattr(hyp, 'state', 'N/A')}")
63
+ print(f" vCPUs: {getattr(hyp, 'vcpus_used', 'N/A')}/{getattr(hyp, 'vcpus', 'N/A')}")
64
+ print(f" 메모리: {getattr(hyp, 'memory_mb_used', 'N/A')}/{getattr(hyp, 'memory_mb', 'N/A')} MB")
65
+ print(f" 실행 중 VM: {getattr(hyp, 'running_vms', 'N/A')}")
66
+ print(f" 타입: {getattr(hyp, 'hypervisor_type', 'N/A')}")
67
+ print()
68
+
69
+ except Exception as e:
70
+ print(f"❌ Hypervisor 조회 실패: {e}")
71
+ print(" → admin 권한이 필요할 수 있습니다")
72
+
73
+ print()
74
+
75
+ # 3. 프로젝트 내 인스턴스 조회 (일반 사용자 권한으로 가능)
76
+ print("--- 프로젝트 인스턴스 조회 (일반 사용자 권한) ---")
77
+ try:
78
+ servers = list(conn.compute.servers(details=True))
79
+ print(f"✅ 인스턴스 조회 성공: {len(servers)}개")
80
+
81
+ total_vcpus_used = 0
82
+ total_memory_used = 0
83
+
84
+ for server in servers:
85
+ flavor = conn.compute.get_flavor(server.flavor['id'])
86
+ total_vcpus_used += flavor.vcpus
87
+ total_memory_used += flavor.ram
88
+
89
+ print(f"인스턴스: {server.name}")
90
+ print(f" 상태: {server.status}")
91
+ print(f" Flavor vCPUs: {flavor.vcpus}")
92
+ print(f" Flavor RAM: {flavor.ram} MB")
93
+ print(f" 호스트: {getattr(server, 'OS-EXT-SRV-ATTR:host', 'N/A')}")
94
+
95
+ print(f"\n📊 프로젝트 리소스 사용량:")
96
+ print(f" 총 vCPUs 사용: {total_vcpus_used}")
97
+ print(f" 총 메모리 사용: {total_memory_used} MB")
98
+
99
+ except Exception as e:
100
+ print(f"❌ 인스턴스 조회 실패: {e}")
101
+
102
+ print()
103
+
104
+ # 4. 쿼터 정보
105
+ print("--- 프로젝트 쿼터 조회 ---")
106
+ try:
107
+ project_id = conn.current_project_id
108
+ quotas = conn.compute.get_quota_set(project_id)
109
+
110
+ print(f"✅ 쿼터 조회 성공:")
111
+ print(f" 인스턴스: {getattr(quotas, 'instances', 'N/A')}")
112
+ print(f" 코어: {getattr(quotas, 'cores', 'N/A')}")
113
+ print(f" RAM: {getattr(quotas, 'ram', 'N/A')} MB")
114
+
115
+ except Exception as e:
116
+ print(f"❌ 쿼터 조회 실패: {e}")
117
+
118
+ print()
119
+
120
+ # 5. 사용량 조회 (또 다른 방법)
121
+ print("--- 프로젝트 사용량 조회 ---")
122
+ try:
123
+ project_id = conn.current_project_id
124
+ usage = conn.compute.get_usage(project_id)
125
+
126
+ print(f"✅ 사용량 조회 성공:")
127
+ print(f" 총 인스턴스 시간: {getattr(usage, 'total_instance_usage', 'N/A')}")
128
+ print(f" 총 vCPU 시간: {getattr(usage, 'total_vcpus_usage', 'N/A')}")
129
+ print(f" 총 메모리 시간: {getattr(usage, 'total_memory_mb_usage', 'N/A')}")
130
+
131
+ except Exception as e:
132
+ print(f"❌ 사용량 조회 실패: {e}")
133
+
134
+ except Exception as e:
135
+ print(f"❌ OpenStack 연결 실패: {e}")
136
+
137
+ if __name__ == "__main__":
138
+ diagnose_openstack_access()