From c3401064c61359ecab769296f4932505775bb2f9 Mon Sep 17 00:00:00 2001 From: Yann Stepienik Date: Tue, 11 Apr 2023 18:33:49 +0100 Subject: [PATCH] [release] v0.1.16 - Fix search - Fix bug where containers would lose their networks after being edited - Self-heal secure network configuration - Auto disconnect from orphan networks - Prevent bootstrapping from creating orphan networks - Monitor Docker and self-heal when docker daemon dies - Recreate lost secure networks (ex. when resetting Cosmos) --- changelog.md | 13 ++ client/src/pages/config/users/proxyman.jsx | 5 +- .../src/pages/config/users/usermanagement.jsx | 1 - client/src/pages/servapps/servapps.jsx | 3 +- client/src/routes/MainRoutes.jsx | 2 +- client/src/themes/index.jsx | 1 - client/src/themes/theme/index.jsx | 1 - package.json | 4 +- sponsors.js | 11 +- src/CRON.go | 7 +- src/config.go | 4 + src/docker/api_secureContainer.go | 4 +- src/docker/bootstrap.go | 24 +- src/docker/docker.go | 60 ++++- src/docker/events.go | 24 ++ src/docker/network.go | 220 ++++++++++++++---- src/httpServer.go | 12 +- src/utils/types.go | 5 + 18 files changed, 318 insertions(+), 83 deletions(-) diff --git a/changelog.md b/changelog.md index e2aec62..f5cbd3a 100644 --- a/changelog.md +++ b/changelog.md @@ -1,4 +1,17 @@ +## Version 0.1.16 + + - Fix search + - Fix bug where containers would lose their networks after being edited + - Self-heal secure network configuration + - Auto disconnect from orphan networks + - Prevent bootstrapping from creating orphan networks + - Monitor Docker and self-heal when docker daemon dies + - Recreate lost secure networks (ex. when resetting Cosmos) + + + ## Version 0.1.15 + - Ports is now freetype, in case container does not expose any - Container picker now tries to pick the best port as default - Hostname now default to container name diff --git a/client/src/pages/config/users/proxyman.jsx b/client/src/pages/config/users/proxyman.jsx index 8e403fa..b0bb42d 100644 --- a/client/src/pages/config/users/proxyman.jsx +++ b/client/src/pages/config/users/proxyman.jsx @@ -62,7 +62,6 @@ const ProxyManagement = () => { }, }; setConfig(con); - setNeedSave(true); return con; } @@ -86,12 +85,14 @@ const ProxyManagement = () => { routes[key] = routes[key-1]; routes[key-1] = tmp; updateRoutes(routes); + setNeedSave(true); } } function deleteRoute(key) { routes.splice(key, 1); updateRoutes(routes); + setNeedSave(true); } function down(key) { @@ -100,6 +101,7 @@ const ProxyManagement = () => { routes[key] = routes[key+1]; routes[key+1] = tmp; updateRoutes(routes); + setNeedSave(true); } } @@ -136,6 +138,7 @@ const ProxyManagement = () => { AuthEnabled: false, }); updateRoutes(routes); + setNeedSave(true); }}>Create

diff --git a/client/src/pages/config/users/usermanagement.jsx b/client/src/pages/config/users/usermanagement.jsx index 7a8bb08..a2f0352 100644 --- a/client/src/pages/config/users/usermanagement.jsx +++ b/client/src/pages/config/users/usermanagement.jsx @@ -40,7 +40,6 @@ const UserManagement = () => { setIsLoading(true); API.users.list() .then(data => { - console.log(data); setRows(data.data); setIsLoading(false); }) diff --git a/client/src/pages/servapps/servapps.jsx b/client/src/pages/servapps/servapps.jsx index 2c64482..3946dc2 100644 --- a/client/src/pages/servapps/servapps.jsx +++ b/client/src/pages/servapps/servapps.jsx @@ -45,7 +45,6 @@ const ServeApps = () => { } const testRoute = (route) => { - console.log(newRoute) try { ValidateRoute.validateSync(route); } catch (e) { @@ -206,7 +205,7 @@ const ServeApps = () => { - {serveApps && serveApps.filter(app => search.length < 2 || app.Names[0].includes(search)).map((app) => { + {serveApps && serveApps.filter(app => search.length < 2 || app.Names[0].toLowerCase().includes(search.toLowerCase())).map((app) => { return }> diff --git a/client/src/routes/MainRoutes.jsx b/client/src/routes/MainRoutes.jsx index f6e4188..049a533 100644 --- a/client/src/routes/MainRoutes.jsx +++ b/client/src/routes/MainRoutes.jsx @@ -33,7 +33,7 @@ const MainRoutes = { element: }, { - path: '/ui/', + path: '/ui', element: }, { diff --git a/client/src/themes/index.jsx b/client/src/themes/index.jsx index 03ef80b..c288b03 100644 --- a/client/src/themes/index.jsx +++ b/client/src/themes/index.jsx @@ -18,7 +18,6 @@ export default function ThemeCustomization({ children }) { window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'); - console.log(theme) // eslint-disable-next-line react-hooks/exhaustive-deps const themeTypography = Typography(`'Public Sans', sans-serif`); diff --git a/client/src/themes/theme/index.jsx b/client/src/themes/theme/index.jsx index 89f8540..73f8016 100644 --- a/client/src/themes/theme/index.jsx +++ b/client/src/themes/theme/index.jsx @@ -3,7 +3,6 @@ import { purple, pink, deepPurple } from '@mui/material/colors'; const Theme = (colors) => { - console.log(colors) const { blue, red, gold, cyan, green, grey } = colors; const greyColors = { 0: grey[0], diff --git a/package.json b/package.json index 74b2b57..303c9af 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cosmos-server", - "version": "0.1.15", + "version": "0.1.16", "description": "", "main": "test-server.js", "bugs": { @@ -57,7 +57,7 @@ "build": " sh build.sh", "dev": "npm run build && npm run start", "dockerdevbuild": "sh build.sh && npm run client-build && docker build --tag cosmos-dev .", - "dockerdevrun": "docker stop cosmos-dev; docker rm cosmos-dev; docker run -d -p 80:80 -p 443:443 -e DOCKER_HOST=tcp://host.docker.internal:2375 -e COSMOS_HOSTNAME=localhost -e COSMOS_MONGODB=$MONGODB -e COSMOS_LOG_LEVEL=DEBUG --restart=unless-stopped --name cosmos-dev cosmos-dev", + "dockerdevrun": "docker stop cosmos-dev; docker rm cosmos-dev; docker run -d -p 80:80 -p 443:443 -e DOCKER_HOST=tcp://host.docker.internal:2375 -e COSMOS_HOSTNAME=localhost -e COSMOS_MONGODB=$MONGODB -e COSMOS_LOG_LEVEL=DEBUG --restart=unless-stopped -h cosmos-dev --name cosmos-dev cosmos-dev", "dockerdev": "npm run dockerdevbuild && npm run dockerdevrun" }, "eslintConfig": { diff --git a/sponsors.js b/sponsors.js index 11925b2..8c4b875 100644 --- a/sponsors.js +++ b/sponsors.js @@ -56,18 +56,21 @@ const sponsorsGenerate = async () => { function changelog() { // get the changes from last commit message const { execSync } = require('child_process') - const commitMessage = execSync('git log -1 --pretty=%B').toString() - if(!commitMessage.toLocaleLowerCase().startsWith('[release]')) { + let commitMessage = execSync('git log -1 --pretty=%B').toString() + + if(!commitMessage.startsWith('[release]')) { console.log('Not a release commit, skipping changelog update') return } const version = packageJson.version + + commitMessage = commitMessage.replace('[release]', 'Version') // open changelog.md const changelog = fs.readFileSync('./changelog.md', 'utf8') // add the new changes to the top of the changelog - const newChangelog = `## Version ${version} \n ${commitMessage}\n\n${changelog}` + const newChangelog = `## ${commitMessage}\n\n${changelog}` // write the new changelog fs.writeFileSync('./changelog.md', newChangelog) @@ -84,4 +87,4 @@ function changelog() { } sponsorsGenerate() -changelog(); \ No newline at end of file +// changelog(); \ No newline at end of file diff --git a/src/CRON.go b/src/CRON.go index 01ff921..f1ef444 100644 --- a/src/CRON.go +++ b/src/CRON.go @@ -5,6 +5,7 @@ import ( "io/ioutil" "net/http" "github.com/azukaar/cosmos-server/src/utils" + // "github.com/azukaar/cosmos-server/src/docker" "os" "path/filepath" "encoding/json" @@ -64,6 +65,8 @@ func checkVersion() { } func CRON() { - gocron.Every(1).Day().At("00:00").Do(checkVersion) - <-gocron.Start() + go func() { + gocron.Every(1).Day().At("00:00").Do(checkVersion) + <-gocron.Start() + }() } \ No newline at end of file diff --git a/src/config.go b/src/config.go index cf4577c..d9fe765 100644 --- a/src/config.go +++ b/src/config.go @@ -24,6 +24,7 @@ func LoadConfig() utils.Config { decoder := json.NewDecoder(file) config := utils.Config{} err = decoder.Decode(&config) + // check file is not empty if err != nil { // check error is not empty @@ -48,6 +49,9 @@ func LoadConfig() utils.Config { } utils.LoadBaseMainConfig(config) + + configJson, _ := json.MarshalIndent(config, "", " ") + utils.Debug("Loaded Configuration " + (string)(configJson)) return config } \ No newline at end of file diff --git a/src/docker/api_secureContainer.go b/src/docker/api_secureContainer.go index 0ee598b..c63ca25 100644 --- a/src/docker/api_secureContainer.go +++ b/src/docker/api_secureContainer.go @@ -21,7 +21,7 @@ func SecureContainerRoute(w http.ResponseWriter, req *http.Request) { if(req.Method == "GET") { container, err := DockerClient.ContainerInspect(DockerContext, containerName) if err != nil { - utils.Error("ContainerSecure", err) + utils.Error("ContainerSecureInscpect", err) utils.HTTPError(w, "Internal server error: " + err.Error(), http.StatusInternalServerError, "DS002") return } @@ -34,7 +34,7 @@ func SecureContainerRoute(w http.ResponseWriter, req *http.Request) { _, errEdit := EditContainer(container.ID, container) if errEdit != nil { - utils.Error("ContainerSecure", errEdit) + utils.Error("ContainerSecureEdit", errEdit) utils.HTTPError(w, "Internal server error: " + err.Error(), http.StatusInternalServerError, "DS003") return } diff --git a/src/docker/bootstrap.go b/src/docker/bootstrap.go index 87efc46..c4c3475 100644 --- a/src/docker/bootstrap.go +++ b/src/docker/bootstrap.go @@ -3,6 +3,7 @@ package docker import ( "github.com/azukaar/cosmos-server/src/utils" "github.com/docker/docker/api/types" + "os" ) func BootstrapAllContainersFromTags() []error { @@ -30,18 +31,27 @@ func BootstrapAllContainersFromTags() []error { return errors } - func BootstrapContainerFromTags(containerID string) error { errD := Connect() if errD != nil { return errD } + selfContainer := types.ContainerJSON{} + if os.Getenv("HOSTNAME") != "" { + var errS error + selfContainer, errS = DockerClient.ContainerInspect(DockerContext, os.Getenv("HOSTNAME")) + if errS != nil { + utils.Error("DockerContainerBootstrapSelfInspect", errS) + return errS + } + } + utils.Log("Bootstrap Container From Tags: " + containerID) container, err := DockerClient.ContainerInspect(DockerContext, containerID) if err != nil { - utils.Error("Docker Container Bootstrap Inspect", err) + utils.Error("DockerContainerBootstrapInspect", err) return err } @@ -51,12 +61,10 @@ func BootstrapContainerFromTags(containerID string) error { utils.Log(container.Name+": Checking Force network secured") // check if connected to bridge and to a cosmos network - isCon, errC := IsConnectedToNetwork(container, "bridge") - isCosmosCon, _ := IsConnectedToASecureCosmosNetwork(container) + isCon := IsConnectedToNetwork(container, "bridge") + isCosmosCon, _ := IsConnectedToASecureCosmosNetwork(selfContainer, container) - if errC != nil { - return errC - } else if isCon || !isCosmosCon { + if isCon || !isCosmosCon { utils.Log(container.Name+": Needs isolating on a secured network") needsRestart := false var errCT error @@ -66,7 +74,7 @@ func BootstrapContainerFromTags(containerID string) error { return errCT } if needsRestart { - utils.Log(container.Name+": Will connect to new network after restart") + utils.Log(container.Name+": Will restart to apply changes") needsUpdate = true } else { utils.Log(container.Name+": Connected to new network") diff --git a/src/docker/docker.go b/src/docker/docker.go index 1c12f57..9102784 100644 --- a/src/docker/docker.go +++ b/src/docker/docker.go @@ -3,13 +3,12 @@ package docker import ( "context" "errors" - + "time" "github.com/azukaar/cosmos-server/src/utils" "github.com/docker/docker/client" // natting "github.com/docker/go-connections/nat" "github.com/docker/docker/api/types/container" - // network "github.com/docker/docker/api/types/network" "github.com/docker/docker/api/types" ) @@ -37,6 +36,18 @@ func getIdFromName(name string) (string, error) { var DockerIsConnected = false func Connect() error { + if DockerClient != nil { + // check if connection is still alive + ping, err := DockerClient.Ping(DockerContext) + if ping.APIVersion != "" && err == nil { + DockerIsConnected = true + return nil + } else { + DockerIsConnected = false + DockerClient = nil + utils.Error("Docker Connection died, will try to connect again", err) + } + } if DockerClient == nil { ctx := context.Background() client, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) @@ -69,11 +80,17 @@ func Connect() error { } func EditContainer(containerID string, newConfig types.ContainerJSON) (string, error) { + DockerNetworkLock <- true + defer func() { + <-DockerNetworkLock + utils.Debug("Unlocking EDIT Container") + }() + errD := Connect() if errD != nil { return "", errD } - utils.Log("Container updating " + containerID) + utils.Log("EditContainer - Container updating " + containerID) // get container informations // https://godoc.org/github.com/docker/docker/api/types#ContainerJSON @@ -98,7 +115,19 @@ func EditContainer(containerID string, newConfig types.ContainerJSON) (string, e return "", removeError } - utils.Log("Container stopped " + containerID) + // wait for container to be destroyed + // + for { + _, err := DockerClient.ContainerInspect(DockerContext, containerID) + if err != nil { + break + } else { + utils.Log("EditContainer - Waiting for container to be destroyed") + time.Sleep(1 * time.Second) + } + } + + utils.Log("EditContainer - Container stopped " + containerID) // recreate container with new informations createResponse, createError := DockerClient.ContainerCreate( @@ -110,24 +139,33 @@ func EditContainer(containerID string, newConfig types.ContainerJSON) (string, e newName, ) + // re-connect to networks + for networkName, _ := range oldContainer.NetworkSettings.Networks { + errNet := ConnectToNetworkSync(networkName, createResponse.ID) + if errNet != nil { + utils.Error("EditContainer - Failed to connect to network " + networkName, errNet) + } else { + utils.Debug("EditContainer - New Container connected to network " + networkName) + } + } + runError := DockerClient.ContainerStart(DockerContext, createResponse.ID, types.ContainerStartOptions{}) if runError != nil { return "", runError } - utils.Log("Container recreated " + createResponse.ID) + utils.Log("EditContainer - Container recreated " + createResponse.ID) if createError != nil { // attempt to restore container _, restoreError := DockerClient.ContainerCreate(DockerContext, oldContainer.Config, nil, nil, nil, oldContainer.Name) if restoreError != nil { - utils.Error("Failed to restore Docker Container after update failure", restoreError) + utils.Error("EditContainer - Failed to restore Docker Container after update failure", restoreError) } return "", createError } - return createResponse.ID, nil } @@ -174,6 +212,14 @@ func AddLabels(containerConfig types.ContainerJSON, labels map[string]string) er return nil } +func RemoveLabels(containerConfig types.ContainerJSON, labels []string) error { + for _, label := range labels { + delete(containerConfig.Config.Labels, label) + } + + return nil +} + func IsLabel(containerConfig types.ContainerJSON, label string) bool { if containerConfig.Config.Labels[label] == "true" { return true diff --git a/src/docker/events.go b/src/docker/events.go index 2235985..9d497b9 100644 --- a/src/docker/events.go +++ b/src/docker/events.go @@ -25,11 +25,25 @@ func DockerListenEvents() error { return } utils.Error("Docker Event Error", err) + // Check connection + errD := Connect() + if errD != nil { + utils.Fatal("Docker connection died, couldn't recover... Restarting", errD) + } + msgs, errs = DockerClient.Events(context.Background(), types.EventsOptions{}) + case msg := <-msgs: utils.Debug("Docker Event: " + msg.Type + " " + msg.Action + " " + msg.Actor.ID) if msg.Type == "container" && msg.Action == "start" { onDockerCreated(msg.Actor.ID) } + // on container destroy and network disconnect + if msg.Type == "container" && msg.Action == "destroy" { + onDockerDestroyed(msg.Actor.ID) + } + if msg.Type == "network" && msg.Action == "disconnect" { + onNetworkDisconnect(msg.Actor.ID) + } } } }() @@ -40,4 +54,14 @@ func DockerListenEvents() error { func onDockerCreated(containerID string) { utils.Debug("onDockerCreated: " + containerID) BootstrapContainerFromTags(containerID) +} + +func onDockerDestroyed(containerID string) { + utils.Debug("onDockerDestroyed: " + containerID) + NetworkCleanUp() +} + +func onNetworkDisconnect(networkID string) { + utils.Debug("onNetworkDisconnect: " + networkID) + NetworkCleanUp() } \ No newline at end of file diff --git a/src/docker/network.go b/src/docker/network.go index ed78d4b..2d71105 100644 --- a/src/docker/network.go +++ b/src/docker/network.go @@ -2,6 +2,8 @@ package docker import ( "os" + "time" + "errors" "github.com/azukaar/cosmos-server/src/utils" @@ -10,6 +12,9 @@ import ( natting "github.com/docker/go-connections/nat" ) +// use a semaphore lock +var DockerNetworkLock = make(chan bool, 1) + func CreateCosmosNetwork() (string, error) { // check if network exists already networks, err := DockerClient.NetworkList(DockerContext, types.NetworkListOptions{}) @@ -35,25 +40,27 @@ func CreateCosmosNetwork() (string, error) { utils.Log("Creating new secure network: " + newNeworkName) // create network - _, err = DockerClient.NetworkCreate(DockerContext, newNeworkName, types.NetworkCreate{ + newNetHan, err := DockerClient.NetworkCreate(DockerContext, newNeworkName, types.NetworkCreate{ Attachable: true, }) + utils.Debug("New network created: " + newNeworkName + " with id " + newNetHan.ID) + if err != nil { utils.Error("Docker Network Create", err) return "", err } //if running in Docker, connect to main network - utils.Debug("HOSTNAME: " + os.Getenv("HOSTNAME")) - if os.Getenv("HOSTNAME") != "" { - err := DockerClient.NetworkConnect(DockerContext, newNeworkName, os.Getenv("HOSTNAME"), &network.EndpointSettings{}) + // utils.Debug("HOSTNAME: " + os.Getenv("HOSTNAME")) + // if os.Getenv("HOSTNAME") != "" { + // err := DockerClient.NetworkConnect(DockerContext, newNeworkName, os.Getenv("HOSTNAME"), &network.EndpointSettings{}) - if err != nil { - utils.Error("Docker Network Connect", err) - return "", err - } - } + // if err != nil { + // utils.Error("Docker Network Connect", err) + // return "", err + // } + // } return newNeworkName, nil } @@ -65,41 +72,53 @@ func ConnectToSecureNetwork(containerConfig types.ContainerJSON) (bool, error) { return false, errD } + needsRestart := false + netName := "" + if(!HasLabel(containerConfig, "cosmos-network-name")) { newNetwork, errNC := CreateCosmosNetwork() if errNC != nil { - utils.Error("Docker Network Create", errNC) + utils.Error("DockerSecureNetworkCreate", errNC) return false, errNC } - utils.Log("Connected to new secure network for container: " + newNetwork) - + utils.Log("Added label to new secure network for container: " + newNetwork) + AddLabels(containerConfig, map[string]string{ "cosmos-network-name": newNetwork, }) - - return true, nil + + needsRestart = true + netName = newNetwork + } else { + netName = GetLabel(containerConfig, "cosmos-network-name") + + //if network doesn't exists + _, err := DockerClient.NetworkInspect(DockerContext, netName, types.NetworkInspectOptions{}) + if err != nil { + utils.Error("Container tries to connect to a non existing Cosmos network, resetting", err) + RemoveLabels(containerConfig, []string{"cosmos-network-name"}) + return ConnectToSecureNetwork(containerConfig) + } + + // else check if already connected + if(IsConnectedToNetwork(containerConfig, netName)) { + return false, nil + } } - netName := GetLabel(containerConfig, "cosmos-network-name") - - connected, err := IsConnectedToNetwork(containerConfig, netName) - if err != nil { - utils.Error("IsConnectedToNetwork", err) - return false, err - } - if(connected) { - return false, nil - } - - errCo := DockerClient.NetworkConnect(DockerContext, netName, containerConfig.ID, &network.EndpointSettings{}) + // at this point network is created and container is not connected to it + + errCo := ConnectToNetworkSync(netName, containerConfig.ID) + + utils.Log("Created and connected to secure network: " + netName) if errCo != nil { - utils.Error("Docker Network Connect", errCo) + utils.Error("ConnectToSecureNetworkConnect", errCo) return false, errCo } - return false, nil + return needsRestart, nil } func UnexposeAllPorts(container *types.ContainerJSON) error { @@ -120,22 +139,21 @@ func GetAllPorts(container types.ContainerJSON) []string { return ports } -func IsConnectedToNetwork(containerConfig types.ContainerJSON, networkName string) (bool, error) { +func IsConnectedToNetwork(containerConfig types.ContainerJSON, networkName string) bool { if(containerConfig.NetworkSettings == nil) { - utils.Error("IsConnectedToNetwork: NetworkSettings is nil", nil) - return false, nil + return false } for name, _ := range containerConfig.NetworkSettings.Networks { if name == networkName { - return true, nil + return true } } - return false, nil + return false } -func IsConnectedToASecureCosmosNetwork(containerConfig types.ContainerJSON) (bool, error) { +func IsConnectedToASecureCosmosNetwork(self types.ContainerJSON, containerConfig types.ContainerJSON) (bool, error) { if(containerConfig.NetworkSettings == nil) { utils.Error("IsConnectedToASecureCosmosNetwork: NetworkSettings is nil", nil) return false, nil @@ -148,12 +166,13 @@ func IsConnectedToASecureCosmosNetwork(containerConfig types.ContainerJSON) (boo for name, _ := range containerConfig.NetworkSettings.Networks { if name == GetLabel(containerConfig, "cosmos-network-name") { if os.Getenv("HOSTNAME") != "" { - // TODO: Check if connected to network first - DockerClient.NetworkConnect(DockerContext, name, os.Getenv("HOSTNAME"), &network.EndpointSettings{}) - // if err != nil { - // utils.Error("Docker Network Connect EXISTING ", err) - // return false, err - // } + if(!IsConnectedToNetwork(self, name)) { + err := DockerClient.NetworkConnect(DockerContext, name, os.Getenv("HOSTNAME"), &network.EndpointSettings{}) + if err != nil { + utils.Error("Docker Network Connect EXISTING ", err) + return false, err + } + } } return true, nil } @@ -161,3 +180,124 @@ func IsConnectedToASecureCosmosNetwork(containerConfig types.ContainerJSON) (boo return false, nil } + +func ConnectToNetworkIfNotConnected(containerConfig types.ContainerJSON, networkName string) error { + if(IsConnectedToNetwork(containerConfig, networkName)) { + return nil + } + return ConnectToNetworkSync(networkName, containerConfig.ID) +} + +func ConnectToNetworkSync(networkName string, containerID string) error { + err := DockerClient.NetworkConnect(DockerContext, networkName, containerID, &network.EndpointSettings{}) + if err != nil { + utils.Error("ConnectToNetworkSync", err) + return err + } + + // wait for connection to be established + retries := 10 + for { + newContainer, err := DockerClient.ContainerInspect(DockerContext, containerID) + if err != nil { + utils.Error("ConnectToNetworkSync", err) + return err + } + + if(IsConnectedToNetwork(newContainer, networkName)) { + break + } + + retries-- + if retries == 0 { + return errors.New("ConnectToNetworkSync: Timeout") + } + time.Sleep(500 * time.Millisecond) + } + + + utils.Log("Connected "+containerID+" to network: " + networkName) + + return nil +} + +func NetworkCleanUp() { + DockerNetworkLock <- true + defer func() { <-DockerNetworkLock }() + + config := utils.GetMainConfig() + + utils.Log("Cleaning up orphan networks...") + + // list every network + networks, err := DockerClient.NetworkList(DockerContext, types.NetworkListOptions{}) + if err != nil { + utils.Error("NetworkCleanUpList", err) + return + } + + + // check if network is empty or has only self as container + for _, networkHollow := range networks { + utils.Debug("Checking network: " + networkHollow.Name) + + if(networkHollow.Name == "bridge" || networkHollow.Name == "host" || networkHollow.Name == "none") { + continue + } + + // inspect network because the Docker API is a complete mess :) + network, err := DockerClient.NetworkInspect(DockerContext, networkHollow.ID, types.NetworkInspectOptions{}) + if err != nil { + utils.Error("NetworkCleanUpInspect", err) + continue + } + + if(len(network.Containers) > 1) { + continue + } + + utils.Debug("Ready to Check network: " + network.Name) + + if(config.DockerConfig.SkipPruneNetwork){ + utils.Debug("Skipping network prune") + } + + if(!config.DockerConfig.SkipPruneNetwork && len(network.Containers) == 0) { + utils.Log("Removing orphan network: " + network.Name) + err := DockerClient.NetworkRemove(DockerContext, network.ID) + if err != nil { + utils.Error("DockerNetworkCleanupRemove", err) + } + continue + } + + self := os.Getenv("HOSTNAME") + if self == "" { + utils.Warn("Skipping zombie network cleanup because not a docker cosmos container") + continue + } + + utils.Debug("Checking self name: " + self) + utils.Debug("Checking non-empty network: " + network.Name) + + containsCosmos := false + for _, container := range network.Containers { + utils.Debug("Checking name: " + container.Name) + if(container.Name == self) { + containsCosmos = true + } + } + + if(containsCosmos) { + utils.Log("Disconnecting and removing zombie network: " + network.Name) + err := DockerClient.NetworkDisconnect(DockerContext, network.ID, self, true) + if err != nil { + utils.Error("DockerNetworkCleanupDisconnect", err) + } + err = DockerClient.NetworkRemove(DockerContext, network.ID) + if err != nil { + utils.Error("DockerNetworkCleanupRemove", err) + } + } + } +} diff --git a/src/httpServer.go b/src/httpServer.go index 8a260b4..252b35a 100644 --- a/src/httpServer.go +++ b/src/httpServer.go @@ -10,7 +10,6 @@ import ( "github.com/gorilla/mux" "strconv" "time" - "encoding/json" "os" "strings" "github.com/go-chi/chi/middleware" @@ -36,13 +35,7 @@ func startHTTPServer(router *mux.Router) { func startHTTPSServer(router *mux.Router, tlsCert string, tlsKey string) { config := utils.GetMainConfig() - - - // check if Docker overwrite Hostname - serverHostname := "0.0.0.0" //utils.GetMainConfig().HTTPConfig.Hostname - // if os.Getenv("HOSTNAME") != "" { - // serverHostname = os.Getenv("HOSTNAME") - // } + serverHostname := "0.0.0.0" cfg := simplecert.Default @@ -147,9 +140,6 @@ func StartServer() { serverPortHTTP = config.HTTPPort serverPortHTTPS = config.HTTPSPort - configJson, _ := json.MarshalIndent(config, "", " ") - utils.Debug("Configuration" + (string)(configJson)) - var tlsCert = config.TLSCert var tlsKey= config.TLSKey diff --git a/src/utils/types.go b/src/utils/types.go index 50e2c5a..481c726 100644 --- a/src/utils/types.go +++ b/src/utils/types.go @@ -76,6 +76,7 @@ type Config struct { DisableUserManagement bool NewInstall bool `validate:"boolean"` HTTPConfig HTTPConfig `validate:"required,dive,required"` + DockerConfig DockerConfig } type HTTPConfig struct { @@ -92,6 +93,10 @@ type HTTPConfig struct { SSLEmail string `validate:"omitempty,email"` } +type DockerConfig struct { + SkipPruneNetwork bool +} + type ProxyConfig struct { Routes []ProxyRouteConfig }