Files
dokku/plugins/network/triggers.go
Jose Diaz-Gonzalez f8ccf52079 refactor: only use detected port mapping if override is not specified
Previously, we would always set the port mapping during a dockerfile build, making it difficult for users to override mappings. We also only _sometimes_ updated the detected port mapping, further confusing issues when users were migrating from Dockerfile to Buildpacks for builds.

Now, we always detect the port mapping during the build process, and only use that detected port mapping if an override is not specified. This greatly simplifies the experience around port mapping, as now a user can create an app, set a port mapping, and that first deploy will respect the port mapping without an additional deploy.

The builder always has the best context for what the app should be listening on, and thus we can always specify a "default" port mapping at this stage. Users can override this map as desired later.

This change also results in the removal of a ton of internal code that is now centralized in the ports plugin.

Closes #4067
2023-08-05 10:58:57 -04:00

265 lines
7.0 KiB
Go

package network
import (
"fmt"
"io/ioutil"
"os"
"strings"
"github.com/dokku/dokku/plugins/common"
)
// TriggerDockerArgsProcess outputs the network plugin docker options for an app
func TriggerDockerArgsProcess(appName string) error {
stdin, err := ioutil.ReadAll(os.Stdin)
if err != nil {
return err
}
initialNetwork := reportComputedInitialNetwork(appName)
if initialNetwork != "" {
fmt.Printf(" --network=%s ", initialNetwork)
}
fmt.Print(string(stdin))
return nil
}
// TriggerInstall runs the install step for the network plugin
func TriggerInstall() error {
if err := common.PropertySetup("network"); err != nil {
return fmt.Errorf("Unable to install the network plugin: %s", err.Error())
}
apps, err := common.UnfilteredDokkuApps()
if err != nil {
return nil
}
for _, appName := range apps {
if common.PropertyExists("network", appName, "bind-all-interfaces") {
continue
}
if err := common.PlugnTrigger("proxy-is-enabled", []string{appName}...); err != nil {
common.LogVerboseQuiet("Setting network property 'bind-all-interfaces' to false")
if err := common.PropertyWrite("network", appName, "bind-all-interfaces", "false"); err != nil {
common.LogWarn(err.Error())
}
} else {
common.LogVerboseQuiet("Setting network property 'bind-all-interfaces' to true")
if err := common.PropertyWrite("network", appName, "bind-all-interfaces", "true"); err != nil {
common.LogWarn(err.Error())
}
}
}
return nil
}
// TriggerNetworkConfigExists writes true or false to stdout whether a given app has network config
func TriggerNetworkConfigExists(appName string) error {
if HasNetworkConfig(appName) {
fmt.Println("true")
return nil
}
fmt.Println("false")
return nil
}
// TriggerNetworkGetIppaddr writes the ipaddress to stdout for a given app container
func TriggerNetworkGetIppaddr(appName string, processType string, containerID string) error {
ipAddress := GetContainerIpaddress(appName, processType, containerID)
fmt.Println(ipAddress)
return nil
}
// TriggerNetworkGetListeners returns the listeners (host:port combinations) for a given app container
func TriggerNetworkGetListeners(appName string, processType string) error {
if processType == "" {
common.LogWarn("Deprecated: Please specify a processType argument for the network-get-listeners plugin trigger")
processType = "web"
}
listeners := GetListeners(appName, processType)
fmt.Println(strings.Join(listeners, " "))
return nil
}
// TriggerNetworkGetProperty writes the network property to stdout for a given app container
func TriggerNetworkGetProperty(appName string, property string) error {
computedValueMap := map[string]common.ReportFunc{
"attach-post-create": reportComputedAttachPostCreate,
"attach-post-deploy": reportComputedAttachPostDeploy,
"bind-all-interfaces": reportComputedBindAllInterfaces,
"initial-network": reportComputedInitialNetwork,
"tld": reportComputedTld,
}
fn, ok := computedValueMap[property]
if !ok {
return fmt.Errorf("Invalid network property specified: %v", property)
}
fmt.Println(fn(appName))
return nil
}
// TriggerNetworkGetStaticListeners fetches the static listener for the specified app/processType combination
func TriggerNetworkGetStaticListeners(appName string, processType string) error {
staticWebListener := reportStaticWebListener(appName)
fmt.Println(staticWebListener)
return nil
}
// TriggerNetworkWriteIpaddr writes the ip to disk
func TriggerNetworkWriteIpaddr(appName string, processType string, containerIndex string, ip string) error {
appRoot := common.AppRoot(appName)
filename := fmt.Sprintf("%v/IP.%v.%v", appRoot, processType, containerIndex)
f, err := os.Create(filename)
if err != nil {
return err
}
defer f.Close()
ipBytes := []byte(ip)
_, err = f.Write(ipBytes)
if err != nil {
return err
}
return nil
}
// TriggerNetworkWritePort writes the port to disk
func TriggerNetworkWritePort(appName string, processType string, containerIndex string, port string) error {
appRoot := common.AppRoot(appName)
filename := fmt.Sprintf("%v/PORT.%v.%v", appRoot, processType, containerIndex)
f, err := os.Create(filename)
if err != nil {
return err
}
defer f.Close()
portBytes := []byte(port)
_, err = f.Write(portBytes)
if err != nil {
return err
}
return nil
}
// TriggerPostAppCloneSetup creates new network files
func TriggerPostAppCloneSetup(oldAppName string, newAppName string) error {
success := ClearNetworkConfig(newAppName)
if !success {
os.Exit(1)
}
err := common.PropertyClone("network", oldAppName, newAppName)
if err != nil {
return err
}
return nil
}
// TriggerPostAppRenameSetup renames network files
func TriggerPostAppRenameSetup(oldAppName string, newAppName string) error {
success := ClearNetworkConfig(newAppName)
if !success {
os.Exit(1)
}
if err := common.PropertyClone("network", oldAppName, newAppName); err != nil {
return err
}
if err := common.PropertyDestroy("network", oldAppName); err != nil {
return err
}
return nil
}
// TriggerPostContainerCreate associates the container with a specified network
func TriggerPostContainerCreate(containerType string, containerID string, appName string, phase string, processType string) error {
if containerType != "app" {
return nil
}
networks := reportComputedAttachPostCreate(appName)
if networks == "" {
return nil
}
for _, networkName := range strings.Split(networks, ",") {
exists, err := networkExists(networkName)
if err != nil {
return err
}
if !exists {
return fmt.Errorf("Network %v does not exist", networkName)
}
return attachAppToNetwork(containerID, networkName, appName, phase, processType)
}
return nil
}
// TriggerPostCreate sets bind-all-interfaces to false by default
func TriggerPostCreate(appName string) error {
err := common.PropertyWrite("network", appName, "bind-all-interfaces", "false")
if err != nil {
common.LogWarn(err.Error())
}
return nil
}
// TriggerPostDelete destroys the network property for a given app container
func TriggerPostDelete(appName string) error {
return common.PropertyDestroy("network", appName)
}
// TriggerCorePostDeploy associates the container with a specified network
func TriggerCorePostDeploy(appName string) error {
networks := reportComputedAttachPostDeploy(appName)
if networks == "" {
return nil
}
for _, networkName := range strings.Split(networks, ",") {
common.LogInfo1Quiet(fmt.Sprintf("Associating app with network %s", networkName))
containerIDs, err := common.GetAppRunningContainerIDs(appName, "")
if err != nil {
return err
}
exists, err := networkExists(networkName)
if err != nil {
return err
}
if !exists {
return fmt.Errorf("Network %v does not exist", networkName)
}
for _, containerID := range containerIDs {
processType, err := common.DockerInspect(containerID, "{{ index .Config.Labels \"com.dokku.process-type\"}}")
if err != nil {
return err
}
if err := attachAppToNetwork(containerID, networkName, appName, "deploy", processType); err != nil {
return err
}
}
}
return nil
}