This commit is contained in:
Yann Stepienik 2023-11-01 13:58:25 +00:00
parent d68f9df66f
commit 53db1b883d
10 changed files with 121 additions and 30 deletions

View file

@ -6,6 +6,10 @@
- New color slider with reset buttons
- Fixed blinking modals issues
- Added lazyloading to URL and Servapp pages images
- Added a button in the config page to easily download the docker backup
- Improve display or icons [fixes #121]
- Refactored Mongo connection code [fixes #111]
- Forward simultaneously TCP and UDP [fixes #122]
## Version 0.11.3
- Fix missing even subscriber on export

View file

@ -83,6 +83,15 @@ async function addRoute(newRoute: Route): Promise<void> {
return rawUpdateRoute("", 'add', newRoute);
}
function getBackup() {
return wrap(fetch('/cosmos/api/get-backup', {
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
}))
}
export {
get,
set,
@ -94,4 +103,5 @@ export {
deleteRoute,
addRoute,
canSendEmail,
getBackup,
};

View file

@ -1,28 +1,41 @@
import { Button } from "@mui/material";
export const DownloadFile = ({ filename, content, label }) => {
const downloadFile = () => {
// Create a blob with the content
const blob = new Blob([content], { type: "text/plain;charset=utf-8" });
export const DownloadFile = ({ filename, content, contentGetter, label }) => {
const downloadFile = async () => {
// Get the content
if (contentGetter) {
try {
content = await contentGetter();
if(typeof content !== "string") {
content = JSON.stringify(content, null, 2);
}
} catch (e) {
console.error(e);
return;
}
}
// Create a link element
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = filename;
// Create a blob with the content
const blob = new Blob([content], { type: "text/plain;charset=utf-8" });
// Append the link to the document (needed for Firefox)
document.body.appendChild(link);
// Create a link element
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = filename;
// Simulate a click to start the download
link.click();
// Append the link to the document (needed for Firefox)
document.body.appendChild(link);
// Cleanup the DOM by removing the link element
document.body.removeChild(link);
}
// Simulate a click to start the download
link.click();
return (
<Button onClick={downloadFile}>
{label}
</Button>
);
// Cleanup the DOM by removing the link element
document.body.removeChild(link);
}
return (
<Button onClick={downloadFile}>
{label}
</Button>
);
}

View file

@ -33,6 +33,7 @@ import { SliderPicker
import {SetPrimaryColor, SetSecondaryColor} from '../../../App';
import { useClientInfos } from '../../../utils/hooks';
import ConfirmModal from '../../../components/confirmModal';
import { DownloadFile } from '../../../api/downloadButton';
const ConfigManagement = () => {
const [config, setConfig] = React.useState(null);
@ -77,6 +78,13 @@ const ConfigManagement = () => {
}}
label={'Purge Metrics Dashboard'}
content={'Are you sure you want to purge all the metrics data from the dashboards?'} />
<DownloadFile
filename={'backup.cosmos-compose.json'}
label={'Download Docker Backup'}
contentGetter={API.config.getBackup}
/>
</Stack>
{config && <>

View file

@ -167,11 +167,12 @@ const _MiniPlotComponent = ({metrics, labels}) => {
<Stack direction='column' justifyContent={'center'} alignItems={'center'} spacing={0} style={{
width: '60px',
}}>
<div style={{
{dataMetric.Values.length && <div style={{
fontWeight: 'bold',
fontSize: '110%',
whiteSpace: 'nowrap',
}}>{formaters[di](dataMetric.Values[dataMetric.Values.length - 1].Value)}</div>
}
<div>
<div style={{
display: 'inline-block',

View file

@ -1,7 +1,7 @@
import React from 'react';
import { Alert, Checkbox, Chip, CircularProgress, Stack, Typography, useMediaQuery } from '@mui/material';
import MainCard from '../../../components/MainCard';
import { ContainerOutlined, DesktopOutlined, InfoCircleOutlined, NodeExpandOutlined, PlayCircleOutlined, PlusCircleOutlined, SafetyCertificateOutlined, SettingOutlined } from '@ant-design/icons';
import { ContainerOutlined, DashboardOutlined, DesktopOutlined, InfoCircleOutlined, NodeExpandOutlined, PlayCircleOutlined, PlusCircleOutlined, SafetyCertificateOutlined, SettingOutlined } from '@ant-design/icons';
import { getFaviconURL, getContainersRoutes } from '../../../utils/routes';
import HostChip from '../../../components/hostChip';
import ExposeModal from '../exposeModal';
@ -169,8 +169,8 @@ const ContainerOverview = ({ containerInfo, config, refresh, updatesAvailable, s
}}
/>
</div>
<strong><NodeExpandOutlined /> Monitoring</strong>
<div style={{ width: '90%' }}>
<strong><DashboardOutlined /> Monitoring</strong>
<div style={{ width: '96%' }}>
<MiniPlotComponent metrics={[
"cosmos.system.docker.cpu." + Name.replace('/', ''),
"cosmos.system.docker.ram." + Name.replace('/', ''),

View file

@ -4,6 +4,7 @@ import (
"net/http"
"encoding/json"
"os"
"io/ioutil"
"github.com/azukaar/cosmos-server/src/utils"
)
@ -50,3 +51,43 @@ func ConfigApiGet(w http.ResponseWriter, req *http.Request) {
return
}
}
func BackupFileApiGet(w http.ResponseWriter, req *http.Request) {
if utils.AdminOnly(w, req) != nil {
return
}
if req.Method == "GET" {
// read file
path := utils.CONFIGFOLDER + "backup.cosmos-compose.json"
file, err := os.Open(path)
if err != nil {
utils.Error("BackupFileApiGet: Error opening file", err)
utils.HTTPError(w, "Error opening file", http.StatusInternalServerError, "HTTP002")
return
}
defer file.Close()
// read content
content, err := ioutil.ReadAll(file)
if err != nil {
utils.Error("BackupFileApiGet: Error reading file content", err)
utils.HTTPError(w, "Error reading file content", http.StatusInternalServerError, "HTTP003")
return
}
// set the content type header, so that the client knows it's receiving a JSON file
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
_, err = w.Write(content)
if err != nil {
utils.Error("BackupFileApiGet: Error writing to response", err)
}
} else {
utils.Error("BackupFileApiGet: Method not allowed " + req.Method, nil)
utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001")
return
}
}

View file

@ -553,12 +553,16 @@ func CreateService(serviceRequest DockerServiceCreateRequest, OnLog func(string)
port, protocol := portdef, portStuff[1]
if protocol == "" {
protocol = "tcp"
}
nextPort := strings.Split(port, ":")
hostPort, contPort := nextPort[0], nextPort[1]
contPort = contPort + "/" + protocol
if hostPortsBound[hostPort] {
if hostPortsBound[hostPort + "/" + protocol] {
utils.Warn("Port " + hostPort + " already bound, skipping")
continue
}
@ -583,7 +587,7 @@ func CreateService(serviceRequest DockerServiceCreateRequest, OnLog func(string)
// Mark the container port as exposed
containerConfig.ExposedPorts[nat.Port(contPort)] = struct{}{}
hostPortsBound[hostPort] = true
hostPortsBound[hostPort + "/" + protocol] = true
}
// Create missing folders for bind mounts

View file

@ -332,6 +332,8 @@ func InitServer() *mux.Router {
srapi.HandleFunc("/api/background", UploadBackground)
srapi.HandleFunc("/api/background/{ext}", GetBackground)
srapi.HandleFunc("/api/get-backup", configapi.BackupFileApiGet)
srapi.HandleFunc("/api/constellation/devices", constellation.ConstellationAPIDevices)
srapi.HandleFunc("/api/constellation/restart", constellation.API_Restart)
srapi.HandleFunc("/api/constellation/reset", constellation.API_Reset)

View file

@ -7,27 +7,35 @@ import (
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/mongo/readpref"
"go.mongodb.org/mongo-driver/mongo/writeconcern"
)
var client *mongo.Client
func DB() error {
if(GetBaseMainConfig().DisableUserManagement) {
if(GetMainConfig().DisableUserManagement) {
return errors.New("User Management is disabled")
}
uri := GetBaseMainConfig().MongoDB + "/?retryWrites=true&w=majority"
mongoURL := GetMainConfig().MongoDB
if(client != nil && client.Ping(context.TODO(), readpref.Primary()) == nil) {
return nil
}
Log("(Re) Connecting to the database...")
if mongoURL == "" {
return errors.New("MongoDB URL is not set, cannot connect to the database.")
}
var err error
client, err = mongo.Connect(context.TODO(), options.Client().ApplyURI(uri))
opts := options.Client().ApplyURI(mongoURL).SetRetryWrites(true).SetWriteConcern(writeconcern.New(writeconcern.WMajority()))
client, err = mongo.Connect(context.TODO(), opts)
if err != nil {
return err
}