diff --git a/command/v7/map_route_command.go b/command/v7/map_route_command.go index 5036a2caaa..d4e3d62889 100644 --- a/command/v7/map_route_command.go +++ b/command/v7/map_route_command.go @@ -2,10 +2,10 @@ package v7 import ( "code.cloudfoundry.org/cli/v9/actor/actionerror" - "code.cloudfoundry.org/cli/v9/api/cloudcontroller/ccversion" - "code.cloudfoundry.org/cli/v9/command" + "code.cloudfoundry.org/cli/v9/api/cloudcontroller/ccversion" + "code.cloudfoundry.org/cli/v9/command" "code.cloudfoundry.org/cli/v9/command/flag" - "code.cloudfoundry.org/cli/v9/resources" + "code.cloudfoundry.org/cli/v9/resources" ) type MapRouteCommand struct { @@ -34,10 +34,11 @@ func (cmd MapRouteCommand) Examples() string { return ` CF_NAME map-route my-app example.com # example.com CF_NAME map-route my-app example.com --hostname myhost # myhost.example.com -CF_NAME map-route my-app example.com --hostname myhost -o loadbalancing=least-connection # myhost.example.com with a per-route option CF_NAME map-route my-app example.com --hostname myhost --path foo # myhost.example.com/foo CF_NAME map-route my-app example.com --hostname myhost --app-protocol http2 # myhost.example.com CF_NAME map-route my-app example.com --hostname myhost --app-port 8090 # myhost.example.com +CF_NAME map-route my-app example.com --hostname myhost -o loadbalancing=least-connection # myhost.example.com with a per-route option +CF_NAME map-route my-app example.com -o loadbalancing=hash -o hash_header=My-Hash-Header # use hash-based routing for example.com CF_NAME map-route my-app example.com --port 5000 # example.com:5000` } diff --git a/command/v7/update_route_command.go b/command/v7/update_route_command.go index 210627b567..af20a2322c 100644 --- a/command/v7/update_route_command.go +++ b/command/v7/update_route_command.go @@ -29,10 +29,13 @@ Update an existing HTTP route: func (cmd UpdateRouteCommand) Examples() string { return ` -CF_NAME update-route example.com -o loadbalancing=round-robin, -CF_NAME update-route example.com -o loadbalancing=least-connection, -CF_NAME update-route example.com -r loadbalancing, -CF_NAME update-route example.com --hostname myhost --path foo -o loadbalancing=round-robin` +CF_NAME update-route example.com -o loadbalancing=round-robin # use round-robin load balancing for route +CF_NAME update-route example.com -o loadbalancing=least-connection # use least-connection load balancing for route +CF_NAME update-route example.com -o loadbalancing=hash -o hash_header=My-Hash-Header # use hash-based load balancing for route +CF_NAME update-route example.com -o loadbalancing=hash -o hash_header=My-Hash-Header -o hash_balance=1.3 # use hash-based load balancing with balance factor +CF_NAME update-route example.com -r loadbalancing # remove load balancing option +CF_NAME update-route example.com --hostname myhost --path foo -o loadbalancing=round-robin # update route myhost.example.com/foo +` } func (cmd UpdateRouteCommand) Execute(args []string) error { err := cmd.SharedActor.CheckTarget(true, true) diff --git a/integration/v7/isolated/map_route_command_test.go b/integration/v7/isolated/map_route_command_test.go index b58bd4b5ab..f2354adcfc 100644 --- a/integration/v7/isolated/map_route_command_test.go +++ b/integration/v7/isolated/map_route_command_test.go @@ -37,10 +37,11 @@ var _ = Describe("map-route command", func() { Eventually(session).Should(Say(`EXAMPLES:`)) Eventually(session).Should(Say(`cf map-route my-app example.com # example.com`)) Eventually(session).Should(Say(`cf map-route my-app example.com --hostname myhost # myhost.example.com`)) - Eventually(session).Should(Say(`cf map-route my-app example.com --hostname myhost -o loadbalancing=least-connection # myhost.example.com with a per-route option`)) Eventually(session).Should(Say(`cf map-route my-app example.com --hostname myhost --path foo # myhost.example.com/foo`)) Eventually(session).Should(Say(`cf map-route my-app example.com --hostname myhost --app-protocol http2 # myhost.example.com`)) Eventually(session).Should(Say(`cf map-route my-app example.com --hostname myhost --app-port 8090 # myhost.example.com`)) + Eventually(session).Should(Say(`cf map-route my-app example.com --hostname myhost -o loadbalancing=least-connection # myhost.example.com with a per-route option`)) + Eventually(session).Should(Say(`cf map-route my-app example.com -o loadbalancing=hash -o hash_header=My-Hash-Header # use hash-based routing for example.com`)) Eventually(session).Should(Say(`cf map-route my-app example.com --port 5000 # example.com:5000`)) Eventually(session).Should(Say(`\n`)) @@ -241,6 +242,27 @@ var _ = Describe("map-route command", func() { Eventually(session).Should(Exit(0)) }) }) + Context("when per-route options are provided", func() { + BeforeEach(func() { + helpers.EnableFeatureFlag("hash_based_routing") + }) + AfterEach(func() { + helpers.DisableFeatureFlag("hash_based_routing") + }) + It("creates the route and maps it to an app", func() { + optionLBAlgo := "loadbalancing=hash" + optionHashHeader := "hash_header=X-Header" + optionHashBalance := "hash_balance=1.3" + + session := helpers.CF("map-route", appName, domainName, "--hostname", hostName, "--path", path, "--option", optionLBAlgo, "--option", optionHashHeader, "--option", optionHashBalance) + Eventually(session).Should(Say(`Creating route %s.%s%s for org %s / space %s as %s\.\.\.`, hostName, domainName, path, orgName, spaceName, userName)) + Eventually(session).Should(Say(`OK`)) + Eventually(session).Should(Say(`Mapping route %s.%s%s to app %s in org %s / space %s as %s\.\.\.`, hostName, domainName, path, appName, orgName, spaceName, userName)) + Eventually(session).Should(Say(`OK`)) + Eventually(session).Should(Exit(0)) + }) + }) + }) When("it is an TCP domain", func() { diff --git a/integration/v7/isolated/update_route_command_test.go b/integration/v7/isolated/update_route_command_test.go index 1a1617f010..13d0167753 100644 --- a/integration/v7/isolated/update_route_command_test.go +++ b/integration/v7/isolated/update_route_command_test.go @@ -31,6 +31,8 @@ var _ = Describe("update-route command", func() { Eventually(session).Should(Say(`EXAMPLES:`)) Eventually(session).Should(Say(`cf update-route example.com -o loadbalancing=round-robin`)) Eventually(session).Should(Say(`cf update-route example.com -o loadbalancing=least-connection`)) + Eventually(session).Should(Say(`cf update-route example.com -o loadbalancing=hash -o hash_header=My-Hash-Header`)) + Eventually(session).Should(Say(`cf update-route example.com -o loadbalancing=hash -o hash_header=My-Hash-Header -o hash_balance=1.3`)) Eventually(session).Should(Say(`cf update-route example.com -r loadbalancing`)) Eventually(session).Should(Say(`cf update-route example.com --hostname myhost --path foo -o loadbalancing=round-robin`)) Eventually(session).Should(Say(`\n`)) @@ -102,7 +104,7 @@ var _ = Describe("update-route command", func() { AfterEach(func() { domain.Delete() }) - When("a route option is specified", func() { + When("a loadbalancing route option is specified", func() { It("updates the route and runs to completion without failing", func() { option = "loadbalancing=round-robin" session := helpers.CF("update-route", domainName, "--hostname", hostname, "--path", path, "--option", option) @@ -113,6 +115,45 @@ var _ = Describe("update-route command", func() { }) }) + When("a hash-based routing is enabled and options are specified", func() { + BeforeEach(func() { + helpers.EnableFeatureFlag("hash_based_routing") + }) + AfterEach(func() { + helpers.DisableFeatureFlag("hash_based_routing") + }) + + It("updates the route and runs to completion without failing", func() { + optionLBAlgo := "loadbalancing=hash" + optionHashHeader := "hash_header=X-Header" + optionHashBalance := "hash_balance=1.3" + session := helpers.CF("update-route", domainName, "--hostname", hostname, "--path", path, "--option", optionLBAlgo, "--option", optionHashHeader, "--option", optionHashBalance) + Eventually(session).Should(Say(`Updating route %s\.%s%s for org %s / space %s as %s\.\.\.`, hostname, domainName, path, orgName, spaceName, userName)) + Eventually(session).Should(Say(`Route %s\.%s%s has been updated`, hostname, domainName, path)) + Eventually(session).Should(Say(`OK`)) + Eventually(session).Should(Exit(0)) + }) + Context("missing required options for hash-based routing", func() { + It("update fails", func() { + optionLBAlgo := "loadbalancing=hash" + session := helpers.CF("update-route", domainName, "--hostname", hostname, "--path", path, "--option", optionLBAlgo) + Eventually(session.Err).Should(Say(`Hash header must be present when loadbalancing is set to hash`)) + Eventually(session).Should(Exit(1)) + }) + }) + Context("with wrong loadbalancing option", func() { + It("update fails", func() { + optionLBAlgo := "loadbalancing=round-robin" + optionHashHeader := "hash_header=X-Header" + optionHashBalance := "hash_balance=1.3" + session := helpers.CF("update-route", domainName, "--hostname", hostname, "--path", path, "--option", optionLBAlgo, "--option", optionHashHeader, "--option", optionHashBalance) + Eventually(session.Err).Should(Say(`Options Hash header can only be set when loadbalancing is hash`)) + Eventually(session.Err).Should(Say(`Options Hash balance can only be set when loadbalancing is hash`)) + Eventually(session).Should(Exit(1)) + }) + }) + }) + When("route options are not specified", func() { It("gives an error message and fails", func() { session := helpers.CF("update-route", domainName, "--hostname", hostname, "--path", path)