Update to 0.7.0-unstable10

This commit is contained in:
Yann Stepienik 2023-06-15 13:07:10 +01:00
parent 2304d269d8
commit 7e565a42d2
11 changed files with 107 additions and 27 deletions

View file

@ -1,6 +1,7 @@
## Version 0.7.0
- Add Cosmos Market
- Fix issue with docker compose timeout healthcheck as string, and inverted ports
- Reforged the DNS CHallenge to be more user friendly. You can select your DNS provider in a list, and it will guide you through the process with the right fields to set (directly in the UI). No more env variables to set!
- Fix issue with docker compose timeout healthcheck as string, inverted ports, and supports for uid:gid syntax in user
## Version 0.6.0
// todo

View file

@ -13,6 +13,9 @@ import * as marketDemo from './market.demo';
import wrap from './wrap';
export let CPU_ARCH = '';
export let CPU_AVX = true;
let getStatus = () => {
return wrap(fetch('/cosmos/api/status', {
method: 'GET',
@ -20,6 +23,11 @@ let getStatus = () => {
'Content-Type': 'application/json'
}
}))
.then(async (response) => {
CPU_ARCH = response.data.CPU;
CPU_AVX = response.data.AVX;
return response
});
}
let isOnline = () => {

View file

@ -128,7 +128,7 @@ export const CosmosInputPassword = ({ name, noStrength, type, placeholder, autoC
</Grid>
}
export const CosmosSelect = ({ name, label, formik, disabled, options }) => {
export const CosmosSelect = ({ name, onChange, label, formik, disabled, options }) => {
return <Grid item xs={12}>
<Stack spacing={1}>
<InputLabel htmlFor={name}>{label}</InputLabel>
@ -140,7 +140,10 @@ export const CosmosSelect = ({ name, label, formik, disabled, options }) => {
disabled={disabled}
select
value={formik.values[name]}
onChange={formik.handleChange}
onChange={(...ar) => {
onChange && onChange(...ar);
formik.handleChange(...ar);
}}
error={
formik.touched[name] &&
Boolean(formik.errors[name])

View file

@ -13,7 +13,7 @@ import DockerComposeImport from '../servapps/containers/docker-compose';
function Screenshots({ screenshots }) {
return (
<Carousel animation="slide" navButtonsAlwaysVisible={false} fullHeightHover="true">
<Carousel animation="slide" navButtonsAlwaysVisible={false} fullHeightHover="true" swipe={false}>
{
screenshots.map((item, i) => <img key={i} src={item} width="100%" />)
}
@ -23,7 +23,7 @@ function Screenshots({ screenshots }) {
function Showcases({ showcase, isDark }) {
return (
<Carousel animation="slide" navButtonsAlwaysVisible={false} fullHeightHover="true">
<Carousel animation="slide" navButtonsAlwaysVisible={false} fullHeightHover="true" swipe={false}>
{
showcase.map((item, i) => <ShowcasesItem isDark={isDark} key={i} item={item} />)
}
@ -33,7 +33,7 @@ function Showcases({ showcase, isDark }) {
function ShowcasesItem({ isDark, item }) {
return (
<Paper style={{
<Paper style={{
position: 'relative',
background: 'url(' + item.screenshots[0] + ')',
height: '31vh',
@ -42,7 +42,6 @@ function ShowcasesItem({ isDark, item }) {
margin: 'auto',
}}>
<Stack direction="row" spacing={2} style={{ height: '100%', overflow: 'hidden' }} justifyContent="flex-end">
{/* <img src={item.screenshots[0]} style={{ height: '100%' }} /> */}
<Stack direction="column" spacing={2} style={{ height: '100%' }} sx={{
backgroundColor: isDark ? '#1A2027' : '#fff',
padding: '20px 100px',
@ -184,7 +183,11 @@ const MarketPage = () => {
</Stack>
<div>
{openedApp.tags.slice(0, 8).map((tag) => <Chip label={tag} />)}
{openedApp.tags && openedApp.tags.slice(0, 8).map((tag) => <Chip label={tag} />)}
</div>
<div>
{openedApp.supported_architectures && openedApp.supported_architectures.slice(0, 8).map((tag) => <Chip label={tag} />)}
</div>
<div>

View file

@ -26,7 +26,7 @@ import ResponsiveButton from '../../../components/responseiveButton';
import UploadButtons from '../../../components/fileUpload';
import NewDockerService from './newService';
import yaml from 'js-yaml';
import { CosmosCollapse, CosmosFormDivider, CosmosInputPassword, CosmosInputText } from '../../config/users/formShortcuts';
import { CosmosCollapse, CosmosFormDivider, CosmosInputPassword, CosmosInputText, CosmosSelect } from '../../config/users/formShortcuts';
import VolumeContainerSetup from './volumes';
import DockerContainerSetup from './setup';
import whiskers from 'whiskers';
@ -117,8 +117,11 @@ const DockerComposeImport = ({ refresh, dockerComposeInit, installerInit, defaul
let isJson = dockerCompose && dockerCompose.trim().startsWith('{') && dockerCompose.trim().endsWith('}');
// if Json
if (isJson) {
if (dockerCompose.trim().match(/{\n*\s*"cosmos-installer"\s*:\s*{/)) {
setInstaller(true);
return;
}
try {
let doc = JSON.parse(dockerCompose);
if(typeof doc['cosmos-installer'] === 'object') {
@ -132,7 +135,7 @@ const DockerComposeImport = ({ refresh, dockerComposeInit, installerInit, defaul
else {
// if Yml
let doc;
let newService = {};
try {
doc = yaml.load(dockerCompose);
@ -231,8 +234,22 @@ const DockerComposeImport = ({ refresh, dockerComposeInit, installerInit, defaul
}
// convert healthcheck
if (doc.services[key].healthcheck && typeof doc.services[key].healthcheck.timeout === 'string') {
doc.services[key].healthcheck.timeout = parseInt(doc.services[key].healthcheck.timeout);
if (doc.services[key].healthcheck) {
const toConvert = ["timeout", "interval", "start_period"];
toConvert.forEach((valT) => {
if(typeof doc.services[key].healthcheck[valT] === 'string') {
let original = doc.services[key].healthcheck[valT];
let value = parseInt(original);
if (original.endsWith('m')) {
value = value * 60;
} else if (original.endsWith('h')) {
value = value * 60 * 60;
} else if (original.endsWith('d')) {
value = value * 60 * 60 * 24;
}
doc.services[key].healthcheck[valT] = value;
}
});
}
});
}
@ -283,7 +300,6 @@ const DockerComposeImport = ({ refresh, dockerComposeInit, installerInit, defaul
}
} catch (e) {
console.log(e);
setYmlError(e.message);
return;
}
@ -303,7 +319,6 @@ const DockerComposeImport = ({ refresh, dockerComposeInit, installerInit, defaul
try {
if (installer) {
console.log(hostnames)
const rendered = whiskers.render(dockerCompose.replace(/{StaticServiceName}/ig, serviceName), {
ServiceName: serviceName,
Hostnames: hostnames,
@ -312,7 +327,9 @@ const DockerComposeImport = ({ refresh, dockerComposeInit, installerInit, defaul
randomString(32),
randomString(32),
randomString(32)
]
],
CPU_ARCH: API.CPU_ARCH,
CPU_AVX: API.CPU_AVX,
});
const jsoned = JSON.parse(rendered);
@ -373,7 +390,6 @@ const DockerComposeImport = ({ refresh, dockerComposeInit, installerInit, defaul
if (jsoned.services[key].volumes && jsoned['cosmos-installer'] && jsoned['cosmos-installer']['frozen-volumes']) {
jsoned['cosmos-installer']['frozen-volumes'].forEach((volumeName) => {
const keyVolume = overrides[key].volumes.findIndex((v) => {
console.log(v)
return v.source === volumeName;
});
delete overrides[key].volumes[keyVolume];
@ -424,7 +440,7 @@ const DockerComposeImport = ({ refresh, dockerComposeInit, installerInit, defaul
setYmlError(e.message);
return;
}
}, [openModal, dockerCompose, serviceName, hostnames, overrides]);
}, [openModal, dockerCompose, serviceName, hostnames, overrides, installer]);
const openModalFunc = () => {
setOpenModal(true);
@ -489,7 +505,7 @@ const DockerComposeImport = ({ refresh, dockerComposeInit, installerInit, defaul
<TextField label="Service Name" value={serviceName} onChange={(e) => setServiceName(e.target.value)} />
{service['cosmos-installer'] && service['cosmos-installer'].form.map((formElement) => {
{service['cosmos-installer'] && service['cosmos-installer'].form && service['cosmos-installer'].form.map((formElement) => {
return formElement.type === 'checkbox' ?
<FormControlLabel
control={<Checkbox checked={context[formElement.name]} onChange={(e) => {
@ -506,6 +522,24 @@ const DockerComposeImport = ({ refresh, dockerComposeInit, installerInit, defaul
setContext({ ...context, [formElement.name]: e.target.value });
}
} />
: (formElement.type === 'select') ?
<CosmosSelect
name={formElement.name}
label={formElement.label}
formik={{
values: {
[formElement.name] : context[formElement.name]
},
touched: {},
errors: {},
setFieldValue: () => {},
handleChange: () => {}
}}
onChange={(e) => {
setContext({ ...context, [formElement.name]: e.target.value });
}}
options={formElement.options}
/>
: formElement.type === 'hostname' ?
<>
<TextField
@ -532,8 +566,6 @@ const DockerComposeImport = ({ refresh, dockerComposeInit, installerInit, defaul
nameOnly={formElement.type === 'container'}
label={formElement.label}
onTargetChange={(_, name) => {
console.log(formElement['name-container'], name)
console.log(context)
setContext({ ...context, [formElement['name-container']]: name });
}}
/>

View file

@ -51,7 +51,7 @@ export const DnsChallengeComp = ({ name, configName, style, multiline, type, pla
onChange={(e) => {
onChange && onChange(e);
}}
options={dnsList.map((dns) => ([dns,dns]))}
options={[["", "DISABLE"], ...(dnsList).map((dns) => ([dns,dns]))]}
/>
<Grid item xs={12}>
@ -71,7 +71,7 @@ export const DnsChallengeComp = ({ name, configName, style, multiline, type, pla
{dnsVar}:
<OutlinedInput
type={type ? type : 'text'}
value={formik.values[configName][dnsVar] || ''}
value={formik.values[configName] ? (formik.values[configName][dnsVar] || '') : ''}
onChange={(...ar) => {
const newConfig = {
...formik.values[configName],

View file

@ -1,6 +1,6 @@
{
"name": "cosmos-server",
"version": "0.7.0-unstable9",
"version": "0.7.0-unstable10",
"description": "",
"main": "test-server.js",
"bugs": {

View file

@ -448,12 +448,14 @@ func CreateService(serviceRequest DockerServiceCreateRequest, OnLog func(string)
OnLog(fmt.Sprintf("Not found. Creating directory %s for bind mount\n", newSource))
err := os.MkdirAll(newSource, 0750)
if err != nil {
utils.Error("CreateService: Unable to create directory for bind mount. Make sure parent directories exist, and that Cosmos has permissions to create directories in the host directory", err)
OnLog(fmt.Sprintf("[ERROR] Unable to create directory for bind mount. Make sure parent directories exist, and that Cosmos has permissions to create directories in the host directory: %s\n", err.Error()))
Rollback(rollbackActions, OnLog)
return err
}
if container.UID != 0 {
// Change the ownership of the directory to the container.UID
err = os.Chown(newSource, container.UID, container.GID)
@ -461,6 +463,15 @@ func CreateService(serviceRequest DockerServiceCreateRequest, OnLog func(string)
utils.Error("CreateService: Unable to change ownership of directory", err)
OnLog(fmt.Sprintf("[ERROR] Unable to change ownership of directory: " + err.Error()))
}
} else if container.User != "" && strings.Contains(container.User, ":") {
uidgid := strings.Split(container.User, ":")
uid, _ := strconv.Atoi(uidgid[0])
gid, _ := strconv.Atoi(uidgid[1])
err = os.Chown(newSource, uid, gid)
if err != nil {
utils.Error("CreateService: Unable to change ownership of directory", err)
OnLog(fmt.Sprintf("[ERROR] Unable to change ownership of directory: " + err.Error()))
}
} else if container.User != "" {
// Change the ownership of the directory to the container.User
userInfo, err := user.Lookup(container.User)
@ -530,13 +541,14 @@ func CreateService(serviceRequest DockerServiceCreateRequest, OnLog func(string)
EndpointsConfig: make(map[string]*network.EndpointSettings),
}
for netName, netConfig := range container.Networks {
// Stupid Docker does not want to connect to multiple networks at once
/*for netName, netConfig := range container.Networks {
networkingConfig.EndpointsConfig[netName] = &network.EndpointSettings{
Aliases: netConfig.Aliases,
IPAddress: netConfig.IPV4Address,
GlobalIPv6Address: netConfig.IPV6Address,
}
}
}*/
_, err = DockerClient.ContainerCreate(DockerContext, containerConfig, hostConfig, networkingConfig, nil, container.Name)
@ -552,6 +564,22 @@ func CreateService(serviceRequest DockerServiceCreateRequest, OnLog func(string)
Type: "container",
Name: container.Name,
})
// connect to networks
for netName, netConfig := range container.Networks {
err = DockerClient.NetworkConnect(DockerContext, netName, container.Name, &network.EndpointSettings{
Aliases: netConfig.Aliases,
IPAddress: netConfig.IPV4Address,
GlobalIPv6Address: netConfig.IPV6Address,
})
if err != nil {
utils.Error("CreateService: Rolling back changes because of -- Network Connection -- ", err)
OnLog(fmt.Sprintf("[ERROR] Rolling back changes because of -- Network connection error: "+err.Error()))
Rollback(rollbackActions, OnLog)
return err
}
}
// add routes
for _, route := range container.Routes {

View file

@ -18,6 +18,7 @@ type appDefinition struct {
Screenshots []string `json:"screenshots"`
Icon string `json:"icon"`
Compose string `json:"compose"`
SupportedArchitectures []string `json:"supported_architectures"`
}
type marketDefinition struct {

View file

@ -3,6 +3,8 @@ package main
import (
"net/http"
"encoding/json"
"runtime"
"golang.org/x/sys/cpu"
"github.com/azukaar/cosmos-server/src/utils"
"github.com/azukaar/cosmos-server/src/docker"
@ -46,6 +48,8 @@ func StatusRoute(w http.ResponseWriter, req *http.Request) {
"needsRestart": utils.NeedsRestart,
"newVersionAvailable": utils.NewVersionAvailable,
"hostname": utils.GetMainConfig().HTTPConfig.Hostname,
"CPU": runtime.GOARCH,
"AVX": cpu.X86.HasAVX,
},
})
} else {

View file

@ -105,7 +105,7 @@ type HTTPConfig struct {
SSLEmail string `validate:"omitempty,email"`
UseWildcardCertificate bool
AcceptAllInsecureHostname bool
DNSChallengeConfig map[string]string
DNSChallengeConfig map[string]string `json:"dnsChallengeConfig,omitempty"`
}
const (