2017-04-24 09:03:30 -06:00
|
|
|
package network
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
2021-08-06 01:29:25 -04:00
|
|
|
"net"
|
2018-04-07 04:49:21 -04:00
|
|
|
"os"
|
2017-10-04 00:48:02 -04:00
|
|
|
"path/filepath"
|
2017-04-24 09:03:30 -06:00
|
|
|
"strconv"
|
|
|
|
|
"strings"
|
|
|
|
|
|
2017-10-02 16:50:05 -07:00
|
|
|
"github.com/dokku/dokku/plugins/common"
|
2017-04-24 09:03:30 -06:00
|
|
|
)
|
|
|
|
|
|
2017-10-02 16:50:05 -07:00
|
|
|
var (
|
|
|
|
|
// DefaultProperties is a map of all valid network properties with corresponding default property values
|
|
|
|
|
DefaultProperties = map[string]string{
|
2020-02-03 04:37:31 -05:00
|
|
|
"attach-post-create": "",
|
|
|
|
|
"attach-post-deploy": "",
|
2021-08-06 01:29:25 -04:00
|
|
|
"bind-all-interfaces": "",
|
2021-03-22 01:05:35 -04:00
|
|
|
"initial-network": "",
|
2021-08-06 01:29:25 -04:00
|
|
|
"static-web-listener": "",
|
2020-02-03 04:37:31 -05:00
|
|
|
"tld": "",
|
2017-10-02 16:50:05 -07:00
|
|
|
}
|
2021-01-04 00:50:14 -05:00
|
|
|
|
|
|
|
|
// GlobalProperties is a map of all valid global network properties
|
2021-03-22 01:05:35 -04:00
|
|
|
GlobalProperties = map[string]bool{
|
2021-03-22 17:13:54 -04:00
|
|
|
"attach-post-create": true,
|
|
|
|
|
"attach-post-deploy": true,
|
2021-08-06 01:29:25 -04:00
|
|
|
"bind-all-interfaces": true,
|
2021-03-22 17:13:54 -04:00
|
|
|
"initial-network": true,
|
|
|
|
|
"tld": true,
|
2021-03-22 01:05:35 -04:00
|
|
|
}
|
2017-10-02 16:50:05 -07:00
|
|
|
)
|
2017-09-03 20:36:09 -04:00
|
|
|
|
2017-09-03 17:31:14 -04:00
|
|
|
// BuildConfig builds network config files
|
2020-05-28 20:30:27 -04:00
|
|
|
func BuildConfig(appName string) error {
|
2017-09-03 17:31:14 -04:00
|
|
|
if !common.IsDeployed(appName) {
|
2020-05-28 20:30:27 -04:00
|
|
|
return nil
|
2017-09-03 17:31:14 -04:00
|
|
|
}
|
2020-05-28 20:30:27 -04:00
|
|
|
|
2021-08-06 01:29:25 -04:00
|
|
|
if staticWebListener := reportStaticWebListener(appName); staticWebListener != "" {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-10 14:12:05 -04:00
|
|
|
appRoot := common.AppRoot(appName)
|
2024-03-14 01:18:28 -04:00
|
|
|
results, err := common.CallPlugnTrigger(common.PlugnTriggerInput{
|
|
|
|
|
Trigger: "ps-current-scale",
|
|
|
|
|
Args: []string{appName},
|
|
|
|
|
})
|
2021-08-01 01:43:35 -04:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
2017-09-03 17:31:14 -04:00
|
|
|
}
|
|
|
|
|
|
2024-03-14 01:18:28 -04:00
|
|
|
scale, err := common.ParseScaleOutput(results.StdoutBytes())
|
2017-09-03 17:31:14 -04:00
|
|
|
if err != nil {
|
2020-05-28 20:30:27 -04:00
|
|
|
return err
|
2017-09-03 17:31:14 -04:00
|
|
|
}
|
2020-05-28 20:30:27 -04:00
|
|
|
|
2021-08-01 01:43:35 -04:00
|
|
|
if len(scale) == 0 {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2017-09-03 17:31:14 -04:00
|
|
|
|
2022-11-27 19:51:12 -05:00
|
|
|
if common.GetAppScheduler(appName) != "docker-local" {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-01 01:43:35 -04:00
|
|
|
common.LogInfo1(fmt.Sprintf("Ensuring network configuration is in sync for %s", appName))
|
2017-09-03 17:31:14 -04:00
|
|
|
|
2021-08-01 01:43:35 -04:00
|
|
|
for processType, procCount := range scale {
|
2024-01-18 19:23:57 -05:00
|
|
|
containerIndex := int32(0)
|
2017-09-03 17:31:14 -04:00
|
|
|
for containerIndex < procCount {
|
|
|
|
|
containerIndex++
|
2024-01-18 19:23:57 -05:00
|
|
|
containerIndexString := strconv.FormatInt(int64(containerIndex), 10)
|
2019-04-08 16:36:30 -04:00
|
|
|
containerIDFile := fmt.Sprintf("%v/CONTAINER.%v.%v", appRoot, processType, containerIndex)
|
2017-09-03 17:31:14 -04:00
|
|
|
|
|
|
|
|
containerID := common.ReadFirstLine(containerIDFile)
|
|
|
|
|
if containerID == "" || !common.ContainerIsRunning(containerID) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-08 16:36:30 -04:00
|
|
|
ipAddress := GetContainerIpaddress(appName, processType, containerID)
|
2017-09-03 17:31:14 -04:00
|
|
|
if ipAddress != "" {
|
2020-02-22 04:30:40 -05:00
|
|
|
args := []string{appName, processType, containerIndexString, ipAddress}
|
2024-03-14 01:18:28 -04:00
|
|
|
_, err := common.CallPlugnTrigger(common.PlugnTriggerInput{
|
|
|
|
|
Trigger: "network-write-ipaddr",
|
|
|
|
|
Args: args,
|
|
|
|
|
})
|
2017-09-03 17:31:14 -04:00
|
|
|
if err != nil {
|
|
|
|
|
common.LogWarn(err.Error())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-28 20:30:27 -04:00
|
|
|
|
|
|
|
|
return nil
|
2017-09-03 17:31:14 -04:00
|
|
|
}
|
|
|
|
|
|
2017-07-22 15:26:23 -06:00
|
|
|
// GetContainerIpaddress returns the ipaddr for a given app container
|
2019-04-08 16:36:30 -04:00
|
|
|
func GetContainerIpaddress(appName, processType, containerID string) (ipAddr string) {
|
2021-08-06 01:29:25 -04:00
|
|
|
if processType == "web" {
|
|
|
|
|
if staticWebListener := reportStaticWebListener(appName); staticWebListener != "" {
|
|
|
|
|
ip, _, err := net.SplitHostPort(staticWebListener)
|
|
|
|
|
if err == nil {
|
|
|
|
|
return ip
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ip2 := net.ParseIP(staticWebListener)
|
|
|
|
|
if ip2 != nil {
|
|
|
|
|
return ip2.String()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return "127.0.0.1"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-18 17:59:49 -04:00
|
|
|
if b, err := common.DockerInspect(containerID, "{{ .HostConfig.NetworkMode }}"); err == nil {
|
2020-01-15 14:15:50 -05:00
|
|
|
if string(b[:]) == "host" {
|
|
|
|
|
return "127.0.0.1"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-09 21:13:57 -04:00
|
|
|
initialNetwork := reportComputedInitialNetwork(appName)
|
|
|
|
|
if initialNetwork == "" {
|
|
|
|
|
initialNetwork = "bridge"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
b, err := common.DockerInspect(containerID, fmt.Sprintf("{{ $network := index .NetworkSettings.Networks \"%s\" }}{{ $network.IPAddress}}", initialNetwork))
|
2017-04-24 09:03:30 -06:00
|
|
|
if err != nil || len(b) == 0 {
|
2021-07-09 21:14:06 -04:00
|
|
|
// Deprecated: docker < 1.9 compatibility
|
2020-03-18 17:59:49 -04:00
|
|
|
b, err = common.DockerInspect(containerID, "{{ .NetworkSettings.IPAddress }}")
|
2017-04-24 09:03:30 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
return string(b[:])
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-02 16:50:05 -07:00
|
|
|
return
|
2017-04-24 09:03:30 -06:00
|
|
|
}
|
|
|
|
|
|
2017-10-04 00:48:02 -04:00
|
|
|
// GetListeners returns a string array of app listeners
|
2020-03-11 12:34:29 -04:00
|
|
|
func GetListeners(appName string, processType string) []string {
|
2021-08-06 01:29:25 -04:00
|
|
|
if processType == "web" {
|
|
|
|
|
if staticWebListener := reportStaticWebListener(appName); staticWebListener != "" {
|
|
|
|
|
return []string{staticWebListener}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-10 14:12:05 -04:00
|
|
|
appRoot := common.AppRoot(appName)
|
2017-10-04 00:48:02 -04:00
|
|
|
|
2020-03-11 12:34:29 -04:00
|
|
|
ipPrefix := fmt.Sprintf("/IP.%s.", processType)
|
|
|
|
|
portPrefix := fmt.Sprintf("/PORT.%s.", processType)
|
|
|
|
|
|
|
|
|
|
files, _ := filepath.Glob(appRoot + ipPrefix + "*")
|
2017-10-04 00:48:02 -04:00
|
|
|
|
|
|
|
|
var listeners []string
|
|
|
|
|
for _, ipfile := range files {
|
2020-03-11 12:34:29 -04:00
|
|
|
portfile := strings.Replace(ipfile, ipPrefix, portPrefix, 1)
|
2017-10-04 00:48:02 -04:00
|
|
|
ipAddress := common.ReadFirstLine(ipfile)
|
|
|
|
|
port := common.ReadFirstLine(portfile)
|
2023-07-11 21:06:40 -04:00
|
|
|
if port == "" {
|
|
|
|
|
port = "5000"
|
|
|
|
|
}
|
2017-10-04 00:48:02 -04:00
|
|
|
listeners = append(listeners, fmt.Sprintf("%s:%s", ipAddress, port))
|
|
|
|
|
}
|
|
|
|
|
return listeners
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-03 03:07:24 -04:00
|
|
|
// HasNetworkConfig returns whether the network configuration for a given app exists
|
|
|
|
|
func HasNetworkConfig(appName string) bool {
|
2020-03-10 14:12:05 -04:00
|
|
|
appRoot := common.AppRoot(appName)
|
2017-09-03 03:07:24 -04:00
|
|
|
ipfile := fmt.Sprintf("%v/IP.web.1", appRoot)
|
|
|
|
|
portfile := fmt.Sprintf("%v/PORT.web.1", appRoot)
|
|
|
|
|
|
2022-11-28 01:34:02 -05:00
|
|
|
if common.FileExists(ipfile) && common.FileExists(portfile) {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return reportStaticWebListener(appName) != ""
|
2017-09-03 03:07:24 -04:00
|
|
|
}
|
2018-04-07 04:49:21 -04:00
|
|
|
|
2020-02-17 19:08:39 -05:00
|
|
|
// ClearNetworkConfig removes old IP and PORT files for a newly cloned app
|
|
|
|
|
func ClearNetworkConfig(appName string) bool {
|
2020-03-10 14:12:05 -04:00
|
|
|
appRoot := common.AppRoot(appName)
|
2018-12-27 05:01:45 -05:00
|
|
|
success := true
|
|
|
|
|
|
|
|
|
|
ipFiles, _ := filepath.Glob(appRoot + "/IP.*")
|
|
|
|
|
for _, file := range ipFiles {
|
|
|
|
|
if err := os.Remove(file); err != nil {
|
|
|
|
|
common.LogWarn(fmt.Sprintf("Unable to remove file %s", file))
|
|
|
|
|
success = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
portFiles, _ := filepath.Glob(appRoot + "/PORT.*")
|
|
|
|
|
for _, file := range portFiles {
|
|
|
|
|
if err := os.Remove(file); err != nil {
|
|
|
|
|
common.LogWarn(fmt.Sprintf("Unable to remove file %s", file))
|
|
|
|
|
success = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return success
|
|
|
|
|
}
|