Replace Go API with PocketBase; update docs
Remove the old Go/Mongo API (api/main.go, go.mod, go.sum, .env.example) and switch telemetry backend to PocketBase (http://db.community-scripts.org). Update documentation and flowcharts to reflect the PocketBase collection (_dev_telemetry_data), new REST endpoints (POST/PATCH/GET), field schema, and revised api.func integration (LXC/VM reporting and status updates). Misc scripts and helpers were adjusted (misc/api.func, misc/build.func, misc/error_handler.func) and a new misc/ingest.go was added. This consolidates telemetry to a hosted PocketBase instance and updates docs and integration points accordingly.
This commit is contained in:
parent
1eb0cc55ff
commit
820d4551a1
@ -1,5 +0,0 @@
|
||||
MONGO_USER=
|
||||
MONGO_PASSWORD=
|
||||
MONGO_IP=
|
||||
MONGO_PORT=
|
||||
MONGO_DATABASE=
|
||||
23
api/go.mod
23
api/go.mod
@ -1,23 +0,0 @@
|
||||
module proxmox-api
|
||||
|
||||
go 1.24.0
|
||||
|
||||
require (
|
||||
github.com/gorilla/mux v1.8.1
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/rs/cors v1.11.1
|
||||
go.mongodb.org/mongo-driver v1.17.2
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/klauspost/compress v1.16.7 // indirect
|
||||
github.com/montanaflynn/stats v0.7.1 // indirect
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||
github.com/xdg-go/scram v1.1.2 // indirect
|
||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||
golang.org/x/crypto v0.45.0 // indirect
|
||||
golang.org/x/sync v0.18.0 // indirect
|
||||
golang.org/x/text v0.31.0 // indirect
|
||||
)
|
||||
56
api/go.sum
56
api/go.sum
@ -1,56 +0,0 @@
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
|
||||
github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
|
||||
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
||||
github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA=
|
||||
github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
|
||||
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
|
||||
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
|
||||
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.mongodb.org/mongo-driver v1.17.2 h1:gvZyk8352qSfzyZ2UMWcpDpMSGEr1eqE4T793SqyhzM=
|
||||
go.mongodb.org/mongo-driver v1.17.2/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
|
||||
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
450
api/main.go
450
api/main.go
@ -1,450 +0,0 @@
|
||||
// Copyright (c) 2021-2025 community-scripts ORG
|
||||
// Author: Michel Roegl-Brunner (michelroegl-brunner)
|
||||
// License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/rs/cors"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
var client *mongo.Client
|
||||
var collection *mongo.Collection
|
||||
|
||||
func loadEnv() {
|
||||
if err := godotenv.Load(); err != nil {
|
||||
log.Fatal("Error loading .env file")
|
||||
}
|
||||
}
|
||||
|
||||
// DataModel represents a single document in MongoDB
|
||||
type DataModel struct {
|
||||
ID primitive.ObjectID `json:"id" bson:"_id,omitempty"`
|
||||
CT_TYPE uint `json:"ct_type" bson:"ct_type"`
|
||||
DISK_SIZE float32 `json:"disk_size" bson:"disk_size"`
|
||||
CORE_COUNT uint `json:"core_count" bson:"core_count"`
|
||||
RAM_SIZE uint `json:"ram_size" bson:"ram_size"`
|
||||
OS_TYPE string `json:"os_type" bson:"os_type"`
|
||||
OS_VERSION string `json:"os_version" bson:"os_version"`
|
||||
DISABLEIP6 string `json:"disableip6" bson:"disableip6"`
|
||||
NSAPP string `json:"nsapp" bson:"nsapp"`
|
||||
METHOD string `json:"method" bson:"method"`
|
||||
CreatedAt time.Time `json:"created_at" bson:"created_at"`
|
||||
PVEVERSION string `json:"pve_version" bson:"pve_version"`
|
||||
STATUS string `json:"status" bson:"status"`
|
||||
RANDOM_ID string `json:"random_id" bson:"random_id"`
|
||||
TYPE string `json:"type" bson:"type"`
|
||||
ERROR string `json:"error" bson:"error"`
|
||||
}
|
||||
|
||||
type StatusModel struct {
|
||||
RANDOM_ID string `json:"random_id" bson:"random_id"`
|
||||
ERROR string `json:"error" bson:"error"`
|
||||
STATUS string `json:"status" bson:"status"`
|
||||
}
|
||||
|
||||
type CountResponse struct {
|
||||
TotalEntries int64 `json:"total_entries"`
|
||||
StatusCount map[string]int64 `json:"status_count"`
|
||||
NSAPPCount map[string]int64 `json:"nsapp_count"`
|
||||
}
|
||||
|
||||
// ConnectDatabase initializes the MongoDB connection
|
||||
func ConnectDatabase() {
|
||||
loadEnv()
|
||||
|
||||
mongoURI := fmt.Sprintf("mongodb://%s:%s@%s:%s",
|
||||
os.Getenv("MONGO_USER"),
|
||||
os.Getenv("MONGO_PASSWORD"),
|
||||
os.Getenv("MONGO_IP"),
|
||||
os.Getenv("MONGO_PORT"))
|
||||
|
||||
database := os.Getenv("MONGO_DATABASE")
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
var err error
|
||||
client, err = mongo.Connect(ctx, options.Client().ApplyURI(mongoURI))
|
||||
if err != nil {
|
||||
log.Fatal("Failed to connect to MongoDB!", err)
|
||||
}
|
||||
collection = client.Database(database).Collection("data_models")
|
||||
fmt.Println("Connected to MongoDB on 10.10.10.18")
|
||||
}
|
||||
|
||||
// UploadJSON handles API requests and stores data as a document in MongoDB
|
||||
func UploadJSON(w http.ResponseWriter, r *http.Request) {
|
||||
var input DataModel
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
input.CreatedAt = time.Now()
|
||||
|
||||
_, err := collection.InsertOne(context.Background(), input)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
log.Println("Received data:", input)
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
json.NewEncoder(w).Encode(map[string]string{"message": "Data saved successfully"})
|
||||
}
|
||||
|
||||
// UpdateStatus updates the status of a record based on RANDOM_ID
|
||||
func UpdateStatus(w http.ResponseWriter, r *http.Request) {
|
||||
var input StatusModel
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
filter := bson.M{"random_id": input.RANDOM_ID}
|
||||
update := bson.M{"$set": bson.M{"status": input.STATUS, "error": input.ERROR}}
|
||||
|
||||
_, err := collection.UpdateOne(context.Background(), filter, update)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
log.Println("Updated data:", input)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(map[string]string{"message": "Record updated successfully"})
|
||||
}
|
||||
|
||||
// GetDataJSON fetches all data from MongoDB
|
||||
func GetDataJSON(w http.ResponseWriter, r *http.Request) {
|
||||
var records []DataModel
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
cursor, err := collection.Find(ctx, bson.M{})
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer cursor.Close(ctx)
|
||||
|
||||
for cursor.Next(ctx) {
|
||||
var record DataModel
|
||||
if err := cursor.Decode(&record); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
records = append(records, record)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(records)
|
||||
}
|
||||
func GetPaginatedData(w http.ResponseWriter, r *http.Request) {
|
||||
page, _ := strconv.Atoi(r.URL.Query().Get("page"))
|
||||
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if limit < 1 {
|
||||
limit = 10
|
||||
}
|
||||
skip := (page - 1) * limit
|
||||
var records []DataModel
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
options := options.Find().SetSkip(int64(skip)).SetLimit(int64(limit))
|
||||
cursor, err := collection.Find(ctx, bson.M{}, options)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer cursor.Close(ctx)
|
||||
|
||||
for cursor.Next(ctx) {
|
||||
var record DataModel
|
||||
if err := cursor.Decode(&record); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
records = append(records, record)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(records)
|
||||
}
|
||||
|
||||
func GetSummary(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
totalCount, err := collection.CountDocuments(ctx, bson.M{})
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
statusCount := make(map[string]int64)
|
||||
nsappCount := make(map[string]int64)
|
||||
|
||||
pipeline := []bson.M{
|
||||
{"$group": bson.M{"_id": "$status", "count": bson.M{"$sum": 1}}},
|
||||
}
|
||||
cursor, err := collection.Aggregate(ctx, pipeline)
|
||||
if err == nil {
|
||||
for cursor.Next(ctx) {
|
||||
var result struct {
|
||||
ID string `bson:"_id"`
|
||||
Count int64 `bson:"count"`
|
||||
}
|
||||
if err := cursor.Decode(&result); err == nil {
|
||||
statusCount[result.ID] = result.Count
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pipeline = []bson.M{
|
||||
{"$group": bson.M{"_id": "$nsapp", "count": bson.M{"$sum": 1}}},
|
||||
}
|
||||
cursor, err = collection.Aggregate(ctx, pipeline)
|
||||
if err == nil {
|
||||
for cursor.Next(ctx) {
|
||||
var result struct {
|
||||
ID string `bson:"_id"`
|
||||
Count int64 `bson:"count"`
|
||||
}
|
||||
if err := cursor.Decode(&result); err == nil {
|
||||
nsappCount[result.ID] = result.Count
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
response := CountResponse{
|
||||
TotalEntries: totalCount,
|
||||
StatusCount: statusCount,
|
||||
NSAPPCount: nsappCount,
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
func GetByNsapp(w http.ResponseWriter, r *http.Request) {
|
||||
nsapp := r.URL.Query().Get("nsapp")
|
||||
var records []DataModel
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
cursor, err := collection.Find(ctx, bson.M{"nsapp": nsapp})
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer cursor.Close(ctx)
|
||||
|
||||
for cursor.Next(ctx) {
|
||||
var record DataModel
|
||||
if err := cursor.Decode(&record); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
records = append(records, record)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(records)
|
||||
}
|
||||
|
||||
func GetByDateRange(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
startDate := r.URL.Query().Get("start_date")
|
||||
endDate := r.URL.Query().Get("end_date")
|
||||
|
||||
if startDate == "" || endDate == "" {
|
||||
http.Error(w, "Both start_date and end_date are required", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
start, err := time.Parse("2006-01-02T15:04:05.999999+00:00", startDate+"T00:00:00+00:00")
|
||||
if err != nil {
|
||||
http.Error(w, "Invalid start_date format", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
end, err := time.Parse("2006-01-02T15:04:05.999999+00:00", endDate+"T23:59:59+00:00")
|
||||
if err != nil {
|
||||
http.Error(w, "Invalid end_date format", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var records []DataModel
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
cursor, err := collection.Find(ctx, bson.M{
|
||||
"created_at": bson.M{
|
||||
"$gte": start,
|
||||
"$lte": end,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer cursor.Close(ctx)
|
||||
|
||||
for cursor.Next(ctx) {
|
||||
var record DataModel
|
||||
if err := cursor.Decode(&record); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
records = append(records, record)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(records)
|
||||
}
|
||||
func GetByStatus(w http.ResponseWriter, r *http.Request) {
|
||||
status := r.URL.Query().Get("status")
|
||||
var records []DataModel
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
cursor, err := collection.Find(ctx, bson.M{"status": status})
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer cursor.Close(ctx)
|
||||
|
||||
for cursor.Next(ctx) {
|
||||
var record DataModel
|
||||
if err := cursor.Decode(&record); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
records = append(records, record)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(records)
|
||||
}
|
||||
|
||||
func GetByOS(w http.ResponseWriter, r *http.Request) {
|
||||
osType := r.URL.Query().Get("os_type")
|
||||
osVersion := r.URL.Query().Get("os_version")
|
||||
var records []DataModel
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
cursor, err := collection.Find(ctx, bson.M{"os_type": osType, "os_version": osVersion})
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer cursor.Close(ctx)
|
||||
|
||||
for cursor.Next(ctx) {
|
||||
var record DataModel
|
||||
if err := cursor.Decode(&record); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
records = append(records, record)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(records)
|
||||
}
|
||||
|
||||
func GetErrors(w http.ResponseWriter, r *http.Request) {
|
||||
errorCount := make(map[string]int)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
cursor, err := collection.Find(ctx, bson.M{"error": bson.M{"$ne": ""}})
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer cursor.Close(ctx)
|
||||
|
||||
for cursor.Next(ctx) {
|
||||
var record DataModel
|
||||
if err := cursor.Decode(&record); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if record.ERROR != "" {
|
||||
errorCount[record.ERROR]++
|
||||
}
|
||||
}
|
||||
|
||||
type ErrorCountResponse struct {
|
||||
Error string `json:"error"`
|
||||
Count int `json:"count"`
|
||||
}
|
||||
|
||||
var errorCounts []ErrorCountResponse
|
||||
for err, count := range errorCount {
|
||||
errorCounts = append(errorCounts, ErrorCountResponse{
|
||||
Error: err,
|
||||
Count: count,
|
||||
})
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(struct {
|
||||
ErrorCounts []ErrorCountResponse `json:"error_counts"`
|
||||
}{
|
||||
ErrorCounts: errorCounts,
|
||||
})
|
||||
}
|
||||
|
||||
func main() {
|
||||
ConnectDatabase()
|
||||
|
||||
router := mux.NewRouter()
|
||||
router.HandleFunc("/upload", UploadJSON).Methods("POST")
|
||||
router.HandleFunc("/upload/updatestatus", UpdateStatus).Methods("POST")
|
||||
router.HandleFunc("/data/json", GetDataJSON).Methods("GET")
|
||||
router.HandleFunc("/data/paginated", GetPaginatedData).Methods("GET")
|
||||
router.HandleFunc("/data/summary", GetSummary).Methods("GET")
|
||||
router.HandleFunc("/data/nsapp", GetByNsapp).Methods("GET")
|
||||
router.HandleFunc("/data/date", GetByDateRange).Methods("GET")
|
||||
router.HandleFunc("/data/status", GetByStatus).Methods("GET")
|
||||
router.HandleFunc("/data/os", GetByOS).Methods("GET")
|
||||
router.HandleFunc("/data/errors", GetErrors).Methods("GET")
|
||||
|
||||
c := cors.New(cors.Options{
|
||||
AllowedOrigins: []string{"*"},
|
||||
AllowedMethods: []string{"GET", "POST"},
|
||||
AllowedHeaders: []string{"Content-Type", "Authorization"},
|
||||
AllowCredentials: true,
|
||||
})
|
||||
|
||||
handler := c.Handler(router)
|
||||
|
||||
fmt.Println("Server running on port 8080")
|
||||
log.Fatal(http.ListenAndServe(":8080", handler))
|
||||
}
|
||||
@ -1,38 +1,30 @@
|
||||
# API Integration Documentation (/api)
|
||||
|
||||
This directory contains comprehensive documentation for API integration and the `/api` directory.
|
||||
# API Integration Documentation
|
||||
|
||||
## Overview
|
||||
|
||||
The `/api` directory contains the Proxmox Community Scripts API backend for diagnostic reporting, telemetry, and analytics integration.
|
||||
The telemetry and diagnostics API uses **PocketBase** as backend, hosted at `http://db.community-scripts.org`. All telemetry data is stored in the `_dev_telemetry_data` collection.
|
||||
|
||||
The Go/MongoDB API server (`/api` directory) has been replaced entirely by PocketBase.
|
||||
|
||||
## Key Components
|
||||
|
||||
### Main API Service
|
||||
Located in `/api/main.go`:
|
||||
### PocketBase Backend
|
||||
- **URL**: `http://db.community-scripts.org`
|
||||
- **Collection**: `_dev_telemetry_data`
|
||||
- **Admin UI**: `http://db.community-scripts.org/_/#/collections`
|
||||
- RESTful API for receiving telemetry data
|
||||
- Installation statistics tracking
|
||||
- Error reporting and analytics
|
||||
- Performance monitoring
|
||||
|
||||
### Integration with Scripts
|
||||
The API is integrated into all installation scripts via `api.func`:
|
||||
- Sends installation start/completion events
|
||||
- Reports errors and exit codes
|
||||
- Reports errors and exit codes with numeric values
|
||||
- Collects anonymous usage statistics
|
||||
- Enables project analytics
|
||||
|
||||
## Documentation Structure
|
||||
|
||||
API documentation covers:
|
||||
- API endpoint specifications
|
||||
- Integration methods
|
||||
- Data formats and schemas
|
||||
- Error handling
|
||||
- Privacy and data handling
|
||||
|
||||
## Key Resources
|
||||
|
||||
- **[misc/api.func/](../misc/api.func/)** - API function library documentation
|
||||
- **[misc/api.func/README.md](../misc/api.func/README.md)** - Quick reference
|
||||
- **[misc/api.func/API_FUNCTIONS_REFERENCE.md](../misc/api.func/API_FUNCTIONS_REFERENCE.md)** - Complete function reference
|
||||
@ -42,48 +34,92 @@ API documentation covers:
|
||||
The `api.func` library provides:
|
||||
|
||||
### `post_to_api()`
|
||||
Send container installation data to API.
|
||||
Send LXC container installation data to PocketBase.
|
||||
|
||||
**Usage**:
|
||||
```bash
|
||||
post_to_api CTID STATUS APP_NAME
|
||||
```
|
||||
Creates a new record in `_dev_telemetry_data` with status `installing`.
|
||||
|
||||
### `post_update_to_api()`
|
||||
Report application update status.
|
||||
### `post_to_api_vm()`
|
||||
Send VM installation data to PocketBase.
|
||||
|
||||
**Usage**:
|
||||
```bash
|
||||
post_update_to_api CTID APP_NAME VERSION
|
||||
```
|
||||
Creates a new record with `type=vm` and `ct_type=2`.
|
||||
|
||||
### `get_error_description()`
|
||||
### `post_update_to_api(status, exit_code)`
|
||||
Update installation status via PocketBase PATCH.
|
||||
|
||||
Maps status values:
|
||||
- `"done"` → PocketBase status `"sucess"`
|
||||
- `"failed"` → PocketBase status `"failed"`
|
||||
|
||||
### `explain_exit_code(code)`
|
||||
Get human-readable error description from exit code.
|
||||
|
||||
**Usage**:
|
||||
```bash
|
||||
ERROR_DESC=$(get_error_description EXIT_CODE)
|
||||
ERROR_DESC=$(explain_exit_code 137)
|
||||
# → "Killed (SIGKILL / Out of memory?)"
|
||||
```
|
||||
|
||||
## PocketBase Collection Schema
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `id` | text (auto) | yes | PocketBase record ID |
|
||||
| `random_id` | text | yes | Session UUID (unique) |
|
||||
| `type` | select | yes | `lxc`, `vm`, `addon`, `pve` |
|
||||
| `ct_type` | number | yes | 1=LXC, 2=VM |
|
||||
| `nsapp` | text | yes | Application name |
|
||||
| `status` | select | yes | `installing`, `sucess`, `failed`, `unknown` |
|
||||
| `disk_size` | number | no | Disk size in GB |
|
||||
| `core_count` | number | no | CPU cores |
|
||||
| `ram_size` | number | no | RAM in MB |
|
||||
| `os_type` | text | no | OS type (debian, ubuntu, etc.) |
|
||||
| `os_version` | text | no | OS version |
|
||||
| `pve_version` | text | no | Proxmox VE version |
|
||||
| `method` | text | no | Installation method |
|
||||
| `error` | text | no | Error description |
|
||||
| `exit_code` | number | no | Numeric exit code |
|
||||
| `created` | autodate | auto | Record creation timestamp |
|
||||
| `updated` | autodate | auto | Last update timestamp |
|
||||
|
||||
## API Endpoints (PocketBase REST)
|
||||
|
||||
**Base URL**: `http://db.community-scripts.org`
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `POST` | `/api/collections/_dev_telemetry_data/records` | Create telemetry record |
|
||||
| `PATCH` | `/api/collections/_dev_telemetry_data/records/{id}` | Update record status |
|
||||
| `GET` | `/api/collections/_dev_telemetry_data/records` | List/search records |
|
||||
|
||||
### Query Parameters (GET)
|
||||
- `filter` – PocketBase filter syntax, e.g. `(nsapp='debian' && status='failed')`
|
||||
- `sort` – Sort fields, e.g. `-created,nsapp`
|
||||
- `page` / `perPage` – Pagination
|
||||
- `fields` – Limit returned fields
|
||||
|
||||
## API Integration Points
|
||||
|
||||
### In Container Creation (`ct/AppName.sh`)
|
||||
- Called by build.func to report container creation
|
||||
- Sends initial container setup data
|
||||
- Reports success or failure
|
||||
- Called by `build.func` to report container creation via `post_to_api`
|
||||
- Sends initial container setup data with status `installing`
|
||||
- Reports success or failure via `post_update_to_api`
|
||||
|
||||
### In Installation Scripts (`install/appname-install.sh`)
|
||||
- Called at start of installation
|
||||
- Called on installation completion
|
||||
- Called on error conditions
|
||||
### In VM Creation (`vm/AppName.sh`)
|
||||
- Calls `post_to_api_vm` after VM creation
|
||||
- Status updates via `post_update_to_api`
|
||||
|
||||
### Data Collected
|
||||
- Container/VM ID
|
||||
- Application name and version
|
||||
- Installation duration
|
||||
- Success/failure status
|
||||
- Error codes (if failure)
|
||||
- Anonymous usage metrics
|
||||
### Data Flow
|
||||
```
|
||||
Installation Scripts
|
||||
│
|
||||
├─ Call: api.func functions
|
||||
│
|
||||
├─ POST → PocketBase (create record, status=installing)
|
||||
│ └─ Returns record ID (stored in PB_RECORD_ID)
|
||||
│
|
||||
└─ PATCH → PocketBase (update record with final status)
|
||||
└─ status=sucess/failed + exit_code + error
|
||||
```
|
||||
|
||||
## Privacy
|
||||
|
||||
@ -92,55 +128,18 @@ All API data:
|
||||
- ✅ Aggregated for statistics
|
||||
- ✅ Used only for project improvement
|
||||
- ✅ No tracking of user identities
|
||||
- ✅ Can be disabled if desired
|
||||
|
||||
## API Architecture
|
||||
|
||||
```
|
||||
Installation Scripts
|
||||
│
|
||||
├─ Call: api.func functions
|
||||
│
|
||||
└─ POST to: https://api.community-scripts.org
|
||||
│
|
||||
├─ Receives data
|
||||
├─ Validates format
|
||||
├─ Stores metrics
|
||||
└─ Aggregates statistics
|
||||
│
|
||||
└─ Used for:
|
||||
├─ Download tracking
|
||||
├─ Error trending
|
||||
├─ Feature usage stats
|
||||
└─ Project health monitoring
|
||||
```
|
||||
|
||||
## Common API Tasks
|
||||
|
||||
- **Enable API reporting** → Built-in by default, no configuration needed
|
||||
- **Disable API** → Set `api_disable="yes"` before running
|
||||
- **View API data** → Visit https://community-scripts.org/stats
|
||||
- **Report API errors** → [GitHub Issues](https://github.com/community-scripts/ProxmoxVED/issues)
|
||||
- ✅ Can be disabled via diagnostics settings
|
||||
|
||||
## Debugging API Issues
|
||||
|
||||
If API calls fail:
|
||||
1. Check internet connectivity
|
||||
2. Verify API endpoint availability
|
||||
2. Verify PocketBase endpoint: `curl -s http://db.community-scripts.org/api/health`
|
||||
3. Review error codes in [EXIT_CODES.md](../EXIT_CODES.md)
|
||||
4. Check API function logs
|
||||
5. Report issues on GitHub
|
||||
|
||||
## API Endpoint
|
||||
|
||||
**Base URL**: `https://api.community-scripts.org`
|
||||
|
||||
**Endpoints**:
|
||||
- `POST /install` - Report container installation
|
||||
- `POST /update` - Report application update
|
||||
- `GET /stats` - Public statistics
|
||||
4. Check that `DIAGNOSTICS=yes` in `/usr/local/community-scripts/diagnostics`
|
||||
5. Report issues on [GitHub](https://git.community-scripts.org/community-scripts/ProxmoxVED/issues)
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: December 2025
|
||||
**Last Updated**: February 2026
|
||||
**Maintainers**: community-scripts team
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
# api.func Execution Flowchart
|
||||
|
||||
## Overview
|
||||
|
||||
This document illustrates the execution flow of `api.func` functions. The backend is **PocketBase** at `http://db.community-scripts.org`, collection `_dev_telemetry_data`.
|
||||
|
||||
## Main API Communication Flow
|
||||
|
||||
```
|
||||
@ -12,331 +16,319 @@
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Prerequisites Check │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ Prerequisites Validation │ │
|
||||
│ │ │ │
|
||||
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────┐ │ │
|
||||
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌──────────────────┐ │ │
|
||||
│ │ │ Check curl │ │ Check │ │ Check │ │ │
|
||||
│ │ │ Availability │ │ Diagnostics │ │ Random UUID │ │ │
|
||||
│ │ │ │ │ Setting │ │ │ │
|
||||
│ │ │ • command -v │ │ • DIAGNOSTICS │ │ • RANDOM_UUID │ │
|
||||
│ │ │ curl │ │ = "yes" │ │ not empty │ │
|
||||
│ │ │ • Return if │ │ • Return if │ │ • Return if │ │
|
||||
│ │ │ not found │ │ disabled │ │ not set │ │
|
||||
│ │ │ │ │ │ │ │ │
|
||||
│ │ └─────────────────┘ └─────────────────┘ └─────────────────────┘ │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────────────┘ │
|
||||
│ │ │ Availability │ │ DIAGNOSTICS │ │ RANDOM_UUID │ │ │
|
||||
│ │ │ │ │ │ │ │ │ │
|
||||
│ │ │ • command -v │ │ • Must be "yes" │ │ • Must not be │ │ │
|
||||
│ │ │ curl │ │ • Return if │ │ empty │ │ │
|
||||
│ │ │ • Return if │ │ "no" or unset │ │ • Return if │ │ │
|
||||
│ │ │ not found │ │ │ │ not set │ │ │
|
||||
│ │ └─────────────────┘ └─────────────────┘ └──────────────────┘ │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Data Collection │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ System Information Gathering │ │
|
||||
│ │ │ │
|
||||
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────┐ │ │
|
||||
│ │ │ Get PVE │ │ Collect │ │ Prepare JSON │ │ │
|
||||
│ │ │ Version │ │ Environment │ │ Payload │ │
|
||||
│ │ │ │ │ Variables │ │ │ │
|
||||
│ │ │ • pveversion │ │ • CT_TYPE │ │ • Create JSON │ │
|
||||
│ │ │ command │ │ • DISK_SIZE │ │ structure │ │
|
||||
│ │ │ • Parse version │ │ • CORE_COUNT │ │ • Include all │ │
|
||||
│ │ │ • Extract │ │ • RAM_SIZE │ │ variables │ │
|
||||
│ │ │ major.minor │ │ • var_os │ │ • Format for API │ │
|
||||
│ │ │ │ │ • var_version │ │ │ │
|
||||
│ │ │ │ │ • NSAPP │ │ │ │
|
||||
│ │ │ │ │ • METHOD │ │ │ │
|
||||
│ │ └─────────────────┘ └─────────────────┘ └─────────────────────┘ │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────────────┘ │
|
||||
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌──────────────────┐ │ │
|
||||
│ │ │ Get PVE │ │ Collect Env │ │ Build JSON │ │ │
|
||||
│ │ │ Version │ │ Variables │ │ Payload │ │ │
|
||||
│ │ │ │ │ │ │ │ │ │
|
||||
│ │ │ • pveversion │ │ • CT_TYPE │ │ • Heredoc JSON │ │ │
|
||||
│ │ │ command │ │ • DISK_SIZE │ │ • Include all │ │ │
|
||||
│ │ │ • Parse version │ │ • CORE_COUNT │ │ fields │ │ │
|
||||
│ │ │ • Fallback: │ │ • RAM_SIZE │ │ • status = │ │ │
|
||||
│ │ │ "not found" │ │ • var_os │ │ "installing" │ │ │
|
||||
│ │ │ │ │ • NSAPP, METHOD │ │ │ │ │
|
||||
│ │ └─────────────────┘ └─────────────────┘ └──────────────────┘ │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ API Request Execution │
|
||||
│ PocketBase API Request │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ HTTP Request Processing │ │
|
||||
│ │ │ │
|
||||
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────┐ │ │
|
||||
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌──────────────────┐ │ │
|
||||
│ │ │ Prepare │ │ Execute │ │ Handle │ │ │
|
||||
│ │ │ Request │ │ HTTP Request │ │ Response │ │
|
||||
│ │ │ │ │ │ │ │ │
|
||||
│ │ │ • Set API URL │ │ • curl -s -w │ │ • Capture HTTP │ │
|
||||
│ │ │ • Set headers │ │ "%{http_code}" │ │ status code │ │
|
||||
│ │ │ • Set payload │ │ • POST request │ │ • Store response │ │
|
||||
│ │ │ • Content-Type │ │ • JSON data │ │ • Handle errors │ │
|
||||
│ │ │ application/ │ │ • Follow │ │ gracefully │ │
|
||||
│ │ │ json │ │ redirects │ │ │ │
|
||||
│ │ └─────────────────┘ └─────────────────┘ └─────────────────────┘ │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────────────┘ │
|
||||
│ │ │ Request │ │ HTTP POST │ │ Response │ │ │
|
||||
│ │ │ │ │ │ │ │ │ │
|
||||
│ │ │ • URL: │ │ • curl -s -w │ │ • Check HTTP │ │ │
|
||||
│ │ │ PB_API_URL │ │ "%{http_code}"│ │ 200/201 │ │ │
|
||||
│ │ │ • Method: POST │ │ • -X POST │ │ • Extract "id" │ │ │
|
||||
│ │ │ • Content-Type: │ │ • -L (follow │ │ from response │ │ │
|
||||
│ │ │ application/ │ │ redirects) │ │ • Store in │ │ │
|
||||
│ │ │ json │ │ • JSON body │ │ PB_RECORD_ID │ │ │
|
||||
│ │ └─────────────────┘ └─────────────────┘ └──────────────────┘ │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## LXC API Reporting Flow
|
||||
## LXC API Reporting Flow — `post_to_api()`
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ POST_TO_API() Flow │
|
||||
│ Send LXC container installation data to API │
|
||||
│ post_to_api() Flow │
|
||||
│ POST → Create LXC telemetry record in PocketBase │
|
||||
└─────────────────────┬───────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Prerequisites: curl? ──► DIAGNOSTICS="yes"? ──► RANDOM_UUID set? │
|
||||
│ (return silently on any failure) │
|
||||
└─────────────────────┬───────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ LXC Data Preparation │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ LXC-Specific Data Collection │ │
|
||||
│ │ │ │
|
||||
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────┐ │ │
|
||||
│ │ │ Set LXC │ │ Include LXC │ │ Set Status │ │ │
|
||||
│ │ │ Type │ │ Variables │ │ Information │ │
|
||||
│ │ │ │ │ │ │ │ │
|
||||
│ │ │ • ct_type: 1 │ │ • DISK_SIZE │ │ • status: │ │
|
||||
│ │ │ • type: "lxc" │ │ • CORE_COUNT │ │ "installing" │ │
|
||||
│ │ │ • Include all │ │ • RAM_SIZE │ │ • Include all │ │
|
||||
│ │ │ LXC data │ │ • var_os │ │ tracking data │ │
|
||||
│ │ │ │ │ • var_version │ │ │ │
|
||||
│ │ │ │ │ • DISABLEIP6 │ │ │ │
|
||||
│ │ │ │ │ • NSAPP │ │ │ │
|
||||
│ │ │ │ │ • METHOD │ │ │ │
|
||||
│ │ │ │ │ • pve_version │ │ │ │
|
||||
│ │ │ │ │ • random_id │ │ │ │
|
||||
│ │ └─────────────────┘ └─────────────────┘ └─────────────────────┘ │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────────────────┘
|
||||
│ ┌─────────────────┐ ┌─────────────────────┐ ┌───────────────────┐ │
|
||||
│ │ Set LXC type │ │ Collect variables │ │ Set initial │ │
|
||||
│ │ │ │ │ │ status │ │
|
||||
│ │ • ct_type: 1 │ │ • DISK_SIZE │ │ │ │
|
||||
│ │ • type: "lxc" │ │ • CORE_COUNT │ │ • status: │ │
|
||||
│ │ │ │ • RAM_SIZE │ │ "installing" │ │
|
||||
│ │ │ │ • var_os, var_version│ │ • random_id: │ │
|
||||
│ │ │ │ • NSAPP, METHOD │ │ RANDOM_UUID │ │
|
||||
│ │ │ │ • pve_version │ │ │ │
|
||||
│ └─────────────────┘ └─────────────────────┘ └───────────────────┘ │
|
||||
└─────────────────────┬───────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ JSON Payload Creation │
|
||||
│ POST → PB_API_URL │
|
||||
│ http://db.community-scripts.org/api/collections/_dev_telemetry_data/records │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ JSON Structure Generation │ │
|
||||
│ │ │ │
|
||||
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────┐ │ │
|
||||
│ │ │ Create JSON │ │ Validate │ │ Format for │ │ │
|
||||
│ │ │ Structure │ │ Data │ │ API Request │ │
|
||||
│ │ │ │ │ │ │ │ │
|
||||
│ │ │ • Use heredoc │ │ • Check all │ │ • Ensure proper │ │
|
||||
│ │ │ syntax │ │ variables │ │ JSON format │ │
|
||||
│ │ │ • Include all │ │ are set │ │ • Escape special │ │
|
||||
│ │ │ required │ │ • Validate │ │ characters │ │
|
||||
│ │ │ fields │ │ data types │ │ • Set content │ │
|
||||
│ │ │ • Format │ │ • Handle │ │ type │ │
|
||||
│ │ │ properly │ │ missing │ │ │ │
|
||||
│ │ │ │ │ values │ │ │ │
|
||||
│ │ └─────────────────┘ └─────────────────┘ └─────────────────────┘ │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────────────┘ │
|
||||
│ Response (HTTP 200/201): │
|
||||
│ { "id": "abc123def456789", ... } │
|
||||
│ │ │
|
||||
│ └──► PB_RECORD_ID = "abc123def456789" │
|
||||
└─────────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## VM API Reporting Flow
|
||||
## VM API Reporting Flow — `post_to_api_vm()`
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ POST_TO_API_VM() Flow │
|
||||
│ Send VM installation data to API │
|
||||
│ post_to_api_vm() Flow │
|
||||
│ POST → Create VM telemetry record in PocketBase │
|
||||
└─────────────────────┬───────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Read /usr/local/community-scripts/diagnostics │
|
||||
│ Extract DIAGNOSTICS=yes/no from file │
|
||||
└─────────────────────┬───────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Prerequisites: curl? ──► DIAGNOSTICS="yes"? ──► RANDOM_UUID set? │
|
||||
│ (return silently on any failure) │
|
||||
└─────────────────────┬───────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ VM Data Preparation │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ VM-Specific Data Collection │ │
|
||||
│ │ │ │
|
||||
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────┐ │ │
|
||||
│ │ │ Check │ │ Set VM │ │ Process Disk │ │ │
|
||||
│ │ │ Diagnostics │ │ Type │ │ Size │ │
|
||||
│ │ │ File │ │ │ │ │ │
|
||||
│ │ │ │ │ • ct_type: 2 │ │ • Remove 'G' │ │
|
||||
│ │ │ • Check file │ │ • type: "vm" │ │ suffix │ │
|
||||
│ │ │ existence │ │ • Include all │ │ • Convert to │ │
|
||||
│ │ │ • Read │ │ VM data │ │ numeric value │ │
|
||||
│ │ │ DIAGNOSTICS │ │ │ │ • Store in │ │
|
||||
│ │ │ setting │ │ │ │ DISK_SIZE_API │ │
|
||||
│ │ │ • Parse value │ │ │ │ │ │
|
||||
│ │ └─────────────────┘ └─────────────────┘ └─────────────────────┘ │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ VM JSON Payload Creation │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ VM-Specific JSON Structure │ │
|
||||
│ │ │ │
|
||||
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────┐ │ │
|
||||
│ │ │ Include VM │ │ Set VM │ │ Format VM │ │ │
|
||||
│ │ │ Variables │ │ Status │ │ Data for API │ │
|
||||
│ │ │ │ │ │ │ │ │
|
||||
│ │ │ • DISK_SIZE_API │ │ • status: │ │ • Ensure proper │ │
|
||||
│ │ │ • CORE_COUNT │ │ "installing" │ │ JSON format │ │
|
||||
│ │ │ • RAM_SIZE │ │ • Include all │ │ • Handle VM- │ │
|
||||
│ │ │ • var_os │ │ tracking │ │ specific data │ │
|
||||
│ │ │ • var_version │ │ information │ │ • Set appropriate │ │
|
||||
│ │ │ • NSAPP │ │ │ │ content type │ │
|
||||
│ │ │ • METHOD │ │ │ │ │ │
|
||||
│ │ │ • pve_version │ │ │ │ │ │
|
||||
│ │ │ • random_id │ │ │ │ │ │
|
||||
│ │ └─────────────────┘ └─────────────────┘ └─────────────────────┘ │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Status Update Flow
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ POST_UPDATE_TO_API() Flow │
|
||||
│ Send installation completion status to API │
|
||||
│ ┌─────────────────┐ ┌─────────────────────┐ ┌───────────────────┐ │
|
||||
│ │ Set VM type │ │ Process disk size │ │ Set initial │ │
|
||||
│ │ │ │ │ │ status │ │
|
||||
│ │ • ct_type: 2 │ │ • Strip 'G' suffix │ │ │ │
|
||||
│ │ • type: "vm" │ │ "20G" → 20 │ │ • status: │ │
|
||||
│ │ │ │ • Store in │ │ "installing" │ │
|
||||
│ │ │ │ DISK_SIZE_API │ │ • random_id: │ │
|
||||
│ │ │ │ │ │ RANDOM_UUID │ │
|
||||
│ └─────────────────┘ └─────────────────────┘ └───────────────────┘ │
|
||||
└─────────────────────┬───────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Update Prevention Check │
|
||||
│ POST → PB_API_URL │
|
||||
│ http://db.community-scripts.org/api/collections/_dev_telemetry_data/records │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ Duplicate Update Prevention │ │
|
||||
│ │ │ │
|
||||
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────┐ │ │
|
||||
│ │ │ Check │ │ Set Flag │ │ Return Early │ │ │
|
||||
│ │ │ POST_UPDATE_ │ │ if First │ │ if Already │ │
|
||||
│ │ │ DONE │ │ Update │ │ Updated │ │
|
||||
│ │ │ │ │ │ │ │ │
|
||||
│ │ │ • Check if │ │ • Set │ │ • Return 0 │ │
|
||||
│ │ │ already │ │ POST_UPDATE_ │ │ • Skip API call │ │
|
||||
│ │ │ updated │ │ DONE=true │ │ • Prevent │ │
|
||||
│ │ │ • Prevent │ │ • Continue │ │ duplicate │ │
|
||||
│ │ │ duplicate │ │ with update │ │ requests │ │
|
||||
│ │ │ requests │ │ │ │ │ │
|
||||
│ │ └─────────────────┘ └─────────────────┘ └─────────────────────┘ │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Status and Error Processing │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ Status Determination │ │
|
||||
│ │ │ │
|
||||
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────┐ │ │
|
||||
│ │ │ Determine │ │ Get Error │ │ Prepare Status │ │ │
|
||||
│ │ │ Status │ │ Description │ │ Data │ │
|
||||
│ │ │ │ │ │ │ │ │
|
||||
│ │ │ • status: │ │ • Call │ │ • Include status │ │
|
||||
│ │ │ "success" or │ │ get_error_ │ │ • Include error │ │
|
||||
│ │ │ "failed" │ │ description() │ │ description │ │
|
||||
│ │ │ • Set exit │ │ • Get human- │ │ • Include random │ │
|
||||
│ │ │ code based │ │ readable │ │ ID for tracking │ │
|
||||
│ │ │ on status │ │ error message │ │ │ │
|
||||
│ │ │ • Default to │ │ • Handle │ │ │ │
|
||||
│ │ │ error if │ │ unknown │ │ │ │
|
||||
│ │ │ not set │ │ errors │ │ │ │
|
||||
│ │ └─────────────────┘ └─────────────────┘ └─────────────────────┘ │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Status Update API Request │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ Status Update Payload Creation │ │
|
||||
│ │ │ │
|
||||
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────┐ │ │
|
||||
│ │ │ Create │ │ Send Status │ │ Mark Update │ │ │
|
||||
│ │ │ Status JSON │ │ Update │ │ Complete │ │
|
||||
│ │ │ │ │ │ │ │ │
|
||||
│ │ │ • Include │ │ • POST to │ │ • Set │ │
|
||||
│ │ │ status │ │ updatestatus │ │ POST_UPDATE_ │ │
|
||||
│ │ │ • Include │ │ endpoint │ │ DONE=true │ │
|
||||
│ │ │ error │ │ • Include JSON │ │ • Prevent further │ │
|
||||
│ │ │ description │ │ payload │ │ updates │ │
|
||||
│ │ │ • Include │ │ • Handle │ │ • Complete │ │
|
||||
│ │ │ random_id │ │ response │ │ process │ │
|
||||
│ │ │ │ │ gracefully │ │ │ │
|
||||
│ │ └─────────────────┘ └─────────────────┘ └─────────────────────┘ │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────────────┘ │
|
||||
│ Response (HTTP 200/201): │
|
||||
│ { "id": "xyz789abc012345", ... } │
|
||||
│ │ │
|
||||
│ └──► PB_RECORD_ID = "xyz789abc012345" │
|
||||
└─────────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Error Description Flow
|
||||
## Status Update Flow — `post_update_to_api()`
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ GET_ERROR_DESCRIPTION() Flow │
|
||||
│ Convert numeric exit codes to human-readable explanations │
|
||||
│ post_update_to_api(status, exit_code) Flow │
|
||||
│ PATCH → Update existing PocketBase record with final status │
|
||||
└─────────────────────┬───────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Error Code Classification │
|
||||
│ Duplicate Prevention Check │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ Error Code Categories │ │
|
||||
│ │ │ │
|
||||
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────┐ │ │
|
||||
│ │ │ General │ │ Network │ │ LXC-Specific │ │ │
|
||||
│ │ │ System │ │ Errors │ │ Errors │ │
|
||||
│ │ │ Errors │ │ │ │ │ │
|
||||
│ │ │ │ │ • 18: Connection│ │ • 100-101: LXC │ │
|
||||
│ │ │ • 0-9: Basic │ │ failed │ │ install errors │ │
|
||||
│ │ │ errors │ │ • 22: Invalid │ │ • 200-209: LXC │ │
|
||||
│ │ │ • 126-128: │ │ argument │ │ creation errors │ │
|
||||
│ │ │ Command │ │ • 28: No space │ │ │ │
|
||||
│ │ │ errors │ │ • 35: Timeout │ │ │ │
|
||||
│ │ │ • 129-143: │ │ • 56: TLS error │ │ │ │
|
||||
│ │ │ Signal │ │ • 60: SSL cert │ │ │ │
|
||||
│ │ │ errors │ │ error │ │ │ │
|
||||
│ │ │ • 152: Resource │ │ │ │ │ │
|
||||
│ │ │ limit │ │ │ │ │ │
|
||||
│ │ │ • 255: Unknown │ │ │ │ │ │
|
||||
│ │ │ critical │ │ │ │ │ │
|
||||
│ │ └─────────────────┘ └─────────────────┘ └─────────────────────┘ │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────────────────┘
|
||||
│ ┌─────────────────┐ ┌──────────────────────────────────────────────┐ │
|
||||
│ │ Check │ │ POST_UPDATE_DONE == "true"? │ │
|
||||
│ │ POST_UPDATE_ │───►│ │ │
|
||||
│ │ DONE flag │ │ YES → return 0 (skip PATCH) │ │
|
||||
│ │ │ │ NO → continue │ │
|
||||
│ └─────────────────┘ └──────────────────────────────────────────────┘ │
|
||||
└─────────────────────┬───────────────────────────────────────────────────────────┘
|
||||
│ (first call only)
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Prerequisites: curl? ──► DIAGNOSTICS="yes"? ──► RANDOM_UUID set? │
|
||||
└─────────────────────┬───────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Error Message Return │
|
||||
│ Status Mapping │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ Error Message Formatting │ │
|
||||
│ │ │ │
|
||||
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────┐ │ │
|
||||
│ │ │ Match Error │ │ Return │ │ Default Case │ │ │
|
||||
│ │ │ Code │ │ Description │ │ │ │
|
||||
│ │ │ │ │ │ │ │ │
|
||||
│ │ │ • Use case │ │ • Return │ │ • Return "Unknown │ │
|
||||
│ │ │ statement │ │ human- │ │ error code │ │
|
||||
│ │ │ • Match │ │ readable │ │ (exit_code)" │ │
|
||||
│ │ │ specific │ │ message │ │ • Handle │ │
|
||||
│ │ │ codes │ │ • Include │ │ unrecognized │ │
|
||||
│ │ │ • Handle │ │ context │ │ codes │ │
|
||||
│ │ │ ranges │ │ information │ │ • Provide fallback │ │
|
||||
│ │ │ │ │ │ │ message │ │
|
||||
│ │ └─────────────────┘ └─────────────────┘ └─────────────────────┘ │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────────────┘ │
|
||||
│ Input $1 │ PocketBase status │ exit_code │ error │
|
||||
│ ─────────────────┼─────────────────────┼──────────────┼────────────────────── │
|
||||
│ "done"/"success" │ "sucess" │ 0 │ "" │
|
||||
│ "failed" │ "failed" │ from $2 │ explain_exit_code() │
|
||||
│ anything else │ "unknown" │ from $2 │ explain_exit_code() │
|
||||
│ │
|
||||
│ Note: PocketBase schema spells it "sucess" intentionally │
|
||||
└─────────────────────┬───────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Record ID Resolution │
|
||||
│ │
|
||||
│ ┌──────────────────────────┐ ┌──────────────────────────────────────┐ │
|
||||
│ │ PB_RECORD_ID set? │ │ Fallback: GET lookup │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ YES → use PB_RECORD_ID │ │ GET PB_API_URL │ │
|
||||
│ │ │ │ ?filter=(random_id='UUID') │ │
|
||||
│ │ NO → try GET lookup ───┼───►│ &fields=id │ │
|
||||
│ │ │ │ &perPage=1 │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ Extract "id" from response │ │
|
||||
│ │ │ │ If not found → set flag, return │ │
|
||||
│ └──────────────────────────┘ └──────────────────────────────────────┘ │
|
||||
└─────────────────────┬───────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ PATCH Request │
|
||||
│ │
|
||||
│ PATCH → PB_API_URL/{record_id} │
|
||||
│ http://db.community-scripts.org/api/collections/_dev_telemetry_data/ │
|
||||
│ records/{record_id} │
|
||||
│ │
|
||||
│ Payload: │
|
||||
│ { │
|
||||
│ "status": "sucess" | "failed" | "unknown", │
|
||||
│ "error": "..." | "", │
|
||||
│ "exit_code": 0 | <numeric> │
|
||||
│ } │
|
||||
│ │
|
||||
│ ──► POST_UPDATE_DONE = true (prevents future calls) │
|
||||
└─────────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Error Description Flow — `explain_exit_code()`
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ explain_exit_code(code) Flow │
|
||||
│ Convert numeric exit codes to human-readable descriptions │
|
||||
│ Canonical function — used by api.func AND error_handler.func │
|
||||
└─────────────────────┬───────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Exit Code Classification (non-overlapping ranges) │
|
||||
│ │
|
||||
│ ┌─────────────────┐ ┌──────────────────┐ ┌──────────────────────────┐ │
|
||||
│ │ Generic/Shell │ │ curl/wget │ │ APT/DPKG │ │
|
||||
│ │ 1–2 │ │ 6, 7, 22, 28, 35│ │ 100–102, 255 │ │
|
||||
│ └─────────────────┘ └──────────────────┘ └──────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────┐ ┌──────────────────┐ ┌──────────────────────────┐ │
|
||||
│ │ System/Signals │ │ Systemd/Service │ │ Python/pip/uv │ │
|
||||
│ │ 124–143 │ │ 150–154 │ │ 160–162 │ │
|
||||
│ └─────────────────┘ └──────────────────┘ └──────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────┐ ┌──────────────────┐ ┌──────────────────────────┐ │
|
||||
│ │ PostgreSQL │ │ MySQL/MariaDB │ │ MongoDB │ │
|
||||
│ │ 170–173 │ │ 180–183 │ │ 190–193 │ │
|
||||
│ └─────────────────┘ └──────────────────┘ └──────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────┐ ┌──────────────────┐ │
|
||||
│ │ Proxmox │ │ Node.js/npm │ │
|
||||
│ │ 200–231 │ │ 243–249 │ │
|
||||
│ └─────────────────┘ └──────────────────┘ │
|
||||
└─────────────────────┬───────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ case "$code" in │
|
||||
│ <matched>) echo "<description>" ;; │
|
||||
│ *) echo "Unknown error" ;; │
|
||||
│ esac │
|
||||
└─────────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Complete Installation Lifecycle
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ Installation Script (e.g. build.func / vm-core.func) │
|
||||
└────────┬─────────────────────────────────────────────────────┘
|
||||
│
|
||||
│ 1. source api.func
|
||||
│ 2. Set DIAGNOSTICS, RANDOM_UUID, NSAPP, etc.
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ post_to_api() / post_to_api_vm() │
|
||||
│ │
|
||||
│ POST → PB_API_URL │
|
||||
│ Body: { ..., "status": "installing", "random_id": "..." } │
|
||||
│ │
|
||||
│ Response → PB_RECORD_ID = "abc123def456789" │
|
||||
└────────┬─────────────────────────────────────────────────────┘
|
||||
│
|
||||
│ 3. Installation proceeds...
|
||||
│ (container/VM creation, package install, etc.)
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ post_update_to_api("done", 0) │
|
||||
│ or │
|
||||
│ post_update_to_api("failed", $exit_code) │
|
||||
│ │
|
||||
│ PATCH → PB_API_URL/{PB_RECORD_ID} │
|
||||
│ Body: { "status": "sucess", "error": "", "exit_code": 0 } │
|
||||
│ or { "status": "failed", "error": "...", "exit_code": N }│
|
||||
│ │
|
||||
│ POST_UPDATE_DONE = true │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Integration Points
|
||||
|
||||
### With Installation Scripts
|
||||
- **build.func**: Sends LXC installation data
|
||||
- **vm-core.func**: Sends VM installation data
|
||||
- **install.func**: Reports installation status
|
||||
- **alpine-install.func**: Reports Alpine installation data
|
||||
- **build.func**: Calls `post_to_api()` for LXC creation, then `post_update_to_api()` on completion
|
||||
- **vm-core.func**: Calls `post_to_api_vm()` for VM creation, then `post_update_to_api()` on completion
|
||||
- **install.func / alpine-install.func**: Reports installation status via `post_update_to_api()`
|
||||
|
||||
### With Error Handling
|
||||
- **error_handler.func**: Provides error explanations
|
||||
- **core.func**: Uses error descriptions in silent execution
|
||||
- **Diagnostic reporting**: Tracks error patterns
|
||||
- **error_handler.func**: Uses `explain_exit_code()` for human-readable error messages
|
||||
- **Diagnostic reporting**: PocketBase records track error patterns anonymously
|
||||
|
||||
### External Dependencies
|
||||
- **curl**: HTTP client for API communication
|
||||
- **Community Scripts API**: External API endpoint
|
||||
- **Network connectivity**: Required for API communication
|
||||
- **curl**: HTTP client for PocketBase API communication
|
||||
- **PocketBase**: Backend at `http://db.community-scripts.org`
|
||||
- **Network connectivity**: Required for API communication (failures are silently ignored)
|
||||
|
||||
@ -2,63 +2,88 @@
|
||||
|
||||
## Overview
|
||||
|
||||
This document provides a comprehensive alphabetical reference of all functions in `api.func`, including parameters, dependencies, usage examples, and error handling.
|
||||
This document provides a comprehensive reference of all functions in `api.func`, including parameters, dependencies, usage examples, and error handling. The backend is **PocketBase** hosted at `http://db.community-scripts.org`.
|
||||
|
||||
## Configuration Variables
|
||||
|
||||
| Variable | Value | Description |
|
||||
|----------|-------|-------------|
|
||||
| `PB_URL` | `http://db.community-scripts.org` | PocketBase server URL |
|
||||
| `PB_COLLECTION` | `_dev_telemetry_data` | PocketBase collection name |
|
||||
| `PB_API_URL` | `${PB_URL}/api/collections/${PB_COLLECTION}/records` | Full API endpoint |
|
||||
| `PB_RECORD_ID` | *(runtime)* | Stores the PocketBase record ID returned by POST for later PATCH calls |
|
||||
|
||||
## Function Categories
|
||||
|
||||
### Error Description Functions
|
||||
|
||||
#### `get_error_description()`
|
||||
#### `explain_exit_code()`
|
||||
|
||||
**Purpose**: Convert numeric exit codes to human-readable explanations
|
||||
**Parameters**:
|
||||
- `$1` - Exit code to explain
|
||||
- `$1` — Exit code to explain
|
||||
**Returns**: Human-readable error explanation string
|
||||
**Side Effects**: None
|
||||
**Dependencies**: None
|
||||
**Environment Variables Used**: None
|
||||
|
||||
**Supported Exit Codes**:
|
||||
- **General System**: 0-9, 18, 22, 28, 35, 56, 60, 125-128, 129-143, 152, 255
|
||||
- **LXC-Specific**: 100-101, 200-209
|
||||
- **Docker**: 125
|
||||
> **Note**: `explain_exit_code()` is the **canonical** function for exit-code mapping. It is used by both `api.func` (telemetry) and `error_handler.func` (error display).
|
||||
|
||||
**Supported Exit Code Ranges** (non-overlapping):
|
||||
|
||||
| Range | Category |
|
||||
|-------|----------|
|
||||
| 1–2 | Generic / Shell |
|
||||
| 6–35 | curl / wget |
|
||||
| 100–102 | APT / Package manager |
|
||||
| 124–143 | System / Signals |
|
||||
| 150–154 | Systemd / Service |
|
||||
| 160–162 | Python / pip / uv |
|
||||
| 170–173 | PostgreSQL |
|
||||
| 180–183 | MySQL / MariaDB |
|
||||
| 190–193 | MongoDB |
|
||||
| 200–231 | Proxmox custom codes |
|
||||
| 243–249 | Node.js / npm |
|
||||
| 255 | DPKG fatal |
|
||||
|
||||
**Usage Example**:
|
||||
```bash
|
||||
error_msg=$(get_error_description 127)
|
||||
error_msg=$(explain_exit_code 127)
|
||||
echo "Error 127: $error_msg"
|
||||
# Output: Error 127: Command not found: Incorrect path or missing dependency.
|
||||
# Output: Error 127: Command not found
|
||||
```
|
||||
|
||||
**Error Code Examples**:
|
||||
```bash
|
||||
get_error_description 0 # " " (space)
|
||||
get_error_description 1 # "General error: An unspecified error occurred."
|
||||
get_error_description 127 # "Command not found: Incorrect path or missing dependency."
|
||||
get_error_description 200 # "LXC creation failed."
|
||||
get_error_description 255 # "Unknown critical error, often due to missing permissions or broken scripts."
|
||||
explain_exit_code 1 # "General error / Operation not permitted"
|
||||
explain_exit_code 22 # "curl: HTTP error returned (404, 429, 500+)"
|
||||
explain_exit_code 127 # "Command not found"
|
||||
explain_exit_code 200 # "Proxmox: Failed to create lock file"
|
||||
explain_exit_code 255 # "DPKG: Fatal internal error"
|
||||
explain_exit_code 999 # "Unknown error"
|
||||
```
|
||||
|
||||
### API Communication Functions
|
||||
|
||||
#### `post_to_api()`
|
||||
**Purpose**: Send LXC container installation data to community-scripts.org API
|
||||
|
||||
**Purpose**: Create an LXC container telemetry record in PocketBase
|
||||
**Parameters**: None (uses environment variables)
|
||||
**Returns**: None
|
||||
**Side Effects**:
|
||||
- Sends HTTP POST request to API
|
||||
- Stores response in RESPONSE variable
|
||||
- Requires curl command and network connectivity
|
||||
- Sends HTTP **POST** to `PB_API_URL`
|
||||
- Stores the returned PocketBase record `id` in `PB_RECORD_ID` for later PATCH updates
|
||||
**Dependencies**: `curl` command
|
||||
**Environment Variables Used**: `DIAGNOSTICS`, `RANDOM_UUID`, `CT_TYPE`, `DISK_SIZE`, `CORE_COUNT`, `RAM_SIZE`, `var_os`, `var_version`, `DISABLEIP6`, `NSAPP`, `METHOD`
|
||||
**Environment Variables Used**: `DIAGNOSTICS`, `RANDOM_UUID`, `CT_TYPE`, `DISK_SIZE`, `CORE_COUNT`, `RAM_SIZE`, `var_os`, `var_version`, `NSAPP`, `METHOD`
|
||||
|
||||
**Prerequisites**:
|
||||
- `curl` command must be available
|
||||
- `DIAGNOSTICS` must be set to "yes"
|
||||
- `curl` must be available
|
||||
- `DIAGNOSTICS` must be `"yes"`
|
||||
- `RANDOM_UUID` must be set and not empty
|
||||
|
||||
**API Endpoint**: `http://api.community-scripts.org/dev/upload`
|
||||
**API Endpoint**: `POST http://db.community-scripts.org/api/collections/_dev_telemetry_data/records`
|
||||
|
||||
**JSON Payload Structure**:
|
||||
**JSON Payload**:
|
||||
```json
|
||||
{
|
||||
"ct_type": 1,
|
||||
@ -68,7 +93,6 @@ get_error_description 255 # "Unknown critical error, often due to missing perm
|
||||
"ram_size": 2048,
|
||||
"os_type": "debian",
|
||||
"os_version": "12",
|
||||
"disableip6": "true",
|
||||
"nsapp": "plex",
|
||||
"method": "install",
|
||||
"pve_version": "8.0",
|
||||
@ -77,6 +101,10 @@ get_error_description 255 # "Unknown critical error, often due to missing perm
|
||||
}
|
||||
```
|
||||
|
||||
**Response Handling**:
|
||||
- On HTTP 200/201, `PB_RECORD_ID` is extracted from the response JSON (`"id"` field)
|
||||
- On failure, the function returns silently without blocking the installation
|
||||
|
||||
**Usage Example**:
|
||||
```bash
|
||||
export DIAGNOSTICS="yes"
|
||||
@ -91,39 +119,39 @@ export NSAPP="plex"
|
||||
export METHOD="install"
|
||||
|
||||
post_to_api
|
||||
# PB_RECORD_ID is now set (e.g. "abc123def456789")
|
||||
```
|
||||
|
||||
#### `post_to_api_vm()`
|
||||
**Purpose**: Send VM installation data to community-scripts.org API
|
||||
|
||||
**Purpose**: Create a VM telemetry record in PocketBase
|
||||
**Parameters**: None (uses environment variables)
|
||||
**Returns**: None
|
||||
**Side Effects**:
|
||||
- Sends HTTP POST request to API
|
||||
- Stores response in RESPONSE variable
|
||||
- Requires curl command and network connectivity
|
||||
- Sends HTTP **POST** to `PB_API_URL`
|
||||
- Stores the returned PocketBase record `id` in `PB_RECORD_ID`
|
||||
**Dependencies**: `curl` command, diagnostics file
|
||||
**Environment Variables Used**: `DIAGNOSTICS`, `RANDOM_UUID`, `DISK_SIZE`, `CORE_COUNT`, `RAM_SIZE`, `var_os`, `var_version`, `NSAPP`, `METHOD`
|
||||
**Environment Variables Used**: `RANDOM_UUID`, `DISK_SIZE`, `CORE_COUNT`, `RAM_SIZE`, `var_os`, `var_version`, `NSAPP`, `METHOD`
|
||||
|
||||
**Prerequisites**:
|
||||
- `/usr/local/community-scripts/diagnostics` file must exist
|
||||
- `DIAGNOSTICS` must be set to "yes" in diagnostics file
|
||||
- `curl` command must be available
|
||||
- `DIAGNOSTICS` must be `"yes"` in that file (read at runtime)
|
||||
- `curl` must be available
|
||||
- `RANDOM_UUID` must be set and not empty
|
||||
|
||||
**API Endpoint**: `http://api.community-scripts.org/dev/upload`
|
||||
**API Endpoint**: `POST http://db.community-scripts.org/api/collections/_dev_telemetry_data/records`
|
||||
|
||||
**JSON Payload Structure**:
|
||||
**JSON Payload**:
|
||||
```json
|
||||
{
|
||||
"ct_type": 2,
|
||||
"type": "vm",
|
||||
"disk_size": 8,
|
||||
"core_count": 2,
|
||||
"ram_size": 2048,
|
||||
"os_type": "debian",
|
||||
"os_version": "12",
|
||||
"disableip6": "",
|
||||
"nsapp": "plex",
|
||||
"disk_size": 20,
|
||||
"core_count": 4,
|
||||
"ram_size": 4096,
|
||||
"os_type": "ubuntu",
|
||||
"os_version": "22.04",
|
||||
"nsapp": "nextcloud",
|
||||
"method": "install",
|
||||
"pve_version": "8.0",
|
||||
"status": "installing",
|
||||
@ -131,50 +159,81 @@ post_to_api
|
||||
}
|
||||
```
|
||||
|
||||
> **Note**: `DISK_SIZE` is stripped of its `G` suffix before sending (e.g. `"20G"` → `20`).
|
||||
|
||||
**Usage Example**:
|
||||
```bash
|
||||
# Create diagnostics file
|
||||
mkdir -p /usr/local/community-scripts
|
||||
echo "DIAGNOSTICS=yes" > /usr/local/community-scripts/diagnostics
|
||||
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
export DISK_SIZE="8G"
|
||||
export CORE_COUNT=2
|
||||
export RAM_SIZE=2048
|
||||
export var_os="debian"
|
||||
export var_version="12"
|
||||
export NSAPP="plex"
|
||||
export DISK_SIZE="20G"
|
||||
export CORE_COUNT=4
|
||||
export RAM_SIZE=4096
|
||||
export var_os="ubuntu"
|
||||
export var_version="22.04"
|
||||
export NSAPP="nextcloud"
|
||||
export METHOD="install"
|
||||
|
||||
post_to_api_vm
|
||||
# PB_RECORD_ID is now set
|
||||
```
|
||||
|
||||
#### `post_update_to_api()`
|
||||
**Purpose**: Send installation completion status to community-scripts.org API
|
||||
|
||||
**Purpose**: Update an existing PocketBase record with installation completion status via PATCH
|
||||
**Parameters**:
|
||||
- `$1` - Status ("success" or "failed", default: "failed")
|
||||
- `$2` - Exit code (default: 1)
|
||||
- `$1` — Status (`"done"`, `"success"`, or `"failed"`; default: `"failed"`)
|
||||
- `$2` — Exit code (numeric, default: `1`)
|
||||
**Returns**: None
|
||||
**Side Effects**:
|
||||
- Sends HTTP POST request to API
|
||||
- Sets POST_UPDATE_DONE=true to prevent duplicates
|
||||
- Stores response in RESPONSE variable
|
||||
**Dependencies**: `curl` command, `get_error_description()`
|
||||
**Environment Variables Used**: `DIAGNOSTICS`, `RANDOM_UUID`
|
||||
- Sends HTTP **PATCH** to `PB_API_URL/{record_id}`
|
||||
- Sets `POST_UPDATE_DONE=true` to prevent duplicate calls
|
||||
**Dependencies**: `curl`, `explain_exit_code()`
|
||||
**Environment Variables Used**: `DIAGNOSTICS`, `RANDOM_UUID`, `PB_RECORD_ID`
|
||||
|
||||
**Prerequisites**:
|
||||
- `curl` command must be available
|
||||
- `DIAGNOSTICS` must be set to "yes"
|
||||
- `curl` must be available
|
||||
- `DIAGNOSTICS` must be `"yes"`
|
||||
- `RANDOM_UUID` must be set and not empty
|
||||
- POST_UPDATE_DONE must be false (prevents duplicates)
|
||||
- `POST_UPDATE_DONE` must not be `"true"` (prevents duplicate updates)
|
||||
|
||||
**API Endpoint**: `http://api.community-scripts.org/dev/upload/updatestatus`
|
||||
**Record Lookup**:
|
||||
1. If `PB_RECORD_ID` is already set (from a prior `post_to_api` / `post_to_api_vm` call), it is used directly.
|
||||
2. Otherwise, the function performs a **GET** lookup:
|
||||
```
|
||||
GET PB_API_URL?filter=(random_id='<RANDOM_UUID>')&fields=id&perPage=1
|
||||
```
|
||||
3. If no record is found, the function sets `POST_UPDATE_DONE=true` and returns.
|
||||
|
||||
**JSON Payload Structure**:
|
||||
**Status Mapping** (PocketBase select field values: `installing`, `sucess`, `failed`, `unknown`):
|
||||
|
||||
| Input Status | PocketBase `status` | `exit_code` | `error` |
|
||||
|---|---|---|---|
|
||||
| `"done"` / `"success"` / `"sucess"` | `"sucess"` | `0` | `""` |
|
||||
| `"failed"` | `"failed"` | *from $2* | *from `explain_exit_code()`* |
|
||||
| anything else | `"unknown"` | *from $2* | *from `explain_exit_code()`* |
|
||||
|
||||
> **Note**: The PocketBase schema intentionally spells success as `"sucess"`.
|
||||
|
||||
**API Endpoint**: `PATCH http://db.community-scripts.org/api/collections/_dev_telemetry_data/records/{record_id}`
|
||||
|
||||
**JSON Payload**:
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"error": "Error description from get_error_description()",
|
||||
"random_id": "uuid-string"
|
||||
"status": "sucess",
|
||||
"error": "",
|
||||
"exit_code": 0
|
||||
}
|
||||
```
|
||||
|
||||
or for failures:
|
||||
```json
|
||||
{
|
||||
"status": "failed",
|
||||
"error": "Command not found",
|
||||
"exit_code": 127
|
||||
}
|
||||
```
|
||||
|
||||
@ -183,10 +242,10 @@ post_to_api_vm
|
||||
export DIAGNOSTICS="yes"
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
|
||||
# Report successful installation
|
||||
post_update_to_api "success" 0
|
||||
# After a successful installation
|
||||
post_update_to_api "done" 0
|
||||
|
||||
# Report failed installation
|
||||
# After a failed installation
|
||||
post_update_to_api "failed" 127
|
||||
```
|
||||
|
||||
@ -196,198 +255,250 @@ post_update_to_api "failed" 127
|
||||
```
|
||||
post_to_api()
|
||||
├── Check curl availability
|
||||
├── Check DIAGNOSTICS setting
|
||||
├── Check RANDOM_UUID
|
||||
├── Check DIAGNOSTICS == "yes"
|
||||
├── Check RANDOM_UUID is set
|
||||
├── Get PVE version
|
||||
├── Create JSON payload
|
||||
└── Send HTTP POST request
|
||||
├── Create JSON payload (ct_type=1, type="lxc", status="installing")
|
||||
├── POST to PB_API_URL
|
||||
└── Extract PB_RECORD_ID from response
|
||||
|
||||
post_to_api_vm()
|
||||
├── Check diagnostics file
|
||||
├── Read DIAGNOSTICS from /usr/local/community-scripts/diagnostics
|
||||
├── Check curl availability
|
||||
├── Check DIAGNOSTICS setting
|
||||
├── Check RANDOM_UUID
|
||||
├── Process disk size
|
||||
├── Check DIAGNOSTICS == "yes"
|
||||
├── Check RANDOM_UUID is set
|
||||
├── Strip 'G' suffix from DISK_SIZE
|
||||
├── Get PVE version
|
||||
├── Create JSON payload
|
||||
└── Send HTTP POST request
|
||||
├── Create JSON payload (ct_type=2, type="vm", status="installing")
|
||||
├── POST to PB_API_URL
|
||||
└── Extract PB_RECORD_ID from response
|
||||
|
||||
post_update_to_api()
|
||||
├── Check POST_UPDATE_DONE flag
|
||||
post_update_to_api(status, exit_code)
|
||||
├── Check curl availability
|
||||
├── Check DIAGNOSTICS setting
|
||||
├── Check RANDOM_UUID
|
||||
├── Determine status and exit code
|
||||
├── Get error description
|
||||
├── Create JSON payload
|
||||
├── Send HTTP POST request
|
||||
├── Check POST_UPDATE_DONE flag
|
||||
├── Check DIAGNOSTICS == "yes"
|
||||
├── Check RANDOM_UUID is set
|
||||
├── Map status → pb_status ("done"→"sucess", "failed"→"failed", *→"unknown")
|
||||
├── For failed/unknown: call explain_exit_code(exit_code)
|
||||
├── Resolve record_id (PB_RECORD_ID or GET lookup by random_id)
|
||||
├── PATCH to PB_API_URL/{record_id}
|
||||
└── Set POST_UPDATE_DONE=true
|
||||
```
|
||||
|
||||
### Error Description Flow
|
||||
```
|
||||
get_error_description()
|
||||
├── Match exit code
|
||||
├── Return appropriate description
|
||||
└── Handle unknown codes
|
||||
explain_exit_code(code)
|
||||
├── Match code against case statement (non-overlapping ranges)
|
||||
├── Return description string
|
||||
└── Default: "Unknown error"
|
||||
```
|
||||
|
||||
## Error Code Reference
|
||||
|
||||
### General System Errors
|
||||
### Generic / Shell (1–2)
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 0 | (space) |
|
||||
| 1 | General error: An unspecified error occurred. |
|
||||
| 2 | Incorrect shell usage or invalid command arguments. |
|
||||
| 3 | Unexecuted function or invalid shell condition. |
|
||||
| 4 | Error opening a file or invalid path. |
|
||||
| 5 | I/O error: An input/output failure occurred. |
|
||||
| 6 | No such device or address. |
|
||||
| 7 | Insufficient memory or resource exhaustion. |
|
||||
| 8 | Non-executable file or invalid file format. |
|
||||
| 9 | Failed child process execution. |
|
||||
| 18 | Connection to a remote server failed. |
|
||||
| 22 | Invalid argument or faulty network connection. |
|
||||
| 28 | No space left on device. |
|
||||
| 35 | Timeout while establishing a connection. |
|
||||
| 56 | Faulty TLS connection. |
|
||||
| 60 | SSL certificate error. |
|
||||
| 1 | General error / Operation not permitted |
|
||||
| 2 | Misuse of shell builtins (e.g. syntax error) |
|
||||
|
||||
### Command Execution Errors
|
||||
### curl / wget (6–35)
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 125 | Docker error: Container could not start. |
|
||||
| 126 | Command not executable: Incorrect permissions or missing dependencies. |
|
||||
| 127 | Command not found: Incorrect path or missing dependency. |
|
||||
| 128 | Invalid exit signal, e.g., incorrect Git command. |
|
||||
| 6 | curl: DNS resolution failed (could not resolve host) |
|
||||
| 7 | curl: Failed to connect (network unreachable / host down) |
|
||||
| 22 | curl: HTTP error returned (404, 429, 500+) |
|
||||
| 28 | curl: Operation timeout (network slow or server not responding) |
|
||||
| 35 | curl: SSL/TLS handshake failed (certificate error) |
|
||||
|
||||
### Signal Errors
|
||||
### APT / Package Manager (100–102)
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 129 | Signal 1 (SIGHUP): Process terminated due to hangup. |
|
||||
| 130 | Signal 2 (SIGINT): Manual termination via Ctrl+C. |
|
||||
| 132 | Signal 4 (SIGILL): Illegal machine instruction. |
|
||||
| 133 | Signal 5 (SIGTRAP): Debugging error or invalid breakpoint signal. |
|
||||
| 134 | Signal 6 (SIGABRT): Program aborted itself. |
|
||||
| 135 | Signal 7 (SIGBUS): Memory error, invalid memory address. |
|
||||
| 137 | Signal 9 (SIGKILL): Process forcibly terminated (OOM-killer or 'kill -9'). |
|
||||
| 139 | Signal 11 (SIGSEGV): Segmentation fault, possibly due to invalid pointer access. |
|
||||
| 141 | Signal 13 (SIGPIPE): Pipe closed unexpectedly. |
|
||||
| 143 | Signal 15 (SIGTERM): Process terminated normally. |
|
||||
| 152 | Signal 24 (SIGXCPU): CPU time limit exceeded. |
|
||||
| 100 | APT: Package manager error (broken packages / dependency problems) |
|
||||
| 101 | APT: Configuration error (bad sources.list, malformed config) |
|
||||
| 102 | APT: Lock held by another process (dpkg/apt still running) |
|
||||
|
||||
### LXC-Specific Errors
|
||||
### System / Signals (124–143)
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 100 | LXC install error: Unexpected error in create_lxc.sh. |
|
||||
| 101 | LXC install error: No network connection detected. |
|
||||
| 200 | LXC creation failed. |
|
||||
| 201 | LXC error: Invalid Storage class. |
|
||||
| 202 | User aborted menu in create_lxc.sh. |
|
||||
| 203 | CTID not set in create_lxc.sh. |
|
||||
| 204 | PCT_OSTYPE not set in create_lxc.sh. |
|
||||
| 205 | CTID cannot be less than 100 in create_lxc.sh. |
|
||||
| 206 | CTID already in use in create_lxc.sh. |
|
||||
| 207 | Template not found in create_lxc.sh. |
|
||||
| 208 | Error downloading template in create_lxc.sh. |
|
||||
| 209 | Container creation failed, but template is intact in create_lxc.sh. |
|
||||
| 124 | Command timed out (timeout command) |
|
||||
| 126 | Command invoked cannot execute (permission problem?) |
|
||||
| 127 | Command not found |
|
||||
| 128 | Invalid argument to exit |
|
||||
| 130 | Terminated by Ctrl+C (SIGINT) |
|
||||
| 134 | Process aborted (SIGABRT — possibly Node.js heap overflow) |
|
||||
| 137 | Killed (SIGKILL / Out of memory?) |
|
||||
| 139 | Segmentation fault (core dumped) |
|
||||
| 141 | Broken pipe (SIGPIPE — output closed prematurely) |
|
||||
| 143 | Terminated (SIGTERM) |
|
||||
|
||||
### Other Errors
|
||||
### Systemd / Service (150–154)
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 255 | Unknown critical error, often due to missing permissions or broken scripts. |
|
||||
| * | Unknown error code (exit_code). |
|
||||
| 150 | Systemd: Service failed to start |
|
||||
| 151 | Systemd: Service unit not found |
|
||||
| 152 | Permission denied (EACCES) |
|
||||
| 153 | Build/compile failed (make/gcc/cmake) |
|
||||
| 154 | Node.js: Native addon build failed (node-gyp) |
|
||||
|
||||
### Python / pip / uv (160–162)
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 160 | Python: Virtualenv / uv environment missing or broken |
|
||||
| 161 | Python: Dependency resolution failed |
|
||||
| 162 | Python: Installation aborted (permissions or EXTERNALLY-MANAGED) |
|
||||
|
||||
### PostgreSQL (170–173)
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 170 | PostgreSQL: Connection failed (server not running / wrong socket) |
|
||||
| 171 | PostgreSQL: Authentication failed (bad user/password) |
|
||||
| 172 | PostgreSQL: Database does not exist |
|
||||
| 173 | PostgreSQL: Fatal error in query / syntax |
|
||||
|
||||
### MySQL / MariaDB (180–183)
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 180 | MySQL/MariaDB: Connection failed (server not running / wrong socket) |
|
||||
| 181 | MySQL/MariaDB: Authentication failed (bad user/password) |
|
||||
| 182 | MySQL/MariaDB: Database does not exist |
|
||||
| 183 | MySQL/MariaDB: Fatal error in query / syntax |
|
||||
|
||||
### MongoDB (190–193)
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 190 | MongoDB: Connection failed (server not running) |
|
||||
| 191 | MongoDB: Authentication failed (bad user/password) |
|
||||
| 192 | MongoDB: Database not found |
|
||||
| 193 | MongoDB: Fatal query error |
|
||||
|
||||
### Proxmox Custom Codes (200–231)
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 200 | Proxmox: Failed to create lock file |
|
||||
| 203 | Proxmox: Missing CTID variable |
|
||||
| 204 | Proxmox: Missing PCT_OSTYPE variable |
|
||||
| 205 | Proxmox: Invalid CTID (<100) |
|
||||
| 206 | Proxmox: CTID already in use |
|
||||
| 207 | Proxmox: Password contains unescaped special characters |
|
||||
| 208 | Proxmox: Invalid configuration (DNS/MAC/Network format) |
|
||||
| 209 | Proxmox: Container creation failed |
|
||||
| 210 | Proxmox: Cluster not quorate |
|
||||
| 211 | Proxmox: Timeout waiting for template lock |
|
||||
| 212 | Proxmox: Storage type 'iscsidirect' does not support containers (VMs only) |
|
||||
| 213 | Proxmox: Storage type does not support 'rootdir' content |
|
||||
| 214 | Proxmox: Not enough storage space |
|
||||
| 215 | Proxmox: Container created but not listed (ghost state) |
|
||||
| 216 | Proxmox: RootFS entry missing in config |
|
||||
| 217 | Proxmox: Storage not accessible |
|
||||
| 218 | Proxmox: Template file corrupted or incomplete |
|
||||
| 219 | Proxmox: CephFS does not support containers — use RBD |
|
||||
| 220 | Proxmox: Unable to resolve template path |
|
||||
| 221 | Proxmox: Template file not readable |
|
||||
| 222 | Proxmox: Template download failed |
|
||||
| 223 | Proxmox: Template not available after download |
|
||||
| 224 | Proxmox: PBS storage is for backups only |
|
||||
| 225 | Proxmox: No template available for OS/Version |
|
||||
| 231 | Proxmox: LXC stack upgrade failed |
|
||||
|
||||
### Node.js / npm (243–249)
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 243 | Node.js: Out of memory (JavaScript heap out of memory) |
|
||||
| 245 | Node.js: Invalid command-line option |
|
||||
| 246 | Node.js: Internal JavaScript Parse Error |
|
||||
| 247 | Node.js: Fatal internal error |
|
||||
| 248 | Node.js: Invalid C++ addon / N-API failure |
|
||||
| 249 | npm/pnpm/yarn: Unknown fatal error |
|
||||
|
||||
### DPKG (255)
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 255 | DPKG: Fatal internal error |
|
||||
|
||||
### Default
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| * | Unknown error |
|
||||
|
||||
## Environment Variable Dependencies
|
||||
|
||||
### Required Variables
|
||||
- **`DIAGNOSTICS`**: Enable/disable diagnostic reporting ("yes"/"no")
|
||||
- **`RANDOM_UUID`**: Unique identifier for tracking
|
||||
- **`DIAGNOSTICS`**: Enable/disable diagnostic reporting (`"yes"` / `"no"`)
|
||||
- **`RANDOM_UUID`**: Unique identifier for session tracking
|
||||
|
||||
### Optional Variables
|
||||
- **`CT_TYPE`**: Container type (1 for LXC, 2 for VM)
|
||||
- **`DISK_SIZE`**: Disk size in GB (or GB with 'G' suffix for VM)
|
||||
### Container / VM Variables
|
||||
- **`CT_TYPE`**: Container type (`1` for LXC, `2` for VM)
|
||||
- **`DISK_SIZE`**: Disk size in GB (VMs may include `G` suffix)
|
||||
- **`CORE_COUNT`**: Number of CPU cores
|
||||
- **`RAM_SIZE`**: RAM size in MB
|
||||
- **`var_os`**: Operating system type
|
||||
- **`var_version`**: OS version
|
||||
- **`DISABLEIP6`**: IPv6 disable setting
|
||||
- **`NSAPP`**: Namespace application name
|
||||
- **`NSAPP`**: Application name
|
||||
- **`METHOD`**: Installation method
|
||||
|
||||
### Internal Variables
|
||||
- **`POST_UPDATE_DONE`**: Prevents duplicate status updates
|
||||
- **`API_URL`**: Community scripts API endpoint
|
||||
- **`JSON_PAYLOAD`**: API request payload
|
||||
- **`RESPONSE`**: API response
|
||||
- **`DISK_SIZE_API`**: Processed disk size for VM API
|
||||
- **`PB_URL`**: PocketBase server URL
|
||||
- **`PB_COLLECTION`**: PocketBase collection name
|
||||
- **`PB_API_URL`**: Full PocketBase API endpoint
|
||||
- **`PB_RECORD_ID`**: PocketBase record ID (set after POST, used for PATCH)
|
||||
- **`POST_UPDATE_DONE`**: Flag to prevent duplicate status updates
|
||||
- **`JSON_PAYLOAD`**: API request payload (local to each function)
|
||||
- **`RESPONSE`**: API response (local to each function)
|
||||
|
||||
## Error Handling Patterns
|
||||
|
||||
### API Communication Errors
|
||||
- All API functions handle curl failures gracefully
|
||||
- Network errors don't block installation process
|
||||
- Missing prerequisites cause early return
|
||||
- Duplicate updates are prevented
|
||||
- All API functions return silently on failure — network errors never block installation
|
||||
- Missing prerequisites (no curl, diagnostics disabled, no UUID) cause early return
|
||||
- `POST_UPDATE_DONE` flag prevents duplicate PATCH updates
|
||||
- PocketBase record lookup falls back to `GET ?filter=(random_id='...')` if `PB_RECORD_ID` is unset
|
||||
|
||||
### Error Description Errors
|
||||
- Unknown error codes return generic message
|
||||
- All error codes are handled with case statement
|
||||
- Fallback message includes the actual error code
|
||||
|
||||
### Prerequisites Validation
|
||||
- Check curl availability before API calls
|
||||
- Validate DIAGNOSTICS setting
|
||||
- Ensure RANDOM_UUID is set
|
||||
- Check for duplicate updates
|
||||
- Unknown error codes return `"Unknown error"`
|
||||
- All recognized codes are handled via a `case` statement with non-overlapping ranges
|
||||
- The fallback message is generic (no error code is embedded)
|
||||
|
||||
## Integration Examples
|
||||
|
||||
### With build.func
|
||||
### With build.func (LXC)
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
source core.func
|
||||
source api.func
|
||||
source build.func
|
||||
|
||||
# Set up API reporting
|
||||
export DIAGNOSTICS="yes"
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
|
||||
# Report installation start
|
||||
# Report LXC installation start → POST creates record
|
||||
post_to_api
|
||||
|
||||
# Container creation...
|
||||
# ... build.func code ...
|
||||
# ... container creation via build.func ...
|
||||
|
||||
# Report completion
|
||||
# Report completion → PATCH updates record
|
||||
if [[ $? -eq 0 ]]; then
|
||||
post_update_to_api "success" 0
|
||||
post_update_to_api "done" 0
|
||||
else
|
||||
post_update_to_api "failed" $?
|
||||
fi
|
||||
```
|
||||
|
||||
### With vm-core.func
|
||||
### With vm-core.func (VM)
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
source core.func
|
||||
source api.func
|
||||
source vm-core.func
|
||||
|
||||
# Set up API reporting
|
||||
export DIAGNOSTICS="yes"
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
|
||||
# Report VM installation start
|
||||
# Report VM installation start → POST creates record
|
||||
post_to_api_vm
|
||||
|
||||
# VM creation...
|
||||
# ... vm-core.func code ...
|
||||
# ... VM creation via vm-core.func ...
|
||||
|
||||
# Report completion
|
||||
post_update_to_api "success" 0
|
||||
# Report completion → PATCH updates record
|
||||
post_update_to_api "done" 0
|
||||
```
|
||||
|
||||
### With error_handler.func
|
||||
@ -397,37 +508,30 @@ source core.func
|
||||
source error_handler.func
|
||||
source api.func
|
||||
|
||||
# Use error descriptions
|
||||
error_code=127
|
||||
error_msg=$(get_error_description $error_code)
|
||||
error_msg=$(explain_exit_code $error_code)
|
||||
echo "Error $error_code: $error_msg"
|
||||
|
||||
# Report error to API
|
||||
# Report error to PocketBase
|
||||
post_update_to_api "failed" $error_code
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### API Usage
|
||||
1. Always check prerequisites before API calls
|
||||
2. Use unique identifiers for tracking
|
||||
3. Handle API failures gracefully
|
||||
4. Don't block installation on API failures
|
||||
1. Always check prerequisites before API calls (handled internally by each function)
|
||||
2. Call `post_to_api` / `post_to_api_vm` **once** at installation start to get a `PB_RECORD_ID`
|
||||
3. Call `post_update_to_api` **once** at the end to finalize the record via PATCH
|
||||
4. Never block the installation on API failures
|
||||
|
||||
### Error Reporting
|
||||
1. Use appropriate error codes
|
||||
2. Provide meaningful error descriptions
|
||||
3. Report both success and failure cases
|
||||
4. Prevent duplicate status updates
|
||||
1. Use `explain_exit_code()` for human-readable error messages
|
||||
2. Pass the actual numeric exit code to `post_update_to_api`
|
||||
3. Report both success (`"done"`) and failure (`"failed"`) cases
|
||||
4. The `POST_UPDATE_DONE` flag automatically prevents duplicate updates
|
||||
|
||||
### Diagnostic Reporting
|
||||
1. Respect user privacy settings
|
||||
2. Only send data when diagnostics enabled
|
||||
3. Use anonymous tracking identifiers
|
||||
4. Include relevant system information
|
||||
|
||||
### Error Handling
|
||||
1. Handle unknown error codes gracefully
|
||||
2. Provide fallback error messages
|
||||
3. Include error code in unknown error messages
|
||||
4. Use consistent error message format
|
||||
1. Respect user privacy — only send data when `DIAGNOSTICS="yes"`
|
||||
2. Use anonymous random UUIDs for session tracking (no personal data)
|
||||
3. Include relevant system information (PVE version, OS, app name)
|
||||
4. The diagnostics file at `/usr/local/community-scripts/diagnostics` controls VM reporting
|
||||
|
||||
@ -2,26 +2,42 @@
|
||||
|
||||
## Overview
|
||||
|
||||
This document describes how `api.func` integrates with other components in the Proxmox Community Scripts project, including dependencies, data flow, and API surface.
|
||||
This document describes how `api.func` integrates with other components in the Proxmox Community Scripts project. The telemetry backend is **PocketBase** at `http://db.community-scripts.org`, using the `_dev_telemetry_data` collection.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
Installation Scripts ──► api.func ──► PocketBase (db.community-scripts.org)
|
||||
│
|
||||
├─ POST → create record (status: "installing")
|
||||
├─ PATCH → update record (status: "sucess"/"failed")
|
||||
└─ GET → lookup record by random_id (fallback)
|
||||
```
|
||||
|
||||
### Key Design Points
|
||||
- **POST** creates a new telemetry record and returns a PocketBase `id`
|
||||
- **PATCH** updates the existing record using that `id` (or a GET lookup by `random_id`)
|
||||
- All communication is fire-and-forget — failures never block the installation
|
||||
- `explain_exit_code()` is the canonical function for exit-code-to-description mapping
|
||||
|
||||
## Dependencies
|
||||
|
||||
### External Dependencies
|
||||
|
||||
#### Required Commands
|
||||
- **`curl`**: HTTP client for API communication
|
||||
- **`uuidgen`**: Generate unique identifiers (optional, can use other methods)
|
||||
- **`curl`**: HTTP client for PocketBase API communication
|
||||
|
||||
#### Optional Commands
|
||||
- **None**: No other external command dependencies
|
||||
- **`uuidgen`**: Generate unique identifiers (any UUID source works)
|
||||
- **`pveversion`**: Retrieve Proxmox VE version (gracefully skipped if missing)
|
||||
|
||||
### Internal Dependencies
|
||||
|
||||
#### Environment Variables from Other Scripts
|
||||
- **build.func**: Provides container creation variables
|
||||
- **build.func**: Provides container creation variables (`CT_TYPE`, `DISK_SIZE`, etc.)
|
||||
- **vm-core.func**: Provides VM creation variables
|
||||
- **core.func**: Provides system information variables
|
||||
- **Installation scripts**: Provide application-specific variables
|
||||
- **core.func**: Provides system information
|
||||
- **Installation scripts**: Provide application-specific variables (`NSAPP`, `METHOD`)
|
||||
|
||||
## Integration Points
|
||||
|
||||
@ -29,17 +45,13 @@ This document describes how `api.func` integrates with other components in the P
|
||||
|
||||
#### LXC Container Reporting
|
||||
```bash
|
||||
# build.func uses api.func for container reporting
|
||||
source core.func
|
||||
source api.func
|
||||
source build.func
|
||||
|
||||
# Set up API reporting
|
||||
export DIAGNOSTICS="yes"
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
|
||||
# Container creation with API reporting
|
||||
create_container() {
|
||||
# Set container parameters
|
||||
export CT_TYPE=1
|
||||
export DISK_SIZE="$var_disk"
|
||||
@ -50,27 +62,24 @@ create_container() {
|
||||
export NSAPP="$APP"
|
||||
export METHOD="install"
|
||||
|
||||
# Report installation start
|
||||
# POST → creates record in PocketBase, saves PB_RECORD_ID
|
||||
post_to_api
|
||||
|
||||
# Container creation using build.func
|
||||
# ... build.func container creation logic ...
|
||||
# ... container creation via build.func ...
|
||||
|
||||
# Report completion
|
||||
# PATCH → updates the record with final status
|
||||
if [[ $? -eq 0 ]]; then
|
||||
post_update_to_api "success" 0
|
||||
post_update_to_api "done" 0
|
||||
else
|
||||
post_update_to_api "failed" $?
|
||||
fi
|
||||
}
|
||||
```
|
||||
|
||||
#### Error Reporting Integration
|
||||
```bash
|
||||
# build.func uses api.func for error reporting
|
||||
handle_container_error() {
|
||||
local exit_code=$1
|
||||
local error_msg=$(get_error_description $exit_code)
|
||||
local error_msg=$(explain_exit_code $exit_code)
|
||||
|
||||
echo "Container creation failed: $error_msg"
|
||||
post_update_to_api "failed" $exit_code
|
||||
@ -81,19 +90,16 @@ handle_container_error() {
|
||||
|
||||
#### VM Installation Reporting
|
||||
```bash
|
||||
# vm-core.func uses api.func for VM reporting
|
||||
source core.func
|
||||
source api.func
|
||||
source vm-core.func
|
||||
|
||||
# Set up VM API reporting
|
||||
# VM reads DIAGNOSTICS from file
|
||||
mkdir -p /usr/local/community-scripts
|
||||
echo "DIAGNOSTICS=yes" > /usr/local/community-scripts/diagnostics
|
||||
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
|
||||
# VM creation with API reporting
|
||||
create_vm() {
|
||||
# Set VM parameters
|
||||
export DISK_SIZE="${var_disk}G"
|
||||
export CORE_COUNT="$var_cpu"
|
||||
@ -103,71 +109,35 @@ create_vm() {
|
||||
export NSAPP="$APP"
|
||||
export METHOD="install"
|
||||
|
||||
# Report VM installation start
|
||||
# POST → creates record in PocketBase (ct_type=2, type="vm")
|
||||
post_to_api_vm
|
||||
|
||||
# VM creation using vm-core.func
|
||||
# ... vm-core.func VM creation logic ...
|
||||
# ... VM creation via vm-core.func ...
|
||||
|
||||
# Report completion
|
||||
post_update_to_api "success" 0
|
||||
}
|
||||
```
|
||||
|
||||
### With core.func
|
||||
|
||||
#### System Information Integration
|
||||
```bash
|
||||
# core.func provides system information for api.func
|
||||
source core.func
|
||||
source api.func
|
||||
|
||||
# Get system information for API reporting
|
||||
get_system_info_for_api() {
|
||||
# Get PVE version using core.func utilities
|
||||
local pve_version=$(pveversion | awk -F'[/ ]' '{print $2}')
|
||||
|
||||
# Set API parameters
|
||||
export var_os="$var_os"
|
||||
export var_version="$var_version"
|
||||
|
||||
# Use core.func error handling with api.func reporting
|
||||
if silent apt-get update; then
|
||||
post_update_to_api "success" 0
|
||||
else
|
||||
post_update_to_api "failed" $?
|
||||
fi
|
||||
}
|
||||
# PATCH → finalizes record
|
||||
post_update_to_api "done" 0
|
||||
```
|
||||
|
||||
### With error_handler.func
|
||||
|
||||
#### Error Description Integration
|
||||
```bash
|
||||
# error_handler.func uses api.func for error descriptions
|
||||
source core.func
|
||||
source error_handler.func
|
||||
source api.func
|
||||
|
||||
# Enhanced error handler with API reporting
|
||||
enhanced_error_handler() {
|
||||
local exit_code=${1:-$?}
|
||||
local command=${2:-${BASH_COMMAND:-unknown}}
|
||||
|
||||
# Get error description from api.func
|
||||
local error_msg=$(get_error_description $exit_code)
|
||||
# explain_exit_code() is the canonical error description function
|
||||
local error_msg=$(explain_exit_code $exit_code)
|
||||
|
||||
# Display error information
|
||||
echo "Error $exit_code: $error_msg"
|
||||
echo "Command: $command"
|
||||
|
||||
# Report error to API
|
||||
export DIAGNOSTICS="yes"
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
# PATCH the telemetry record with failure details
|
||||
post_update_to_api "failed" $exit_code
|
||||
|
||||
# Use standard error handler
|
||||
error_handler $exit_code $command
|
||||
}
|
||||
```
|
||||
|
||||
@ -175,32 +145,28 @@ enhanced_error_handler() {
|
||||
|
||||
#### Installation Process Reporting
|
||||
```bash
|
||||
# install.func uses api.func for installation reporting
|
||||
source core.func
|
||||
source api.func
|
||||
source install.func
|
||||
|
||||
# Installation with API reporting
|
||||
install_package_with_reporting() {
|
||||
local package="$1"
|
||||
|
||||
# Set up API reporting
|
||||
export DIAGNOSTICS="yes"
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
export NSAPP="$package"
|
||||
export METHOD="install"
|
||||
|
||||
# Report installation start
|
||||
# POST → create telemetry record
|
||||
post_to_api
|
||||
|
||||
# Package installation using install.func
|
||||
if install_package "$package"; then
|
||||
echo "$package installed successfully"
|
||||
post_update_to_api "success" 0
|
||||
post_update_to_api "done" 0
|
||||
return 0
|
||||
else
|
||||
local exit_code=$?
|
||||
local error_msg=$(get_error_description $exit_code)
|
||||
local error_msg=$(explain_exit_code $exit_code)
|
||||
echo "$package installation failed: $error_msg"
|
||||
post_update_to_api "failed" $exit_code
|
||||
return $exit_code
|
||||
@ -208,270 +174,105 @@ install_package_with_reporting() {
|
||||
}
|
||||
```
|
||||
|
||||
### With alpine-install.func
|
||||
|
||||
#### Alpine Installation Reporting
|
||||
```bash
|
||||
# alpine-install.func uses api.func for Alpine reporting
|
||||
source core.func
|
||||
source api.func
|
||||
source alpine-install.func
|
||||
|
||||
# Alpine installation with API reporting
|
||||
install_alpine_with_reporting() {
|
||||
local app="$1"
|
||||
|
||||
# Set up API reporting
|
||||
export DIAGNOSTICS="yes"
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
export NSAPP="$app"
|
||||
export METHOD="install"
|
||||
export var_os="alpine"
|
||||
|
||||
# Report Alpine installation start
|
||||
post_to_api
|
||||
|
||||
# Alpine installation using alpine-install.func
|
||||
if install_alpine_app "$app"; then
|
||||
echo "Alpine $app installed successfully"
|
||||
post_update_to_api "success" 0
|
||||
return 0
|
||||
else
|
||||
local exit_code=$?
|
||||
local error_msg=$(get_error_description $exit_code)
|
||||
echo "Alpine $app installation failed: $error_msg"
|
||||
post_update_to_api "failed" $exit_code
|
||||
return $exit_code
|
||||
fi
|
||||
}
|
||||
```
|
||||
|
||||
### With alpine-tools.func
|
||||
|
||||
#### Alpine Tools Reporting
|
||||
```bash
|
||||
# alpine-tools.func uses api.func for Alpine tools reporting
|
||||
source core.func
|
||||
source api.func
|
||||
source alpine-tools.func
|
||||
|
||||
# Alpine tools with API reporting
|
||||
run_alpine_tool_with_reporting() {
|
||||
local tool="$1"
|
||||
|
||||
# Set up API reporting
|
||||
export DIAGNOSTICS="yes"
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
export NSAPP="alpine-tools"
|
||||
export METHOD="tool"
|
||||
|
||||
# Report tool execution start
|
||||
post_to_api
|
||||
|
||||
# Run Alpine tool using alpine-tools.func
|
||||
if run_alpine_tool "$tool"; then
|
||||
echo "Alpine tool $tool executed successfully"
|
||||
post_update_to_api "success" 0
|
||||
return 0
|
||||
else
|
||||
local exit_code=$?
|
||||
local error_msg=$(get_error_description $exit_code)
|
||||
echo "Alpine tool $tool failed: $error_msg"
|
||||
post_update_to_api "failed" $exit_code
|
||||
return $exit_code
|
||||
fi
|
||||
}
|
||||
```
|
||||
|
||||
### With passthrough.func
|
||||
|
||||
#### Hardware Passthrough Reporting
|
||||
```bash
|
||||
# passthrough.func uses api.func for hardware reporting
|
||||
source core.func
|
||||
source api.func
|
||||
source passthrough.func
|
||||
|
||||
# Hardware passthrough with API reporting
|
||||
configure_passthrough_with_reporting() {
|
||||
local hardware_type="$1"
|
||||
|
||||
# Set up API reporting
|
||||
export DIAGNOSTICS="yes"
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
export NSAPP="passthrough"
|
||||
export METHOD="hardware"
|
||||
|
||||
# Report passthrough configuration start
|
||||
post_to_api
|
||||
|
||||
# Configure passthrough using passthrough.func
|
||||
if configure_passthrough "$hardware_type"; then
|
||||
echo "Hardware passthrough configured successfully"
|
||||
post_update_to_api "success" 0
|
||||
return 0
|
||||
else
|
||||
local exit_code=$?
|
||||
local error_msg=$(get_error_description $exit_code)
|
||||
echo "Hardware passthrough failed: $error_msg"
|
||||
post_update_to_api "failed" $exit_code
|
||||
return $exit_code
|
||||
fi
|
||||
}
|
||||
```
|
||||
|
||||
### With tools.func
|
||||
|
||||
#### Maintenance Operations Reporting
|
||||
```bash
|
||||
# tools.func uses api.func for maintenance reporting
|
||||
source core.func
|
||||
source api.func
|
||||
source tools.func
|
||||
|
||||
# Maintenance operations with API reporting
|
||||
run_maintenance_with_reporting() {
|
||||
local operation="$1"
|
||||
|
||||
# Set up API reporting
|
||||
export DIAGNOSTICS="yes"
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
export NSAPP="maintenance"
|
||||
export METHOD="tool"
|
||||
|
||||
# Report maintenance start
|
||||
post_to_api
|
||||
|
||||
# Run maintenance using tools.func
|
||||
if run_maintenance_operation "$operation"; then
|
||||
echo "Maintenance operation $operation completed successfully"
|
||||
post_update_to_api "success" 0
|
||||
return 0
|
||||
else
|
||||
local exit_code=$?
|
||||
local error_msg=$(get_error_description $exit_code)
|
||||
echo "Maintenance operation $operation failed: $error_msg"
|
||||
post_update_to_api "failed" $exit_code
|
||||
return $exit_code
|
||||
fi
|
||||
}
|
||||
```
|
||||
|
||||
## Data Flow
|
||||
|
||||
### Input Data
|
||||
|
||||
#### Environment Variables from Other Scripts
|
||||
- **`CT_TYPE`**: Container type (1 for LXC, 2 for VM)
|
||||
- **`DISK_SIZE`**: Disk size in GB
|
||||
- **`CORE_COUNT`**: Number of CPU cores
|
||||
- **`RAM_SIZE`**: RAM size in MB
|
||||
- **`var_os`**: Operating system type
|
||||
- **`var_version`**: OS version
|
||||
- **`DISABLEIP6`**: IPv6 disable setting
|
||||
- **`NSAPP`**: Namespace application name
|
||||
- **`METHOD`**: Installation method
|
||||
- **`DIAGNOSTICS`**: Enable/disable diagnostic reporting
|
||||
- **`RANDOM_UUID`**: Unique identifier for tracking
|
||||
#### Environment Variables
|
||||
| Variable | Source | Description |
|
||||
|----------|--------|-------------|
|
||||
| `CT_TYPE` | build.func | Container type (1=LXC, 2=VM) |
|
||||
| `DISK_SIZE` | build.func / vm-core.func | Disk size in GB (VMs may have `G` suffix) |
|
||||
| `CORE_COUNT` | build.func / vm-core.func | CPU core count |
|
||||
| `RAM_SIZE` | build.func / vm-core.func | RAM in MB |
|
||||
| `var_os` | core.func | Operating system type |
|
||||
| `var_version` | core.func | OS version |
|
||||
| `NSAPP` | Installation scripts | Application name |
|
||||
| `METHOD` | Installation scripts | Installation method |
|
||||
| `DIAGNOSTICS` | User config / diagnostics file | Enable/disable telemetry |
|
||||
| `RANDOM_UUID` | Caller | Session tracking UUID |
|
||||
|
||||
#### Function Parameters
|
||||
- **Exit codes**: Passed to `get_error_description()` and `post_update_to_api()`
|
||||
- **Status information**: Passed to `post_update_to_api()`
|
||||
- **API endpoints**: Hardcoded in functions
|
||||
- **Exit codes**: Passed to `explain_exit_code()` and `post_update_to_api()`
|
||||
- **Status strings**: Passed to `post_update_to_api()` (`"done"`, `"failed"`)
|
||||
|
||||
#### System Information
|
||||
- **PVE version**: Retrieved from `pveversion` command
|
||||
- **Disk size processing**: Processed for VM API (removes 'G' suffix)
|
||||
- **Error codes**: Retrieved from command exit codes
|
||||
- **PVE version**: Retrieved from `pveversion` command at runtime
|
||||
- **Disk size**: VM disk size is stripped of `G` suffix before sending
|
||||
|
||||
### Processing Data
|
||||
### Processing
|
||||
|
||||
#### API Request Preparation
|
||||
- **JSON payload creation**: Format data for API consumption
|
||||
- **Data validation**: Ensure required fields are present
|
||||
- **Error handling**: Handle missing or invalid data
|
||||
- **Content type setting**: Set appropriate HTTP headers
|
||||
#### Record Creation (POST)
|
||||
1. Validate prerequisites (curl, DIAGNOSTICS, RANDOM_UUID)
|
||||
2. Gather PVE version
|
||||
3. Build JSON payload with all telemetry fields
|
||||
4. `POST` to `PB_API_URL`
|
||||
5. Extract `PB_RECORD_ID` from PocketBase response (HTTP 200/201)
|
||||
|
||||
#### Error Processing
|
||||
- **Error code mapping**: Map numeric codes to descriptions
|
||||
- **Error message formatting**: Format error descriptions
|
||||
- **Unknown error handling**: Handle unrecognized error codes
|
||||
- **Fallback messages**: Provide default error messages
|
||||
|
||||
#### API Communication
|
||||
- **HTTP request preparation**: Prepare curl commands
|
||||
- **Response handling**: Capture HTTP response codes
|
||||
- **Error handling**: Handle network and API errors
|
||||
- **Duplicate prevention**: Prevent duplicate status updates
|
||||
#### Record Update (PATCH)
|
||||
1. Validate prerequisites + check `POST_UPDATE_DONE` flag
|
||||
2. Map status string → PocketBase select value (`"done"` → `"sucess"`)
|
||||
3. For failures: call `explain_exit_code()` to get error description
|
||||
4. Resolve record ID: use `PB_RECORD_ID` or fall back to GET lookup
|
||||
5. `PATCH` to `PB_API_URL/{record_id}` with status, error, exit_code
|
||||
6. Set `POST_UPDATE_DONE=true`
|
||||
|
||||
### Output Data
|
||||
|
||||
#### API Communication
|
||||
- **HTTP requests**: Sent to community-scripts.org API
|
||||
- **Response codes**: Captured from API responses
|
||||
- **Error information**: Reported to API
|
||||
- **Status updates**: Sent to API
|
||||
#### PocketBase Records
|
||||
- **POST response**: Returns record with `id` field → stored in `PB_RECORD_ID`
|
||||
- **PATCH response**: Updates record fields (status, error, exit_code)
|
||||
- **GET response**: Used for record ID lookup by `random_id` filter
|
||||
|
||||
#### Error Information
|
||||
- **Error descriptions**: Human-readable error messages
|
||||
- **Error codes**: Mapped to descriptions
|
||||
- **Context information**: Error context and details
|
||||
- **Fallback messages**: Default error messages
|
||||
|
||||
#### System State
|
||||
- **POST_UPDATE_DONE**: Prevents duplicate updates
|
||||
- **RESPONSE**: Stores API response
|
||||
- **JSON_PAYLOAD**: Stores formatted API data
|
||||
- **API_URL**: Stores API endpoint
|
||||
#### Internal State
|
||||
| Variable | Description |
|
||||
|----------|-------------|
|
||||
| `PB_RECORD_ID` | PocketBase record ID for PATCH calls |
|
||||
| `POST_UPDATE_DONE` | Flag preventing duplicate updates |
|
||||
|
||||
## API Surface
|
||||
|
||||
### Public Functions
|
||||
|
||||
#### Error Description
|
||||
- **`get_error_description()`**: Convert exit codes to explanations
|
||||
- **Parameters**: Exit code to explain
|
||||
- **Returns**: Human-readable explanation string
|
||||
- **Usage**: Called by other functions and scripts
|
||||
| Function | Purpose | HTTP Method |
|
||||
|----------|---------|-------------|
|
||||
| `explain_exit_code(code)` | Map exit code to description | — |
|
||||
| `post_to_api()` | Create LXC telemetry record | POST |
|
||||
| `post_to_api_vm()` | Create VM telemetry record | POST |
|
||||
| `post_update_to_api(status, exit_code)` | Update record with final status | PATCH |
|
||||
|
||||
#### API Communication
|
||||
- **`post_to_api()`**: Send LXC installation data
|
||||
- **`post_to_api_vm()`**: Send VM installation data
|
||||
- **`post_update_to_api()`**: Send status updates
|
||||
- **Parameters**: Status and exit code (for updates)
|
||||
- **Returns**: None
|
||||
- **Usage**: Called by installation scripts
|
||||
### PocketBase Collection Schema
|
||||
|
||||
### Internal Functions
|
||||
Collection: `_dev_telemetry_data`
|
||||
|
||||
#### None
|
||||
- All functions in api.func are public
|
||||
- No internal helper functions
|
||||
- Direct implementation of all functionality
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `id` | text (auto) | yes | PocketBase record ID (15 chars) |
|
||||
| `random_id` | text | yes | Session UUID (min 8 chars, unique) |
|
||||
| `type` | select | yes | `"lxc"`, `"vm"`, `"addon"`, `"pve"` |
|
||||
| `ct_type` | number | yes | 1 (LXC) or 2 (VM) |
|
||||
| `nsapp` | text | yes | Application name |
|
||||
| `status` | select | yes | `"installing"`, `"sucess"`, `"failed"`, `"unknown"` |
|
||||
| `disk_size` | number | no | Disk size in GB |
|
||||
| `core_count` | number | no | CPU cores |
|
||||
| `ram_size` | number | no | RAM in MB |
|
||||
| `os_type` | text | no | OS type |
|
||||
| `os_version` | text | no | OS version |
|
||||
| `pve_version` | text | no | Proxmox VE version |
|
||||
| `method` | text | no | Installation method |
|
||||
| `error` | text | no | Error description |
|
||||
| `exit_code` | number | no | Numeric exit code |
|
||||
| `created` | autodate | auto | Record creation timestamp |
|
||||
| `updated` | autodate | auto | Last update timestamp |
|
||||
|
||||
### Global Variables
|
||||
> **Note**: The `status` field intentionally uses the spelling `"sucess"` (not `"success"`).
|
||||
|
||||
#### Configuration Variables
|
||||
- **`DIAGNOSTICS`**: Diagnostic reporting setting
|
||||
- **`RANDOM_UUID`**: Unique tracking identifier
|
||||
- **`POST_UPDATE_DONE`**: Duplicate update prevention
|
||||
|
||||
#### Data Variables
|
||||
- **`CT_TYPE`**: Container type
|
||||
- **`DISK_SIZE`**: Disk size
|
||||
- **`CORE_COUNT`**: CPU core count
|
||||
- **`RAM_SIZE`**: RAM size
|
||||
- **`var_os`**: Operating system
|
||||
- **`var_version`**: OS version
|
||||
- **`DISABLEIP6`**: IPv6 setting
|
||||
- **`NSAPP`**: Application namespace
|
||||
- **`METHOD`**: Installation method
|
||||
|
||||
#### Internal Variables
|
||||
- **`API_URL`**: API endpoint URL
|
||||
- **`JSON_PAYLOAD`**: API request payload
|
||||
- **`RESPONSE`**: API response
|
||||
- **`DISK_SIZE_API`**: Processed disk size for VM API
|
||||
### Configuration Variables
|
||||
| Variable | Value |
|
||||
|----------|-------|
|
||||
| `PB_URL` | `http://db.community-scripts.org` |
|
||||
| `PB_COLLECTION` | `_dev_telemetry_data` |
|
||||
| `PB_API_URL` | `${PB_URL}/api/collections/${PB_COLLECTION}/records` |
|
||||
|
||||
## Integration Patterns
|
||||
|
||||
@ -479,45 +280,39 @@ run_maintenance_with_reporting() {
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
# Standard integration pattern
|
||||
|
||||
# 1. Source core.func first
|
||||
# 1. Source dependencies
|
||||
source core.func
|
||||
|
||||
# 2. Source api.func
|
||||
source api.func
|
||||
|
||||
# 3. Set up API reporting
|
||||
# 2. Enable telemetry
|
||||
export DIAGNOSTICS="yes"
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
|
||||
# 4. Set application parameters
|
||||
# 3. Set application parameters
|
||||
export NSAPP="$APP"
|
||||
export METHOD="install"
|
||||
|
||||
# 5. Report installation start
|
||||
# 4. POST → create telemetry record in PocketBase
|
||||
post_to_api
|
||||
|
||||
# 6. Perform installation
|
||||
# 5. Perform installation
|
||||
# ... installation logic ...
|
||||
|
||||
# 7. Report completion
|
||||
post_update_to_api "success" 0
|
||||
# 6. PATCH → update record with final status
|
||||
post_update_to_api "done" 0
|
||||
```
|
||||
|
||||
### Minimal Integration Pattern
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
# Minimal integration pattern
|
||||
|
||||
source api.func
|
||||
|
||||
# Basic error reporting
|
||||
export DIAGNOSTICS="yes"
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
|
||||
# Report failure
|
||||
# Report failure (PATCH via record lookup)
|
||||
post_update_to_api "failed" 127
|
||||
```
|
||||
|
||||
@ -525,13 +320,10 @@ post_update_to_api "failed" 127
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
# Advanced integration pattern
|
||||
|
||||
source core.func
|
||||
source api.func
|
||||
source error_handler.func
|
||||
|
||||
# Set up comprehensive API reporting
|
||||
export DIAGNOSTICS="yes"
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
export CT_TYPE=1
|
||||
@ -542,12 +334,12 @@ export var_os="debian"
|
||||
export var_version="12"
|
||||
export METHOD="install"
|
||||
|
||||
# Enhanced error handling with API reporting
|
||||
# Enhanced error handler with PocketBase reporting
|
||||
enhanced_error_handler() {
|
||||
local exit_code=${1:-$?}
|
||||
local command=${2:-${BASH_COMMAND:-unknown}}
|
||||
|
||||
local error_msg=$(get_error_description $exit_code)
|
||||
local error_msg=$(explain_exit_code $exit_code)
|
||||
echo "Error $exit_code: $error_msg"
|
||||
|
||||
post_update_to_api "failed" $exit_code
|
||||
@ -556,88 +348,39 @@ enhanced_error_handler() {
|
||||
|
||||
trap 'enhanced_error_handler' ERR
|
||||
|
||||
# Advanced operations with API reporting
|
||||
# POST → create record
|
||||
post_to_api
|
||||
|
||||
# ... operations ...
|
||||
post_update_to_api "success" 0
|
||||
|
||||
# PATCH → finalize
|
||||
post_update_to_api "done" 0
|
||||
```
|
||||
|
||||
## Error Handling Integration
|
||||
|
||||
### Automatic Error Reporting
|
||||
- **Error Descriptions**: Provides human-readable error messages
|
||||
- **API Integration**: Reports errors to community-scripts.org API
|
||||
- **Error Tracking**: Tracks error patterns for project improvement
|
||||
- **Diagnostic Data**: Contributes to anonymous usage analytics
|
||||
|
||||
### Manual Error Reporting
|
||||
- **Custom Error Codes**: Use appropriate error codes for different scenarios
|
||||
- **Error Context**: Provide context information for errors
|
||||
- **Status Updates**: Report both success and failure cases
|
||||
- **Error Analysis**: Analyze error patterns and trends
|
||||
- **Error Descriptions**: `explain_exit_code()` provides human-readable messages for all recognized exit codes
|
||||
- **PocketBase Integration**: Errors are recorded via PATCH with `status`, `error`, and `exit_code` fields
|
||||
- **Error Tracking**: Anonymous telemetry helps track common failure patterns
|
||||
- **Diagnostic Data**: Contributes to project-wide analytics without PII
|
||||
|
||||
### API Communication Errors
|
||||
- **Network Failures**: Handle API communication failures gracefully
|
||||
- **Missing Prerequisites**: Check prerequisites before API calls
|
||||
- **Duplicate Prevention**: Prevent duplicate status updates
|
||||
- **Error Recovery**: Handle API errors without blocking installation
|
||||
- **Network Failures**: All API calls use `|| true` — failures are swallowed silently
|
||||
- **Missing Prerequisites**: Functions return early if curl, DIAGNOSTICS, or UUID are missing
|
||||
- **Duplicate Prevention**: `POST_UPDATE_DONE` flag ensures only one PATCH per session
|
||||
- **Record Lookup Fallback**: If `PB_RECORD_ID` is unset, a GET filter query resolves the record
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### API Communication Overhead
|
||||
- **Minimal Impact**: API calls add minimal overhead
|
||||
- **Asynchronous**: API calls don't block installation process
|
||||
- **Error Handling**: API failures don't affect installation
|
||||
- **Optional**: API reporting is optional and can be disabled
|
||||
- **Minimal Impact**: Only 2 HTTP calls per installation (1 POST + 1 PATCH)
|
||||
- **Non-blocking**: API failures never block the installation process
|
||||
- **Fire-and-forget**: curl stderr is suppressed (`2>/dev/null`)
|
||||
- **Optional**: Telemetry is entirely opt-in via `DIAGNOSTICS` setting
|
||||
|
||||
### Memory Usage
|
||||
- **Minimal Footprint**: API functions use minimal memory
|
||||
- **Variable Reuse**: Global variables reused across functions
|
||||
- **No Memory Leaks**: Proper cleanup prevents memory leaks
|
||||
- **Efficient Processing**: Efficient JSON payload creation
|
||||
|
||||
### Execution Speed
|
||||
- **Fast API Calls**: Quick API communication
|
||||
- **Efficient Error Processing**: Fast error code processing
|
||||
- **Minimal Delay**: Minimal delay in API operations
|
||||
- **Non-blocking**: API calls don't block installation
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Data Privacy
|
||||
- **Anonymous Reporting**: Only anonymous data is sent
|
||||
- **No Sensitive Data**: No sensitive information is transmitted
|
||||
- **User Control**: Users can disable diagnostic reporting
|
||||
- **Data Minimization**: Only necessary data is sent
|
||||
|
||||
### API Security
|
||||
- **HTTPS**: API communication uses secure protocols
|
||||
- **Data Validation**: API data is validated before sending
|
||||
- **Error Handling**: API errors are handled securely
|
||||
- **No Credentials**: No authentication credentials are sent
|
||||
|
||||
### Network Security
|
||||
- **Secure Communication**: Uses secure HTTP protocols
|
||||
- **Error Handling**: Network errors are handled gracefully
|
||||
- **No Data Leakage**: No sensitive data is leaked
|
||||
- **Secure Endpoints**: Uses trusted API endpoints
|
||||
|
||||
## Future Integration Considerations
|
||||
|
||||
### Extensibility
|
||||
- **New API Endpoints**: Easy to add new API endpoints
|
||||
- **Additional Data**: Easy to add new data fields
|
||||
- **Error Codes**: Easy to add new error code descriptions
|
||||
- **API Versions**: Easy to support new API versions
|
||||
|
||||
### Compatibility
|
||||
- **API Versioning**: Compatible with different API versions
|
||||
- **Data Format**: Compatible with different data formats
|
||||
- **Error Codes**: Compatible with different error code systems
|
||||
- **Network Protocols**: Compatible with different network protocols
|
||||
|
||||
### Performance
|
||||
- **Optimization**: API communication can be optimized
|
||||
- **Caching**: API responses can be cached
|
||||
- **Batch Operations**: Multiple operations can be batched
|
||||
- **Async Processing**: API calls can be made asynchronous
|
||||
### Security Considerations
|
||||
- **Anonymous**: No personal data is transmitted — only system specs and app names
|
||||
- **No Auth Required**: PocketBase collection rules allow anonymous create/update
|
||||
- **User Control**: Users can disable telemetry by setting `DIAGNOSTICS=no`
|
||||
- **HTTP**: API uses HTTP (not HTTPS) for compatibility with minimal containers
|
||||
|
||||
@ -1,794 +0,0 @@
|
||||
# api.func Usage Examples
|
||||
|
||||
## Overview
|
||||
|
||||
This document provides practical usage examples for `api.func` functions, covering common scenarios, integration patterns, and best practices.
|
||||
|
||||
## Basic API Setup
|
||||
|
||||
### Standard API Initialization
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
# Standard API setup for LXC containers
|
||||
|
||||
source api.func
|
||||
|
||||
# Set up diagnostic reporting
|
||||
export DIAGNOSTICS="yes"
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
|
||||
# Set container parameters
|
||||
export CT_TYPE=1
|
||||
export DISK_SIZE=8
|
||||
export CORE_COUNT=2
|
||||
export RAM_SIZE=2048
|
||||
export var_os="debian"
|
||||
export var_version="12"
|
||||
export NSAPP="plex"
|
||||
export METHOD="install"
|
||||
|
||||
# Report installation start
|
||||
post_to_api
|
||||
|
||||
# Your installation code here
|
||||
# ... installation logic ...
|
||||
|
||||
# Report completion
|
||||
if [[ $? -eq 0 ]]; then
|
||||
post_update_to_api "success" 0
|
||||
else
|
||||
post_update_to_api "failed" $?
|
||||
fi
|
||||
```
|
||||
|
||||
### VM API Setup
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
# API setup for VMs
|
||||
|
||||
source api.func
|
||||
|
||||
# Create diagnostics file for VM
|
||||
mkdir -p /usr/local/community-scripts
|
||||
echo "DIAGNOSTICS=yes" > /usr/local/community-scripts/diagnostics
|
||||
|
||||
# Set up VM parameters
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
export DISK_SIZE="20G"
|
||||
export CORE_COUNT=4
|
||||
export RAM_SIZE=4096
|
||||
export var_os="ubuntu"
|
||||
export var_version="22.04"
|
||||
export NSAPP="nextcloud"
|
||||
export METHOD="install"
|
||||
|
||||
# Report VM installation start
|
||||
post_to_api_vm
|
||||
|
||||
# Your VM installation code here
|
||||
# ... VM creation logic ...
|
||||
|
||||
# Report completion
|
||||
post_update_to_api "success" 0
|
||||
```
|
||||
|
||||
## Error Description Examples
|
||||
|
||||
### Basic Error Explanation
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
source api.func
|
||||
|
||||
# Explain common error codes
|
||||
echo "Error 0: '$(get_error_description 0)'"
|
||||
echo "Error 1: $(get_error_description 1)"
|
||||
echo "Error 127: $(get_error_description 127)"
|
||||
echo "Error 200: $(get_error_description 200)"
|
||||
echo "Error 255: $(get_error_description 255)"
|
||||
```
|
||||
|
||||
### Error Code Testing
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
source api.func
|
||||
|
||||
# Test all error codes
|
||||
test_error_codes() {
|
||||
local codes=(0 1 2 127 128 130 137 139 143 200 203 205 255)
|
||||
|
||||
for code in "${codes[@]}"; do
|
||||
echo "Code $code: $(get_error_description $code)"
|
||||
done
|
||||
}
|
||||
|
||||
test_error_codes
|
||||
```
|
||||
|
||||
### Error Handling with Descriptions
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
source api.func
|
||||
|
||||
# Function with error handling
|
||||
run_command_with_error_handling() {
|
||||
local command="$1"
|
||||
local description="$2"
|
||||
|
||||
echo "Running: $description"
|
||||
|
||||
if $command; then
|
||||
echo "Success: $description"
|
||||
return 0
|
||||
else
|
||||
local exit_code=$?
|
||||
local error_msg=$(get_error_description $exit_code)
|
||||
echo "Error $exit_code: $error_msg"
|
||||
return $exit_code
|
||||
fi
|
||||
}
|
||||
|
||||
# Usage
|
||||
run_command_with_error_handling "apt-get update" "Package list update"
|
||||
run_command_with_error_handling "nonexistent_command" "Test command"
|
||||
```
|
||||
|
||||
## API Communication Examples
|
||||
|
||||
### LXC Installation Reporting
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
source api.func
|
||||
|
||||
# Complete LXC installation with API reporting
|
||||
install_lxc_with_reporting() {
|
||||
local app="$1"
|
||||
local ctid="$2"
|
||||
|
||||
# Set up API reporting
|
||||
export DIAGNOSTICS="yes"
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
export CT_TYPE=1
|
||||
export DISK_SIZE=10
|
||||
export CORE_COUNT=2
|
||||
export RAM_SIZE=2048
|
||||
export var_os="debian"
|
||||
export var_version="12"
|
||||
export NSAPP="$app"
|
||||
export METHOD="install"
|
||||
|
||||
# Report installation start
|
||||
post_to_api
|
||||
|
||||
# Installation process
|
||||
echo "Installing $app container (ID: $ctid)..."
|
||||
|
||||
# Simulate installation
|
||||
sleep 2
|
||||
|
||||
# Check if installation succeeded
|
||||
if [[ $? -eq 0 ]]; then
|
||||
echo "Installation completed successfully"
|
||||
post_update_to_api "success" 0
|
||||
return 0
|
||||
else
|
||||
echo "Installation failed"
|
||||
post_update_to_api "failed" $?
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Install multiple containers
|
||||
install_lxc_with_reporting "plex" "100"
|
||||
install_lxc_with_reporting "nextcloud" "101"
|
||||
install_lxc_with_reporting "nginx" "102"
|
||||
```
|
||||
|
||||
### VM Installation Reporting
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
source api.func
|
||||
|
||||
# Complete VM installation with API reporting
|
||||
install_vm_with_reporting() {
|
||||
local app="$1"
|
||||
local vmid="$2"
|
||||
|
||||
# Create diagnostics file
|
||||
mkdir -p /usr/local/community-scripts
|
||||
echo "DIAGNOSTICS=yes" > /usr/local/community-scripts/diagnostics
|
||||
|
||||
# Set up API reporting
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
export DISK_SIZE="20G"
|
||||
export CORE_COUNT=4
|
||||
export RAM_SIZE=4096
|
||||
export var_os="ubuntu"
|
||||
export var_version="22.04"
|
||||
export NSAPP="$app"
|
||||
export METHOD="install"
|
||||
|
||||
# Report VM installation start
|
||||
post_to_api_vm
|
||||
|
||||
# VM installation process
|
||||
echo "Installing $app VM (ID: $vmid)..."
|
||||
|
||||
# Simulate VM creation
|
||||
sleep 3
|
||||
|
||||
# Check if VM creation succeeded
|
||||
if [[ $? -eq 0 ]]; then
|
||||
echo "VM installation completed successfully"
|
||||
post_update_to_api "success" 0
|
||||
return 0
|
||||
else
|
||||
echo "VM installation failed"
|
||||
post_update_to_api "failed" $?
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Install multiple VMs
|
||||
install_vm_with_reporting "nextcloud" "200"
|
||||
install_vm_with_reporting "wordpress" "201"
|
||||
```
|
||||
|
||||
## Status Update Examples
|
||||
|
||||
### Success Reporting
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
source api.func
|
||||
|
||||
# Report successful installation
|
||||
report_success() {
|
||||
local operation="$1"
|
||||
|
||||
export DIAGNOSTICS="yes"
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
|
||||
echo "Reporting successful $operation"
|
||||
post_update_to_api "success" 0
|
||||
}
|
||||
|
||||
# Usage
|
||||
report_success "container installation"
|
||||
report_success "package installation"
|
||||
report_success "service configuration"
|
||||
```
|
||||
|
||||
### Failure Reporting
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
source api.func
|
||||
|
||||
# Report failed installation
|
||||
report_failure() {
|
||||
local operation="$1"
|
||||
local exit_code="$2"
|
||||
|
||||
export DIAGNOSTICS="yes"
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
|
||||
local error_msg=$(get_error_description $exit_code)
|
||||
echo "Reporting failed $operation: $error_msg"
|
||||
post_update_to_api "failed" $exit_code
|
||||
}
|
||||
|
||||
# Usage
|
||||
report_failure "container creation" 200
|
||||
report_failure "package installation" 127
|
||||
report_failure "service start" 1
|
||||
```
|
||||
|
||||
### Conditional Status Reporting
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
source api.func
|
||||
|
||||
# Conditional status reporting
|
||||
report_installation_status() {
|
||||
local operation="$1"
|
||||
local exit_code="$2"
|
||||
|
||||
export DIAGNOSTICS="yes"
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
|
||||
if [[ $exit_code -eq 0 ]]; then
|
||||
echo "Reporting successful $operation"
|
||||
post_update_to_api "success" 0
|
||||
else
|
||||
local error_msg=$(get_error_description $exit_code)
|
||||
echo "Reporting failed $operation: $error_msg"
|
||||
post_update_to_api "failed" $exit_code
|
||||
fi
|
||||
}
|
||||
|
||||
# Usage
|
||||
report_installation_status "container creation" 0
|
||||
report_installation_status "package installation" 127
|
||||
```
|
||||
|
||||
## Advanced Usage Examples
|
||||
|
||||
### Batch Installation with API Reporting
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
source api.func
|
||||
|
||||
# Batch installation with comprehensive API reporting
|
||||
batch_install_with_reporting() {
|
||||
local apps=("plex" "nextcloud" "nginx" "mysql")
|
||||
local ctids=(100 101 102 103)
|
||||
|
||||
# Set up API reporting
|
||||
export DIAGNOSTICS="yes"
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
export CT_TYPE=1
|
||||
export DISK_SIZE=8
|
||||
export CORE_COUNT=2
|
||||
export RAM_SIZE=2048
|
||||
export var_os="debian"
|
||||
export var_version="12"
|
||||
export METHOD="install"
|
||||
|
||||
local success_count=0
|
||||
local failure_count=0
|
||||
|
||||
for i in "${!apps[@]}"; do
|
||||
local app="${apps[$i]}"
|
||||
local ctid="${ctids[$i]}"
|
||||
|
||||
echo "Installing $app (ID: $ctid)..."
|
||||
|
||||
# Set app-specific parameters
|
||||
export NSAPP="$app"
|
||||
|
||||
# Report installation start
|
||||
post_to_api
|
||||
|
||||
# Simulate installation
|
||||
if install_app "$app" "$ctid"; then
|
||||
echo "$app installed successfully"
|
||||
post_update_to_api "success" 0
|
||||
((success_count++))
|
||||
else
|
||||
echo "$app installation failed"
|
||||
post_update_to_api "failed" $?
|
||||
((failure_count++))
|
||||
fi
|
||||
|
||||
echo "---"
|
||||
done
|
||||
|
||||
echo "Batch installation completed: $success_count successful, $failure_count failed"
|
||||
}
|
||||
|
||||
# Mock installation function
|
||||
install_app() {
|
||||
local app="$1"
|
||||
local ctid="$2"
|
||||
|
||||
# Simulate installation
|
||||
sleep 1
|
||||
|
||||
# Simulate occasional failures
|
||||
if [[ $((RANDOM % 10)) -eq 0 ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
batch_install_with_reporting
|
||||
```
|
||||
|
||||
### Error Analysis and Reporting
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
source api.func
|
||||
|
||||
# Analyze and report errors
|
||||
analyze_and_report_errors() {
|
||||
local log_file="$1"
|
||||
|
||||
export DIAGNOSTICS="yes"
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
|
||||
if [[ ! -f "$log_file" ]]; then
|
||||
echo "Log file not found: $log_file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Extract error codes from log
|
||||
local error_codes=$(grep -o 'exit code [0-9]\+' "$log_file" | grep -o '[0-9]\+' | sort -u)
|
||||
|
||||
if [[ -z "$error_codes" ]]; then
|
||||
echo "No errors found in log"
|
||||
post_update_to_api "success" 0
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "Found error codes: $error_codes"
|
||||
|
||||
# Report each unique error
|
||||
for code in $error_codes; do
|
||||
local error_msg=$(get_error_description $code)
|
||||
echo "Error $code: $error_msg"
|
||||
post_update_to_api "failed" $code
|
||||
done
|
||||
}
|
||||
|
||||
# Usage
|
||||
analyze_and_report_errors "/var/log/installation.log"
|
||||
```
|
||||
|
||||
### API Health Check
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
source api.func
|
||||
|
||||
# Check API connectivity and functionality
|
||||
check_api_health() {
|
||||
echo "Checking API health..."
|
||||
|
||||
# Test prerequisites
|
||||
if ! command -v curl >/dev/null 2>&1; then
|
||||
echo "ERROR: curl not available"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Test error description function
|
||||
local test_error=$(get_error_description 127)
|
||||
if [[ -z "$test_error" ]]; then
|
||||
echo "ERROR: Error description function not working"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "Error description test: $test_error"
|
||||
|
||||
# Test API connectivity (without sending data)
|
||||
local api_url="http://api.community-scripts.org/dev/upload"
|
||||
if curl -s --head "$api_url" >/dev/null 2>&1; then
|
||||
echo "API endpoint is reachable"
|
||||
else
|
||||
echo "WARNING: API endpoint not reachable"
|
||||
fi
|
||||
|
||||
echo "API health check completed"
|
||||
}
|
||||
|
||||
check_api_health
|
||||
```
|
||||
|
||||
## Integration Examples
|
||||
|
||||
### With build.func
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
# Integration with build.func
|
||||
|
||||
source core.func
|
||||
source api.func
|
||||
source build.func
|
||||
|
||||
# Set up API reporting
|
||||
export DIAGNOSTICS="yes"
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
|
||||
# Container creation with API reporting
|
||||
create_container_with_reporting() {
|
||||
local app="$1"
|
||||
local ctid="$2"
|
||||
|
||||
# Set container parameters
|
||||
export APP="$app"
|
||||
export CTID="$ctid"
|
||||
export var_hostname="${app}-server"
|
||||
export var_os="debian"
|
||||
export var_version="12"
|
||||
export var_cpu="2"
|
||||
export var_ram="2048"
|
||||
export var_disk="10"
|
||||
export var_net="vmbr0"
|
||||
export var_gateway="192.168.1.1"
|
||||
export var_ip="192.168.1.$ctid"
|
||||
export var_template_storage="local"
|
||||
export var_container_storage="local"
|
||||
|
||||
# Report installation start
|
||||
post_to_api
|
||||
|
||||
# Create container using build.func
|
||||
if source build.func; then
|
||||
echo "Container $app created successfully"
|
||||
post_update_to_api "success" 0
|
||||
return 0
|
||||
else
|
||||
echo "Container $app creation failed"
|
||||
post_update_to_api "failed" $?
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Create containers
|
||||
create_container_with_reporting "plex" "100"
|
||||
create_container_with_reporting "nextcloud" "101"
|
||||
```
|
||||
|
||||
### With vm-core.func
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
# Integration with vm-core.func
|
||||
|
||||
source core.func
|
||||
source api.func
|
||||
source vm-core.func
|
||||
|
||||
# Set up VM API reporting
|
||||
mkdir -p /usr/local/community-scripts
|
||||
echo "DIAGNOSTICS=yes" > /usr/local/community-scripts/diagnostics
|
||||
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
|
||||
# VM creation with API reporting
|
||||
create_vm_with_reporting() {
|
||||
local app="$1"
|
||||
local vmid="$2"
|
||||
|
||||
# Set VM parameters
|
||||
export APP="$app"
|
||||
export VMID="$vmid"
|
||||
export var_hostname="${app}-vm"
|
||||
export var_os="ubuntu"
|
||||
export var_version="22.04"
|
||||
export var_cpu="4"
|
||||
export var_ram="4096"
|
||||
export var_disk="20"
|
||||
|
||||
# Report VM installation start
|
||||
post_to_api_vm
|
||||
|
||||
# Create VM using vm-core.func
|
||||
if source vm-core.func; then
|
||||
echo "VM $app created successfully"
|
||||
post_update_to_api "success" 0
|
||||
return 0
|
||||
else
|
||||
echo "VM $app creation failed"
|
||||
post_update_to_api "failed" $?
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Create VMs
|
||||
create_vm_with_reporting "nextcloud" "200"
|
||||
create_vm_with_reporting "wordpress" "201"
|
||||
```
|
||||
|
||||
### With error_handler.func
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
# Integration with error_handler.func
|
||||
|
||||
source core.func
|
||||
source error_handler.func
|
||||
source api.func
|
||||
|
||||
# Enhanced error handling with API reporting
|
||||
enhanced_error_handler() {
|
||||
local exit_code=${1:-$?}
|
||||
local command=${2:-${BASH_COMMAND:-unknown}}
|
||||
|
||||
# Get error description from api.func
|
||||
local error_msg=$(get_error_description $exit_code)
|
||||
|
||||
# Display error information
|
||||
echo "Error $exit_code: $error_msg"
|
||||
echo "Command: $command"
|
||||
|
||||
# Report error to API
|
||||
export DIAGNOSTICS="yes"
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
post_update_to_api "failed" $exit_code
|
||||
|
||||
# Use standard error handler
|
||||
error_handler $exit_code $command
|
||||
}
|
||||
|
||||
# Set up enhanced error handling
|
||||
trap 'enhanced_error_handler' ERR
|
||||
|
||||
# Test enhanced error handling
|
||||
nonexistent_command
|
||||
```
|
||||
|
||||
## Best Practices Examples
|
||||
|
||||
### Comprehensive API Integration
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
# Comprehensive API integration example
|
||||
|
||||
source core.func
|
||||
source api.func
|
||||
|
||||
# Set up comprehensive API reporting
|
||||
setup_api_reporting() {
|
||||
# Enable diagnostics
|
||||
export DIAGNOSTICS="yes"
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
|
||||
# Set common parameters
|
||||
export CT_TYPE=1
|
||||
export DISK_SIZE=8
|
||||
export CORE_COUNT=2
|
||||
export RAM_SIZE=2048
|
||||
export var_os="debian"
|
||||
export var_version="12"
|
||||
export METHOD="install"
|
||||
|
||||
echo "API reporting configured"
|
||||
}
|
||||
|
||||
# Installation with comprehensive reporting
|
||||
install_with_comprehensive_reporting() {
|
||||
local app="$1"
|
||||
local ctid="$2"
|
||||
|
||||
# Set up API reporting
|
||||
setup_api_reporting
|
||||
export NSAPP="$app"
|
||||
|
||||
# Report installation start
|
||||
post_to_api
|
||||
|
||||
# Installation process
|
||||
echo "Installing $app..."
|
||||
|
||||
# Simulate installation steps
|
||||
local steps=("Downloading" "Installing" "Configuring" "Starting")
|
||||
for step in "${steps[@]}"; do
|
||||
echo "$step $app..."
|
||||
sleep 1
|
||||
done
|
||||
|
||||
# Check installation result
|
||||
if [[ $? -eq 0 ]]; then
|
||||
echo "$app installation completed successfully"
|
||||
post_update_to_api "success" 0
|
||||
return 0
|
||||
else
|
||||
echo "$app installation failed"
|
||||
post_update_to_api "failed" $?
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Install multiple applications
|
||||
apps=("plex" "nextcloud" "nginx" "mysql")
|
||||
ctids=(100 101 102 103)
|
||||
|
||||
for i in "${!apps[@]}"; do
|
||||
install_with_comprehensive_reporting "${apps[$i]}" "${ctids[$i]}"
|
||||
echo "---"
|
||||
done
|
||||
```
|
||||
|
||||
### Error Recovery with API Reporting
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
source api.func
|
||||
|
||||
# Error recovery with API reporting
|
||||
retry_with_api_reporting() {
|
||||
local operation="$1"
|
||||
local max_attempts=3
|
||||
local attempt=1
|
||||
|
||||
export DIAGNOSTICS="yes"
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
|
||||
while [[ $attempt -le $max_attempts ]]; do
|
||||
echo "Attempt $attempt of $max_attempts: $operation"
|
||||
|
||||
if $operation; then
|
||||
echo "Operation succeeded on attempt $attempt"
|
||||
post_update_to_api "success" 0
|
||||
return 0
|
||||
else
|
||||
local exit_code=$?
|
||||
local error_msg=$(get_error_description $exit_code)
|
||||
echo "Attempt $attempt failed: $error_msg"
|
||||
|
||||
post_update_to_api "failed" $exit_code
|
||||
|
||||
((attempt++))
|
||||
|
||||
if [[ $attempt -le $max_attempts ]]; then
|
||||
echo "Retrying in 5 seconds..."
|
||||
sleep 5
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Operation failed after $max_attempts attempts"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Usage
|
||||
retry_with_api_reporting "apt-get update"
|
||||
retry_with_api_reporting "apt-get install -y package"
|
||||
```
|
||||
|
||||
### API Reporting with Logging
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
source api.func
|
||||
|
||||
# API reporting with detailed logging
|
||||
install_with_logging_and_api() {
|
||||
local app="$1"
|
||||
local log_file="/var/log/${app}_installation.log"
|
||||
|
||||
# Set up API reporting
|
||||
export DIAGNOSTICS="yes"
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
export NSAPP="$app"
|
||||
|
||||
# Start logging
|
||||
exec > >(tee -a "$log_file")
|
||||
exec 2>&1
|
||||
|
||||
echo "Starting $app installation at $(date)"
|
||||
|
||||
# Report installation start
|
||||
post_to_api
|
||||
|
||||
# Installation process
|
||||
echo "Installing $app..."
|
||||
|
||||
# Simulate installation
|
||||
if install_app "$app"; then
|
||||
echo "$app installation completed successfully at $(date)"
|
||||
post_update_to_api "success" 0
|
||||
return 0
|
||||
else
|
||||
local exit_code=$?
|
||||
local error_msg=$(get_error_description $exit_code)
|
||||
echo "$app installation failed at $(date): $error_msg"
|
||||
post_update_to_api "failed" $exit_code
|
||||
return $exit_code
|
||||
fi
|
||||
}
|
||||
|
||||
# Mock installation function
|
||||
install_app() {
|
||||
local app="$1"
|
||||
echo "Installing $app..."
|
||||
sleep 2
|
||||
return 0
|
||||
}
|
||||
|
||||
# Install with logging and API reporting
|
||||
install_with_logging_and_api "plex"
|
||||
```
|
||||
@ -2,22 +2,27 @@
|
||||
|
||||
## Overview
|
||||
|
||||
The `api.func` file provides Proxmox API integration and diagnostic reporting functionality for the Community Scripts project. It handles API communication, error reporting, and status updates to the community-scripts.org API.
|
||||
The `api.func` file provides PocketBase API integration and diagnostic reporting for the Community Scripts project. It handles telemetry communication, error reporting, and status updates to the PocketBase backend at `db.community-scripts.org`.
|
||||
|
||||
## Purpose and Use Cases
|
||||
|
||||
- **API Communication**: Send installation and status data to community-scripts.org API
|
||||
- **API Communication**: Send installation and status data to PocketBase
|
||||
- **Diagnostic Reporting**: Report installation progress and errors for analytics
|
||||
- **Error Description**: Provide detailed error code explanations
|
||||
- **Error Description**: Provide detailed error code explanations (canonical source of truth)
|
||||
- **Status Updates**: Track installation success/failure status
|
||||
- **Analytics**: Contribute anonymous usage data for project improvement
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### Key Function Groups
|
||||
- **Error Handling**: `get_error_description()` - Convert exit codes to human-readable messages
|
||||
- **API Communication**: `post_to_api()`, `post_to_api_vm()` - Send installation data
|
||||
- **Status Updates**: `post_update_to_api()` - Report installation completion status
|
||||
- **Error Handling**: `explain_exit_code()` - Convert exit codes to human-readable messages
|
||||
- **API Communication**: `post_to_api()`, `post_to_api_vm()` - Send installation data to PocketBase
|
||||
- **Status Updates**: `post_update_to_api()` - Report installation completion status via PATCH
|
||||
|
||||
### PocketBase Configuration
|
||||
- **URL**: `http://db.community-scripts.org`
|
||||
- **Collection**: `_dev_telemetry_data`
|
||||
- **API Endpoint**: `/api/collections/_dev_telemetry_data/records`
|
||||
|
||||
### Dependencies
|
||||
- **External**: `curl` command for HTTP requests
|
||||
@ -26,7 +31,7 @@ The `api.func` file provides Proxmox API integration and diagnostic reporting fu
|
||||
### Integration Points
|
||||
- Used by: All installation scripts for diagnostic reporting
|
||||
- Uses: Environment variables from build.func and other scripts
|
||||
- Provides: API communication and error reporting services
|
||||
- Provides: API communication, error reporting, and exit code descriptions
|
||||
|
||||
## Documentation Files
|
||||
|
||||
@ -44,17 +49,18 @@ How api.func integrates with other components and provides API services.
|
||||
|
||||
## Key Features
|
||||
|
||||
### Error Code Descriptions
|
||||
- **Comprehensive Coverage**: 50+ error codes with detailed explanations
|
||||
- **LXC-Specific Errors**: Container creation and management errors
|
||||
- **System Errors**: General system and network errors
|
||||
### Exit Code Descriptions
|
||||
- **Canonical source**: Single authoritative `explain_exit_code()` for the entire project
|
||||
- **Non-overlapping ranges**: Clean separation between error categories
|
||||
- **Comprehensive Coverage**: 60+ error codes with detailed explanations
|
||||
- **System Errors**: General system, curl, and network errors
|
||||
- **Signal Errors**: Process termination and signal errors
|
||||
|
||||
### API Communication
|
||||
- **LXC Reporting**: Send LXC container installation data
|
||||
- **VM Reporting**: Send VM installation data
|
||||
- **Status Updates**: Report installation success/failure
|
||||
- **Diagnostic Data**: Anonymous usage analytics
|
||||
### PocketBase Integration
|
||||
- **Record Creation**: POST to create telemetry records with status `installing`
|
||||
- **Record Updates**: PATCH to update with final status, exit code, and error
|
||||
- **ID Tracking**: Stores `PB_RECORD_ID` for efficient updates
|
||||
- **Fallback Lookup**: Searches by `random_id` filter if record ID is lost
|
||||
|
||||
### Diagnostic Integration
|
||||
- **Optional Reporting**: Only sends data when diagnostics enabled
|
||||
@ -67,15 +73,13 @@ How api.func integrates with other components and provides API services.
|
||||
### Basic API Setup
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
# Basic API setup
|
||||
|
||||
source api.func
|
||||
|
||||
# Set up diagnostic reporting
|
||||
export DIAGNOSTICS="yes"
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
export RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
|
||||
|
||||
# Report installation start
|
||||
# Report installation start (creates PocketBase record)
|
||||
post_to_api
|
||||
```
|
||||
|
||||
@ -85,9 +89,9 @@ post_to_api
|
||||
source api.func
|
||||
|
||||
# Get error description
|
||||
error_msg=$(get_error_description 127)
|
||||
echo "Error 127: $error_msg"
|
||||
# Output: Error 127: Command not found: Incorrect path or missing dependency.
|
||||
error_msg=$(explain_exit_code 137)
|
||||
echo "Error 137: $error_msg"
|
||||
# Output: Error 137: Killed (SIGKILL / Out of memory?)
|
||||
```
|
||||
|
||||
### Status Updates
|
||||
@ -96,9 +100,9 @@ echo "Error 127: $error_msg"
|
||||
source api.func
|
||||
|
||||
# Report successful installation
|
||||
post_update_to_api "success" 0
|
||||
post_update_to_api "done" 0
|
||||
|
||||
# Report failed installation
|
||||
# Report failed installation with exit code
|
||||
post_update_to_api "failed" 127
|
||||
```
|
||||
|
||||
@ -106,7 +110,7 @@ post_update_to_api "failed" 127
|
||||
|
||||
### Required Variables
|
||||
- `DIAGNOSTICS`: Enable/disable diagnostic reporting ("yes"/"no")
|
||||
- `RANDOM_UUID`: Unique identifier for tracking
|
||||
- `RANDOM_UUID`: Unique identifier for session tracking
|
||||
|
||||
### Optional Variables
|
||||
- `CT_TYPE`: Container type (1 for LXC, 2 for VM)
|
||||
@ -115,33 +119,31 @@ post_update_to_api "failed" 127
|
||||
- `RAM_SIZE`: RAM size in MB
|
||||
- `var_os`: Operating system type
|
||||
- `var_version`: OS version
|
||||
- `DISABLEIP6`: IPv6 disable setting
|
||||
- `NSAPP`: Namespace application name
|
||||
- `NSAPP`: Application name
|
||||
- `METHOD`: Installation method
|
||||
|
||||
### Internal Variables
|
||||
- `POST_UPDATE_DONE`: Prevents duplicate status updates
|
||||
- `API_URL`: Community scripts API endpoint
|
||||
- `JSON_PAYLOAD`: API request payload
|
||||
- `RESPONSE`: API response
|
||||
- `PB_URL`: PocketBase base URL
|
||||
- `PB_API_URL`: Full API endpoint URL
|
||||
- `PB_RECORD_ID`: Stored PocketBase record ID for updates
|
||||
|
||||
## Error Code Categories
|
||||
## Error Code Categories (Non-Overlapping Ranges)
|
||||
|
||||
### General System Errors
|
||||
- **0-9**: Basic system errors
|
||||
- **18, 22, 28, 35**: Network and I/O errors
|
||||
- **56, 60**: TLS/SSL errors
|
||||
- **125-128**: Command execution errors
|
||||
- **129-143**: Signal errors
|
||||
- **152**: Resource limit errors
|
||||
- **255**: Unknown critical errors
|
||||
|
||||
### LXC-Specific Errors
|
||||
- **100-101**: LXC installation errors
|
||||
- **200-209**: LXC creation and management errors
|
||||
|
||||
### Docker Errors
|
||||
- **125**: Docker container start errors
|
||||
| Range | Category |
|
||||
|-------|----------|
|
||||
| 1-2 | Generic shell errors |
|
||||
| 6-35 | curl/wget network errors |
|
||||
| 100-102 | APT/DPKG package errors |
|
||||
| 124-143 | Command execution & signal errors |
|
||||
| 150-154 | Systemd/service errors |
|
||||
| 160-162 | Python/pip/uv errors |
|
||||
| 170-173 | PostgreSQL errors |
|
||||
| 180-183 | MySQL/MariaDB errors |
|
||||
| 190-193 | MongoDB errors |
|
||||
| 200-231 | Proxmox custom codes |
|
||||
| 243-249 | Node.js/npm errors |
|
||||
| 255 | DPKG fatal error |
|
||||
|
||||
## Best Practices
|
||||
|
||||
@ -152,48 +154,56 @@ post_update_to_api "failed" 127
|
||||
4. Report both success and failure cases
|
||||
|
||||
### Error Handling
|
||||
1. Use appropriate error codes
|
||||
2. Provide meaningful error descriptions
|
||||
1. Use the correct non-overlapping exit code ranges
|
||||
2. Use `explain_exit_code()` from api.func (canonical source)
|
||||
3. Handle API communication failures gracefully
|
||||
4. Don't block installation on API failures
|
||||
|
||||
### API Usage
|
||||
1. Check for curl availability
|
||||
2. Handle network failures gracefully
|
||||
3. Use appropriate HTTP methods
|
||||
4. Include all required data
|
||||
1. Check for curl availability before API calls
|
||||
2. Handle network failures gracefully (all calls use `|| true`)
|
||||
3. Store and reuse PB_RECORD_ID for updates
|
||||
4. Use proper PocketBase REST methods (POST for create, PATCH for update)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
1. **API Communication Fails**: Check network connectivity and curl availability
|
||||
2. **Diagnostics Not Working**: Verify DIAGNOSTICS setting and RANDOM_UUID
|
||||
3. **Missing Error Descriptions**: Check error code coverage
|
||||
4. **Duplicate Updates**: POST_UPDATE_DONE prevents duplicates
|
||||
2. **Diagnostics Not Working**: Verify `DIAGNOSTICS=yes` in `/usr/local/community-scripts/diagnostics`
|
||||
3. **Status Update Fails**: Check that `PB_RECORD_ID` was captured or `random_id` filter works
|
||||
4. **Duplicate Updates**: `POST_UPDATE_DONE` flag prevents duplicates
|
||||
|
||||
### Debug Mode
|
||||
Enable diagnostic reporting for debugging:
|
||||
```bash
|
||||
export DIAGNOSTICS="yes"
|
||||
export RANDOM_UUID="$(uuidgen)"
|
||||
export RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
|
||||
```
|
||||
|
||||
### API Testing
|
||||
Test API communication:
|
||||
Test PocketBase connectivity:
|
||||
```bash
|
||||
curl -s http://db.community-scripts.org/api/health
|
||||
```
|
||||
|
||||
Test record creation:
|
||||
```bash
|
||||
source api.func
|
||||
export DIAGNOSTICS="yes"
|
||||
export RANDOM_UUID="test-$(date +%s)"
|
||||
export NSAPP="test"
|
||||
export CT_TYPE=1
|
||||
post_to_api
|
||||
echo "Record ID: $PB_RECORD_ID"
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [core.func](../core.func/) - Core utilities and error handling
|
||||
- [error_handler.func](../error_handler.func/) - Error handling utilities
|
||||
- [core.func](../core.func/) - Core utilities
|
||||
- [error_handler.func](../error_handler.func/) - Error handling (fallback `explain_exit_code`)
|
||||
- [build.func](../build.func/) - Container creation with API integration
|
||||
- [tools.func](../tools.func/) - Extended utilities with API integration
|
||||
- [tools.func](../tools.func/) - Extended utilities
|
||||
|
||||
---
|
||||
|
||||
*This documentation covers the api.func file which provides API communication and diagnostic reporting for all Proxmox Community Scripts.*
|
||||
*This documentation covers the api.func file which provides PocketBase communication and diagnostic reporting for all Proxmox Community Scripts.*
|
||||
|
||||
208
misc/api.func
208
misc/api.func
@ -3,11 +3,11 @@
|
||||
# License: MIT | https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/LICENSE
|
||||
|
||||
# ==============================================================================
|
||||
# API.FUNC - TELEMETRY & DIAGNOSTICS API
|
||||
# API.FUNC - TELEMETRY & DIAGNOSTICS API (PocketBase)
|
||||
# ==============================================================================
|
||||
#
|
||||
# Provides functions for sending anonymous telemetry data to Community-Scripts
|
||||
# API for analytics and diagnostics purposes.
|
||||
# Provides functions for sending anonymous telemetry data to PocketBase
|
||||
# backend at db.community-scripts.org for analytics and diagnostics.
|
||||
#
|
||||
# Features:
|
||||
# - Container/VM creation statistics
|
||||
@ -18,6 +18,7 @@
|
||||
# Usage:
|
||||
# source <(curl -fsSL .../api.func)
|
||||
# post_to_api # Report container creation
|
||||
# post_to_api_vm # Report VM creation
|
||||
# post_update_to_api # Report installation status
|
||||
#
|
||||
# Privacy:
|
||||
@ -27,6 +28,16 @@
|
||||
#
|
||||
# ==============================================================================
|
||||
|
||||
# ==============================================================================
|
||||
# PocketBase Configuration
|
||||
# ==============================================================================
|
||||
PB_URL="http://db.community-scripts.org"
|
||||
PB_COLLECTION="_dev_telemetry_data"
|
||||
PB_API_URL="${PB_URL}/api/collections/${PB_COLLECTION}/records"
|
||||
|
||||
# Store PocketBase record ID for update operations
|
||||
PB_RECORD_ID=""
|
||||
|
||||
# ==============================================================================
|
||||
# SECTION 1: ERROR CODE DESCRIPTIONS
|
||||
# ==============================================================================
|
||||
@ -35,6 +46,8 @@
|
||||
# explain_exit_code()
|
||||
#
|
||||
# - Maps numeric exit codes to human-readable error descriptions
|
||||
# - Canonical source of truth for ALL exit code mappings
|
||||
# - Used by both api.func (telemetry) and error_handler.func (error display)
|
||||
# - Supports:
|
||||
# * Generic/Shell errors (1, 2, 124, 126-130, 134, 137, 139, 141, 143)
|
||||
# * curl/wget errors (6, 7, 22, 28, 35)
|
||||
@ -47,7 +60,6 @@
|
||||
# * Proxmox custom codes (200-231)
|
||||
# * Node.js/npm errors (243, 245-249)
|
||||
# - Returns description string for given exit code
|
||||
# - Shared function with error_handler.func for consistency
|
||||
# ------------------------------------------------------------------------------
|
||||
explain_exit_code() {
|
||||
local code="$1"
|
||||
@ -160,7 +172,8 @@ explain_exit_code() {
|
||||
# ------------------------------------------------------------------------------
|
||||
# post_to_api()
|
||||
#
|
||||
# - Sends LXC container creation statistics to Community-Scripts API
|
||||
# - Sends LXC container creation statistics to PocketBase
|
||||
# - Creates a new record in the _dev_telemetry_data collection
|
||||
# - Only executes if:
|
||||
# * curl is available
|
||||
# * DIAGNOSTICS=yes
|
||||
@ -168,62 +181,71 @@ explain_exit_code() {
|
||||
# - Payload includes:
|
||||
# * Container type, disk size, CPU cores, RAM
|
||||
# * OS type and version
|
||||
# * IPv6 disable status
|
||||
# * Application name (NSAPP)
|
||||
# * Installation method
|
||||
# * PVE version
|
||||
# * Status: "installing"
|
||||
# * Random UUID for session tracking
|
||||
# - Stores PB_RECORD_ID for later updates
|
||||
# - Anonymous telemetry (no personal data)
|
||||
# ------------------------------------------------------------------------------
|
||||
post_to_api() {
|
||||
|
||||
if ! command -v curl &>/dev/null; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [ "$DIAGNOSTICS" = "no" ]; then
|
||||
if [[ "${DIAGNOSTICS:-no}" == "no" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -z "$RANDOM_UUID" ]; then
|
||||
if [[ -z "${RANDOM_UUID:-}" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
local API_URL="http://api.community-scripts.org/dev/upload"
|
||||
local pve_version="not found"
|
||||
if command -v pveversion &>/dev/null; then
|
||||
pve_version=$(pveversion | awk -F'[/ ]' '{print $2}')
|
||||
fi
|
||||
|
||||
local JSON_PAYLOAD
|
||||
JSON_PAYLOAD=$(
|
||||
cat <<EOF
|
||||
{
|
||||
"ct_type": $CT_TYPE,
|
||||
"ct_type": ${CT_TYPE:-1},
|
||||
"type": "lxc",
|
||||
"disk_size": $DISK_SIZE,
|
||||
"core_count": $CORE_COUNT,
|
||||
"ram_size": $RAM_SIZE,
|
||||
"os_type": "$var_os",
|
||||
"os_version": "$var_version",
|
||||
"nsapp": "$NSAPP",
|
||||
"method": "$METHOD",
|
||||
"pve_version": "$pve_version",
|
||||
"disk_size": ${DISK_SIZE:-0},
|
||||
"core_count": ${CORE_COUNT:-0},
|
||||
"ram_size": ${RAM_SIZE:-0},
|
||||
"os_type": "${var_os:-}",
|
||||
"os_version": "${var_version:-}",
|
||||
"nsapp": "${NSAPP:-}",
|
||||
"method": "${METHOD:-default}",
|
||||
"pve_version": "${pve_version}",
|
||||
"status": "installing",
|
||||
"random_id": "$RANDOM_UUID"
|
||||
"random_id": "${RANDOM_UUID}"
|
||||
}
|
||||
EOF
|
||||
)
|
||||
if [[ "$DIAGNOSTICS" == "yes" ]]; then
|
||||
RESPONSE=$(curl -s -w "%{http_code}" -L -X POST "$API_URL" --post301 --post302 \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$JSON_PAYLOAD") || true
|
||||
fi
|
||||
|
||||
local RESPONSE
|
||||
RESPONSE=$(curl -s -w "\n%{http_code}" -L -X POST "${PB_API_URL}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$JSON_PAYLOAD" 2>/dev/null) || true
|
||||
|
||||
# Extract PocketBase record ID from response for later updates
|
||||
local http_code body
|
||||
http_code=$(echo "$RESPONSE" | tail -n1)
|
||||
body=$(echo "$RESPONSE" | sed '$d')
|
||||
|
||||
if [[ "$http_code" == "200" ]] || [[ "$http_code" == "201" ]]; then
|
||||
PB_RECORD_ID=$(echo "$body" | grep -o '"id":"[^"]*"' | head -1 | cut -d'"' -f4) || true
|
||||
fi
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# post_to_api_vm()
|
||||
#
|
||||
# - Sends VM creation statistics to Community-Scripts API
|
||||
# - Sends VM creation statistics to PocketBase
|
||||
# - Similar to post_to_api() but for virtual machines (not containers)
|
||||
# - Reads DIAGNOSTICS from /usr/local/community-scripts/diagnostics file
|
||||
# - Payload differences:
|
||||
@ -233,66 +255,78 @@ EOF
|
||||
# - Only executes if DIAGNOSTICS=yes and RANDOM_UUID is set
|
||||
# ------------------------------------------------------------------------------
|
||||
post_to_api_vm() {
|
||||
|
||||
if [[ ! -f /usr/local/community-scripts/diagnostics ]]; then
|
||||
return
|
||||
fi
|
||||
DIAGNOSTICS=$(grep -i "^DIAGNOSTICS=" /usr/local/community-scripts/diagnostics | awk -F'=' '{print $2}')
|
||||
|
||||
if ! command -v curl &>/dev/null; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [ "$DIAGNOSTICS" = "no" ]; then
|
||||
if [[ "${DIAGNOSTICS:-no}" == "no" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -z "$RANDOM_UUID" ]; then
|
||||
if [[ -z "${RANDOM_UUID:-}" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
local API_URL="http://api.community-scripts.org/dev/upload"
|
||||
local pve_version="not found"
|
||||
if command -v pveversion &>/dev/null; then
|
||||
pve_version=$(pveversion | awk -F'[/ ]' '{print $2}')
|
||||
fi
|
||||
|
||||
DISK_SIZE_API=${DISK_SIZE%G}
|
||||
local DISK_SIZE_API="${DISK_SIZE%G}"
|
||||
|
||||
local JSON_PAYLOAD
|
||||
JSON_PAYLOAD=$(
|
||||
cat <<EOF
|
||||
{
|
||||
"ct_type": 2,
|
||||
"type": "vm",
|
||||
"disk_size": $DISK_SIZE_API,
|
||||
"core_count": $CORE_COUNT,
|
||||
"ram_size": $RAM_SIZE,
|
||||
"os_type": "$var_os",
|
||||
"os_version": "$var_version",
|
||||
"nsapp": "$NSAPP",
|
||||
"method": "$METHOD",
|
||||
"pve_version": "$pve_version",
|
||||
"disk_size": ${DISK_SIZE_API:-0},
|
||||
"core_count": ${CORE_COUNT:-0},
|
||||
"ram_size": ${RAM_SIZE:-0},
|
||||
"os_type": "${var_os:-}",
|
||||
"os_version": "${var_version:-}",
|
||||
"nsapp": "${NSAPP:-}",
|
||||
"method": "${METHOD:-default}",
|
||||
"pve_version": "${pve_version}",
|
||||
"status": "installing",
|
||||
"random_id": "$RANDOM_UUID"
|
||||
"random_id": "${RANDOM_UUID}"
|
||||
}
|
||||
EOF
|
||||
)
|
||||
if [[ "$DIAGNOSTICS" == "yes" ]]; then
|
||||
RESPONSE=$(curl -s -w "%{http_code}" -L -X POST "$API_URL" --post301 --post302 \
|
||||
|
||||
local RESPONSE
|
||||
RESPONSE=$(curl -s -w "\n%{http_code}" -L -X POST "${PB_API_URL}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$JSON_PAYLOAD") || true
|
||||
-d "$JSON_PAYLOAD" 2>/dev/null) || true
|
||||
|
||||
# Extract PocketBase record ID from response for later updates
|
||||
local http_code body
|
||||
http_code=$(echo "$RESPONSE" | tail -n1)
|
||||
body=$(echo "$RESPONSE" | sed '$d')
|
||||
|
||||
if [[ "$http_code" == "200" ]] || [[ "$http_code" == "201" ]]; then
|
||||
PB_RECORD_ID=$(echo "$body" | grep -o '"id":"[^"]*"' | head -1 | cut -d'"' -f4) || true
|
||||
fi
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# post_update_to_api()
|
||||
#
|
||||
# - Reports installation completion status to API
|
||||
# - Reports installation completion status to PocketBase via PATCH
|
||||
# - Prevents duplicate submissions via POST_UPDATE_DONE flag
|
||||
# - Arguments:
|
||||
# * $1: status ("success" or "failed")
|
||||
# * $2: exit_code (default: 1 for failed, 0 for success)
|
||||
# * $1: status ("done" or "failed")
|
||||
# * $2: exit_code (numeric, default: 1 for failed, 0 for done)
|
||||
# - Uses PB_RECORD_ID if available, otherwise looks up by random_id
|
||||
# - Payload includes:
|
||||
# * Final status (success/failed)
|
||||
# * Error description via get_error_description()
|
||||
# * Random UUID for session correlation
|
||||
# * Final status (mapped: "done"→"sucess", "failed"→"failed")
|
||||
# * Error description via explain_exit_code()
|
||||
# * Numeric exit code
|
||||
# - Only executes once per session
|
||||
# - Silently returns if:
|
||||
# * curl not available
|
||||
@ -300,7 +334,6 @@ EOF
|
||||
# * DIAGNOSTICS=no
|
||||
# ------------------------------------------------------------------------------
|
||||
post_update_to_api() {
|
||||
|
||||
if ! command -v curl &>/dev/null; then
|
||||
return
|
||||
fi
|
||||
@ -308,42 +341,79 @@ post_update_to_api() {
|
||||
# Initialize flag if not set (prevents 'unbound variable' error with set -u)
|
||||
POST_UPDATE_DONE=${POST_UPDATE_DONE:-false}
|
||||
|
||||
if [ "$POST_UPDATE_DONE" = true ]; then
|
||||
if [[ "$POST_UPDATE_DONE" == "true" ]]; then
|
||||
return 0
|
||||
fi
|
||||
exit_code=${2:-1}
|
||||
local API_URL="http://api.community-scripts.org/dev/upload/updatestatus"
|
||||
local status="${1:-failed}"
|
||||
if [[ "$status" == "failed" ]]; then
|
||||
local exit_code="${2:-1}"
|
||||
elif [[ "$status" == "success" ]]; then
|
||||
local exit_code="${2:-0}"
|
||||
|
||||
if [[ "${DIAGNOSTICS:-no}" == "no" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ -z "$exit_code" ]]; then
|
||||
if [[ -z "${RANDOM_UUID:-}" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
local status="${1:-failed}"
|
||||
local raw_exit_code="${2:-1}"
|
||||
local exit_code error pb_status
|
||||
|
||||
# Map status to PocketBase select values: installing, sucess, failed, unknown
|
||||
case "$status" in
|
||||
done | success | sucess)
|
||||
pb_status="sucess"
|
||||
exit_code=0
|
||||
error=""
|
||||
;;
|
||||
failed) pb_status="failed" ;;
|
||||
*) pb_status="unknown" ;;
|
||||
esac
|
||||
|
||||
# For failed status, resolve exit code and error description
|
||||
if [[ "$pb_status" == "failed" ]] || [[ "$pb_status" == "unknown" ]]; then
|
||||
# If exit_code is numeric, use it; otherwise default to 1
|
||||
if [[ "$raw_exit_code" =~ ^[0-9]+$ ]]; then
|
||||
exit_code="$raw_exit_code"
|
||||
else
|
||||
exit_code=1
|
||||
fi
|
||||
|
||||
error=$(explain_exit_code "$exit_code")
|
||||
|
||||
if [ -z "$error" ]; then
|
||||
if [[ -z "$error" ]]; then
|
||||
error="Unknown error"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Resolve PocketBase record ID if not already known
|
||||
local record_id="${PB_RECORD_ID:-}"
|
||||
|
||||
if [[ -z "$record_id" ]]; then
|
||||
# Look up record by random_id filter
|
||||
local lookup_url="${PB_API_URL}?filter=(random_id='${RANDOM_UUID}')&fields=id&perPage=1"
|
||||
local lookup_response
|
||||
lookup_response=$(curl -s -L "${lookup_url}" 2>/dev/null) || true
|
||||
|
||||
record_id=$(echo "$lookup_response" | grep -o '"id":"[^"]*"' | head -1 | cut -d'"' -f4) || true
|
||||
|
||||
if [[ -z "$record_id" ]]; then
|
||||
POST_UPDATE_DONE=true
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
local JSON_PAYLOAD
|
||||
JSON_PAYLOAD=$(
|
||||
cat <<EOF
|
||||
{
|
||||
"status": "$status",
|
||||
"error": "$error",
|
||||
"random_id": "$RANDOM_UUID"
|
||||
"status": "${pb_status}",
|
||||
"error": "${error:-}",
|
||||
"exit_code": ${exit_code:-0}
|
||||
}
|
||||
EOF
|
||||
)
|
||||
if [[ "$DIAGNOSTICS" == "yes" ]]; then
|
||||
RESPONSE=$(curl -s -w "%{http_code}" -L -X POST "$API_URL" --post301 --post302 \
|
||||
|
||||
# PATCH to update the existing record
|
||||
curl -s -L -X PATCH "${PB_API_URL}/${record_id}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$JSON_PAYLOAD") || true
|
||||
fi
|
||||
-d "$JSON_PAYLOAD" &>/dev/null || true
|
||||
|
||||
POST_UPDATE_DONE=true
|
||||
}
|
||||
|
||||
@ -5157,9 +5157,9 @@ EOF
|
||||
# api_exit_script()
|
||||
#
|
||||
# - Exit trap handler for reporting to API telemetry
|
||||
# - Captures exit code and reports to API using centralized error descriptions
|
||||
# - Uses explain_exit_code() from error_handler.func for consistent error messages
|
||||
# - Posts failure status with exit code to API (error description added automatically)
|
||||
# - Captures exit code and reports to PocketBase using centralized error descriptions
|
||||
# - Uses explain_exit_code() from api.func for consistent error messages
|
||||
# - Posts failure status with exit code to API (error description resolved automatically)
|
||||
# - Only executes on non-zero exit codes
|
||||
# ------------------------------------------------------------------------------
|
||||
api_exit_script() {
|
||||
@ -5172,6 +5172,6 @@ api_exit_script() {
|
||||
if command -v pveversion >/dev/null 2>&1; then
|
||||
trap 'api_exit_script' EXIT
|
||||
fi
|
||||
trap 'post_update_to_api "failed" "$BASH_COMMAND"' ERR
|
||||
trap 'post_update_to_api "failed" "INTERRUPTED"' SIGINT
|
||||
trap 'post_update_to_api "failed" "TERMINATED"' SIGTERM
|
||||
trap 'post_update_to_api "failed" "$?"' ERR
|
||||
trap 'post_update_to_api "failed" "130"' SIGINT
|
||||
trap 'post_update_to_api "failed" "143"' SIGTERM
|
||||
|
||||
@ -27,70 +27,54 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
# explain_exit_code()
|
||||
#
|
||||
# - Maps numeric exit codes to human-readable error descriptions
|
||||
# - Supports:
|
||||
# * Generic/Shell errors (1, 2, 126, 127, 128, 130, 137, 139, 143)
|
||||
# * Package manager errors (APT, DPKG: 100, 101, 255)
|
||||
# * Node.js/npm errors (243-249, 254)
|
||||
# * Python/pip/uv errors (210-212)
|
||||
# * PostgreSQL errors (231-234)
|
||||
# * MySQL/MariaDB errors (241-244)
|
||||
# * MongoDB errors (251-254)
|
||||
# * Proxmox custom codes (200-231)
|
||||
# - Returns description string for given exit code
|
||||
# - Canonical version is defined in api.func (sourced before this file)
|
||||
# - This section only provides a fallback if api.func was not loaded
|
||||
# - See api.func SECTION 1 for the authoritative exit code mappings
|
||||
# ------------------------------------------------------------------------------
|
||||
if ! declare -f explain_exit_code &>/dev/null; then
|
||||
explain_exit_code() {
|
||||
local code="$1"
|
||||
case "$code" in
|
||||
# --- Generic / Shell ---
|
||||
1) echo "General error / Operation not permitted" ;;
|
||||
2) echo "Misuse of shell builtins (e.g. syntax error)" ;;
|
||||
6) echo "curl: DNS resolution failed (could not resolve host)" ;;
|
||||
7) echo "curl: Failed to connect (network unreachable / host down)" ;;
|
||||
22) echo "curl: HTTP error returned (404, 429, 500+)" ;;
|
||||
28) echo "curl: Operation timeout (network slow or server not responding)" ;;
|
||||
35) echo "curl: SSL/TLS handshake failed (certificate error)" ;;
|
||||
100) echo "APT: Package manager error (broken packages / dependency problems)" ;;
|
||||
101) echo "APT: Configuration error (bad sources.list, malformed config)" ;;
|
||||
102) echo "APT: Lock held by another process (dpkg/apt still running)" ;;
|
||||
124) echo "Command timed out (timeout command)" ;;
|
||||
126) echo "Command invoked cannot execute (permission problem?)" ;;
|
||||
127) echo "Command not found" ;;
|
||||
128) echo "Invalid argument to exit" ;;
|
||||
130) echo "Terminated by Ctrl+C (SIGINT)" ;;
|
||||
134) echo "Process aborted (SIGABRT - possibly Node.js heap overflow)" ;;
|
||||
137) echo "Killed (SIGKILL / Out of memory?)" ;;
|
||||
139) echo "Segmentation fault (core dumped)" ;;
|
||||
141) echo "Broken pipe (SIGPIPE - output closed prematurely)" ;;
|
||||
143) echo "Terminated (SIGTERM)" ;;
|
||||
|
||||
# --- Package manager / APT / DPKG ---
|
||||
100) echo "APT: Package manager error (broken packages / dependency problems)" ;;
|
||||
101) echo "APT: Configuration error (bad sources.list, malformed config)" ;;
|
||||
255) echo "DPKG: Fatal internal error" ;;
|
||||
|
||||
# --- Node.js / npm / pnpm / yarn ---
|
||||
243) echo "Node.js: Out of memory (JavaScript heap out of memory)" ;;
|
||||
245) echo "Node.js: Invalid command-line option" ;;
|
||||
246) echo "Node.js: Internal JavaScript Parse Error" ;;
|
||||
247) echo "Node.js: Fatal internal error" ;;
|
||||
248) echo "Node.js: Invalid C++ addon / N-API failure" ;;
|
||||
249) echo "Node.js: Inspector error" ;;
|
||||
254) echo "npm/pnpm/yarn: Unknown fatal error" ;;
|
||||
|
||||
# --- Python / pip / uv ---
|
||||
210) echo "Python: Virtualenv / uv environment missing or broken" ;;
|
||||
211) echo "Python: Dependency resolution failed" ;;
|
||||
212) echo "Python: Installation aborted (permissions or EXTERNALLY-MANAGED)" ;;
|
||||
|
||||
# --- PostgreSQL ---
|
||||
231) echo "PostgreSQL: Connection failed (server not running / wrong socket)" ;;
|
||||
232) echo "PostgreSQL: Authentication failed (bad user/password)" ;;
|
||||
233) echo "PostgreSQL: Database does not exist" ;;
|
||||
234) echo "PostgreSQL: Fatal error in query / syntax" ;;
|
||||
|
||||
# --- MySQL / MariaDB ---
|
||||
241) echo "MySQL/MariaDB: Connection failed (server not running / wrong socket)" ;;
|
||||
242) echo "MySQL/MariaDB: Authentication failed (bad user/password)" ;;
|
||||
243) echo "MySQL/MariaDB: Database does not exist" ;;
|
||||
244) echo "MySQL/MariaDB: Fatal error in query / syntax" ;;
|
||||
|
||||
# --- MongoDB ---
|
||||
251) echo "MongoDB: Connection failed (server not running)" ;;
|
||||
252) echo "MongoDB: Authentication failed (bad user/password)" ;;
|
||||
253) echo "MongoDB: Database not found" ;;
|
||||
254) echo "MongoDB: Fatal query error" ;;
|
||||
|
||||
# --- Proxmox Custom Codes ---
|
||||
150) echo "Systemd: Service failed to start" ;;
|
||||
151) echo "Systemd: Service unit not found" ;;
|
||||
152) echo "Permission denied (EACCES)" ;;
|
||||
153) echo "Build/compile failed (make/gcc/cmake)" ;;
|
||||
154) echo "Node.js: Native addon build failed (node-gyp)" ;;
|
||||
160) echo "Python: Virtualenv / uv environment missing or broken" ;;
|
||||
161) echo "Python: Dependency resolution failed" ;;
|
||||
162) echo "Python: Installation aborted (permissions or EXTERNALLY-MANAGED)" ;;
|
||||
170) echo "PostgreSQL: Connection failed (server not running / wrong socket)" ;;
|
||||
171) echo "PostgreSQL: Authentication failed (bad user/password)" ;;
|
||||
172) echo "PostgreSQL: Database does not exist" ;;
|
||||
173) echo "PostgreSQL: Fatal error in query / syntax" ;;
|
||||
180) echo "MySQL/MariaDB: Connection failed (server not running / wrong socket)" ;;
|
||||
181) echo "MySQL/MariaDB: Authentication failed (bad user/password)" ;;
|
||||
182) echo "MySQL/MariaDB: Database does not exist" ;;
|
||||
183) echo "MySQL/MariaDB: Fatal error in query / syntax" ;;
|
||||
190) echo "MongoDB: Connection failed (server not running)" ;;
|
||||
191) echo "MongoDB: Authentication failed (bad user/password)" ;;
|
||||
192) echo "MongoDB: Database not found" ;;
|
||||
193) echo "MongoDB: Fatal query error" ;;
|
||||
200) echo "Proxmox: Failed to create lock file" ;;
|
||||
203) echo "Proxmox: Missing CTID variable" ;;
|
||||
204) echo "Proxmox: Missing PCT_OSTYPE variable" ;;
|
||||
@ -107,20 +91,26 @@ explain_exit_code() {
|
||||
215) echo "Proxmox: Container created but not listed (ghost state)" ;;
|
||||
216) echo "Proxmox: RootFS entry missing in config" ;;
|
||||
217) echo "Proxmox: Storage not accessible" ;;
|
||||
219) echo "Proxmox: CephFS does not support containers - use RBD" ;;
|
||||
224) echo "Proxmox: PBS storage is for backups only" ;;
|
||||
218) echo "Proxmox: Template file corrupted or incomplete" ;;
|
||||
219) echo "Proxmox: CephFS does not support containers - use RBD" ;;
|
||||
220) echo "Proxmox: Unable to resolve template path" ;;
|
||||
221) echo "Proxmox: Template file not readable" ;;
|
||||
222) echo "Proxmox: Template download failed" ;;
|
||||
223) echo "Proxmox: Template not available after download" ;;
|
||||
224) echo "Proxmox: PBS storage is for backups only" ;;
|
||||
225) echo "Proxmox: No template available for OS/Version" ;;
|
||||
231) echo "Proxmox: LXC stack upgrade failed" ;;
|
||||
|
||||
# --- Default ---
|
||||
243) echo "Node.js: Out of memory (JavaScript heap out of memory)" ;;
|
||||
245) echo "Node.js: Invalid command-line option" ;;
|
||||
246) echo "Node.js: Internal JavaScript Parse Error" ;;
|
||||
247) echo "Node.js: Fatal internal error" ;;
|
||||
248) echo "Node.js: Invalid C++ addon / N-API failure" ;;
|
||||
249) echo "npm/pnpm/yarn: Unknown fatal error" ;;
|
||||
255) echo "DPKG: Fatal internal error" ;;
|
||||
*) echo "Unknown error" ;;
|
||||
esac
|
||||
}
|
||||
fi
|
||||
|
||||
# ==============================================================================
|
||||
# SECTION 2: ERROR HANDLERS
|
||||
|
||||
0
misc/ingest.go
Normal file
0
misc/ingest.go
Normal file
Loading…
x
Reference in New Issue
Block a user