- Add .gitignore: exclude compiled binaries, build artifacts, and Helm values files containing real secrets (authentik, prometheus) - Add all Kubernetes deployment manifests (deployment/) - Add services source code: ha-sync, device-inventory, games-console, paperclip, parts-inventory - Add Ansible orchestration: playbooks, roles, inventory, cloud-init - Add hardware specs, execution plans, scripts, HOMELAB.md - Add skills/homelab/SKILL.md + skills/install.sh to preserve Copilot skill - Remove previously-tracked inventory-cli binary from git index Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
159 lines
4.1 KiB
Go
159 lines
4.1 KiB
Go
package api
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
)
|
|
|
|
// Server mirrors the backend Server type.
|
|
type Server struct {
|
|
Name string `json:"name"`
|
|
Type string `json:"type"`
|
|
Image string `json:"image"`
|
|
Replicas int32 `json:"replicas"`
|
|
Ready int32 `json:"ready"`
|
|
Status string `json:"status"`
|
|
NodePort int32 `json:"nodePort,omitempty"`
|
|
Port int32 `json:"port"`
|
|
EnvVars map[string]string `json:"envVars"`
|
|
CreatedAt string `json:"createdAt"`
|
|
}
|
|
|
|
type CreateServerRequest struct {
|
|
Name string `json:"name"`
|
|
Type string `json:"type"`
|
|
Image string `json:"image"`
|
|
Port int32 `json:"port"`
|
|
NodePort int32 `json:"nodePort,omitempty"`
|
|
EnvVars map[string]string `json:"envVars"`
|
|
}
|
|
|
|
type UpdateServerRequest struct {
|
|
Image string `json:"image,omitempty"`
|
|
EnvVars map[string]string `json:"envVars,omitempty"`
|
|
}
|
|
|
|
// Client is an HTTP client for the games-console backend.
|
|
type Client struct {
|
|
BaseURL string
|
|
http *http.Client
|
|
}
|
|
|
|
func NewClient(baseURL string) *Client {
|
|
return &Client{BaseURL: baseURL, http: &http.Client{}}
|
|
}
|
|
|
|
func (c *Client) ListServers() ([]Server, error) {
|
|
var servers []Server
|
|
return servers, c.get("/api/servers", &servers)
|
|
}
|
|
|
|
func (c *Client) GetServer(name string) (*Server, error) {
|
|
var s Server
|
|
return &s, c.get("/api/servers/"+name, &s)
|
|
}
|
|
|
|
func (c *Client) CreateServer(req CreateServerRequest) (*Server, error) {
|
|
var s Server
|
|
return &s, c.post("/api/servers", req, &s)
|
|
}
|
|
|
|
func (c *Client) UpdateServer(name string, req UpdateServerRequest) (*Server, error) {
|
|
var s Server
|
|
return &s, c.put("/api/servers/"+name, req, &s)
|
|
}
|
|
|
|
func (c *Client) DeleteServer(name string) error {
|
|
return c.delete("/api/servers/" + name)
|
|
}
|
|
|
|
func (c *Client) GetLogs(name string, lines int) (string, error) {
|
|
var resp struct {
|
|
Logs string `json:"logs"`
|
|
}
|
|
return resp.Logs, c.get(fmt.Sprintf("/api/servers/%s/logs?lines=%d", name, lines), &resp)
|
|
}
|
|
|
|
func (c *Client) GetHealth(name string) (map[string]interface{}, error) {
|
|
var resp map[string]interface{}
|
|
return resp, c.get("/api/servers/"+name+"/health", &resp)
|
|
}
|
|
|
|
func (c *Client) Start(name string) error {
|
|
return c.postAction("/api/servers/" + name + "/start")
|
|
}
|
|
|
|
func (c *Client) Stop(name string) error {
|
|
return c.postAction("/api/servers/" + name + "/stop")
|
|
}
|
|
|
|
func (c *Client) Restart(name string) error {
|
|
return c.postAction("/api/servers/" + name + "/restart")
|
|
}
|
|
|
|
// --- HTTP helpers ---
|
|
|
|
func (c *Client) get(path string, out interface{}) error {
|
|
resp, err := c.http.Get(c.BaseURL + path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return decode(resp, out)
|
|
}
|
|
|
|
func (c *Client) post(path string, body interface{}, out interface{}) error {
|
|
b, _ := json.Marshal(body)
|
|
resp, err := c.http.Post(c.BaseURL+path, "application/json", bytes.NewReader(b))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return decode(resp, out)
|
|
}
|
|
|
|
func (c *Client) postAction(path string) error {
|
|
resp, err := c.http.Post(c.BaseURL+path, "application/json", nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
resp.Body.Close()
|
|
if resp.StatusCode >= 400 {
|
|
return fmt.Errorf("server returned %d", resp.StatusCode)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *Client) put(path string, body interface{}, out interface{}) error {
|
|
b, _ := json.Marshal(body)
|
|
req, _ := http.NewRequest(http.MethodPut, c.BaseURL+path, bytes.NewReader(b))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, err := c.http.Do(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return decode(resp, out)
|
|
}
|
|
|
|
func (c *Client) delete(path string) error {
|
|
req, _ := http.NewRequest(http.MethodDelete, c.BaseURL+path, nil)
|
|
resp, err := c.http.Do(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
resp.Body.Close()
|
|
if resp.StatusCode >= 400 {
|
|
return fmt.Errorf("server returned %d", resp.StatusCode)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func decode(resp *http.Response, out interface{}) error {
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode >= 400 {
|
|
body, _ := io.ReadAll(resp.Body)
|
|
return fmt.Errorf("server error %d: %s", resp.StatusCode, string(body))
|
|
}
|
|
return json.NewDecoder(resp.Body).Decode(out)
|
|
}
|