laniakea-api-server 0.2.8__tar.gz → 0.3.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {laniakea_api_server-0.2.8 → laniakea_api_server-0.3.1}/PKG-INFO +1 -1
- {laniakea_api_server-0.2.8 → laniakea_api_server-0.3.1}/laniakea_api/models.py +1 -0
- {laniakea_api_server-0.2.8 → laniakea_api_server-0.3.1}/laniakea_api/queue.py +36 -5
- {laniakea_api_server-0.2.8 → laniakea_api_server-0.3.1}/laniakea_api/routers/agent.py +5 -0
- {laniakea_api_server-0.2.8 → laniakea_api_server-0.3.1}/laniakea_api/routers/credentials.py +35 -3
- {laniakea_api_server-0.2.8 → laniakea_api_server-0.3.1}/pyproject.toml +1 -1
- {laniakea_api_server-0.2.8 → laniakea_api_server-0.3.1}/.github/workflows/publish.yml +0 -0
- {laniakea_api_server-0.2.8 → laniakea_api_server-0.3.1}/.gitignore +0 -0
- {laniakea_api_server-0.2.8 → laniakea_api_server-0.3.1}/LICENSE +0 -0
- {laniakea_api_server-0.2.8 → laniakea_api_server-0.3.1}/README.md +0 -0
- {laniakea_api_server-0.2.8 → laniakea_api_server-0.3.1}/laniakea_api/__init__.py +0 -0
- {laniakea_api_server-0.2.8 → laniakea_api_server-0.3.1}/laniakea_api/auth.py +0 -0
- {laniakea_api_server-0.2.8 → laniakea_api_server-0.3.1}/laniakea_api/cli.py +0 -0
- {laniakea_api_server-0.2.8 → laniakea_api_server-0.3.1}/laniakea_api/config.py +0 -0
- {laniakea_api_server-0.2.8 → laniakea_api_server-0.3.1}/laniakea_api/credential_parser.py +0 -0
- {laniakea_api_server-0.2.8 → laniakea_api_server-0.3.1}/laniakea_api/database.py +0 -0
- {laniakea_api_server-0.2.8 → laniakea_api_server-0.3.1}/laniakea_api/installer.py +0 -0
- {laniakea_api_server-0.2.8 → laniakea_api_server-0.3.1}/laniakea_api/main.py +0 -0
- {laniakea_api_server-0.2.8 → laniakea_api_server-0.3.1}/laniakea_api/routers/.health.py.swp +0 -0
- {laniakea_api_server-0.2.8 → laniakea_api_server-0.3.1}/laniakea_api/routers/__init__.py +0 -0
- {laniakea_api_server-0.2.8 → laniakea_api_server-0.3.1}/laniakea_api/routers/agents.py +0 -0
- {laniakea_api_server-0.2.8 → laniakea_api_server-0.3.1}/laniakea_api/routers/deployments.py +0 -0
- {laniakea_api_server-0.2.8 → laniakea_api_server-0.3.1}/laniakea_api/routers/health.py +0 -0
- {laniakea_api_server-0.2.8 → laniakea_api_server-0.3.1}/laniakea_api/routers/tfstate.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: laniakea-api-server
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Laniakea Queue API — OIDC-authenticated gateway for cloud deployment orchestration
|
|
5
5
|
Project-URL: Homepage, https://github.com/laniakea/laniakea-api
|
|
6
6
|
Project-URL: Issues, https://github.com/laniakea/laniakea-api/issues
|
|
@@ -65,6 +65,7 @@ class DeploymentRequest(BaseModel):
|
|
|
65
65
|
selected_provider: str # OpenStack | AWS
|
|
66
66
|
service_type: Optional[str] = "galaxy"
|
|
67
67
|
cloud_providers: dict
|
|
68
|
+
credentials_name: Optional[str] = "" # NOTE: remove here if no cred selection
|
|
68
69
|
|
|
69
70
|
|
|
70
71
|
class JobResponse(BaseModel):
|
|
@@ -119,8 +119,20 @@ def _sc_path(user_sub: str, name: str = "") -> str:
|
|
|
119
119
|
base = f"{user_sub}/service_creds"
|
|
120
120
|
return f"{base}/{name}" if name else base
|
|
121
121
|
|
|
122
|
+
def _infer_service_type(data: dict) -> str:
|
|
123
|
+
"""
|
|
124
|
+
Derive the credential type from the field names themselves —
|
|
125
|
+
nothing but secrets is stored in Vault.
|
|
126
|
+
"""
|
|
127
|
+
if any(k.startswith("aws_") for k in data):
|
|
128
|
+
return "aws"
|
|
129
|
+
if any(k.startswith("openstack_") for k in data):
|
|
130
|
+
return "openstack"
|
|
131
|
+
return "unknown"
|
|
132
|
+
|
|
133
|
+
|
|
122
134
|
def vault_list_service_creds(user_sub: str) -> list:
|
|
123
|
-
client = vault_client
|
|
135
|
+
client = vault_client
|
|
124
136
|
try:
|
|
125
137
|
resp = client.secrets.kv.v2.list_secrets(path=_sc_path(user_sub), mount_point=VAULT_MOUNT)
|
|
126
138
|
names = [k.rstrip("/") for k in resp["data"]["keys"]]
|
|
@@ -129,11 +141,11 @@ def vault_list_service_creds(user_sub: str) -> list:
|
|
|
129
141
|
out = []
|
|
130
142
|
for n in names:
|
|
131
143
|
data = vault_read_service_creds(user_sub, n)
|
|
132
|
-
out.append({"name": n, "service_type": data
|
|
144
|
+
out.append({"name": n, "service_type": _infer_service_type(data)})
|
|
133
145
|
return out
|
|
134
146
|
|
|
135
147
|
def vault_read_service_creds(user_sub: str, name: str) -> dict:
|
|
136
|
-
client = vault_client
|
|
148
|
+
client = vault_client
|
|
137
149
|
try:
|
|
138
150
|
resp = client.secrets.kv.v2.read_secret_version(path=_sc_path(user_sub, name), mount_point=VAULT_MOUNT)
|
|
139
151
|
return resp["data"]["data"] or {}
|
|
@@ -141,11 +153,30 @@ def vault_read_service_creds(user_sub: str, name: str) -> dict:
|
|
|
141
153
|
return {}
|
|
142
154
|
|
|
143
155
|
def vault_write_service_creds(user_sub: str, name: str, data: dict) -> None:
|
|
144
|
-
client = vault_client
|
|
156
|
+
client = vault_client
|
|
145
157
|
client.secrets.kv.v2.create_or_update_secret(
|
|
146
158
|
path=_sc_path(user_sub, name), secret=data, mount_point=VAULT_MOUNT)
|
|
147
159
|
|
|
148
160
|
def vault_delete_service_creds(user_sub: str, name: str) -> None:
|
|
149
|
-
client = vault_client
|
|
161
|
+
client = vault_client
|
|
150
162
|
client.secrets.kv.v2.delete_metadata_and_all_versions(
|
|
151
163
|
path=_sc_path(user_sub, name), mount_point=VAULT_MOUNT)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def vault_read_global(user_sub: str) -> dict:
|
|
167
|
+
client = vault_client
|
|
168
|
+
try:
|
|
169
|
+
resp = client.secrets.kv.v2.read_secret_version(
|
|
170
|
+
path=f"{user_sub}/credentials", mount_point=VAULT_MOUNT)
|
|
171
|
+
return resp["data"]["data"] or {}
|
|
172
|
+
except Exception:
|
|
173
|
+
return {}
|
|
174
|
+
|
|
175
|
+
def vault_strip_global_keys(user_sub: str, keys: list) -> None:
|
|
176
|
+
"""Remove specific fields from the global path, keep the rest."""
|
|
177
|
+
data = vault_read_global(user_sub)
|
|
178
|
+
for k in keys:
|
|
179
|
+
data.pop(k, None)
|
|
180
|
+
client = vault_client
|
|
181
|
+
client.secrets.kv.v2.create_or_update_secret(
|
|
182
|
+
path=f"{user_sub}/credentials", secret=data, mount_point=VAULT_MOUNT)
|
|
@@ -78,6 +78,11 @@ async def agent_update_status(
|
|
|
78
78
|
if not updated:
|
|
79
79
|
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="DB update failed.")
|
|
80
80
|
|
|
81
|
+
# Deployment lifecycle ends here: drop the record and its tf state.
|
|
82
|
+
if new_status == "DELETE_COMPLETE":
|
|
83
|
+
db.tfstate_delete(uuid)
|
|
84
|
+
db.delete_deployment(uuid)
|
|
85
|
+
|
|
81
86
|
return {
|
|
82
87
|
"deployment_uuid": uuid,
|
|
83
88
|
"previous_status": current,
|
|
@@ -13,6 +13,8 @@ from laniakea_api.models import (OIDCLoginRequest, SessionTokenResponse,UserCred
|
|
|
13
13
|
from laniakea_api.queue import vault_write_credentials, VAULT_MOUNT
|
|
14
14
|
from laniakea_api.queue import (vault_list_service_creds, vault_read_service_creds,
|
|
15
15
|
vault_write_service_creds, vault_delete_service_creds)
|
|
16
|
+
from laniakea_api.queue import vault_read_global, vault_strip_global_keys
|
|
17
|
+
|
|
16
18
|
|
|
17
19
|
router = APIRouter()
|
|
18
20
|
|
|
@@ -108,9 +110,12 @@ async def read_service_creds(name: str, caller: dict = Depends(verify_session_to
|
|
|
108
110
|
|
|
109
111
|
@router.put("/profile/service_creds/{name}")
|
|
110
112
|
async def write_service_creds(name: str, body: dict, caller: dict = Depends(verify_session_token)):
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
113
|
+
import re
|
|
114
|
+
if not re.fullmatch(r"[A-Za-z0-9_-]+", name or ""):
|
|
115
|
+
raise HTTPException(status_code=400,
|
|
116
|
+
detail="Invalid name: only letters, digits, '_' and '-' (e.g. openstack_garr).")
|
|
117
|
+
body = {k: v for k, v in body.items()
|
|
118
|
+
if v not in (None, "") and k not in ("name", "service_type")}
|
|
114
119
|
vault_write_service_creds(caller["sub"], name, body) # KV2: ogni write = nuova versione
|
|
115
120
|
return {"name": name, "saved": True}
|
|
116
121
|
|
|
@@ -118,3 +123,30 @@ async def write_service_creds(name: str, body: dict, caller: dict = Depends(veri
|
|
|
118
123
|
async def delete_service_creds(name: str, caller: dict = Depends(verify_session_token)):
|
|
119
124
|
vault_delete_service_creds(caller["sub"], name)
|
|
120
125
|
return {"name": name, "deleted": True}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@router.get("/profile/ssh_key")
|
|
129
|
+
async def get_ssh_key(caller: dict = Depends(verify_session_token)):
|
|
130
|
+
data = vault_read_global(caller["sub"])
|
|
131
|
+
return {"ssh_key": data.get("ssh_key", "")}
|
|
132
|
+
|
|
133
|
+
@router.get("/profile/ssh_key/private")
|
|
134
|
+
async def get_ssh_private_key(caller: dict = Depends(verify_session_token)):
|
|
135
|
+
data = vault_read_global(caller["sub"])
|
|
136
|
+
if not data.get("ssh_private_key"):
|
|
137
|
+
raise HTTPException(status_code=404, detail="No private key stored.")
|
|
138
|
+
return {"ssh_private_key": data["ssh_private_key"]}
|
|
139
|
+
|
|
140
|
+
@router.put("/profile/ssh_key")
|
|
141
|
+
async def put_ssh_key(body: dict, caller: dict = Depends(verify_session_token)):
|
|
142
|
+
fields = {k: v for k, v in body.items()
|
|
143
|
+
if k in ("ssh_key", "ssh_private_key") and v}
|
|
144
|
+
if not fields:
|
|
145
|
+
raise HTTPException(status_code=400, detail="Nothing to store.")
|
|
146
|
+
vault_write_credentials(caller["sub"], fields) # merge-write sul path globale
|
|
147
|
+
return {"saved": sorted(fields.keys())}
|
|
148
|
+
|
|
149
|
+
@router.delete("/profile/ssh_key")
|
|
150
|
+
async def delete_ssh_key(caller: dict = Depends(verify_session_token)):
|
|
151
|
+
vault_strip_global_keys(caller["sub"], ["ssh_key", "ssh_private_key"])
|
|
152
|
+
return {"deleted": True}
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "laniakea-api-server"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.1"
|
|
8
8
|
description = "Laniakea Queue API — OIDC-authenticated gateway for cloud deployment orchestration"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|