[release] v0.12.0-unstable5

This commit is contained in:
Yann Stepienik 2023-10-28 13:44:14 +01:00
parent 8a547e1b9c
commit 33590ce369
8 changed files with 147 additions and 111 deletions

View file

@ -1,3 +1,8 @@
## Version 0.12.0
- New Dashboard
- New metrics gathering system
- Added Button to force reset HTTPS cert in settings
## Version 0.11.3 ## Version 0.11.3
- Fix missing even subscriber on export - Fix missing even subscriber on export

View file

@ -687,6 +687,15 @@ const ConfigManagement = () => {
</Stack> </Stack>
</Grid> </Grid>
<Grid item xs={12}>
<CosmosCheckbox
label={"Force HTTPS Certificate Renewal On Next Save"}
name="ForceHTTPSCertificateRenewal"
formik={formik}
/>
</Grid>
</Grid> </Grid>
</MainCard> </MainCard>

View file

@ -45,9 +45,12 @@ function toUTC(date, time) {
return formatDate(now, time); return formatDate(now, time);
} }
const PlotComponent = ({ data, defaultSlot = 'day' }) => { const PlotComponent = ({ title, data, defaultSlot = 'latest' }) => {
const [slot, setSlot] = useState(defaultSlot); const [slot, setSlot] = useState(defaultSlot);
const theme = useTheme(); const theme = useTheme();
const { primary, secondary } = theme.palette.text;
const line = theme.palette.divider;
const [series, setSeries] = useState([]);
// chart options // chart options
const areaChartOptions = { const areaChartOptions = {
@ -69,116 +72,108 @@ const PlotComponent = ({ data, defaultSlot = 'day' }) => {
strokeDashArray: 0 strokeDashArray: 0
} }
}; };
let hourlyDates = [];
for(let i = 0; i < 48; i++) {
let now = new Date();
now.setHours(now.getHours() - i);
now.setMinutes(0);
now.setSeconds(0);
// get as YYYY-MM-DD HH:MM:SS
hourlyDates.unshift(formatDate(now, true));
}
let dailyDates = [];
for(let i = 0; i < 30; i++) {
let now = new Date();
now.setDate(now.getDate() - i);
dailyDates.unshift(formatDate(now));
}
const { primary, secondary } = theme.palette.text;
const line = theme.palette.divider;
const [options, setOptions] = useState(areaChartOptions); const [options, setOptions] = useState(areaChartOptions);
useEffect(() => { useEffect(() => {
let xAxis = [];
if(slot === 'latest') {
for(let i = 0; i < 100; i++) {
xAxis.unshift(i);
}
}
else if(slot === 'hourly') {
for(let i = 0; i < 48; i++) {
let now = new Date();
now.setHours(now.getHours() - i);
now.setMinutes(0);
now.setSeconds(0);
xAxis.unshift(formatDate(now, true));
}
} else if(slot === 'daily') {
for(let i = 0; i < 30; i++) {
let now = new Date();
now.setDate(now.getDate() - i);
xAxis.unshift(formatDate(now));
}
}
const dataSeries = [];
data.forEach((serie) => {
dataSeries.push({
name: serie.Label,
dataAxis: xAxis.map((date) => {
if(slot === 'latest') {
return serie.Values[serie.Values.length - 1 - date] ?
serie.Values[serie.Values.length - 1 - date].Value :
0;
} else {
let key = slot === 'hourly' ? "hour_" : "day_";
let k = key + toUTC(date, slot === 'hourly');
if (k in serie.ValuesAggl) {
return serie.ValuesAggl[k].Value;
} else {
return 0;
}
}
})
});
});
setOptions((prevState) => ({ setOptions((prevState) => ({
...prevState, ...prevState,
colors: [theme.palette.primary.main, theme.palette.secondary.main], colors: [theme.palette.primary.main, theme.palette.secondary.main],
xaxis: { xaxis: {
categories: categories:
slot === 'hourly' slot === 'hourly'
? hourlyDates.map((date) => date.split(' ')[1]) ? xAxis.map((date) => date.split(' ')[1])
: dailyDates, : xAxis,
labels: { labels: {
style: { style: {
fontSize: '11px', fontSize: slot === 'latest' ? '0' : '11px',
} }
}, },
axisBorder: { axisBorder: {
show: true, show: true,
color: line color: line
}, },
tickAmount: slot === 'hourly' ? hourlyDates.length : dailyDates.length, tickAmount: xAxis.length,
}, },
yaxis: [{ yaxis: data.map((thisdata, ida) => ({
opposite: ida === 1,
labels: { labels: {
style: { style: {
colors: [secondary] colors: [secondary]
},
formatter: (num) => {
if (Math.abs(num) >= 1e9) {
return (num / 1e9).toFixed(1) + 'G'; // Convert to Millions
} else if (Math.abs(num) >= 1e6) {
return (num / 1e6).toFixed(1) + 'M'; // Convert to Millions
} else if (Math.abs(num) >= 1e3) {
return (num / 1e3).toFixed(1) + 'K'; // Convert to Thousands
} else {
return num.toString();
}
} }
}, },
title: { title: {
text: data[0].Label, text: thisdata.Label,
} }
}, })),
{
opposite: true,
labels: {
style: {
colors: [secondary]
}
},
title: {
text: data[1].Label,
}
}
],
grid: { grid: {
borderColor: line borderColor: line
}, },
tooltip: { tooltip: {
theme: 'light' theme: theme.palette.mode,
} }
})); }));
}, [primary, secondary, line, theme, slot]);
let dataSeries = [];
data.forEach((serie) => {
dataSeries.push({
name: serie.Label,
dataDaily: dailyDates.map((date) => {
let k = "day_" + toUTC(date);
if (k in serie.ValuesAggl) {
return serie.ValuesAggl[k].Value;
} else {
console.log(k)
return 0;
}
}),
dataHourly: hourlyDates.map((date) => {
let k = "hour_" + toUTC(date, true);
if (k in serie.ValuesAggl) {
return serie.ValuesAggl[k].Value;
} else {
return 0;
}
}),
});
});
const [series, setSeries] = useState(dataSeries.map((serie) => {
return {
name: serie.name,
data: slot === 'hourly' ? serie.dataHourly : serie.dataDaily
}
}));
useEffect(() => {
setSeries(dataSeries.map((serie) => { setSeries(dataSeries.map((serie) => {
return { return {
name: serie.name, name: serie.name,
data: slot === 'hourly' ? serie.dataHourly : serie.dataDaily data: serie.dataAxis
} }
})); }));
}, [slot, data]); }, [slot, data]);
@ -187,10 +182,18 @@ const PlotComponent = ({ data, defaultSlot = 'day' }) => {
return <Grid item xs={12} md={7} lg={8}> return <Grid item xs={12} md={7} lg={8}>
<Grid container alignItems="center" justifyContent="space-between"> <Grid container alignItems="center" justifyContent="space-between">
<Grid item> <Grid item>
<Typography variant="h5">Server Resources</Typography> <Typography variant="h5">{title}</Typography>
</Grid> </Grid>
<Grid item> <Grid item>
<Stack direction="row" alignItems="center" spacing={0}> <Stack direction="row" alignItems="center" spacing={0}>
<Button
size="small"
onClick={() => setSlot('latest')}
color={slot === 'latest' ? 'primary' : 'secondary'}
variant={slot === 'latest' ? 'outlined' : 'text'}
>
Latest
</Button>
<Button <Button
size="small" size="small"
onClick={() => setSlot('hourly')} onClick={() => setSlot('hourly')}
@ -211,8 +214,8 @@ const PlotComponent = ({ data, defaultSlot = 'day' }) => {
</Grid> </Grid>
</Grid> </Grid>
<MainCard content={false} sx={{ mt: 1.5 }}> <MainCard content={false} sx={{ mt: 1.5 }}>
<Box sx={{ pt: 1, pr: 2 }} className="force-light"> <Box sx={{ pt: 1, pr: 2 }}>
<ReactApexChart options={options} series={series} type="area" height={450} />; <ReactApexChart options={options} series={series} type="area" height={450} />
</Box> </Box>
</MainCard> </MainCard>
</Grid> </Grid>

View file

@ -175,7 +175,29 @@ const DashboardDefault = () => {
{/* row 2 */} {/* row 2 */}
<PlotComponent data={[metrics["cosmos.system.cpu.0"], metrics["cosmos.system.ram"]]}/> <PlotComponent title={'Resources'} data={[metrics["cosmos.system.cpu.0"], metrics["cosmos.system.ram"]]}/>
<Grid item xs={12} md={5} lg={4}>
<Grid container alignItems="center" justifyContent="space-between">
<Grid item>
<Typography variant="h5">Income Overview</Typography>
</Grid>
<Grid item />
</Grid>
<MainCard sx={{ mt: 2 }} content={false}>
<Box sx={{ p: 3, pb: 0 }}>
<Stack spacing={2}>
<Typography variant="h6" color="textSecondary">
This Week Statistics
</Typography>
<Typography variant="h3">$7,650</Typography>
</Stack>
</Box>
<MonthlyBarChart />
</MainCard>
</Grid>
<PlotComponent title={'Network'} data={[metrics["cosmos.system.netTx"], metrics["cosmos.system.netRx"]]}/>
<Grid item xs={12} md={5} lg={4}> <Grid item xs={12} md={5} lg={4}>
<Grid container alignItems="center" justifyContent="space-between"> <Grid container alignItems="center" justifyContent="space-between">
@ -209,6 +231,7 @@ const DashboardDefault = () => {
<OrdersTable /> <OrdersTable />
</MainCard> </MainCard>
</Grid> </Grid>
<Grid item xs={12} md={5} lg={4}> <Grid item xs={12} md={5} lg={4}>
<Grid container alignItems="center" justifyContent="space-between"> <Grid container alignItems="center" justifyContent="space-between">
<Grid item> <Grid item>

View file

@ -1,6 +1,6 @@
{ {
"name": "cosmos-server", "name": "cosmos-server",
"version": "0.12.0-unstable4", "version": "0.12.0-unstable5",
"description": "", "description": "",
"main": "test-server.js", "main": "test-server.js",
"bugs": { "bugs": {
@ -67,7 +67,7 @@
"start": "env COSMOS_CONFIG_FOLDER=/mnt/e/work/Cosmos-Server/zz_test_config/ CONFIG_FILE=./config_dev.json EZ=UTC ACME_STAGING=true build/cosmos", "start": "env COSMOS_CONFIG_FOLDER=/mnt/e/work/Cosmos-Server/zz_test_config/ CONFIG_FILE=./config_dev.json EZ=UTC ACME_STAGING=true build/cosmos",
"build": "sh build.sh", "build": "sh build.sh",
"dev": "npm run build && npm run start", "dev": "npm run build && npm run start",
"dockerdevbuild": "sh build.sh && docker build -f dockerfile.local --tag cosmos-dev .", "dockerdevbuild": "docker build -f dockerfile.local --tag cosmos-dev .",
"dockerdevrun": "docker stop cosmos-dev; docker rm cosmos-dev; docker run --cap-add NET_ADMIN -d -p 7200:443 -p 80:80 -p 53:53 -p 443:443 -p 4242:4242 -e DOCKER_HOST=tcp://host.docker.internal:2375 -e COSMOS_MONGODB=$MONGODB -e COSMOS_LOG_LEVEL=DEBUG -v /:/mnt/host --restart=unless-stopped -h cosmos-dev --name cosmos-dev cosmos-dev", "dockerdevrun": "docker stop cosmos-dev; docker rm cosmos-dev; docker run --cap-add NET_ADMIN -d -p 7200:443 -p 80:80 -p 53:53 -p 443:443 -p 4242:4242 -e DOCKER_HOST=tcp://host.docker.internal:2375 -e COSMOS_MONGODB=$MONGODB -e COSMOS_LOG_LEVEL=DEBUG -v /:/mnt/host --restart=unless-stopped -h cosmos-dev --name cosmos-dev cosmos-dev",
"dockerdev": "npm run client-build && npm run dockerdevbuild && npm run dockerdevrun", "dockerdev": "npm run client-build && npm run dockerdevbuild && npm run dockerdevrun",
"demo": "vite build --base=/cosmos-ui/ --mode demo", "demo": "vite build --base=/cosmos-ui/ --mode demo",

View file

@ -31,7 +31,7 @@ type DataDefDB struct {
AggloType string AggloType string
} }
func AggloMetrics() { func AggloMetrics() []DataDefDB {
lock <- true lock <- true
defer func() { <-lock }() defer func() { <-lock }()
@ -42,7 +42,7 @@ func AggloMetrics() {
c, errCo := utils.GetCollection(utils.GetRootAppId(), "metrics") c, errCo := utils.GetCollection(utils.GetRootAppId(), "metrics")
if errCo != nil { if errCo != nil {
utils.Error("Metrics - Database Connect", errCo) utils.Error("Metrics - Database Connect", errCo)
return return []DataDefDB{}
} }
// get all metrics from database // get all metrics from database
@ -50,13 +50,13 @@ func AggloMetrics() {
cursor, err := c.Find(nil, map[string]interface{}{}) cursor, err := c.Find(nil, map[string]interface{}{})
if err != nil { if err != nil {
utils.Error("Metrics: Error fetching metrics", err) utils.Error("Metrics: Error fetching metrics", err)
return return []DataDefDB{}
} }
defer cursor.Close(nil) defer cursor.Close(nil)
if err = cursor.All(nil, &metrics); err != nil { if err = cursor.All(nil, &metrics); err != nil {
utils.Error("Metrics: Error decoding metrics", err) utils.Error("Metrics: Error decoding metrics", err)
return return []DataDefDB{}
} }
// populate aggregation pools // populate aggregation pools
@ -153,8 +153,18 @@ func AggloMetrics() {
metrics[metInd] = metric metrics[metInd] = metric
} }
return metrics
}
func CommitAggl(metrics []DataDefDB) {
utils.Log("Metrics: Agglomeration done. Saving to DB") utils.Log("Metrics: Agglomeration done. Saving to DB")
c, errCo := utils.GetCollection(utils.GetRootAppId(), "metrics")
if errCo != nil {
utils.Error("Metrics - Database Connect", errCo)
return
}
// save metrics // save metrics
for _, metric := range metrics { for _, metric := range metrics {
options := options.Update().SetUpsert(true) options := options.Update().SetUpsert(true)
@ -166,12 +176,18 @@ func AggloMetrics() {
return return
} }
} }
utils.Log("Metrics: Agglomeration saved to DB")
}
func AggloAndCommitMetrics() {
CommitAggl(AggloMetrics())
} }
func InitAggl() { func InitAggl() {
go func() { go func() {
s := gocron.NewScheduler() s := gocron.NewScheduler()
s.Every(1).Hour().From(gocron.NextTick()).Do(AggloMetrics) s.Every(1).Hour().From(gocron.NextTick()).Do(AggloAndCommitMetrics)
// s.Every(3).Minute().From(gocron.NextTick()).Do(AggloMetrics) // s.Every(3).Minute().From(gocron.NextTick()).Do(AggloMetrics)
s.Start() s.Start()

View file

@ -13,29 +13,9 @@ func API_GetMetrics(w http.ResponseWriter, req *http.Request) {
} }
if(req.Method == "GET") { if(req.Method == "GET") {
c, errCo := utils.GetCollection(utils.GetRootAppId(), "metrics")
if errCo != nil {
utils.Error("Metrics - Database Connect", errCo)
return
}
// get all metrics from database
var metrics []DataDefDB
cursor, err := c.Find(nil, map[string]interface{}{})
if err != nil {
utils.Error("Metrics: Error fetching metrics", err)
return
}
defer cursor.Close(nil)
if err = cursor.All(nil, &metrics); err != nil {
utils.Error("Metrics: Error decoding metrics", err)
return
}
json.NewEncoder(w).Encode(map[string]interface{}{ json.NewEncoder(w).Encode(map[string]interface{}{
"status": "OK", "status": "OK",
"data": metrics, "data": AggloMetrics(),
}) })
} else { } else {
utils.Error("SettingGet: Method not allowed" + req.Method, nil) utils.Error("SettingGet: Method not allowed" + req.Method, nil)

View file

@ -124,7 +124,7 @@ func GetSystemMetrics() {
} }
for _, part := range parts { for _, part := range parts {
if strings.HasPrefix(part.Mountpoint, "/dev") || strings.HasPrefix(part.Mountpoint, "/mnt") { if strings.HasPrefix(part.Mountpoint, "/dev") || (strings.HasPrefix(part.Mountpoint, "/mnt") && !strings.HasPrefix(part.Mountpoint, "/mnt/host")) {
realMount := part.Mountpoint realMount := part.Mountpoint
if os.Getenv("HOSTANME") != "" { if os.Getenv("HOSTANME") != "" {