Skip to content

Commit

Permalink
Added range options to --scale
Browse files Browse the repository at this point in the history
  • Loading branch information
Mike Petersen committed Aug 20, 2020
1 parent 4ea31c4 commit 29dc3a9
Show file tree
Hide file tree
Showing 5 changed files with 264 additions and 11 deletions.
2 changes: 1 addition & 1 deletion docs/cmd/kn_service_create.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ kn service create NAME --image IMAGE
--requests-cpu string DEPRECATED: please use --request instead. The requested CPU (e.g., 250m).
--requests-memory string DEPRECATED: please use --request instead. The requested memory (e.g., 64Mi).
--revision-name string The revision name to set. Must start with the service name and a dash as a prefix. Empty revision name will result in the server generating a name for the revision. Accepts golang templates, allowing {{.Service}} for the service name, {{.Generation}} for the generation, and {{.Random [n]}} for n random consonants. (default "{{.Service}}-{{.Random 5}}-{{.Generation}}")
--scale int Minimum and maximum number of replicas.
--scale string Minimum and maximum number of replicas. Example: --scale 5 or --scale 1..5 or --scale 1.. or --scale ..5.
--scale-max int Maximum number of replicas.
--scale-min int Minimum number of replicas.
--service-account string Service account name to set. An empty argument ("") clears the service account. The referenced service account must exist in the service's namespace.
Expand Down
2 changes: 1 addition & 1 deletion docs/cmd/kn_service_update.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ kn service update NAME
--requests-cpu string DEPRECATED: please use --request instead. The requested CPU (e.g., 250m).
--requests-memory string DEPRECATED: please use --request instead. The requested memory (e.g., 64Mi).
--revision-name string The revision name to set. Must start with the service name and a dash as a prefix. Empty revision name will result in the server generating a name for the revision. Accepts golang templates, allowing {{.Service}} for the service name, {{.Generation}} for the generation, and {{.Random [n]}} for n random consonants. (default "{{.Service}}-{{.Random 5}}-{{.Generation}}")
--scale int Minimum and maximum number of replicas.
--scale string Minimum and maximum number of replicas. Example: --scale 5 or --scale 1..5 or --scale 1.. or --scale ..5.
--scale-max int Maximum number of replicas.
--scale-min int Minimum number of replicas.
--service-account string Service account name to set. An empty argument ("") clears the service account. The referenced service account must exist in the service's namespace.
Expand Down
51 changes: 42 additions & 9 deletions pkg/kn/commands/service/configuration_edit_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package service

import (
"fmt"
"strconv"
"strings"

"github.com/spf13/cobra"
Expand All @@ -36,7 +37,7 @@ type ConfigurationEditFlags struct {
PodSpecFlags knflags.PodSpecFlags

// Direct field manipulation
Scale int
Scale string
MinScale int
MaxScale int
ConcurrencyTarget int
Expand Down Expand Up @@ -82,7 +83,7 @@ func (p *ConfigurationEditFlags) addSharedFlags(command *cobra.Command) {
command.Flags().MarkHidden("max-scale")
p.markFlagMakesRevision("max-scale")

command.Flags().IntVar(&p.Scale, "scale", 0, "Minimum and maximum number of replicas.")
command.Flags().StringVar(&p.Scale, "scale", "", "Minimum and maximum number of replicas.")
p.markFlagMakesRevision("scale")

command.Flags().IntVar(&p.MinScale, "scale-min", 0, "Minimum number of replicas.")
Expand Down Expand Up @@ -333,13 +334,45 @@ func (p *ConfigurationEditFlags) Apply(
} else if cmd.Flags().Changed("scale-min") {
return fmt.Errorf("only --scale or --scale-min can be specified")
} else {
err = servinglib.UpdateMaxScale(template, p.Scale)
if err != nil {
return err
}
err = servinglib.UpdateMinScale(template, p.Scale)
if err != nil {
return err
if !strings.Contains(p.Scale, "..") {
scaleInt, _ := strconv.Atoi(p.Scale)
err = servinglib.UpdateMaxScale(template, scaleInt)
if err != nil {
return err
}
err = servinglib.UpdateMinScale(template, scaleInt)
if err != nil {
return err
}
} else if len(p.Scale) == 4 {
scaleParts := strings.Split(p.Scale, "..")
scaleMin, _ := strconv.Atoi(scaleParts[0])
scaleMax, _ := strconv.Atoi(scaleParts[1])
err = servinglib.UpdateMinScale(template, scaleMin)
if err != nil {
return err
}
err = servinglib.UpdateMaxScale(template, scaleMax)
if err != nil {
return err
}
} else {
scaleParts := strings.Split(p.Scale, "")
if scaleParts[0] == "." {
scaleParts = strings.Split(p.Scale, "..")
scaleMax, _ := strconv.Atoi(scaleParts[1])
err = servinglib.UpdateMaxScale(template, scaleMax)
if err != nil {
return err
}
} else {
scaleParts = strings.Split(p.Scale, "..")
scaleMin, _ := strconv.Atoi(scaleParts[0])
err = servinglib.UpdateMinScale(template, scaleMin)
if err != nil {
return err
}
}
}
}
}
Expand Down
82 changes: 82 additions & 0 deletions pkg/kn/commands/service/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,88 @@ func TestServiceCreateScaleWithMinScaleSet(t *testing.T) {

}

func TestServiceCreateScaleRange(t *testing.T) {
action, created, _, err := fakeServiceCreate([]string{
"service", "create", "foo", "--image", "gcr.io/foo/bar:baz",
"--scale", "1..5", "--no-wait"}, false)

if err != nil {
t.Fatal(err)
} else if !action.Matches("create", "services") {
t.Fatalf("Bad action %v", action)
}

template := &created.Spec.Template

actualAnnos := template.Annotations
expectedAnnos := []string{
"autoscaling.knative.dev/minScale", "1",
"autoscaling.knative.dev/maxScale", "5",
}

for i := 0; i < len(expectedAnnos); i += 2 {
anno := expectedAnnos[i]
if actualAnnos[anno] != expectedAnnos[i+1] {
t.Fatalf("Unexpected annotation value for %s : %s (actual) != %s (expected)",
anno, actualAnnos[anno], expectedAnnos[i+1])
}
}
}

func TestServiceCreateScaleRangeOnlyMin(t *testing.T) {
action, created, _, err := fakeServiceCreate([]string{
"service", "create", "foo", "--image", "gcr.io/foo/bar:baz",
"--scale", "1..", "--no-wait"}, false)

if err != nil {
t.Fatal(err)
} else if !action.Matches("create", "services") {
t.Fatalf("Bad action %v", action)
}

template := &created.Spec.Template

actualAnnos := template.Annotations
expectedAnnos := []string{
"autoscaling.knative.dev/minScale", "1",
}

for i := 0; i < len(expectedAnnos); i += 2 {
anno := expectedAnnos[i]
if actualAnnos[anno] != expectedAnnos[i+1] {
t.Fatalf("Unexpected annotation value for %s : %s (actual) != %s (expected)",
anno, actualAnnos[anno], expectedAnnos[i+1])
}
}
}

func TestServiceCreateScaleRangeOnlyMax(t *testing.T) {
action, created, _, err := fakeServiceCreate([]string{
"service", "create", "foo", "--image", "gcr.io/foo/bar:baz",
"--scale", "..5", "--no-wait"}, false)

if err != nil {
t.Fatal(err)
} else if !action.Matches("create", "services") {
t.Fatalf("Bad action %v", action)
}

template := &created.Spec.Template

actualAnnos := template.Annotations
expectedAnnos := []string{
"autoscaling.knative.dev/maxScale", "5",
}

for i := 0; i < len(expectedAnnos); i += 2 {
anno := expectedAnnos[i]
if actualAnnos[anno] != expectedAnnos[i+1] {
t.Fatalf("Unexpected annotation value for %s : %s (actual) != %s (expected)",
anno, actualAnnos[anno], expectedAnnos[i+1])
}
}
}

func TestServiceCreateRequestsLimitsCPUMemory(t *testing.T) {
action, created, _, err := fakeServiceCreate([]string{
"service", "create", "foo", "--image", "gcr.io/foo/bar:baz",
Expand Down
138 changes: 138 additions & 0 deletions pkg/kn/commands/service/update_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,144 @@ func TestServiceUpdateScaleWithMinScaleSet(t *testing.T) {
}

}

func TestServiceUpdateScaleWithRange(t *testing.T) {
original := newEmptyService()

action, updated, _, err := fakeServiceUpdate(original, []string{
"service", "update", "foo",
"--scale", "1..5", "--no-wait"})

if err != nil {
t.Fatal(err)
} else if !action.Matches("update", "services") {
t.Fatalf("Bad action %v", action)
}

template := updated.Spec.Template
if err != nil {
t.Fatal(err)
}

actualAnnos := template.Annotations
expectedAnnos := []string{
"autoscaling.knative.dev/minScale", "1",
"autoscaling.knative.dev/maxScale", "5",
}

for i := 0; i < len(expectedAnnos); i += 2 {
anno := expectedAnnos[i]
if actualAnnos[anno] != expectedAnnos[i+1] {
t.Fatalf("Unexpected annotation value for %s : %s (actual) != %s (expected)",
anno, actualAnnos[anno], expectedAnnos[i+1])
}
}

}

func TestServiceUpdateScaleMinWithRange(t *testing.T) {
original := newEmptyService()

action, updated, _, err := fakeServiceUpdate(original, []string{
"service", "update", "foo",
"--scale", "1..", "--no-wait"})

if err != nil {
t.Fatal(err)
} else if !action.Matches("update", "services") {
t.Fatalf("Bad action %v", action)
}

template := updated.Spec.Template
if err != nil {
t.Fatal(err)
}

actualAnnos := template.Annotations
expectedAnnos := []string{
"autoscaling.knative.dev/minScale", "1",
}

for i := 0; i < len(expectedAnnos); i += 2 {
anno := expectedAnnos[i]
if actualAnnos[anno] != expectedAnnos[i+1] {
t.Fatalf("Unexpected annotation value for %s : %s (actual) != %s (expected)",
anno, actualAnnos[anno], expectedAnnos[i+1])
}
}

}

func TestServiceUpdateScaleMaxWithRange(t *testing.T) {
original := newEmptyService()

action, updated, _, err := fakeServiceUpdate(original, []string{
"service", "update", "foo",
"--scale", "..5", "--no-wait"})

if err != nil {
t.Fatal(err)
} else if !action.Matches("update", "services") {
t.Fatalf("Bad action %v", action)
}

template := updated.Spec.Template
if err != nil {
t.Fatal(err)
}

actualAnnos := template.Annotations
expectedAnnos := []string{
"autoscaling.knative.dev/maxScale", "5",
}

for i := 0; i < len(expectedAnnos); i += 2 {
anno := expectedAnnos[i]
if actualAnnos[anno] != expectedAnnos[i+1] {
t.Fatalf("Unexpected annotation value for %s : %s (actual) != %s (expected)",
anno, actualAnnos[anno], expectedAnnos[i+1])
}
}

}

func TestServiceUpdateScaleWithMinScaleNegativeSet(t *testing.T) {
original := newEmptyService()

_, _, _, err := fakeServiceUpdate(original, []string{
"service", "update", "foo",
"--scale", "-1..", "--no-wait"})

if err == nil {
t.Fatal("Expected error, got nil")
}

expectedErrMsg := "expected 0 <= -1 <= 2147483647: autoscaling.knative.dev/minScale"

if !strings.Contains(err.Error(), expectedErrMsg) {
t.Errorf("Invalid error output, expected: %s, got : '%s'", expectedErrMsg, err)
}

}

func TestServiceUpdateScaleWithMaxScaleNegativeSet(t *testing.T) {
original := newEmptyService()

_, _, _, err := fakeServiceUpdate(original, []string{
"service", "update", "foo",
"--scale", "..-1", "--no-wait"})

if err == nil {
t.Fatal("Expected error, got nil")
}

expectedErrMsg := "expected 0 <= -1 <= 2147483647: autoscaling.knative.dev/maxScale"

if !strings.Contains(err.Error(), expectedErrMsg) {
t.Errorf("Invalid error output, expected: %s, got : '%s'", expectedErrMsg, err)
}
}

func TestServiceUpdateEnv(t *testing.T) {
orig := newEmptyService()

Expand Down

0 comments on commit 29dc3a9

Please sign in to comment.