release] v0.22.0-unstable14

This commit is contained in:
Yann Stepienik
2026-03-20 14:26:26 +00:00
parent 0c151cf987
commit 78d40c8c03
16 changed files with 1236 additions and 406 deletions
+128 -1
View File
@@ -4,7 +4,7 @@
"description": "REST API for Cosmos Cloud server management",
"title": "Cosmos Server API",
"contact": {},
"version": "0.22.0-unstable13"
"version": "0.22.0-unstable14"
},
"paths": {
"/_logs": {
@@ -7817,6 +7817,68 @@
}
}
},
"/api/setup": {
"post": {
"description": "Performs the entire initial setup in a single call: database, HTTPS, admin user, optional Constellation connect, and optional admin API token creation. Only available when the server is in NewInstall mode.",
"tags": [
"system"
],
"summary": "One-shot server provisioning",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/main.SetupJSON"
}
}
},
"description": "Setup configuration",
"required": true
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/utils.APIResponse"
}
}
}
},
"400": {
"description": "Bad Request",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/utils.HTTPErrorResult"
}
}
}
},
"403": {
"description": "Forbidden",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/utils.HTTPErrorResult"
}
}
}
},
"500": {
"description": "Internal Server Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/utils.HTTPErrorResult"
}
}
}
}
}
}
},
"/api/smart-def": {
"get": {
"security": [
@@ -10759,6 +10821,71 @@
}
}
},
"main.SetupJSON": {
"type": "object",
"properties": {
"DNSChallengeConfig": {
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"allowHTTPLocalIPAccess": {
"type": "boolean"
},
"clearConfig": {
"description": "Optional: clear config before setup",
"type": "boolean"
},
"constellationConfig": {
"description": "Optional: Constellation connect",
"type": "string"
},
"createAdminToken": {
"description": "Optional: create admin API token",
"type": "boolean"
},
"dnsChallengeProvider": {
"type": "string"
},
"email": {
"type": "string"
},
"hostname": {
"description": "HTTPS",
"type": "string"
},
"httpsCertificateMode": {
"type": "string"
},
"mongodb": {
"type": "string"
},
"mongodbMode": {
"description": "Database",
"type": "string"
},
"nickname": {
"description": "Admin",
"type": "string"
},
"password": {
"type": "string"
},
"sslEmail": {
"type": "string"
},
"tlsCert": {
"type": "string"
},
"tlsKey": {
"type": "string"
},
"useWildcardCertificate": {
"type": "boolean"
}
}
},
"mount.BindOptions": {
"type": "object",
"properties": {
+118 -1
View File
@@ -4,7 +4,7 @@
"description": "REST API for Cosmos Cloud server management",
"title": "Cosmos Server API",
"contact": {},
"version": "0.22.0-unstable13"
"version": "0.22.0-unstable14"
},
"basePath": "/cosmos",
"paths": {
@@ -6442,6 +6442,58 @@
}
}
},
"/api/setup": {
"post": {
"description": "Performs the entire initial setup in a single call: database, HTTPS, admin user, optional Constellation connect, and optional admin API token creation. Only available when the server is in NewInstall mode.",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"system"
],
"summary": "One-shot server provisioning",
"parameters": [
{
"description": "Setup configuration",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/main.SetupJSON"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/utils.APIResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/utils.HTTPErrorResult"
}
},
"403": {
"description": "Forbidden",
"schema": {
"$ref": "#/definitions/utils.HTTPErrorResult"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/utils.HTTPErrorResult"
}
}
}
}
},
"/api/smart-def": {
"get": {
"security": [
@@ -9000,6 +9052,71 @@
}
}
},
"main.SetupJSON": {
"type": "object",
"properties": {
"DNSChallengeConfig": {
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"allowHTTPLocalIPAccess": {
"type": "boolean"
},
"clearConfig": {
"description": "Optional: clear config before setup",
"type": "boolean"
},
"constellationConfig": {
"description": "Optional: Constellation connect",
"type": "string"
},
"createAdminToken": {
"description": "Optional: create admin API token",
"type": "boolean"
},
"dnsChallengeProvider": {
"type": "string"
},
"email": {
"type": "string"
},
"hostname": {
"description": "HTTPS",
"type": "string"
},
"httpsCertificateMode": {
"type": "string"
},
"mongodb": {
"type": "string"
},
"mongodbMode": {
"description": "Database",
"type": "string"
},
"nickname": {
"description": "Admin",
"type": "string"
},
"password": {
"type": "string"
},
"sslEmail": {
"type": "string"
},
"tlsCert": {
"type": "string"
},
"tlsKey": {
"type": "string"
},
"useWildcardCertificate": {
"type": "boolean"
}
}
},
"mount.BindOptions": {
"type": "object",
"properties": {
+82 -1
View File
@@ -753,6 +753,51 @@ definitions:
useWildcardCertificate:
type: boolean
type: object
main.SetupJSON:
properties:
DNSChallengeConfig:
additionalProperties:
type: string
type: object
allowHTTPLocalIPAccess:
type: boolean
clearConfig:
description: 'Optional: clear config before setup'
type: boolean
constellationConfig:
description: 'Optional: Constellation connect'
type: string
createAdminToken:
description: 'Optional: create admin API token'
type: boolean
dnsChallengeProvider:
type: string
email:
type: string
hostname:
description: HTTPS
type: string
httpsCertificateMode:
type: string
mongodb:
type: string
mongodbMode:
description: Database
type: string
nickname:
description: Admin
type: string
password:
type: string
sslEmail:
type: string
tlsCert:
type: string
tlsKey:
type: string
useWildcardCertificate:
type: boolean
type: object
mount.BindOptions:
properties:
createMountpoint:
@@ -1929,7 +1974,7 @@ info:
contact: {}
description: REST API for Cosmos Cloud server management
title: Cosmos Server API
version: 0.22.0-unstable13
version: 0.22.0-unstable14
paths:
/_logs:
get:
@@ -5993,6 +6038,42 @@ paths:
summary: Update a Docker container's settings
tags:
- docker
/api/setup:
post:
consumes:
- application/json
description: 'Performs the entire initial setup in a single call: database,
HTTPS, admin user, optional Constellation connect, and optional admin API
token creation. Only available when the server is in NewInstall mode.'
parameters:
- description: Setup configuration
in: body
name: request
required: true
schema:
$ref: '#/definitions/main.SetupJSON'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/utils.APIResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/utils.HTTPErrorResult'
"403":
description: Forbidden
schema:
$ref: '#/definitions/utils.HTTPErrorResult'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/utils.HTTPErrorResult'
summary: One-shot server provisioning
tags:
- system
/api/smart-def:
get:
produces:
+486 -282
View File
@@ -642,6 +642,39 @@ type MainNewInstallJSON struct {
UseWildcardCertificate *bool `json:"useWildcardCertificate,omitempty"`
}
// MainSetupJSON defines model for main.SetupJSON.
type MainSetupJSON struct {
DNSChallengeConfig *map[string]string `json:"DNSChallengeConfig,omitempty"`
AllowHTTPLocalIPAccess *bool `json:"allowHTTPLocalIPAccess,omitempty"`
// ClearConfig Optional: clear config before setup
ClearConfig *bool `json:"clearConfig,omitempty"`
// ConstellationConfig Optional: Constellation connect
ConstellationConfig *string `json:"constellationConfig,omitempty"`
// CreateAdminToken Optional: create admin API token
CreateAdminToken *bool `json:"createAdminToken,omitempty"`
DnsChallengeProvider *string `json:"dnsChallengeProvider,omitempty"`
Email *string `json:"email,omitempty"`
// Hostname HTTPS
Hostname *string `json:"hostname,omitempty"`
HttpsCertificateMode *string `json:"httpsCertificateMode,omitempty"`
Mongodb *string `json:"mongodb,omitempty"`
// MongodbMode Database
MongodbMode *string `json:"mongodbMode,omitempty"`
// Nickname Admin
Nickname *string `json:"nickname,omitempty"`
Password *string `json:"password,omitempty"`
SslEmail *string `json:"sslEmail,omitempty"`
TlsCert *string `json:"tlsCert,omitempty"`
TlsKey *string `json:"tlsKey,omitempty"`
UseWildcardCertificate *bool `json:"useWildcardCertificate,omitempty"`
}
// MountBindOptions defines model for mount.BindOptions.
type MountBindOptions struct {
CreateMountpoint *bool `json:"createMountpoint,omitempty"`
@@ -1601,6 +1634,9 @@ type PutApiRoutesNameJSONRequestBody = UtilsProxyRouteConfig
// PostApiServappsContainerIdUpdateJSONRequestBody defines body for PostApiServappsContainerIdUpdate for application/json ContentType.
type PostApiServappsContainerIdUpdateJSONRequestBody = DockerContainerForm
// PostApiSetupJSONRequestBody defines body for PostApiSetup for application/json ContentType.
type PostApiSetupJSONRequestBody = MainSetupJSON
// GetApiSnapraidJSONRequestBody defines body for GetApiSnapraid for application/json ContentType.
type GetApiSnapraidJSONRequestBody = UtilsSnapRAIDConfig
@@ -2191,6 +2227,11 @@ type ClientInterface interface {
PostApiServappsContainerIdUpdate(ctx context.Context, containerId string, body PostApiServappsContainerIdUpdateJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
// PostApiSetupWithBody request with any body
PostApiSetupWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
PostApiSetup(ctx context.Context, body PostApiSetupJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
// GetApiSmartDef request
GetApiSmartDef(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
@@ -4380,6 +4421,30 @@ func (c *Client) PostApiServappsContainerIdUpdate(ctx context.Context, container
return c.Client.Do(req)
}
func (c *Client) PostApiSetupWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewPostApiSetupRequestWithBody(c.Server, contentType, body)
if err != nil {
return nil, err
}
req = req.WithContext(ctx)
if err := c.applyEditors(ctx, req, reqEditors); err != nil {
return nil, err
}
return c.Client.Do(req)
}
func (c *Client) PostApiSetup(ctx context.Context, body PostApiSetupJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewPostApiSetupRequest(c.Server, body)
if err != nil {
return nil, err
}
req = req.WithContext(ctx)
if err := c.applyEditors(ctx, req, reqEditors); err != nil {
return nil, err
}
return c.Client.Do(req)
}
func (c *Client) GetApiSmartDef(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewGetApiSmartDefRequest(c.Server)
if err != nil {
@@ -9781,6 +9846,46 @@ func NewPostApiServappsContainerIdUpdateRequestWithBody(server string, container
return req, nil
}
// NewPostApiSetupRequest calls the generic PostApiSetup builder with application/json body
func NewPostApiSetupRequest(server string, body PostApiSetupJSONRequestBody) (*http.Request, error) {
var bodyReader io.Reader
buf, err := json.Marshal(body)
if err != nil {
return nil, err
}
bodyReader = bytes.NewReader(buf)
return NewPostApiSetupRequestWithBody(server, "application/json", bodyReader)
}
// NewPostApiSetupRequestWithBody generates requests for PostApiSetup with any type of body
func NewPostApiSetupRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
var err error
serverURL, err := url.Parse(server)
if err != nil {
return nil, err
}
operationPath := fmt.Sprintf("/api/setup")
if operationPath[0] == '/' {
operationPath = "." + operationPath
}
queryURL, err := serverURL.Parse(operationPath)
if err != nil {
return nil, err
}
req, err := http.NewRequest("POST", queryURL.String(), body)
if err != nil {
return nil, err
}
req.Header.Add("Content-Type", contentType)
return req, nil
}
// NewGetApiSmartDefRequest generates requests for GetApiSmartDef
func NewGetApiSmartDefRequest(server string) (*http.Request, error) {
var err error
@@ -11321,6 +11426,11 @@ type ClientWithResponsesInterface interface {
PostApiServappsContainerIdUpdateWithResponse(ctx context.Context, containerId string, body PostApiServappsContainerIdUpdateJSONRequestBody, reqEditors ...RequestEditorFn) (*PostApiServappsContainerIdUpdateResponse, error)
// PostApiSetupWithBodyWithResponse request with any body
PostApiSetupWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostApiSetupResponse, error)
PostApiSetupWithResponse(ctx context.Context, body PostApiSetupJSONRequestBody, reqEditors ...RequestEditorFn) (*PostApiSetupResponse, error)
// GetApiSmartDefWithResponse request
GetApiSmartDefWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetApiSmartDefResponse, error)
@@ -14542,6 +14652,31 @@ func (r PostApiServappsContainerIdUpdateResponse) StatusCode() int {
return 0
}
type PostApiSetupResponse struct {
Body []byte
HTTPResponse *http.Response
JSON200 *UtilsAPIResponse
JSON400 *UtilsHTTPErrorResult
JSON403 *UtilsHTTPErrorResult
JSON500 *UtilsHTTPErrorResult
}
// Status returns HTTPResponse.Status
func (r PostApiSetupResponse) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
return http.StatusText(0)
}
// StatusCode returns HTTPResponse.StatusCode
func (r PostApiSetupResponse) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
type GetApiSmartDefResponse struct {
Body []byte
HTTPResponse *http.Response
@@ -16749,6 +16884,23 @@ func (c *ClientWithResponses) PostApiServappsContainerIdUpdateWithResponse(ctx c
return ParsePostApiServappsContainerIdUpdateResponse(rsp)
}
// PostApiSetupWithBodyWithResponse request with arbitrary body returning *PostApiSetupResponse
func (c *ClientWithResponses) PostApiSetupWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostApiSetupResponse, error) {
rsp, err := c.PostApiSetupWithBody(ctx, contentType, body, reqEditors...)
if err != nil {
return nil, err
}
return ParsePostApiSetupResponse(rsp)
}
func (c *ClientWithResponses) PostApiSetupWithResponse(ctx context.Context, body PostApiSetupJSONRequestBody, reqEditors ...RequestEditorFn) (*PostApiSetupResponse, error) {
rsp, err := c.PostApiSetup(ctx, body, reqEditors...)
if err != nil {
return nil, err
}
return ParsePostApiSetupResponse(rsp)
}
// GetApiSmartDefWithResponse request returning *GetApiSmartDefResponse
func (c *ClientWithResponses) GetApiSmartDefWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetApiSmartDefResponse, error) {
rsp, err := c.GetApiSmartDef(ctx, reqEditors...)
@@ -22504,6 +22656,53 @@ func ParsePostApiServappsContainerIdUpdateResponse(rsp *http.Response) (*PostApi
return response, nil
}
// ParsePostApiSetupResponse parses an HTTP response from a PostApiSetupWithResponse call
func ParsePostApiSetupResponse(rsp *http.Response) (*PostApiSetupResponse, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
defer func() { _ = rsp.Body.Close() }()
if err != nil {
return nil, err
}
response := &PostApiSetupResponse{
Body: bodyBytes,
HTTPResponse: rsp,
}
switch {
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
var dest UtilsAPIResponse
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
return nil, err
}
response.JSON200 = &dest
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400:
var dest UtilsHTTPErrorResult
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
return nil, err
}
response.JSON400 = &dest
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403:
var dest UtilsHTTPErrorResult
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
return nil, err
}
response.JSON403 = &dest
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500:
var dest UtilsHTTPErrorResult
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
return nil, err
}
response.JSON500 = &dest
}
return response, nil
}
// ParseGetApiSmartDefResponse parses an HTTP response from a GetApiSmartDefWithResponse call
func ParseGetApiSmartDefResponse(rsp *http.Response) (*GetApiSmartDefResponse, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
@@ -23763,288 +23962,293 @@ func ParsePostRcloneVfsStatsResponse(rsp *http.Response) (*PostRcloneVfsStatsRes
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
"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",
"TqF5wclea9HThna04QfX7HjBicnKFUQ2Km/m9Kki9Rx+Za5ifmPxEOvAomlXhW5NVyjvHq4ZYijSxbpZ",
"c1FyPXxpTN+Tcf21rx7Sk5q/qRhSFDUJYPmWYiYGjfNC0Lm+RqYQkRmBOIzVpcfMS0fpH1FxwD5k+odL",
"TzG+P8WwpVUM4lf5tucBg1W08GmgY1wUys+Jh8yiBcISQYIJNbZ7wamnmooe8lmRjid6H53ERG15HZ0S",
"oLG0ymUXmds/jHra8zMblGOiwrJK/iJZcpolcPjV/veitVf9J9P+U9FrG1nRbfLa2XYujYtuGi+VWZbH",
"7vO7/I2yfDkp2wVxO2ipe8XWwrdty23ZiT65Vj2c/FxFc5bFvXZN/laGiCdLlWEnqWhyfQdjm631uH2+",
"jN5t5vuoLitoFCKzlM95K3fkYy4TLnMfGd3NZqu/uvi9MA7XqPMHPfpWwDbdD1M2rx7qdl+RAAz/o+0M",
"3y13gX42ugOk9ki8dnQRUc7g0Hp2H7qUy40egWPTw4Y0Hecpmnclels968aQ8KKIpTW4aRY+RLqn9Tkv",
"yYy9U2BP3Z6Ouo2PNeSbvPCV2o/2dy9ClQ0zTa+hMlKN8gfNkyHVpfmyxib9qLK7qjyoelx6hri0yzOI",
"7QS6WZI2PYMqIKvb9klsOt1NlqRGyplllOb3s5m0qsU1USKVvVbZ9rY+lLr0l9b5vVjBJYn2DAU1+WNX",
"KZhCN0PEuH5+xcAUwVS+aneVEi87yF4TvIT++rpl/MRLMDi3O7qVsnlmvkvKKnf0sWwneEr52GXGXHP0",
"XjDuBePvkSaTIbgnUhE27yhjCDCRya2Ylk183TOrl27GnlM+xYWwowRmcubCi+UWgClgQx7iKc9UGz55",
"WfQ5Ml12yONiWvbEsieWNdjXq3nzY1JLnCUpNVWqIO6Ogy7eFmVS/z9hM+7K7zkFwJ7iCtMhyiTEQzQT",
"ANuk1+VMrkn5Npz8NJNrWt4j499CDaHB7tPpxNJ5B20m1hbiJmnBTKFRzvoCZIIO3g0OI6PTHnz78u3/",
"BQAA//9nKpErAYUCAA==",
}
// GetSwagger returns the content of the embedded swagger specification file
+1 -1
View File
@@ -1,4 +1,4 @@
package cosmossdk
// Version is the SDK version, synced with Cosmos Server at build time.
const Version = "0.22.0-unstable13"
const Version = "0.22.0-unstable14"
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "cosmos-server",
"version": "0.22.0-unstable13",
"version": "0.22.0-unstable14",
"description": "",
"main": "test-server.js",
"bugs": {
@@ -90,7 +90,7 @@
"scripts": {
"client": "vite",
"client-build": "vite build --base=/cosmos-ui/",
"start": "build/cosmos-launcher && env COSMOS_CONFIG_FOLDER=./zz_test_config/ CONFIG_FILE=./config_dev.json EZ=UTC ACME_STAGING=true build/cosmos",
"start": "build/cosmos-launcher && env COSMOS_LOG_LEVEL=DEBUG COSMOS_CONFIG_FOLDER=./zz_test_config/ CONFIG_FILE=./config_dev.json EZ=UTC ACME_STAGING=true build/cosmos",
"build": "sh build-dev.sh",
"dev": "npm run build && npm run start",
"dockerdevbuild": "docker build -f dockerfile.local --tag cosmos-dev .",
+28
View File
@@ -14,6 +14,26 @@ import createApiTokensAPI from '../../client/src/api/apiTokens';
import createOpenIDAPI from '../../client/src/api/openid';
import wrap from '../../client/src/api/wrap';
export interface SetupRequest {
mongodbMode: string;
mongodb?: string;
hostname: string;
httpsCertificateMode: string;
sslEmail?: string;
useWildcardCertificate?: boolean;
dnsChallengeProvider?: string;
DNSChallengeConfig?: Record<string, string>;
tlsCert?: string;
tlsKey?: string;
allowHTTPLocalIPAccess?: boolean;
nickname: string;
password: string;
email?: string;
clearConfig?: boolean;
constellationConfig?: string;
createAdminToken?: boolean;
}
export function createClient({ baseUrl, token }: { baseUrl: string; token: string }) {
const { apiFetch, createWs } = createApiClient(baseUrl, token);
@@ -32,6 +52,14 @@ export function createClient({ baseUrl, token }: { baseUrl: string; token: strin
apiTokens: createApiTokensAPI(apiFetch),
openid: createOpenIDAPI(apiFetch),
setup: (request: SetupRequest) => {
return wrap(apiFetch('/cosmos/api/setup', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(request),
}));
},
getStatus: () => {
return wrap(apiFetch('/cosmos/api/status', {
method: 'GET',
+41 -42
View File
@@ -17,6 +17,33 @@ import (
var validTokenName = regexp.MustCompile(`^[a-zA-Z0-9_-]+$`)
// GenerateAPIToken creates a new API token with the given parameters and returns
// the raw token (to be shown once to the caller) and the config to store.
// The caller is responsible for persisting the config.
func GenerateAPIToken(name, description, owner string, permissions []utils.Permission) (string, utils.APITokenConfig, error) {
rawBytes := make([]byte, 32)
if _, err := rand.Read(rawBytes); err != nil {
return "", utils.APITokenConfig{}, err
}
rawToken := "cosmos_" + base64.RawURLEncoding.EncodeToString(rawBytes)
tokenSuffix := rawToken[len(rawToken)-5:]
h := sha256.Sum256([]byte(rawToken))
tokenHash := hex.EncodeToString(h[:])
tokenConfig := utils.APITokenConfig{
Name: name,
Description: description,
Owner: owner,
TokenHash: tokenHash,
TokenSuffix: tokenSuffix,
Permissions: permissions,
CreatedAt: time.Now(),
}
return rawToken, tokenConfig, nil
}
type CreateAPITokenRequest struct {
Name string `json:"name" validate:"required"`
Description string `json:"description,omitempty"`
@@ -129,20 +156,6 @@ func createAPIToken(w http.ResponseWriter, req *http.Request) {
return
}
// Generate raw token: "cosmos_" + base64url(32 random bytes)
rawBytes := make([]byte, 32)
if _, err := rand.Read(rawBytes); err != nil {
utils.Error("CreateAPIToken: Failed to generate random bytes", err)
utils.HTTPError(w, "Internal error", http.StatusInternalServerError, "AT012")
return
}
rawToken := "cosmos_" + base64.RawURLEncoding.EncodeToString(rawBytes)
tokenSuffix := rawToken[len(rawToken)-5:]
// Hash for storage
h := sha256.Sum256([]byte(rawToken))
tokenHash := hex.EncodeToString(h[:])
// Build permissions array
var permissions []utils.Permission
if len(request.Permissions) > 0 {
@@ -155,37 +168,23 @@ func createAPIToken(w http.ResponseWriter, req *http.Request) {
utils.PERM_CONFIGURATION_READ,
}
} else {
permissions = []utils.Permission{
utils.PERM_ADMIN_READ,
utils.PERM_ADMIN,
utils.PERM_USERS_READ,
utils.PERM_USERS,
utils.PERM_RESOURCES_READ,
utils.PERM_RESOURCES,
utils.PERM_CONFIGURATION_READ,
utils.PERM_CONFIGURATION,
utils.PERM_CREDENTIALS_READ,
}
permissions = utils.DefaultAdminTokenPermissions
}
owner := utils.GetAuthContext(req).Nickname
var expiresAt time.Time
if request.ExpiryDays > 0 {
expiresAt = time.Now().Add(time.Duration(request.ExpiryDays) * 24 * time.Hour)
rawToken, tokenConfig, err := GenerateAPIToken(request.Name, request.Description, owner, permissions)
if err != nil {
utils.Error("CreateAPIToken: Failed to generate token", err)
utils.HTTPError(w, "Internal error", http.StatusInternalServerError, "AT012")
return
}
tokenConfig := utils.APITokenConfig{
Name: request.Name,
Description: request.Description,
Owner: owner,
TokenHash: tokenHash,
TokenSuffix: tokenSuffix,
Permissions: permissions,
IPWhitelist: request.IPWhitelist,
RestrictToConstellation: request.RestrictToConstellation,
CreatedAt: time.Now(),
ExpiresAt: expiresAt,
// Set extra fields not handled by GenerateAPIToken
tokenConfig.IPWhitelist = request.IPWhitelist
tokenConfig.RestrictToConstellation = request.RestrictToConstellation
if request.ExpiryDays > 0 {
tokenConfig.ExpiresAt = time.Now().Add(time.Duration(request.ExpiryDays) * 24 * time.Hour)
}
utils.ConfigLock.Lock()
@@ -223,10 +222,10 @@ func createAPIToken(w http.ResponseWriter, req *http.Request) {
responseData := map[string]interface{}{
"token": rawToken,
"name": request.Name,
"tokenSuffix": tokenSuffix,
"tokenSuffix": tokenConfig.TokenSuffix,
}
if !expiresAt.IsZero() {
responseData["expiresAt"] = expiresAt
if !tokenConfig.ExpiresAt.IsZero() {
responseData["expiresAt"] = tokenConfig.ExpiresAt
}
json.NewEncoder(w).Encode(map[string]interface{}{
+62 -56
View File
@@ -1,9 +1,10 @@
package constellation
import (
"net/http"
"encoding/json"
"errors"
"io/ioutil"
"net/http"
"os"
"gopkg.in/yaml.v2"
@@ -156,6 +157,58 @@ func API_NewConstellation(w http.ResponseWriter, req *http.Request) {
}
}
// ConnectToExisting applies a Nebula YAML config to connect this node to an
// existing Constellation network. It returns the updated config. The caller
// is responsible for persisting the config and restarting Nebula.
func ConnectToExisting(yamlBody []byte, config utils.Config) (utils.Config, error) {
utils.Log("ConnectToExisting: connecting to an external Constellation")
config.ConstellationConfig.Enabled = true
var configMap map[string]interface{}
err := yaml.Unmarshal(yamlBody, &configMap)
if err != nil {
return config, err
}
configMap = setDefaultConstConfig(configMap)
configMapString, err := yaml.Marshal(configMap)
if err != nil {
return config, err
}
err = ioutil.WriteFile(utils.CONFIGFOLDER+"nebula.yml", configMapString, 0600)
if err != nil {
return config, err
}
if deviceNameVal, ok := configMap["cstln_device_name"]; ok {
config.ConstellationConfig.ThisDeviceName = deviceNameVal.(string)
} else {
return config, errors.New("device name not found in constellation config")
}
if publicHostnameVal, ok := configMap["cstln_public_hostname"]; ok {
config.ConstellationConfig.ConstellationHostname = publicHostnameVal.(string)
}
if licence, ok := configMap["cstln_server_licence"]; ok {
config.Licence = licence.(string)
}
if cosmosNode, ok := configMap["cstln_cosmos_node"]; ok {
config.AgentMode = cosmosNode.(int) == 1
}
if ipRange, ok := configMap["cstln_ip_range"]; ok {
config.ConstellationConfig.IPRange = ipRange.(string)
}
utils.Log("ConnectToExisting: connected to an external Constellation")
return config, nil
}
// API_ConnectToExisting godoc
// @Summary Connect this node to an existing Constellation VPN network
// @Tags constellation
@@ -176,69 +229,25 @@ func API_ConnectToExisting(w http.ResponseWriter, req *http.Request) {
utils.ConfigLock.Lock()
defer utils.ConfigLock.Unlock()
utils.Log("API_ConnectToExisting: connecting to an external Constellation")
body, err := ioutil.ReadAll(req.Body)
if err != nil {
utils.Error("API_Restart: Invalid User Request", err)
utils.HTTPError(w, "API_Restart Error",
utils.Error("API_ConnectToExisting: Invalid User Request", err)
utils.HTTPError(w, "API_ConnectToExisting Error",
http.StatusInternalServerError, "AR001")
return
return
}
config := utils.ReadConfigFromFile()
config.ConstellationConfig.Enabled = true
var configMap map[string]interface{}
err = yaml.Unmarshal(body, &configMap)
config, err = ConnectToExisting(body, config)
if err != nil {
utils.Error("API_ConnectToExisting: Invalid User Request", err)
utils.HTTPError(w, "API_ConnectToExisting Error",
utils.Error("API_ConnectToExisting: Error", err)
utils.HTTPError(w, "API_ConnectToExisting Error: "+err.Error(),
http.StatusInternalServerError, "ACE001")
return
}
configMap = setDefaultConstConfig(configMap)
configMapString, err := yaml.Marshal(configMap)
if err != nil {
utils.Error("API_ConnectToExisting: Invalid User Request", err)
utils.HTTPError(w, "API_ConnectToExisting Error",
http.StatusInternalServerError, "ACE002")
return
}
// output utils.CONFIGFOLDER + "nebula.yml"
err = ioutil.WriteFile(utils.CONFIGFOLDER + "nebula.yml", configMapString, 0600)
if deviceNameVal, ok := configMap["cstln_device_name"]; ok {
config.ConstellationConfig.ThisDeviceName = deviceNameVal.(string)
} else {
utils.Error("API_ConnectToExisting: device name not found in config", nil)
utils.HTTPError(w, "API_ConnectToExisting Error: device name not found in config",
http.StatusInternalServerError, "ACE003")
return
}
if publicHostnameVal, ok := configMap["cstln_public_hostname"]; ok {
config.ConstellationConfig.ConstellationHostname = publicHostnameVal.(string)
}
if licence, ok := configMap["cstln_server_licence"]; ok {
config.Licence = licence.(string)
}
if cosmosNode, ok := configMap["cstln_cosmos_node"]; ok {
config.AgentMode = cosmosNode.(int) == 1
}
if ipRange, ok := configMap["cstln_ip_range"]; ok {
config.ConstellationConfig.IPRange = ipRange.(string)
}
utils.SetBaseMainConfig(config)
utils.TriggerEvent(
"cosmos.settings",
"Settings updated",
@@ -247,14 +256,11 @@ func API_ConnectToExisting(w http.ResponseWriter, req *http.Request) {
map[string]interface{}{
"from": "Constellation",
})
utils.Log("API_ConnectToExisting: connected to an external Constellation")
json.NewEncoder(w).Encode(map[string]interface{}{
"status": "OK",
})
go func() {
RestartNebula()
utils.RestartHTTPServer()
+1
View File
@@ -611,6 +611,7 @@ func InitServer() *mux.Router {
srapiStrict.HandleFunc("/api/mfa", user.API2FA)
srapiStrict.HandleFunc("/api/register", user.UserRegister)
srapiStrict.HandleFunc("/api/newInstall", NewInstallRoute)
srapiStrict.HandleFunc("/api/setup", SetupRoute)
srapi.HandleFunc("/api/status", StatusRoute)
srapi.HandleFunc("/api/can-send-email", CanSendEmail)
srapi.HandleFunc("/api/logout", user.UserLogout)
+1 -1
View File
@@ -201,7 +201,7 @@ func main() {
}
// @title Cosmos Server API
// @version 0.22.0-unstable12
// @version 0.22.0-unstable13
// @description REST API for Cosmos Cloud server management
// @BasePath /cosmos
// @securityDefinitions.apikey BearerAuth
+251 -14
View File
@@ -1,20 +1,24 @@
package main
import (
"net/http"
"encoding/json"
"time"
"net/http"
"os"
"golang.org/x/crypto/bcrypt"
"time"
"github.com/azukaar/cosmos-server/src/utils"
"golang.org/x/crypto/bcrypt"
"github.com/azukaar/cosmos-server/src/configapi"
"github.com/azukaar/cosmos-server/src/constellation"
"github.com/azukaar/cosmos-server/src/docker"
"github.com/azukaar/cosmos-server/src/utils"
)
func waitForDB() {
time.Sleep(1 * time.Second)
err := utils.DB()
if err != nil {
utils.Debug("DB error: " + err.Error())
utils.Warn("DB Not ready yet")
waitForDB()
}
@@ -40,7 +44,7 @@ type NewInstallJSON struct {
type AdminJSON struct {
Nickname string `validate:"required,min=3,max=32,alphanum"`
Password string `validate:"required,min=9,max=128,containsany=~!@#$%^&*()_+=-{[}]:;"'<>.?/,containsany=ABCDEFGHIJKLMNOPQRSTUVWXYZ,containsany=abcdefghijklmnopqrstuvwxyz,containsany=0123456789"`
Password string `validate:"required,min=9,max=128,containsany=~!@#$%^&*()_+=-{[}]:;\"'<>.?/,containsany=ABCDEFGHIJKLMNOPQRSTUVWXYZ,containsany=abcdefghijklmnopqrstuvwxyz,containsany=0123456789"`
}
// NewInstallRoute godoc
@@ -67,9 +71,9 @@ func NewInstallRoute(w http.ResponseWriter, req *http.Request) {
err1 := json.NewDecoder(req.Body).Decode(&request)
if err1 != nil {
utils.Error("NewInstall: Invalid User Request", err1)
utils.HTTPError(w, "New Install: Invalid User Request" + err1.Error(),
utils.HTTPError(w, "New Install: Invalid User Request" + err1.Error(),
http.StatusInternalServerError, "NI001")
return
return
}
errV := utils.Validate.Struct(request)
@@ -77,7 +81,7 @@ func NewInstallRoute(w http.ResponseWriter, req *http.Request) {
utils.Error("NewInstall: Invalid User Request", errV)
utils.HTTPError(w, "New Install: Invalid User Request " + errV.Error(),
http.StatusInternalServerError, "NI001")
return
return
}
newConfig := utils.GetBaseMainConfig()
@@ -108,18 +112,20 @@ func NewInstallRoute(w http.ResponseWriter, req *http.Request) {
utils.Log("NewInstall: DB Provided")
newConfig.DisableUserManagement = false
newConfig.MongoDB = request.MongoDB
newConfig.Database.PuppetMode = false
utils.SaveConfigTofile(newConfig)
utils.LoadBaseMainConfig(newConfig)
} else if (request.MongoDBMode == "Create") {
utils.Log("NewInstall: Create DB")
newConfig.DisableUserManagement = false
newConfig.MongoDB = ""
strco, err := docker.NewDB(w, req)
if err != nil {
utils.Error("NewInstall: Error creating MongoDB", err)
return
}
return
}
newConfig.Database = strco
utils.SaveConfigTofile(newConfig)
utils.LoadBaseMainConfig(newConfig)
@@ -132,7 +138,7 @@ func NewInstallRoute(w http.ResponseWriter, req *http.Request) {
utils.Error("NewInstall: Invalid MongoDBMode", nil)
utils.HTTPError(w, "New Install: Invalid MongoDBMode",
http.StatusInternalServerError, "NI001")
return
return
}
} else if (request.Step == "3") {
// HTTPS Certificate Mode & Certs & Let's Encrypt
@@ -154,7 +160,7 @@ func NewInstallRoute(w http.ResponseWriter, req *http.Request) {
adminObj := AdminJSON{
Nickname: request.Nickname,
Password: request.Password,
}
}
errV2 := utils.Validate.Struct(adminObj)
if errV2 != nil {
@@ -221,4 +227,235 @@ func NewInstallRoute(w http.ResponseWriter, req *http.Request) {
utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001")
return
}
}
}
// noopResponseWriter discards all output — used to call docker.NewDB without streaming.
type noopResponseWriter struct {
header http.Header
}
func (n *noopResponseWriter) Header() http.Header { return n.header }
func (n *noopResponseWriter) Write(b []byte) (int, error) { return len(b), nil }
func (n *noopResponseWriter) WriteHeader(int) {}
func (n *noopResponseWriter) Flush() {}
type SetupJSON struct {
// Database
MongoDBMode string `json:"mongodbMode"`
MongoDB string `json:"mongodb"`
// HTTPS
Hostname string `json:"hostname"`
HTTPSCertificateMode string `json:"httpsCertificateMode"`
SSLEmail string `json:"sslEmail"`
UseWildcardCertificate bool `json:"useWildcardCertificate"`
DNSChallengeProvider string `json:"dnsChallengeProvider"`
DNSChallengeConfig map[string]string `json:"DNSChallengeConfig"`
TLSCert string `json:"tlsCert"`
TLSKey string `json:"tlsKey"`
AllowHTTPLocalIPAccess bool `json:"allowHTTPLocalIPAccess"`
// Admin
Nickname string `json:"nickname"`
Password string `json:"password"`
Email string `json:"email,omitempty"`
// Optional: clear config before setup
ClearConfig bool `json:"clearConfig,omitempty"`
// Optional: Constellation connect
ConstellationConfig string `json:"constellationConfig,omitempty"`
// Optional: create admin API token
CreateAdminToken bool `json:"createAdminToken,omitempty"`
}
// SetupRoute godoc
// @Summary One-shot server provisioning
// @Description Performs the entire initial setup in a single call: database, HTTPS, admin user, optional Constellation connect, and optional admin API token creation. Only available when the server is in NewInstall mode.
// @Tags system
// @Accept json
// @Produce json
// @Param request body SetupJSON true "Setup configuration"
// @Success 200 {object} utils.APIResponse
// @Failure 403 {object} utils.HTTPErrorResult
// @Failure 400 {object} utils.HTTPErrorResult
// @Failure 500 {object} utils.HTTPErrorResult
// @Router /api/setup [post]
func SetupRoute(w http.ResponseWriter, req *http.Request) {
if !utils.GetMainConfig().NewInstall {
utils.Error("Setup: not a new install", nil)
utils.HTTPError(w, "Server is already configured", http.StatusForbidden, "SU001")
return
}
if req.Method != "POST" {
utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001")
return
}
var request SetupJSON
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
utils.Error("Setup: Invalid request", err)
utils.HTTPError(w, "Invalid request: "+err.Error(), http.StatusBadRequest, "SU002")
return
}
// ── Step 0: Clear config (optional) ──────────────────────────────
if request.ClearConfig {
utils.Log("Setup: Clearing config")
configFile := utils.GetConfigFileName()
os.Remove(configFile)
if utils.IsInsideContainer {
os.RemoveAll("/config")
os.Mkdir("/config", 0700)
}
utils.DisconnectDB()
LoadConfig()
}
config := utils.GetBaseMainConfig()
// ── Step 1: Database ──────────────────────────────────────────────
if request.MongoDBMode == "" {
utils.HTTPError(w, "mongodbMode is required", http.StatusBadRequest, "SU003")
return
}
switch request.MongoDBMode {
case "DisableUserManagement":
utils.Log("Setup: Disable User Management")
config.DisableUserManagement = true
case "Provided":
utils.Log("Setup: DB Provided")
config.DisableUserManagement = false
config.MongoDB = request.MongoDB
config.Database.PuppetMode = false
case "Create":
utils.Log("Setup: Create DB")
config.DisableUserManagement = false
config.MongoDB = ""
noop := &noopResponseWriter{header: make(http.Header)}
dbConf, err := docker.NewDB(noop, req)
if err != nil {
utils.Error("Setup: Error creating MongoDB", err)
utils.HTTPError(w, "Error creating MongoDB: "+err.Error(), http.StatusInternalServerError, "SU004")
return
}
config.Database = dbConf
default:
utils.HTTPError(w, "Invalid mongodbMode", http.StatusBadRequest, "SU003")
return
}
utils.SaveConfigTofile(config)
utils.LoadBaseMainConfig(config)
if !config.DisableUserManagement {
waitForDB()
}
// ── Step 2: HTTPS ─────────────────────────────────────────────────
config.HTTPConfig.Hostname = request.Hostname
config.HTTPConfig.HTTPSCertificateMode = request.HTTPSCertificateMode
config.HTTPConfig.SSLEmail = request.SSLEmail
config.HTTPConfig.UseWildcardCertificate = request.UseWildcardCertificate
config.HTTPConfig.DNSChallengeProvider = request.DNSChallengeProvider
config.HTTPConfig.DNSChallengeConfig = request.DNSChallengeConfig
config.HTTPConfig.TLSCert = request.TLSCert
config.HTTPConfig.TLSKey = request.TLSKey
config.HTTPConfig.AllowHTTPLocalIPAccess = request.AllowHTTPLocalIPAccess
utils.SaveConfigTofile(config)
utils.LoadBaseMainConfig(config)
// ── Step 3: Admin User ────────────────────────────────────────────
if !config.DisableUserManagement {
adminObj := AdminJSON{
Nickname: request.Nickname,
Password: request.Password,
}
if errV := utils.Validate.Struct(adminObj); errV != nil {
utils.Error("Setup: Invalid admin credentials", errV)
utils.HTTPError(w, "Invalid admin credentials: "+errV.Error(), http.StatusBadRequest, "SU005")
return
}
c, closeDb, errCo := utils.GetEmbeddedCollection(utils.GetRootAppId(), "users")
defer closeDb()
if errCo != nil {
utils.Error("Setup: Database Connect", errCo)
utils.HTTPError(w, "Database error", http.StatusInternalServerError, "SU006")
return
}
nickname := utils.Sanitize(request.Nickname)
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(request.Password), 14)
if err != nil {
utils.Error("Setup: Error hashing password", err)
utils.HTTPError(w, "Error hashing password", http.StatusInternalServerError, "SU007")
return
}
c.DeleteMany(nil, map[string]interface{}{})
_, err = c.InsertOne(nil, map[string]interface{}{
"Nickname": nickname,
"Email": request.Email,
"Password": hashedPassword,
"Role": utils.ADMIN,
"PasswordCycle": 0,
"CreatedAt": time.Now(),
"RegisteredAt": time.Now(),
})
if err != nil {
utils.Error("Setup: Error creating admin user", err)
utils.HTTPError(w, "Error creating admin user: "+err.Error(), http.StatusInternalServerError, "SU008")
return
}
}
// ── Step 4: Constellation (optional) ──────────────────────────────
if request.ConstellationConfig != "" {
var err error
config, err = constellation.ConnectToExisting([]byte(request.ConstellationConfig), config)
if err != nil {
utils.Error("Setup: Constellation connect error", err)
utils.HTTPError(w, "Constellation error: "+err.Error(), http.StatusInternalServerError, "SU009")
return
}
utils.SaveConfigTofile(config)
utils.LoadBaseMainConfig(config)
}
// ── Step 5: Admin Token (optional) ────────────────────────────────
responseData := map[string]interface{}{}
if request.CreateAdminToken {
tokenName := "provisioning-token"
owner := utils.Sanitize(request.Nickname)
rawToken, tokenConfig, err := configapi.GenerateAPIToken(tokenName, "Auto-generated during setup", owner, utils.DefaultAdminTokenPermissions)
if err != nil {
utils.Error("Setup: Error generating token", err)
utils.HTTPError(w, "Error generating token", http.StatusInternalServerError, "SU010")
return
}
if config.APITokens == nil {
config.APITokens = make(map[string]utils.APITokenConfig)
}
config.APITokens[tokenName] = tokenConfig
responseData["adminToken"] = rawToken
responseData["adminTokenName"] = tokenName
}
// ── Finalize ──────────────────────────────────────────────────────
config.NewInstall = false
utils.SaveConfigTofile(config)
utils.LoadBaseMainConfig(config)
json.NewEncoder(w).Encode(map[string]interface{}{
"status": "OK",
"data": responseData,
})
}
+1 -1
View File
@@ -38,7 +38,7 @@ func RefreshUserToken(w http.ResponseWriter, req *http.Request) ([]utils.Permiss
// if new install
if config.NewInstall {
// check route
if req.URL.Path != "/cosmos/api/status" && req.URL.Path != "/cosmos/api/newInstall" && req.URL.Path != "/cosmos/api/dns" {
if req.URL.Path != "/cosmos/api/status" && req.URL.Path != "/cosmos/api/newInstall" && req.URL.Path != "/cosmos/api/dns" && req.URL.Path != "/cosmos/api/setup" {
json.NewEncoder(w).Encode(map[string]interface{}{
"status": "NEW_INSTALL",
})
+1 -1
View File
@@ -53,7 +53,7 @@ func DB() error {
if mongoURL == "" {
DBStatus = false
return errors.New("MongoDB URL is not set, cannot connect to the database.")
return errors.New("MongoDB URL is not set, cannot connect to the database. If you are in the setup, this is not an issue, please proceed with the setup.")
}
var err error
+12
View File
@@ -39,6 +39,18 @@ const (
PERM_LOGIN_WEAK Permission = 101 // Any logged-in user, no MFA check
)
var DefaultAdminTokenPermissions = []Permission{
PERM_ADMIN_READ,
PERM_ADMIN,
PERM_USERS_READ,
PERM_USERS,
PERM_RESOURCES_READ,
PERM_RESOURCES,
PERM_CONFIGURATION_READ,
PERM_CONFIGURATION,
PERM_CREDENTIALS_READ,
}
var PermissionLabels = map[Permission]string{
PERM_ADMIN_READ: "Admin Read (view logs)",
PERM_ADMIN: "Admin (system ops)",
@@ -19,6 +19,7 @@ import (
var (
_ resource.Resource = &backupResource{}
_ resource.ResourceWithImportState = &backupResource{}
_ resource.ResourceWithModifyPlan = &backupResource{}
)
// NewBackupResource returns a new resource.Resource for backup configurations.
@@ -46,7 +47,7 @@ func (r *backupResource) Metadata(_ context.Context, req resource.MetadataReques
func (r *backupResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "Manages a Cosmos Server backup configuration.",
Description: "Manages a Cosmos Server backup configuration. WARNING: destroying this resource permanently deletes all its snapshots. Use lifecycle { prevent_destroy = true } to protect against accidental deletion.",
Attributes: map[string]schema.Attribute{
"name": schema.StringAttribute{
Description: "The unique name of the backup configuration (used as the resource ID). Changing this forces re-creation.",
@@ -56,12 +57,18 @@ func (r *backupResource) Schema(_ context.Context, _ resource.SchemaRequest, res
},
},
"repository": schema.StringAttribute{
Description: "The repository path for storing backups.",
Description: "The repository path for storing backups. Changing this forces re-creation.",
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"source": schema.StringAttribute{
Description: "The source path to back up.",
Description: "The source path to back up. Changing this forces re-creation.",
Optional: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"crontab": schema.StringAttribute{
Description: "Cron schedule for running backups.",
@@ -263,6 +270,17 @@ func (r *backupResource) Delete(ctx context.Context, req resource.DeleteRequest,
}
}
func (r *backupResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
// If the plan is to destroy (plan state is null), warn about data loss.
if req.Plan.Raw.IsNull() {
resp.Diagnostics.AddWarning(
"Destroying this backup will permanently delete all its snapshots",
"The Cosmos backup delete endpoint removes all snapshots for this backup from the repository. "+
"This is irreversible. Use lifecycle { prevent_destroy = true } to protect against accidental deletion.",
)
}
}
func (r *backupResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
resource.ImportStatePassthroughID(ctx, path.Root("name"), req, resp)
}