Skip to content

Commit b234243

Browse files
choieastseahalucinor
authored andcommitted
feat: create server (#41)
1 parent c107935 commit b234243

File tree

3 files changed

+266
-121
lines changed

3 files changed

+266
-121
lines changed
Lines changed: 56 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from typing import Any
2+
13
from fastmcp import FastMCP
24

35
from openstack_mcp_server.tools.response.compute import Server
@@ -15,37 +17,73 @@ def register_tools(self, mcp: FastMCP):
1517
Register Compute-related tools with the FastMCP instance.
1618
"""
1719

18-
mcp.tool()(self.get_compute_servers)
19-
mcp.tool()(self.get_compute_server)
20+
mcp.tool()(self.get_servers)
21+
mcp.tool()(self.get_server)
22+
mcp.tool()(self.create_server)
2023

21-
def get_compute_servers(self) -> list[Server]:
24+
def get_servers(self) -> list[Server]:
2225
"""
23-
Get the list of Compute servers by invoking the registered tool.
26+
Get the list of Compute servers.
2427
25-
:return: A list of Server objects representing the Compute servers.
28+
:return: A list of Server objects.
2629
"""
27-
# Initialize connection
2830
conn = get_openstack_conn()
29-
30-
# List the servers
3131
server_list = []
3232
for server in conn.compute.servers():
33-
server_list.append(
34-
Server(name=server.name, id=server.id, status=server.status),
35-
)
33+
server_list.append(Server(**server))
3634

3735
return server_list
3836

39-
def get_compute_server(self, id: str) -> Server:
37+
def get_server(self, id: str) -> Server:
4038
"""
41-
Get a specific Compute server by invoking the registered tool.
39+
Get a specific Compute server.
4240
4341
:param id: The ID of the server to retrieve.
44-
:return: A Server object representing the Compute server.
42+
:return: A Server object.
4543
"""
46-
# Initialize connection
4744
conn = get_openstack_conn()
48-
49-
# Get a specific server (for example, the first one)
5045
server = conn.compute.get_server(id)
51-
return Server(name=server.name, id=server.id, status=server.status)
46+
return Server(**server)
47+
48+
def create_server(
49+
self,
50+
name: str,
51+
image: str,
52+
flavor: int,
53+
network: str,
54+
key_name: str | None = None,
55+
security_groups: list[str] | None = None,
56+
user_data: str | None = None,
57+
) -> Server:
58+
"""
59+
Create a new Compute server.
60+
61+
:param name: The name of the server.
62+
:param image: The ID of the image to use.
63+
:param flavor: The (integer) ID of the flavor to use.
64+
:param network: The ID of the network to attach.
65+
:param key_name: The name of the key pair to use.
66+
:param security_groups: A list of security group names to attach.
67+
:param user_data: User data to pass to the server.
68+
:return: A Server object
69+
"""
70+
conn = get_openstack_conn()
71+
server_params: dict[str, Any] = {
72+
"name": name,
73+
"flavorRef": flavor,
74+
"imageRef": image,
75+
"networks": [{"uuid": network}],
76+
"key_name": key_name,
77+
"security_groups": security_groups,
78+
"user_data": user_data,
79+
}
80+
server_params = {
81+
k: v for k, v in server_params.items() if v is not None
82+
}
83+
84+
resp = conn.compute.create_server(**server_params)
85+
# NOTE: The create_server method returns a server object with minimal information.
86+
# To get the full server details, we need to fetch it again.
87+
server = conn.compute.get_server(resp.id)
88+
89+
return Server(**server)
Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,34 @@
1-
from pydantic import BaseModel
1+
from pydantic import BaseModel, ConfigDict, Field
22

33

4-
class Server(BaseModel):
5-
"""A model to represent a Compute server."""
4+
class Flavor(BaseModel):
5+
id: str | None = Field(default=None, exclude=True)
6+
name: str = Field(validation_alias="original_name")
7+
model_config = ConfigDict(validate_by_name=True)
8+
9+
10+
class Image(BaseModel):
11+
id: str
12+
13+
14+
class ServerIp(BaseModel):
15+
addr: str
16+
version: int
17+
type: str = Field(validation_alias="OS-EXT-IPS:type")
618

19+
model_config = ConfigDict(validate_by_name=True)
20+
21+
22+
class ServerSecurityGroup(BaseModel):
723
name: str
24+
25+
26+
class Server(BaseModel):
827
id: str
9-
status: str
28+
name: str
29+
status: str | None = None
30+
flavor: Flavor | None = None
31+
image: Image | None = None
32+
addresses: dict[str, list[ServerIp]] | None = None
33+
key_name: str | None = None
34+
security_groups: list[ServerSecurityGroup] | None = None

0 commit comments

Comments
 (0)