Update to 0.7.0-unstable10
This commit is contained in:
parent
2304d269d8
commit
7e565a42d2
|
@ -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
|
||||
|
|
|
@ -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 = () => {
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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} />)
|
||||
}
|
||||
|
@ -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>
|
||||
|
|
|
@ -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 });
|
||||
}}
|
||||
/>
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "cosmos-server",
|
||||
"version": "0.7.0-unstable9",
|
||||
"version": "0.7.0-unstable10",
|
||||
"description": "",
|
||||
"main": "test-server.js",
|
||||
"bugs": {
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
@ -553,6 +565,22 @@ func CreateService(serviceRequest DockerServiceCreateRequest, OnLog func(string)
|
|||
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 {
|
||||
// check if route already exists
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 (
|
||||
|
|
Loading…
Reference in a new issue