[release] 0.9.11
This commit is contained in:
parent
8e9649ec2c
commit
26d5fe5767
10
changelog.md
10
changelog.md
|
@ -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
|
## Version 0.9.10
|
||||||
- Never ban gateway ips
|
- Never ban gateway ips
|
||||||
- Prevent deleting networks if there's an error on disconnect
|
- Prevent deleting networks if there's an error on disconnect
|
||||||
|
|
|
@ -199,7 +199,7 @@ const DockerComposeImport = ({ refresh, dockerComposeInit, installerInit, defaul
|
||||||
let volumeObj = {
|
let volumeObj = {
|
||||||
source: volumeSplit[0],
|
source: volumeSplit[0],
|
||||||
target: volumeSplit[1],
|
target: volumeSplit[1],
|
||||||
type: volume[0] === '/' ? 'bind' : 'volume',
|
type: (volume[0] === '/' || volume[0] === '.') ? 'bind' : 'volume',
|
||||||
};
|
};
|
||||||
volumes.push(volumeObj);
|
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
|
// convert expose
|
||||||
if (doc.services[key].expose) {
|
if (doc.services[key].expose) {
|
||||||
doc.services[key].expose = doc.services[key].expose.map((port) => {
|
doc.services[key].expose = doc.services[key].expose.map((port) => {
|
||||||
|
|
|
@ -68,25 +68,22 @@ const NetworkContainerSetup = ({ config, containerInfo, refresh, newContainer, O
|
||||||
<Formik
|
<Formik
|
||||||
initialValues={{
|
initialValues={{
|
||||||
networkMode: containerInfo.HostConfig.NetworkMode,
|
networkMode: containerInfo.HostConfig.NetworkMode,
|
||||||
ports: Object.keys(containerInfo.NetworkSettings.Ports).map((port) => {
|
ports: Object.keys(containerInfo.NetworkSettings.Ports).map((contPort) => {
|
||||||
return {
|
return containerInfo.NetworkSettings.Ports[contPort] ? containerInfo.NetworkSettings.Ports[contPort].map((hostPort) => {
|
||||||
port: port.split('/')[0],
|
return {
|
||||||
protocol: port.split('/')[1],
|
port: contPort.split('/')[0],
|
||||||
hostPort: containerInfo.NetworkSettings.Ports[port] && containerInfo.NetworkSettings.Ports[port][0] ?
|
protocol: contPort.split('/')[1],
|
||||||
containerInfo.NetworkSettings.Ports[port][0].HostPort : '',
|
hostPort: hostPort.HostPort,
|
||||||
};
|
};
|
||||||
})
|
}) : {
|
||||||
|
port: contPort.split('/')[0],
|
||||||
|
protocol: contPort.split('/')[1],
|
||||||
|
hostPort: '',
|
||||||
|
}
|
||||||
|
}).flat(),
|
||||||
}}
|
}}
|
||||||
validate={(values) => {
|
validate={(values) => {
|
||||||
const errors = {};
|
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);
|
OnChange && OnChange(values);
|
||||||
return errors;
|
return errors;
|
||||||
}}
|
}}
|
||||||
|
@ -98,12 +95,14 @@ const NetworkContainerSetup = ({ config, containerInfo, refresh, newContainer, O
|
||||||
networkMode: values.networkMode,
|
networkMode: values.networkMode,
|
||||||
};
|
};
|
||||||
values.ports.forEach((port) => {
|
values.ports.forEach((port) => {
|
||||||
|
let key = `${port.port}/${port.protocol}`;
|
||||||
|
|
||||||
if (port.hostPort) {
|
if (port.hostPort) {
|
||||||
realvalues.portBindings[`${port.port}/${port.protocol}`] = [
|
if(!realvalues.portBindings[key]) realvalues.portBindings[key] = [];
|
||||||
{
|
|
||||||
HostPort: port.hostPort,
|
realvalues.portBindings[`${port.port}/${port.protocol}`].push({
|
||||||
}
|
HostPort: port.hostPort,
|
||||||
];
|
})
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return API.docker.updateContainer(containerInfo.Name.replace('/', ''), realvalues)
|
return API.docker.updateContainer(containerInfo.Name.replace('/', ''), realvalues)
|
||||||
|
|
|
@ -208,7 +208,7 @@ const ServApps = () => {
|
||||||
<Stack style={noOver} margin={1} direction="row" spacing={1}>
|
<Stack style={noOver} margin={1} direction="row" spacing={1}>
|
||||||
{app.Ports.filter(p => p.IP != '::').map((port) => {
|
{app.Ports.filter(p => p.IP != '::').map((port) => {
|
||||||
return <Tooltip title={port.PublicPort ? 'Warning, this port is publicly accessible' : ''}>
|
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>
|
</Tooltip>
|
||||||
})}
|
})}
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
|
@ -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 {
|
func CreateService(serviceRequest DockerServiceCreateRequest, OnLog func(string)) error {
|
||||||
utils.ConfigLock.Lock()
|
utils.ConfigLock.Lock()
|
||||||
|
@ -408,24 +426,69 @@ func CreateService(serviceRequest DockerServiceCreateRequest, OnLog func(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// For Expose / Ports
|
// For Expose / Ports
|
||||||
|
|
||||||
for _, expose := range container.Expose {
|
for _, expose := range container.Expose {
|
||||||
exposePort := nat.Port(expose)
|
exposePort := nat.Port(expose)
|
||||||
containerConfig.ExposedPorts[exposePort] = struct{}{}
|
containerConfig.ExposedPorts[exposePort] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
PortBindings := nat.PortMap{}
|
PortBindings := nat.PortMap{}
|
||||||
|
finalPorts := []string{}
|
||||||
|
|
||||||
for _, port := range container.Ports {
|
for _, portRaw := range container.Ports {
|
||||||
portHost := strings.Split(port, ":")[0]
|
portStuff := strings.Split(portRaw, "/")
|
||||||
portContainer := strings.Split(port, ":")[1]
|
|
||||||
|
|
||||||
containerConfig.ExposedPorts[nat.Port(portContainer)] = struct{}{}
|
if len(portStuff) == 1 {
|
||||||
PortBindings[nat.Port(portContainer)] = []nat.PortBinding{
|
portStuff = append(portStuff, "tcp")
|
||||||
{
|
|
||||||
HostIP: "",
|
|
||||||
HostPort: portHost,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
// Create missing folders for bind mounts
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/azukaar/cosmos-server/src/utils"
|
"github.com/azukaar/cosmos-server/src/utils"
|
||||||
containerType "github.com/docker/docker/api/types/container"
|
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
|
container.Config.Labels = form.Labels
|
||||||
}
|
}
|
||||||
if(form.PortBindings != nil) {
|
if(form.PortBindings != nil) {
|
||||||
|
utils.Debug(fmt.Sprintf("UpdateContainer: PortBindings: %v", form.PortBindings))
|
||||||
container.HostConfig.PortBindings = form.PortBindings
|
container.HostConfig.PortBindings = form.PortBindings
|
||||||
container.Config.ExposedPorts = make(map[nat.Port]struct{})
|
container.Config.ExposedPorts = make(map[nat.Port]struct{})
|
||||||
for port := range form.PortBindings {
|
for port := range form.PortBindings {
|
||||||
|
|
Loading…
Reference in a new issue