diff --git a/docs/networking/network.md b/docs/networking/network.md index 899a97ded51..30f898de42d 100644 --- a/docs/networking/network.md +++ b/docs/networking/network.md @@ -173,6 +173,13 @@ dokku network:set node-js-app attach-post-deploy other-test-network dokku network:set node-js-app initial-network global-network ``` +Multiple networks can also be specified for the `attach-post-create` and `attach-post-deploy` phases. + +```shell +# one or more networks can be specified +dokku network:set node-js-app attach-post-create test-network test-network-2 +``` + Setting the `attach` network property to an empty value will de-associate the container with the network. ```shell diff --git a/plugins/common/common.go b/plugins/common/common.go index 53a7e27fd02..99b8f47773c 100644 --- a/plugins/common/common.go +++ b/plugins/common/common.go @@ -596,6 +596,15 @@ func (err *AppDoesNotExist) Error() string { return fmt.Sprintf("App %s does not exist", err.appName) } +// VarArgs skips a number of incoming arguments, returning what is left over +func VarArgs(arguments []string, skip int) []string { + if len(arguments) <= skip { + return []string{} + } + + return arguments[skip:] +} + // VerifyAppName checks if an app conforming to either the old or new // naming conventions exists func VerifyAppName(appName string) error { diff --git a/plugins/network/src/commands/commands.go b/plugins/network/src/commands/commands.go index 7160ceab9df..e916485c5b0 100644 --- a/plugins/network/src/commands/commands.go +++ b/plugins/network/src/commands/commands.go @@ -23,10 +23,10 @@ Additional commands:` network:exists , Checks if a docker network exists network:info , Outputs information about a docker network network:list, Lists all docker networks - network:report [] [], Displays a network report for one or more apps network:rebuild , Rebuilds network settings for an app network:rebuildall, Rebuild network settings for all apps - network:set (), Set or clear a network property for an app + network:report [] [], Displays a network report for one or more apps + network:set (...), Set or clear a network property for an app ` ) diff --git a/plugins/network/src/subcommands/subcommands.go b/plugins/network/src/subcommands/subcommands.go index d2b9cfb2c96..e81c49be161 100644 --- a/plugins/network/src/subcommands/subcommands.go +++ b/plugins/network/src/subcommands/subcommands.go @@ -67,12 +67,14 @@ func main() { appName := args.Arg(0) property := args.Arg(1) value := args.Arg(2) + values := common.VarArgs(args.Args(), 2) if *global { appName = "--global" property = args.Arg(0) value = args.Arg(1) + values = common.VarArgs(args.Args(), 1) } - err = network.CommandSet(appName, property, value) + err = network.CommandSet(appName, property, value, values) default: err = fmt.Errorf("Invalid plugin subcommand call: %s", subcommand) } diff --git a/plugins/network/subcommands.go b/plugins/network/subcommands.go index bf04f57844c..987caf13688 100644 --- a/plugins/network/subcommands.go +++ b/plugins/network/subcommands.go @@ -141,7 +141,7 @@ func CommandReport(appName string, format string, infoFlag string) error { } // CommandSet set or clear a network property for an app -func CommandSet(appName string, property string, value string) error { +func CommandSet(appName string, property string, value string, values []string) error { if appName != "--global" { if err := common.VerifyAppName(appName); err != nil { return err @@ -152,7 +152,7 @@ func CommandSet(appName string, property string, value string) error { value = "false" } - attachProperites := map[string]bool{ + attachProperties := map[string]bool{ "attach-post-create": true, "attach-post-deploy": true, } @@ -161,14 +161,17 @@ func CommandSet(appName string, property string, value string) error { "host": true, "bridge": true, } - if attachProperites[property] { - if invalidNetworks[value] { - return errors.New("Invalid network name specified for attach") - } + if attachProperties[property] { + for _, networkName := range values { + if invalidNetworks[networkName] { + return fmt.Errorf("Invalid network name specified for attach: %s", networkName) + } - if isConflictingPropertyValue(appName, property, value) { - return errors.New("Network name already associated with this app") + if isConflictingPropertyValue(appName, property, networkName) { + return fmt.Errorf("Network name already associated with this app: %s", networkName) + } } + value = strings.Join(values, ",") } common.CommandPropertySet("network", appName, property, value, DefaultProperties, GlobalProperties) diff --git a/plugins/network/triggers.go b/plugins/network/triggers.go index fbdc8d510a4..02673cdca0e 100644 --- a/plugins/network/triggers.go +++ b/plugins/network/triggers.go @@ -225,22 +225,26 @@ func TriggerPostContainerCreate(containerType string, containerID string, appNam } - networkName := reportComputedAttachPostCreate(appName) - if networkName == "" { + networks := reportComputedAttachPostCreate(appName) + if networks == "" { return nil } - exists, err := networkExists(networkName) - if err != nil { - return err - } + 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) + } - if !exists { - return fmt.Errorf("Network %v does not exist", networkName) + return attachAppToNetwork(containerID, networkName, appName, phase, processType) } - return attachAppToNetwork(containerID, networkName, appName, phase, processType) + return nil } // TriggerPostCreate sets bind-all-interfaces to false by default @@ -260,34 +264,37 @@ func TriggerPostDelete(appName string) error { // TriggerCorePostDeploy associates the container with a specified network func TriggerCorePostDeploy(appName string) error { - networkName := reportComputedAttachPostDeploy(appName) - if networkName == "" { + networks := reportComputedAttachPostDeploy(appName) + if networks == "" { return nil } - 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\"}}") + 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 } - if err := attachAppToNetwork(containerID, networkName, appName, "deploy", processType); err != nil { + + 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 } diff --git a/tests/unit/network.bats b/tests/unit/network.bats index 9a5abb6bd6e..dd9f846b752 100644 --- a/tests/unit/network.bats +++ b/tests/unit/network.bats @@ -156,11 +156,21 @@ teardown() { echo "status: $status" assert_success + run /bin/bash -c "dokku network:create create-network-2" + echo "output: $output" + echo "status: $status" + assert_success + run /bin/bash -c "dokku network:create deploy-network" echo "output: $output" echo "status: $status" assert_success + run /bin/bash -c "dokku network:create deploy-network-2" + echo "output: $output" + echo "status: $status" + assert_success + run /bin/bash -c "dokku network:create initial-network" echo "output: $output" echo "status: $status" @@ -208,6 +218,22 @@ teardown() { assert_success assert_http_success "${TEST_APP}.dokku.me" + run /bin/bash -c "dokku network:set $TEST_APP attach-post-create create-network create-network-2" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku network:set $TEST_APP attach-post-deploy deploy-network deploy-network-2" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku ps:rebuild $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + assert_http_success "${TEST_APP}.dokku.me" + run /bin/bash -c "dokku --force network:destroy create-network" echo "output: $output" echo "status: $status"