[release] 0.9.11

This commit is contained in:
Yann Stepienik 2023-07-24 13:01:24 +01:00
parent 8e9649ec2c
commit 26d5fe5767
6 changed files with 114 additions and 32 deletions

View file

@ -1,3 +1,13 @@
## Version 0.9.11
- Add support for port ranges in cosmos-compose
- Fix bug where multiple host port to the same container would override each other
- Port display on Servapp tab was inverted
- Fixed Network screen to support complex port mappings
- Add support for protocol in cosmos-compose port exposing logic
- Add support for relative bind path in docker-compose import
- Fix environment vars and labels containing multiple equals (@jwr1)
- Fix link to Other Setups page (@jwr1)
## Version 0.9.10
- Never ban gateway ips
- Prevent deleting networks if there's an error on disconnect

View file

@ -199,7 +199,7 @@ const DockerComposeImport = ({ refresh, dockerComposeInit, installerInit, defaul
let volumeObj = {
source: volumeSplit[0],
target: volumeSplit[1],
type: volume[0] === '/' ? 'bind' : 'volume',
type: (volume[0] === '/' || volume[0] === '.') ? 'bind' : 'volume',
};
volumes.push(volumeObj);
}
@ -208,6 +208,14 @@ const DockerComposeImport = ({ refresh, dockerComposeInit, installerInit, defaul
}
}
if(doc.services[key].volumes)
Object.values(doc.services[key].volumes).forEach((volume) => {
if (volume.source && volume.source[0] === '.') {
let defaultPath = (config && config.DockerConfig && config.DockerConfig.DefaultDataPath) || "/usr"
volume.source = defaultPath + volume.source.replace('.', '');
}
});
// convert expose
if (doc.services[key].expose) {
doc.services[key].expose = doc.services[key].expose.map((port) => {

View file

@ -68,25 +68,22 @@ const NetworkContainerSetup = ({ config, containerInfo, refresh, newContainer, O
<Formik
initialValues={{
networkMode: containerInfo.HostConfig.NetworkMode,
ports: Object.keys(containerInfo.NetworkSettings.Ports).map((port) => {
return {
port: port.split('/')[0],
protocol: port.split('/')[1],
hostPort: containerInfo.NetworkSettings.Ports[port] && containerInfo.NetworkSettings.Ports[port][0] ?
containerInfo.NetworkSettings.Ports[port][0].HostPort : '',
};
})
ports: Object.keys(containerInfo.NetworkSettings.Ports).map((contPort) => {
return containerInfo.NetworkSettings.Ports[contPort] ? containerInfo.NetworkSettings.Ports[contPort].map((hostPort) => {
return {
port: contPort.split('/')[0],
protocol: contPort.split('/')[1],
hostPort: hostPort.HostPort,
};
}) : {
port: contPort.split('/')[0],
protocol: contPort.split('/')[1],
hostPort: '',
}
}).flat(),
}}
validate={(values) => {
const errors = {};
// check unique
const ports = values.ports.map((port) => {
return `${port.port}/${port.protocol}`;
});
const unique = [...new Set(ports)];
if (unique.length !== ports.length) {
errors.submit = 'Ports must be unique';
}
OnChange && OnChange(values);
return errors;
}}
@ -98,12 +95,14 @@ const NetworkContainerSetup = ({ config, containerInfo, refresh, newContainer, O
networkMode: values.networkMode,
};
values.ports.forEach((port) => {
let key = `${port.port}/${port.protocol}`;
if (port.hostPort) {
realvalues.portBindings[`${port.port}/${port.protocol}`] = [
{
HostPort: port.hostPort,
}
];
if(!realvalues.portBindings[key]) realvalues.portBindings[key] = [];
realvalues.portBindings[`${port.port}/${port.protocol}`].push({
HostPort: port.hostPort,
})
}
});
return API.docker.updateContainer(containerInfo.Name.replace('/', ''), realvalues)

View file

@ -208,7 +208,7 @@ const ServApps = () => {
<Stack style={noOver} margin={1} direction="row" spacing={1}>
{app.Ports.filter(p => p.IP != '::').map((port) => {
return <Tooltip title={port.PublicPort ? 'Warning, this port is publicly accessible' : ''}>
<Chip style={{ fontSize: '80%' }} label={port.PrivatePort + (port.PublicPort ? (":" + port.PublicPort) : '')} color={port.PublicPort ? 'warning' : 'default'} />
<Chip style={{ fontSize: '80%' }} label={(port.PublicPort ? (port.PublicPort + ":") : '') + port.PrivatePort} color={port.PublicPort ? 'warning' : 'default'} />
</Tooltip>
})}
</Stack>

View file

@ -206,6 +206,24 @@ func CreateServiceRoute(w http.ResponseWriter, req *http.Request) {
}
}
// generatePorts is a helper function to generate a slice of ports from a string range.
func generatePorts(portRangeStr string) []string {
portsStr := strings.Split(portRangeStr, "-")
if len(portsStr) != 2 {
return []string{
portsStr[0],
}
}
start, _ := strconv.Atoi(portsStr[0])
end, _ := strconv.Atoi(portsStr[1])
ports := make([]string, end-start+1)
for i := range ports {
ports[i] = strconv.Itoa(start + i)
}
return ports
}
func CreateService(serviceRequest DockerServiceCreateRequest, OnLog func(string)) error {
utils.ConfigLock.Lock()
@ -408,24 +426,69 @@ func CreateService(serviceRequest DockerServiceCreateRequest, OnLog func(string)
}
// For Expose / Ports
for _, expose := range container.Expose {
exposePort := nat.Port(expose)
containerConfig.ExposedPorts[exposePort] = struct{}{}
}
PortBindings := nat.PortMap{}
finalPorts := []string{}
for _, port := range container.Ports {
portHost := strings.Split(port, ":")[0]
portContainer := strings.Split(port, ":")[1]
for _, portRaw := range container.Ports {
portStuff := strings.Split(portRaw, "/")
containerConfig.ExposedPorts[nat.Port(portContainer)] = struct{}{}
PortBindings[nat.Port(portContainer)] = []nat.PortBinding{
{
HostIP: "",
HostPort: portHost,
},
if len(portStuff) == 1 {
portStuff = append(portStuff, "tcp")
}
port, protocol := portStuff[0], portStuff[1]
ports := strings.Split(port, ":")
hostPorts := generatePorts(ports[0])
containerPorts := generatePorts(ports[1])
for i := 0; i < utils.Max(len(hostPorts), len(containerPorts)); i++ {
hostPort := hostPorts[i%len(hostPorts)]
containerPort := containerPorts[i%len(containerPorts)]
finalPorts = append(finalPorts, fmt.Sprintf("%s:%s/%s", hostPort, containerPort, protocol))
}
}
utils.Debug(fmt.Sprintf("Final ports: %s", finalPorts))
hostPortsBound := make(map[string]bool)
for _, portRaw := range finalPorts {
portStuff := strings.Split(portRaw, "/")
port, protocol := portStuff[0], portStuff[1]
nextPort := strings.Split(port, ":")
hostPort, contPort := nextPort[0], nextPort[1]
contPort = contPort + "/" + protocol
if hostPortsBound[hostPort] {
utils.Warn("Port " + hostPort + " already bound, skipping")
continue
}
// Get the existing bindings for this container port, if any
bindings := PortBindings[nat.Port(contPort)]
// Append a new PortBinding to the slice of bindings
bindings = append(bindings, nat.PortBinding{
HostPort: hostPort,
})
// Update the port bindings for this container port
PortBindings[nat.Port(contPort)] = bindings
// Mark the container port as exposed
containerConfig.ExposedPorts[nat.Port(contPort)] = struct{}{}
hostPortsBound[hostPort] = true
}
// Create missing folders for bind mounts

View file

@ -4,6 +4,7 @@ import (
"encoding/json"
"net/http"
"os"
"fmt"
"github.com/azukaar/cosmos-server/src/utils"
containerType "github.com/docker/docker/api/types/container"
@ -77,6 +78,7 @@ func UpdateContainerRoute(w http.ResponseWriter, req *http.Request) {
container.Config.Labels = form.Labels
}
if(form.PortBindings != nil) {
utils.Debug(fmt.Sprintf("UpdateContainer: PortBindings: %v", form.PortBindings))
container.HostConfig.PortBindings = form.PortBindings
container.Config.ExposedPorts = make(map[nat.Port]struct{})
for port := range form.PortBindings {