mirror of https://github.com/knative/client.git
Add changes for --scale-init support (#990)
* Add changes for --scale-init support * Added test cases * Add test case in e2e tests * minor fix * Test case failure fix * Incorporated review comments * Add service update test cases * Incorporate review comments
This commit is contained in:
parent
fb47409837
commit
6c7fc7ca70
|
|
@ -87,6 +87,7 @@ kn service create NAME --image IMAGE
|
|||
--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-init int Initial number of replicas with which a service starts. Can be 0 or a positive integer.
|
||||
--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.
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ kn service update NAME
|
|||
--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-init int Initial number of replicas with which a service starts. Can be 0 or a positive integer.
|
||||
--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.
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ package service
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
|
@ -27,6 +28,7 @@ import (
|
|||
knflags "knative.dev/client/pkg/kn/flags"
|
||||
servinglib "knative.dev/client/pkg/serving"
|
||||
"knative.dev/client/pkg/util"
|
||||
"knative.dev/serving/pkg/apis/autoscaling"
|
||||
"knative.dev/serving/pkg/apis/serving"
|
||||
servingv1 "knative.dev/serving/pkg/apis/serving/v1"
|
||||
)
|
||||
|
|
@ -49,6 +51,7 @@ type ConfigurationEditFlags struct {
|
|||
RevisionName string
|
||||
Annotations []string
|
||||
ClusterLocal bool
|
||||
ScaleInit int
|
||||
|
||||
// Preferences about how to do the action.
|
||||
LockToDigest bool
|
||||
|
|
@ -149,6 +152,9 @@ func (p *ConfigurationEditFlags) addSharedFlags(command *cobra.Command) {
|
|||
"any number of times to set multiple annotations. "+
|
||||
"To unset, specify the annotation name followed by a \"-\" (e.g., name-).")
|
||||
p.markFlagMakesRevision("annotation")
|
||||
|
||||
command.Flags().IntVar(&p.ScaleInit, "scale-init", 0, "Initial number of replicas with which a service starts. Can be 0 or a positive integer.")
|
||||
p.markFlagMakesRevision("scale-init")
|
||||
}
|
||||
|
||||
// AddUpdateFlags adds the flags specific to update.
|
||||
|
|
@ -427,6 +433,29 @@ func (p *ConfigurationEditFlags) Apply(
|
|||
servinglib.UpdateUser(template, p.PodSpecFlags.User)
|
||||
}
|
||||
|
||||
if cmd.Flags().Changed("scale-init") {
|
||||
containsAnnotation := func(annotationList []string, annotation string) bool {
|
||||
for _, element := range annotationList {
|
||||
if strings.Contains(element, annotation) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
if cmd.Flags().Changed("annotation") && containsAnnotation(p.Annotations, autoscaling.InitialScaleAnnotationKey) {
|
||||
return fmt.Errorf("only one of the --scale-init or --annotation %s can be specified", autoscaling.InitialScaleAnnotationKey)
|
||||
}
|
||||
annotationsMap := map[string]string{
|
||||
autoscaling.InitialScaleAnnotationKey: strconv.Itoa(p.ScaleInit),
|
||||
}
|
||||
|
||||
err = servinglib.UpdateAnnotations(service, template, annotationsMap, []string{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -512,6 +512,39 @@ func getService(name string) *servingv1.Service {
|
|||
return service
|
||||
}
|
||||
|
||||
func TestServiceCreateWithInitScaleAsOption(t *testing.T) {
|
||||
client := knclient.NewMockKnServiceClient(t)
|
||||
|
||||
r := client.Recorder()
|
||||
|
||||
// Check for existing service --> no
|
||||
r.GetService("foo", nil, errors.NewNotFound(servingv1.Resource("service"), "foo"))
|
||||
// Create service (don't validate given service --> "Any()" arg is allowed)
|
||||
r.CreateService(mock.Any(), nil)
|
||||
// Wait for service to become ready
|
||||
r.WaitForService("foo", mock.Any(), wait.NoopMessageCallback(), nil, time.Second)
|
||||
// Get for showing the URL
|
||||
r.GetService("foo", getServiceWithUrl("foo", "http://foo.example.com"), nil)
|
||||
|
||||
output, err := executeServiceCommand(client, "create", "foo", "--image", "gcr.io/foo/bar:baz", "--scale-init", "0")
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, util.ContainsAll(output, "created", "foo", "default"))
|
||||
|
||||
r.Validate()
|
||||
}
|
||||
|
||||
func TestServiceCreateWithBothAnnotationAndInitScaleAsOption(t *testing.T) {
|
||||
client := knclient.NewMockKnServiceClient(t)
|
||||
|
||||
r := client.Recorder()
|
||||
|
||||
output, err := executeServiceCommand(client, "create", "foo", "--image", "gcr.io/foo/bar:baz", "--annotation", "autoscaling.knative.dev/initialScale=0", "--scale-init", "0")
|
||||
assert.Assert(t, err != nil)
|
||||
assert.Assert(t, util.ContainsAll(output, "only one of the", "--scale-init", "--annotation", "autoscaling.knative.dev/initialScale", "can be specified"))
|
||||
|
||||
r.Validate()
|
||||
}
|
||||
|
||||
func getServiceWithUrl(name string, urlName string) *servingv1.Service {
|
||||
service := servingv1.Service{}
|
||||
url, _ := apis.ParseURL(urlName)
|
||||
|
|
|
|||
|
|
@ -1473,3 +1473,50 @@ func TestServiceUpdateUser(t *testing.T) {
|
|||
|
||||
r.Validate()
|
||||
}
|
||||
|
||||
func TestServiceUpdateInitialScaleMock(t *testing.T) {
|
||||
client := clientservingv1.NewMockKnServiceClient(t)
|
||||
svcName := "svc1"
|
||||
newService := getService(svcName)
|
||||
template := &newService.Spec.Template
|
||||
template.Spec.Containers[0].Image = "gcr.io/foo/bar:baz"
|
||||
newService.ObjectMeta.Annotations = map[string]string{
|
||||
"autoscaling.knative.dev/initialScale": "1",
|
||||
}
|
||||
template.ObjectMeta.Annotations = map[string]string{
|
||||
"autoscaling.knative.dev/initialScale": "1",
|
||||
clientserving.UserImageAnnotationKey: "gcr.io/foo/bar:baz",
|
||||
}
|
||||
|
||||
updatedService := getService(svcName)
|
||||
template = &updatedService.Spec.Template
|
||||
template.Spec.Containers[0].Image = "gcr.io/foo/bar:baz"
|
||||
updatedService.ObjectMeta.Annotations = map[string]string{
|
||||
"autoscaling.knative.dev/initialScale": "2",
|
||||
}
|
||||
template.ObjectMeta.Annotations = map[string]string{
|
||||
"autoscaling.knative.dev/initialScale": "2",
|
||||
clientserving.UserImageAnnotationKey: "gcr.io/foo/bar:baz",
|
||||
}
|
||||
|
||||
r := client.Recorder()
|
||||
recordServiceUpdateWithSuccess(r, svcName, newService, updatedService)
|
||||
|
||||
output, err := executeServiceCommand(client,
|
||||
"create", svcName, "--image", "gcr.io/foo/bar:baz",
|
||||
"--scale-init", "1",
|
||||
"--no-wait", "--revision-name=",
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, util.ContainsAll(output, "created", svcName, "default"))
|
||||
|
||||
output, err = executeServiceCommand(client,
|
||||
"update", svcName,
|
||||
"--scale-init", "2",
|
||||
"--no-wait", "--revision-name=",
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, util.ContainsAll(output, "updated", svcName, "default"))
|
||||
|
||||
r.Validate()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -147,6 +147,15 @@ func TestServiceOptions(t *testing.T) {
|
|||
serviceCreateWithOptions(r, "svc9", "--image", pkgtest.ImagePath("grpc-ping"), "--port", "h2c:8080")
|
||||
validatePort(r, "svc9", 8080, "h2c")
|
||||
test.ServiceDelete(r, "svc9")
|
||||
|
||||
t.Log("create and validate service with scale init option")
|
||||
serviceCreateWithOptions(r, "svc10", "--scale-init", "1")
|
||||
validateServiceInitScale(r, "svc10", "1")
|
||||
test.ServiceUpdate(r, "svc10", "--scale-init", "2")
|
||||
validateServiceInitScale(r, "svc10", "2")
|
||||
t.Log("delete service")
|
||||
test.ServiceDelete(r, "svc10")
|
||||
|
||||
}
|
||||
|
||||
func serviceCreateWithOptions(r *test.KnRunResultCollector, serviceName string, options ...string) {
|
||||
|
|
@ -211,6 +220,13 @@ func validateServiceMaxScale(r *test.KnRunResultCollector, serviceName, maxScale
|
|||
r.AssertNoError(out)
|
||||
}
|
||||
|
||||
func validateServiceInitScale(r *test.KnRunResultCollector, serviceName, initScale string) {
|
||||
jsonpath := "jsonpath={.items[0].spec.template.metadata.annotations.autoscaling\\.knative\\.dev/initialScale}"
|
||||
out := r.KnTest().Kn().Run("service", "list", serviceName, "-o", jsonpath)
|
||||
assert.Equal(r.T(), out.Stdout, initScale)
|
||||
r.AssertNoError(out)
|
||||
}
|
||||
|
||||
func validateServiceAnnotations(r *test.KnRunResultCollector, serviceName string, annotations map[string]string) {
|
||||
metadataAnnotationsJsonpathFormat := "jsonpath={.metadata.annotations.%s}"
|
||||
templateAnnotationsJsonpathFormat := "jsonpath={.spec.template.metadata.annotations.%s}"
|
||||
|
|
|
|||
Loading…
Reference in New Issue