mirror of
https://github.com/community-scripts/ProxmoxVE.git
synced 2025-11-05 19:02:50 +00:00
Compare commits
12 Commits
2025-02-13
...
2025-02-14
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
347a23ad60 | ||
|
|
29806c4525 | ||
|
|
a045dc8012 | ||
|
|
80e7e2f5b6 | ||
|
|
1789d181aa | ||
|
|
f0ca0c3379 | ||
|
|
1711e44a4d | ||
|
|
afe4af2ff6 | ||
|
|
ec8c564e25 | ||
|
|
fd9d64b342 | ||
|
|
1d928f7ea8 | ||
|
|
f3c9e8f013 |
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,6 +1,6 @@
|
|||||||
name: "🐞 Script Issue Report"
|
name: "🐞 Script Issue Report"
|
||||||
description: Report a specific issue with a script. For other inquiries, please use the Discussions section.
|
description: Report a specific issue with a script. For other inquiries, please use the Discussions section.
|
||||||
|
labels: ["bug"]
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
|
|||||||
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -3,7 +3,7 @@ contact_links:
|
|||||||
- name: 🤔 Questions and Help
|
- name: 🤔 Questions and Help
|
||||||
url: https://github.com/community-scripts/ProxmoxVE/discussions
|
url: https://github.com/community-scripts/ProxmoxVE/discussions
|
||||||
about: For suggestions or questions, please use the Discussions section.
|
about: For suggestions or questions, please use the Discussions section.
|
||||||
- name: 🌟 Feature request
|
- name: 🌟 new Script request
|
||||||
url: https://github.com/community-scripts/ProxmoxVE/discussions/new?category=request-script
|
url: https://github.com/community-scripts/ProxmoxVE/discussions/new?category=request-script
|
||||||
about: For feature/script requests, please use the Discussions section.
|
about: For feature/script requests, please use the Discussions section.
|
||||||
- name: 💻 Discord
|
- name: 💻 Discord
|
||||||
|
|||||||
33
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
33
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
name: "✨ Feature Request"
|
||||||
|
description: "Suggest a new feature or enhancement."
|
||||||
|
labels: ["enhancement"]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
# ✨ **Feature Request**
|
||||||
|
Have an idea for a new feature? Share your thoughts below!
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: feature_summary
|
||||||
|
attributes:
|
||||||
|
label: "🌟 Briefly describe the feature"
|
||||||
|
placeholder: "e.g., Add support for XYZ"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: feature_description
|
||||||
|
attributes:
|
||||||
|
label: "📝 Detailed description"
|
||||||
|
placeholder: "Explain the feature in detail"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: use_case
|
||||||
|
attributes:
|
||||||
|
label: "💡 Why is this useful?"
|
||||||
|
placeholder: "Describe the benefit of this feature"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
25
.github/ISSUE_TEMPLATE/task.yml
vendored
Normal file
25
.github/ISSUE_TEMPLATE/task.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
name: "🛠️ Task / General Request"
|
||||||
|
description: "Request a general task, improvement, or refactor."
|
||||||
|
labels: ["task"]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
# 🛠️ **Task / General Request**
|
||||||
|
Request a task that isn't a bug or feature request.
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: task_summary
|
||||||
|
attributes:
|
||||||
|
label: "📌 Task summary"
|
||||||
|
placeholder: "e.g., Refactor XYZ"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: task_details
|
||||||
|
attributes:
|
||||||
|
label: "📋 Task details"
|
||||||
|
placeholder: "Explain what needs to be done"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
10
.github/workflows/script-test.yml
vendored
10
.github/workflows/script-test.yml
vendored
@@ -89,10 +89,12 @@ jobs:
|
|||||||
chmod +x "$INSTALL_SCRIPT"
|
chmod +x "$INSTALL_SCRIPT"
|
||||||
RUNNING_FILE=$FILE
|
RUNNING_FILE=$FILE
|
||||||
fi
|
fi
|
||||||
git checkout origin/main .github/workflows/scripts/app-test/pr-build.func
|
git remote add community-scripts https://github.com/community-scripts/ProxmoxVE.git
|
||||||
git checkout origin/main .github/workflows/scripts/app-test/pr-install.func
|
git fetch community-scripts
|
||||||
git checkout origin/main .github/workflows/scripts/app-test/pr-alpine-install.func
|
git checkout community-scripts/main -- .github/workflows/scripts/app-test/pr-build.func
|
||||||
git checkout origin/main .github/workflows/scripts/app-test/pr-create-lxc.sh
|
git checkout community-scripts/main -- .github/workflows/scripts/app-test/pr-install.func
|
||||||
|
git checkout community-scripts/main -- .github/workflows/scripts/app-test/pr-alpine-install.func
|
||||||
|
git checkout community-scripts/main -- .github/workflows/scripts/app-test/pr-create-lxc.sh
|
||||||
chmod +x $RUNNING_FILE
|
chmod +x $RUNNING_FILE
|
||||||
chmod +x .github/workflows/scripts/app-test/pr-create-lxc.sh
|
chmod +x .github/workflows/scripts/app-test/pr-create-lxc.sh
|
||||||
chmod +x .github/workflows/scripts/app-test/pr-install.func
|
chmod +x .github/workflows/scripts/app-test/pr-install.func
|
||||||
|
|||||||
22
CHANGELOG.md
22
CHANGELOG.md
@@ -17,6 +17,28 @@ All LXC instances created using this repository come pre-installed with Midnight
|
|||||||
Do not break established syntax in this file, as it is automatically updated by a Github Workflow
|
Do not break established syntax in this file, as it is automatically updated by a Github Workflow
|
||||||
|
|
||||||
|
|
||||||
|
## 2025-02-14
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- Fix homarr [@CrazyWolf13](https://github.com/CrazyWolf13) ([#2369](https://github.com/community-scripts/ProxmoxVE/pull/2369))
|
||||||
|
|
||||||
|
### 🌐 Website
|
||||||
|
|
||||||
|
- RustDesk Server - Added configuration guide to json [@tremor021](https://github.com/tremor021) ([#2389](https://github.com/community-scripts/ProxmoxVE/pull/2389))
|
||||||
|
|
||||||
|
### 🧰 Maintenance
|
||||||
|
|
||||||
|
- [gh] Update script-test.yml [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#2399](https://github.com/community-scripts/ProxmoxVE/pull/2399))
|
||||||
|
- [gh] Introducing new Issue Github Template Feature (Bug, Feature, Task) [@MickLesk](https://github.com/MickLesk) ([#2394](https://github.com/community-scripts/ProxmoxVE/pull/2394))
|
||||||
|
|
||||||
|
### 📡 API
|
||||||
|
|
||||||
|
- [API]Add more enpoints to API [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#2390](https://github.com/community-scripts/ProxmoxVE/pull/2390))
|
||||||
|
- [API] Update api.func: Remove unwanted file creation [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#2378](https://github.com/community-scripts/ProxmoxVE/pull/2378))
|
||||||
|
|
||||||
## 2025-02-13
|
## 2025-02-13
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
|
|||||||
283
api/main.go
283
api/main.go
@@ -11,6 +11,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
@@ -31,6 +32,7 @@ func loadEnv() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DataModel represents a single document in MongoDB
|
||||||
type DataModel struct {
|
type DataModel struct {
|
||||||
ID primitive.ObjectID `json:"id" bson:"_id,omitempty"`
|
ID primitive.ObjectID `json:"id" bson:"_id,omitempty"`
|
||||||
CT_TYPE uint `json:"ct_type" bson:"ct_type"`
|
CT_TYPE uint `json:"ct_type" bson:"ct_type"`
|
||||||
@@ -56,6 +58,13 @@ type StatusModel struct {
|
|||||||
STATUS string `json:"status" bson:"status"`
|
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() {
|
func ConnectDatabase() {
|
||||||
loadEnv()
|
loadEnv()
|
||||||
|
|
||||||
@@ -78,6 +87,7 @@ func ConnectDatabase() {
|
|||||||
fmt.Println("Connected to MongoDB on 10.10.10.18")
|
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) {
|
func UploadJSON(w http.ResponseWriter, r *http.Request) {
|
||||||
var input DataModel
|
var input DataModel
|
||||||
|
|
||||||
@@ -98,6 +108,7 @@ func UploadJSON(w http.ResponseWriter, r *http.Request) {
|
|||||||
json.NewEncoder(w).Encode(map[string]string{"message": "Data saved successfully"})
|
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) {
|
func UpdateStatus(w http.ResponseWriter, r *http.Request) {
|
||||||
var input StatusModel
|
var input StatusModel
|
||||||
|
|
||||||
@@ -120,6 +131,7 @@ func UpdateStatus(w http.ResponseWriter, r *http.Request) {
|
|||||||
json.NewEncoder(w).Encode(map[string]string{"message": "Record updated successfully"})
|
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) {
|
func GetDataJSON(w http.ResponseWriter, r *http.Request) {
|
||||||
var records []DataModel
|
var records []DataModel
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
@@ -144,6 +156,270 @@ func GetDataJSON(w http.ResponseWriter, r *http.Request) {
|
|||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(records)
|
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() {
|
func main() {
|
||||||
ConnectDatabase()
|
ConnectDatabase()
|
||||||
@@ -152,6 +428,13 @@ func main() {
|
|||||||
router.HandleFunc("/upload", UploadJSON).Methods("POST")
|
router.HandleFunc("/upload", UploadJSON).Methods("POST")
|
||||||
router.HandleFunc("/upload/updatestatus", UpdateStatus).Methods("POST")
|
router.HandleFunc("/upload/updatestatus", UpdateStatus).Methods("POST")
|
||||||
router.HandleFunc("/data/json", GetDataJSON).Methods("GET")
|
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{
|
c := cors.New(cors.Options{
|
||||||
AllowedOrigins: []string{"*"},
|
AllowedOrigins: []string{"*"},
|
||||||
|
|||||||
25
ct/homarr.sh
25
ct/homarr.sh
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
source <(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
source <(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
||||||
# Copyright (c) 2021-2025 tteck
|
# Copyright (c) 2021-2025 tteck
|
||||||
# Author: tteck (tteckster) | Co-Author: MickLesk (Canbiz)
|
# Author: tteck (tteckster) | Co-Author: MickLesk (Canbiz) | Co-Author: CrazyWolf13
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://homarr.dev/
|
# Source: https://homarr.dev/
|
||||||
|
|
||||||
@@ -15,6 +15,7 @@ var_version="12"
|
|||||||
var_unprivileged="1"
|
var_unprivileged="1"
|
||||||
|
|
||||||
header_info "$APP"
|
header_info "$APP"
|
||||||
|
|
||||||
variables
|
variables
|
||||||
color
|
color
|
||||||
catch_errors
|
catch_errors
|
||||||
@@ -37,7 +38,7 @@ fi
|
|||||||
RELEASE=$(curl -s https://api.github.com/repos/homarr-labs/homarr/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
|
RELEASE=$(curl -s https://api.github.com/repos/homarr-labs/homarr/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
|
||||||
if [[ ! -f /opt/${APP}_version.txt ]] || [[ "${RELEASE}" != "$(cat /opt/${APP}_version.txt)" ]]; then
|
if [[ ! -f /opt/${APP}_version.txt ]] || [[ "${RELEASE}" != "$(cat /opt/${APP}_version.txt)" ]]; then
|
||||||
|
|
||||||
msg_info "Stopping Services"
|
msg_info "Stopping Services (Patience)"
|
||||||
systemctl stop homarr
|
systemctl stop homarr
|
||||||
msg_ok "Services Stopped"
|
msg_ok "Services Stopped"
|
||||||
|
|
||||||
@@ -55,9 +56,23 @@ fi
|
|||||||
mv /opt/homarr-data-backup/.env /opt/homarr/.env
|
mv /opt/homarr-data-backup/.env /opt/homarr/.env
|
||||||
cd /opt/homarr
|
cd /opt/homarr
|
||||||
pnpm install &>/dev/null
|
pnpm install &>/dev/null
|
||||||
pnpm run db:migration:sqlite:run &>/dev/null
|
|
||||||
pnpm build &>/dev/null
|
pnpm build &>/dev/null
|
||||||
mkdir build
|
cp /opt/homarr/apps/nextjs/next.config.ts .
|
||||||
|
cp /opt/homarr/apps/nextjs/package.json .
|
||||||
|
cp -r /opt/homarr/packages/db/migrations /opt/homarr_db/migrations
|
||||||
|
cp -r /opt/homarr/apps/nextjs/.next/standalone/* /opt/homarr
|
||||||
|
mkdir -p /appdata/redis
|
||||||
|
cp /opt/homarr/packages/redis/redis.conf /opt/homarr/redis.conf
|
||||||
|
rm /etc/nginx/nginx.conf
|
||||||
|
mkdir -p /etc/nginx/templates
|
||||||
|
cp /opt/homarr/nginx.conf /etc/nginx/templates/nginx.conf
|
||||||
|
|
||||||
|
mkdir -p /opt/homarr/apps/cli
|
||||||
|
cp /opt/homarr/packages/cli/cli.cjs /opt/homarr/apps/cli/cli.cjs
|
||||||
|
echo $'#!/bin/bash\ncd /opt/homarr/apps/cli && node ./cli.cjs "$@"' > /usr/bin/homarr
|
||||||
|
chmod +x /usr/bin/homarr
|
||||||
|
|
||||||
|
mkdir /opt/homarr/build
|
||||||
cp ./node_modules/better-sqlite3/build/Release/better_sqlite3.node ./build/better_sqlite3.node
|
cp ./node_modules/better-sqlite3/build/Release/better_sqlite3.node ./build/better_sqlite3.node
|
||||||
echo "${RELEASE}" >/opt/${APP}_version.txt
|
echo "${RELEASE}" >/opt/${APP}_version.txt
|
||||||
msg_ok "Updated ${APP}"
|
msg_ok "Updated ${APP}"
|
||||||
@@ -79,4 +94,4 @@ description
|
|||||||
msg_ok "Completed Successfully!\n"
|
msg_ok "Completed Successfully!\n"
|
||||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3000${CL}"
|
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:7575${CL}"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
# Copyright (c) 2021-2025 community-scripts ORG
|
# Copyright (c) 2021-2025 community-scripts ORG
|
||||||
# Author: MickLesk (Canbiz)
|
# Author: MickLesk (Canbiz)
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://github.com/ajnart/homarr
|
# Source: https://github.com/homarr-labs/homarr
|
||||||
|
|
||||||
source /dev/stdin <<< "$FUNCTIONS_FILE_PATH"
|
source /dev/stdin <<< "$FUNCTIONS_FILE_PATH"
|
||||||
color
|
color
|
||||||
@@ -20,10 +20,13 @@ $STD apt-get install -y \
|
|||||||
curl \
|
curl \
|
||||||
redis-server \
|
redis-server \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
gnupg \
|
gpg \
|
||||||
make \
|
make \
|
||||||
g++ \
|
g++ \
|
||||||
build-essential
|
build-essential \
|
||||||
|
nginx \
|
||||||
|
gettext \
|
||||||
|
openssl
|
||||||
msg_ok "Installed Dependencies"
|
msg_ok "Installed Dependencies"
|
||||||
|
|
||||||
msg_info "Setting up Node.js Repository"
|
msg_info "Setting up Node.js Repository"
|
||||||
@@ -46,27 +49,56 @@ unzip -q v${RELEASE}.zip
|
|||||||
mv homarr-${RELEASE} /opt/homarr
|
mv homarr-${RELEASE} /opt/homarr
|
||||||
mkdir -p /opt/homarr_db
|
mkdir -p /opt/homarr_db
|
||||||
touch /opt/homarr_db/db.sqlite
|
touch /opt/homarr_db/db.sqlite
|
||||||
AUTH_SECRET="$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | cut -c1-13)"
|
|
||||||
SECRET_ENCRYPTION_KEY="$(openssl rand -hex 32)"
|
SECRET_ENCRYPTION_KEY="$(openssl rand -hex 32)"
|
||||||
|
cd /opt/homarr
|
||||||
cat <<EOF >/opt/homarr/.env
|
cat <<EOF >/opt/homarr/.env
|
||||||
AUTH_SECRET='${AUTH_SECRET}'
|
|
||||||
DB_DRIVER='better-sqlite3'
|
DB_DRIVER='better-sqlite3'
|
||||||
|
DB_DIALECT='sqlite'
|
||||||
SECRET_ENCRYPTION_KEY='${SECRET_ENCRYPTION_KEY}'
|
SECRET_ENCRYPTION_KEY='${SECRET_ENCRYPTION_KEY}'
|
||||||
DB_URL='/opt/homarr_db/db.sqlite'
|
DB_URL='/opt/homarr_db/db.sqlite'
|
||||||
TURBO_TELEMETRY_DISABLED=1
|
TURBO_TELEMETRY_DISABLED=1
|
||||||
|
AUTH_PROVIDERS='credentials'
|
||||||
|
NODE_ENV='production'
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
cd /opt/homarr
|
|
||||||
$STD pnpm install
|
$STD pnpm install
|
||||||
$STD pnpm run db:migration:sqlite:run
|
|
||||||
$STD pnpm build
|
$STD pnpm build
|
||||||
mkdir build
|
|
||||||
cp ./node_modules/better-sqlite3/build/Release/better_sqlite3.node ./build/better_sqlite3.node
|
|
||||||
echo "${RELEASE}" >"/opt/${APPLICATION}_version.txt"
|
|
||||||
msg_ok "Installed Homarr"
|
msg_ok "Installed Homarr"
|
||||||
|
|
||||||
msg_info "Creating Service"
|
msg_info "Copying build and config files"
|
||||||
|
cp /opt/homarr/apps/nextjs/next.config.ts .
|
||||||
|
cp /opt/homarr/apps/nextjs/package.json .
|
||||||
|
cp -r /opt/homarr/packages/db/migrations /opt/homarr_db/migrations
|
||||||
|
cp -r /opt/homarr/apps/nextjs/.next/standalone/* /opt/homarr
|
||||||
|
mkdir -p /appdata/redis
|
||||||
|
cp /opt/homarr/packages/redis/redis.conf /opt/homarr/redis.conf
|
||||||
|
mkdir -p /etc/nginx/templates
|
||||||
|
rm /etc/nginx/nginx.conf
|
||||||
|
cp /opt/homarr/nginx.conf /etc/nginx/templates/nginx.conf
|
||||||
|
mkdir -p /opt/homarr/apps/cli
|
||||||
|
cp /opt/homarr/packages/cli/cli.cjs /opt/homarr/apps/cli/cli.cjs
|
||||||
|
echo $'#!/bin/bash\ncd /opt/homarr/apps/cli && node ./cli.cjs "$@"' > /usr/bin/homarr
|
||||||
|
chmod +x /usr/bin/homarr
|
||||||
|
mkdir /opt/homarr/build
|
||||||
|
cp ./node_modules/better-sqlite3/build/Release/better_sqlite3.node ./build/better_sqlite3.node
|
||||||
|
echo "${RELEASE}" >"/opt/${APPLICATION}_version.txt"
|
||||||
|
msg_ok "Finished copying"
|
||||||
|
|
||||||
|
msg_info "Creating Services"
|
||||||
|
cat <<'EOF' >/opt/run_homarr.sh
|
||||||
|
#!/bin/bash
|
||||||
|
export DB_DIALECT='sqlite'
|
||||||
|
export AUTH_SECRET=$(openssl rand -base64 32)
|
||||||
|
node /opt/homarr_db/migrations/$DB_DIALECT/migrate.cjs /opt/homarr_db/migrations/$DB_DIALECT
|
||||||
|
export HOSTNAME=$(ip route get 1.1.1.1 | grep -oP 'src \K[^ ]+')
|
||||||
|
envsubst '${HOSTNAME}' < /etc/nginx/templates/nginx.conf > /etc/nginx/nginx.conf
|
||||||
|
nginx -g 'daemon off;' &
|
||||||
|
redis-server /opt/homarr/packages/redis/redis.conf &
|
||||||
|
node apps/tasks/tasks.cjs &
|
||||||
|
node apps/websocket/wssServer.cjs &
|
||||||
|
node apps/nextjs/server.js & PID=$!
|
||||||
|
wait $PID
|
||||||
|
EOF
|
||||||
|
chmod +x /opt/run_homarr.sh
|
||||||
cat <<EOF >/etc/systemd/system/homarr.service
|
cat <<EOF >/etc/systemd/system/homarr.service
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Homarr Service
|
Description=Homarr Service
|
||||||
@@ -76,7 +108,7 @@ After=network.target
|
|||||||
Type=exec
|
Type=exec
|
||||||
WorkingDirectory=/opt/homarr
|
WorkingDirectory=/opt/homarr
|
||||||
EnvironmentFile=-/opt/homarr/.env
|
EnvironmentFile=-/opt/homarr/.env
|
||||||
ExecStart=/usr/bin/pnpm start
|
ExecStart=/opt/run_homarr.sh
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
"type": "ct",
|
"type": "ct",
|
||||||
"updateable": true,
|
"updateable": true,
|
||||||
"privileged": false,
|
"privileged": false,
|
||||||
"interface_port": 3000,
|
"interface_port": 7575,
|
||||||
"documentation": null,
|
"documentation": null,
|
||||||
"website": "https://homarr.dev/",
|
"website": "https://homarr.dev/",
|
||||||
"logo": "https://raw.githubusercontent.com/loganmarchione/homelab-svg-assets/main/assets/homarr.svg",
|
"logo": "https://raw.githubusercontent.com/loganmarchione/homelab-svg-assets/main/assets/homarr.svg",
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
},
|
},
|
||||||
"notes": [
|
"notes": [
|
||||||
{
|
{
|
||||||
"text": "Check documentation on how to configure RustDesk Server. `https://rustdesk.com/docs/en/`",
|
"text": "Check our configuration guide for help: `https://github.com/community-scripts/ProxmoxVE/discussions/2388`",
|
||||||
"type": "info"
|
"type": "info"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ post_to_api() {
|
|||||||
EOF
|
EOF
|
||||||
)
|
)
|
||||||
|
|
||||||
RESPONSE=$(curl -s -o response.txt -w "%{http_code}" -L -X POST "$API_URL" --post301 --post302 \
|
RESPONSE=$(curl -s -w "%{http_code}" -L -X POST "$API_URL" --post301 --post302 \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d "$JSON_PAYLOAD") || true
|
-d "$JSON_PAYLOAD") || true
|
||||||
}
|
}
|
||||||
@@ -87,7 +87,7 @@ post_to_api_vm() {
|
|||||||
EOF
|
EOF
|
||||||
)
|
)
|
||||||
|
|
||||||
RESPONSE=$(curl -s -o response.txt -w "%{http_code}" -L -X POST "$API_URL" --post301 --post302 \
|
RESPONSE=$(curl -s -w "%{http_code}" -L -X POST "$API_URL" --post301 --post302 \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d "$JSON_PAYLOAD") || true
|
-d "$JSON_PAYLOAD") || true
|
||||||
}
|
}
|
||||||
@@ -115,7 +115,7 @@ post_update_to_api() {
|
|||||||
EOF
|
EOF
|
||||||
)
|
)
|
||||||
|
|
||||||
RESPONSE=$(curl -s -o response.txt -w "%{http_code}" -L -X POST "$API_URL" --post301 --post302 \
|
RESPONSE=$(curl -s -w "%{http_code}" -L -X POST "$API_URL" --post301 --post302 \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d "$JSON_PAYLOAD") || true
|
-d "$JSON_PAYLOAD") || true
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user