Skip to content

Commit

Permalink
push now accepts log rate limit flag
Browse files Browse the repository at this point in the history
Signed-off-by: Carson Long <lcarson@vmware.com>
Signed-off-by: Rebecca Roberts <robertsre@vmware.com>
  • Loading branch information
rroberts2222 committed Aug 2, 2022
1 parent 950baff commit f1f0c78
Show file tree
Hide file tree
Showing 14 changed files with 264 additions and 6 deletions.
1 change: 1 addition & 0 deletions actor/v7pushaction/actor.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ func NewActor(v3Actor V7Actor, sharedActor SharedActor) *Actor {
HandleHealthCheckTimeoutOverride,
HandleMemoryOverride,
HandleDiskOverride,
HandleLogRateLimitOverride,
HandleNoRouteOverride,
HandleRandomRouteOverride,
HandleTaskOverride,
Expand Down
24 changes: 24 additions & 0 deletions actor/v7pushaction/handle_log_rate_limit_override.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package v7pushaction

import (
"code.cloudfoundry.org/cli/command/translatableerror"
"code.cloudfoundry.org/cli/util/manifestparser"
)

func HandleLogRateLimitOverride(manifest manifestparser.Manifest, overrides FlagOverrides) (manifestparser.Manifest, error) {
if overrides.LogRateLimit != "" {
if manifest.ContainsMultipleApps() {
return manifest, translatableerror.CommandLineArgsWithMultipleAppsError{}
}

webProcess := manifest.GetFirstAppWebProcess()
if webProcess != nil {
webProcess.LogRateLimit = overrides.LogRateLimit
} else {
app := manifest.GetFirstApp()
app.LogRateLimit = overrides.LogRateLimit
}
}

return manifest, nil
}
149 changes: 149 additions & 0 deletions actor/v7pushaction/handle_log_rate_limit_override_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package v7pushaction_test

import (
"code.cloudfoundry.org/cli/command/translatableerror"
"code.cloudfoundry.org/cli/util/manifestparser"

. "code.cloudfoundry.org/cli/actor/v7pushaction"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

var _ = Describe("HandleLogRateLimitOverride", func() {
var (
originalManifest manifestparser.Manifest
transformedManifest manifestparser.Manifest
overrides FlagOverrides
executeErr error
)

BeforeEach(func() {
originalManifest = manifestparser.Manifest{}
overrides = FlagOverrides{}
})

JustBeforeEach(func() {
transformedManifest, executeErr = HandleLogRateLimitOverride(originalManifest, overrides)
})

When("log rate limit is not set on a flag override", func() {
BeforeEach(func() {
originalManifest.Applications = []manifestparser.Application{
{
Processes: []manifestparser.Process{
{Type: "web"},
{Type: "worker", LogRateLimit: "1B"},
},
},
}
})

It("does not change the manifest", func() {
Expect(executeErr).ToNot(HaveOccurred())
Expect(transformedManifest.Applications).To(ConsistOf(
manifestparser.Application{
Processes: []manifestparser.Process{
{Type: "web"},
{Type: "worker", LogRateLimit: "1B"},
},
},
))
})
})

When("manifest web process does not specify log rate limit", func() {
BeforeEach(func() {
overrides.LogRateLimit = "64K"

originalManifest.Applications = []manifestparser.Application{
{
Processes: []manifestparser.Process{
{Type: "web"},
},
},
}
})

It("changes the log rate limit of the web process in the manifest", func() {
Expect(executeErr).ToNot(HaveOccurred())
Expect(transformedManifest.Applications).To(ConsistOf(
manifestparser.Application{
Processes: []manifestparser.Process{
{Type: "web", LogRateLimit: "64K"},
},
},
))
})
})

When("manifest app has only non-web processes", func() {
BeforeEach(func() {
overrides.LogRateLimit = "32B"

originalManifest.Applications = []manifestparser.Application{
{
Processes: []manifestparser.Process{
{Type: "worker"},
},
},
}
})

It("changes the log rate limit of the app in the manifest", func() {
Expect(executeErr).ToNot(HaveOccurred())
Expect(transformedManifest.Applications).To(ConsistOf(
manifestparser.Application{
LogRateLimit: "32B",
Processes: []manifestparser.Process{
{Type: "worker"},
},
},
))
})
})

When("manifest app has web and non-web processes", func() {
BeforeEach(func() {
overrides.LogRateLimit = "4MB"

originalManifest.Applications = []manifestparser.Application{
{
Processes: []manifestparser.Process{
{Type: "worker"},
{Type: "web"},
},
LogRateLimit: "1GB",
},
}
})

It("changes the log rate limit of the web process in the manifest", func() {
Expect(executeErr).ToNot(HaveOccurred())
Expect(transformedManifest.Applications).To(ConsistOf(
manifestparser.Application{
Processes: []manifestparser.Process{
{Type: "worker"},
{Type: "web", LogRateLimit: "4MB"},
},
LogRateLimit: "1GB",
},
))
})
})

When("there are multiple apps in the manifest", func() {
BeforeEach(func() {
overrides.LogRateLimit = "64M"

originalManifest.Applications = []manifestparser.Application{
{},
{},
}
})

It("returns an error", func() {
Expect(executeErr).To(MatchError(translatableerror.CommandLineArgsWithMultipleAppsError{}))
})
})
})
1 change: 0 additions & 1 deletion actor/v7pushaction/handle_memory_override.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package v7pushaction

import (
//"code.cloudfoundry.org/cli/command/translatableerror"
"code.cloudfoundry.org/cli/command/translatableerror"
"code.cloudfoundry.org/cli/util/manifestparser"
)
Expand Down
1 change: 1 addition & 0 deletions actor/v7pushaction/push_plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ type FlagOverrides struct {
Vars []template.VarKV
NoManifest bool
Task bool
LogRateLimit string
}

func (state PushPlan) String() string {
Expand Down
4 changes: 3 additions & 1 deletion command/v7/push_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,11 @@ type PushCommand struct {
StartCommand flag.Command `long:"start-command" short:"c" description:"Startup command, set to null to reset to default start command"`
Strategy flag.DeploymentStrategy `long:"strategy" description:"Deployment strategy, either rolling or null."`
Task bool `long:"task" description:"Push an app that is used only to execute tasks. The app will be staged, but not started and will have no route assigned."`
LogRateLimit string `long:"log-rate-limit" short:"l" description:"Log rate limit per second, in bytes (e.g. 128B, 4K, 1M). -1 represents unlimited."`
Vars []template.VarKV `long:"var" description:"Variable key value pair for variable substitution, (e.g., name=app1); can specify multiple times"`
PathsToVarsFiles []flag.PathWithExistenceCheck `long:"vars-file" description:"Path to a variable substitution file for manifest; can specify multiple times"`
dockerPassword interface{} `environmentName:"CF_DOCKER_PASSWORD" environmentDescription:"Password used for private docker repository"`
usage interface{} `usage:"CF_NAME push APP_NAME [-b BUILDPACK_NAME]\n [-c COMMAND] [-f MANIFEST_PATH | --no-manifest] [--no-start] [--no-wait] [-i NUM_INSTANCES]\n [-k DISK] [-m MEMORY] [-p PATH] [-s STACK] [-t HEALTH_TIMEOUT] [--task TASK]\n [-u (process | port | http)] [--no-route | --random-route]\n [--var KEY=VALUE] [--vars-file VARS_FILE_PATH]...\n \n CF_NAME push APP_NAME --docker-image [REGISTRY_HOST:PORT/]IMAGE[:TAG] [--docker-username USERNAME]\n [-c COMMAND] [-f MANIFEST_PATH | --no-manifest] [--no-start] [--no-wait] [-i NUM_INSTANCES]\n [-k DISK] [-m MEMORY] [-p PATH] [-s STACK] [-t HEALTH_TIMEOUT] [--task TASK]\n [-u (process | port | http)] [--no-route | --random-route ]\n [--var KEY=VALUE] [--vars-file VARS_FILE_PATH]..."`
usage interface{} `usage:"CF_NAME push APP_NAME [-b BUILDPACK_NAME]\n [-c COMMAND] [-f MANIFEST_PATH | --no-manifest] [--no-start] [--no-wait] [-i NUM_INSTANCES]\n [-k DISK] [-m MEMORY] [-p PATH] [-s STACK] [-t HEALTH_TIMEOUT] [--task TASK]\n [-u (process | port | http)] [--no-route | --random-route] [-l LOG_RATE_LIMIT]\n [--var KEY=VALUE] [--vars-file VARS_FILE_PATH]...\n \n CF_NAME push APP_NAME --docker-image [REGISTRY_HOST:PORT/]IMAGE[:TAG] [--docker-username USERNAME]\n [-c COMMAND] [-f MANIFEST_PATH | --no-manifest] [--no-start] [--no-wait] [-i NUM_INSTANCES]\n [-k DISK] [-m MEMORY] [-p PATH] [-s STACK] [-t HEALTH_TIMEOUT] [--task TASK]\n [-u (process | port | http)] [--no-route | --random-route ] [-l LOG_RATE_LIMIT]\n [--var KEY=VALUE] [--vars-file VARS_FILE_PATH]..."`
envCFStagingTimeout interface{} `environmentName:"CF_STAGING_TIMEOUT" environmentDescription:"Max wait time for staging, in minutes" environmentDefault:"15"`
envCFStartupTimeout interface{} `environmentName:"CF_STARTUP_TIMEOUT" environmentDescription:"Max wait time for app instance startup, in minutes" environmentDefault:"5"`

Expand Down Expand Up @@ -358,6 +359,7 @@ func (cmd PushCommand) GetFlagOverrides() (v7pushaction.FlagOverrides, error) {
Vars: cmd.Vars,
NoManifest: cmd.NoManifest,
Task: cmd.Task,
LogRateLimit: cmd.LogRateLimit,
}, nil
}

Expand Down
4 changes: 3 additions & 1 deletion command/v7/push_command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ var _ = Describe("push Command", func() {
})
})

When("marsahlling the manifest succeeds", func() {
When("marshalling the manifest succeeds", func() {
BeforeEach(func() {
fakeManifestParser.MarshalManifestReturns([]byte("our-manifest"), nil)
})
Expand Down Expand Up @@ -1078,6 +1078,7 @@ var _ = Describe("push Command", func() {
cmd.PathsToVarsFiles = []flag.PathWithExistenceCheck{"/vars1", "/vars2"}
cmd.Vars = []template.VarKV{{Name: "key", Value: "val"}}
cmd.Task = true
cmd.LogRateLimit = "512M"
})

JustBeforeEach(func() {
Expand Down Expand Up @@ -1106,6 +1107,7 @@ var _ = Describe("push Command", func() {
Expect(overrides.PathsToVarsFiles).To(Equal([]string{"/vars1", "/vars2"}))
Expect(overrides.Vars).To(Equal([]template.VarKV{{Name: "key", Value: "val"}}))
Expect(overrides.Task).To(BeTrue())
Expect(overrides.LogRateLimit).To(Equal("512M"))
})

When("a docker image is provided", func() {
Expand Down
1 change: 1 addition & 0 deletions integration/v7/push/combination_manifest_and_flag_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ var _ = Describe("push with a simple manifest and flags", func() {
Entry("health check type", "-u", "port"),
Entry("instances", "-i", "10"),
Entry("memory", "-m", "100M"),
Entry("log rate limit", "-l", "5K"),
Entry("no route", "--no-route"),
Entry("stack", "-s", "something"),
)
Expand Down
7 changes: 5 additions & 2 deletions integration/v7/push/help_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ var _ = Describe("help", func() {
"[--task TASK]",
"[-u (process | port | http)]",
"[--no-route | --random-route]",
"[-l LOG_RATE_LIMIT]",
"[--var KEY=VALUE]",
"[--vars-file VARS_FILE_PATH]...",
}
Expand All @@ -61,16 +62,17 @@ var _ = Describe("help", func() {
"[--task TASK]",
"[-u (process | port | http)]",
"[--no-route | --random-route ]",
"[-l LOG_RATE_LIMIT]",
"[--var KEY=VALUE]",
"[--vars-file VARS_FILE_PATH]...",
}

assertUsage(session, buildpackAppUsage, dockerAppUsage)

Eventually(session).Should(Say("OPTIONS:"))
Eventually(session).Should(Say(`app-start-timeout, -t`))
Eventually(session).Should(Say(`--app-start-timeout, -t`))
Eventually(session).Should(Say(`--buildpack, -b`))
Eventually(session).Should(Say(`disk, -k`))
Eventually(session).Should(Say(`--disk, -k`))
Eventually(session).Should(Say(`--docker-image, -o`))
Eventually(session).Should(Say(`--docker-username`))
Eventually(session).Should(Say(`--droplet`))
Expand All @@ -89,6 +91,7 @@ var _ = Describe("help", func() {
Eventually(session).Should(Say(`--start-command, -c`))
Eventually(session).Should(Say(`--strategy`))
Eventually(session).Should(Say(`--task`))
Eventually(session).Should(Say(`--log-rate-limit, -l\s+Log rate limit per second, in bytes \(e.g. 128B, 4K, 1M\). -1 represents unlimited.`))
Eventually(session).Should(Say(`--var`))
Eventually(session).Should(Say(`--vars-file`))
Eventually(session).Should(Say("ENVIRONMENT:"))
Expand Down
46 changes: 46 additions & 0 deletions integration/v7/push/log_rate_limit_flag_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package push

import (
"time"

"code.cloudfoundry.org/cli/api/cloudcontroller/ccversion"
"code.cloudfoundry.org/cli/integration/helpers"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gbytes"
. "github.com/onsi/gomega/gexec"
)

var _ = Describe("push with log rate limit flag", func() {
var (
appName string
)

BeforeEach(func() {
helpers.SkipIfVersionLessThan(ccversion.MinVersionLogRateLimitingV3)

appName = helpers.NewAppName()
})

Context("when the -l flag is provided with application log rate limit", func() {
It("creates the app with the specified log rate limit", func() {
helpers.WithHelloWorldApp(func(dir string) {
session := helpers.CustomCF(helpers.CFEnv{WorkingDirectory: dir},
PushCommandName, appName,
"-l", "5K",
)
Eventually(session).Should(Exit(0))
})

time.Sleep(5 * time.Second)
session := helpers.CF("app", appName)
Eventually(session).Should(Say(`name:\s+%s`, appName))
Eventually(session).Should(Say(`last uploaded:\s+%s`, helpers.ReadableDateTimeRegex))
//TODO: check output of push command
// Eventually(session).Should(Say(`log rate usage per second:\s+5K`))
// Eventually(session).Should(Say(`\s+state\s+since\s+cpu\s+memory\s+disk\s+log rate per second`))
Eventually(session).Should(Say(`#0\s+running\s+\d{4}-[01]\d-[0-3]\dT[0-2][0-9]:[0-5]\d:[0-5]\dZ`))
Eventually(session).Should(Exit(0))
})
})
})
1 change: 1 addition & 0 deletions util/manifestparser/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type Application struct {
RandomRoute bool `yaml:"random-route,omitempty"`
DefaultRoute bool `yaml:"default-route,omitempty"`
Stack string `yaml:"stack,omitempty"`
LogRateLimit string `yaml:"log_rate_limit_per_second,omitempty"`
RemainingManifestFields map[string]interface{} `yaml:"-,inline"`
}

Expand Down
29 changes: 29 additions & 0 deletions util/manifestparser/application_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,22 @@ processes:
})
})

Context("when a log rate limit is provided", func() {
BeforeEach(func() {
rawYAML = []byte(`---
processes:
- log_rate_limit_per_second: 512M
`)
})

It("unmarshals the processes property with the log rate limit", func() {
Expect(executeErr).ToNot(HaveOccurred())
Expect(application.Processes).To(Equal([]Process{
{LogRateLimit: "512M", RemainingManifestFields: emptyMap},
}))
})
})

Context("when an unknown field is provided", func() {
BeforeEach(func() {
rawYAML = []byte(`---
Expand Down Expand Up @@ -392,6 +408,19 @@ processes:
Expect(remarshalledYaml).To(MatchYAML(rawYAML))
})
})

Context("when a log rate limit is provided", func() {
BeforeEach(func() {
rawYAML = []byte(`---
log_rate_limit_per_second: 5K
`)
})

It("unmarshals the log rate limit", func() {
Expect(executeErr).ToNot(HaveOccurred())
Expect(application.LogRateLimit).To(Equal("5K"))
})
})
})

Describe("SetStartCommand", func() {
Expand Down
1 change: 1 addition & 0 deletions util/manifestparser/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type Process struct {
Instances *int `yaml:"instances,omitempty"`
Memory string `yaml:"memory,omitempty"`
Type string `yaml:"type"`
LogRateLimit string `yaml:"log_rate_limit_per_second,omitempty"`
RemainingManifestFields map[string]interface{} `yaml:"-,inline"`
}

Expand Down
Loading

0 comments on commit f1f0c78

Please sign in to comment.