Add support for command and args in service create (#635)

* Add support for command and args in service create

* Add tests for new update functions
This commit is contained in:
David Simansky 2020-02-04 17:45:31 +01:00 committed by GitHub
parent d82d55731c
commit ffdeafe33e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 141 additions and 0 deletions

View File

@ -24,6 +24,10 @@
| Show envFrom when running describe service or revision | Show envFrom when running describe service or revision
| https://github.com/knative/client/pull/630 | https://github.com/knative/client/pull/630
| 🎁
| Add `--cmd` and `--arg` for customization of container entrypoint
| https://github.com/knative/client/pull/635[#635]
## v0.12.0 (2020-01-29) ## v0.12.0 (2020-01-29)
[cols="1,10,3", options="header", width="100%"] [cols="1,10,3", options="header", width="100%"]

View File

@ -43,8 +43,10 @@ kn service create NAME --image IMAGE [flags]
``` ```
--annotation stringArray Service annotation to set. name=value; you may provide this flag any number of times to set multiple annotations. To unset, specify the annotation name followed by a "-" (e.g., name-). --annotation stringArray Service annotation to set. name=value; you may provide this flag any number of times to set multiple annotations. To unset, specify the annotation name followed by a "-" (e.g., name-).
--arg stringArray Add argument to the container command. Example: --arg myArg1 --arg --myArg2 --arg myArg3=3. You can use this flag multiple times.
--async Create service and don't wait for it to become ready. --async Create service and don't wait for it to become ready.
--autoscale-window string Duration to look back for making auto-scaling decisions. The service is scaled to zero if no request was received in during that time. (eg: 10s) --autoscale-window string Duration to look back for making auto-scaling decisions. The service is scaled to zero if no request was received in during that time. (eg: 10s)
--cmd string Specify command to be used as entrypoint instead of default one. Example: --cmd /app/start or --cmd /app/start --arg myArg to pass aditional arguments.
--concurrency-limit int Hard Limit of concurrent requests to be processed by a single replica. --concurrency-limit int Hard Limit of concurrent requests to be processed by a single replica.
--concurrency-target int Recommendation for when to scale up based on the concurrent number of incoming request. Defaults to --concurrency-limit when given. --concurrency-target int Recommendation for when to scale up based on the concurrent number of incoming request. Defaults to --concurrency-limit when given.
-e, --env stringArray Environment variable to set. NAME=value; you may provide this flag any number of times to set multiple environment variables. To unset, specify the environment variable name followed by a "-" (e.g., NAME-). -e, --env stringArray Environment variable to set. NAME=value; you may provide this flag any number of times to set multiple environment variables. To unset, specify the environment variable name followed by a "-" (e.g., NAME-).

View File

@ -39,8 +39,10 @@ kn service update NAME [flags]
``` ```
--annotation stringArray Service annotation to set. name=value; you may provide this flag any number of times to set multiple annotations. To unset, specify the annotation name followed by a "-" (e.g., name-). --annotation stringArray Service annotation to set. name=value; you may provide this flag any number of times to set multiple annotations. To unset, specify the annotation name followed by a "-" (e.g., name-).
--arg stringArray Add argument to the container command. Example: --arg myArg1 --arg --myArg2 --arg myArg3=3. You can use this flag multiple times.
--async Update service and don't wait for it to become ready. --async Update service and don't wait for it to become ready.
--autoscale-window string Duration to look back for making auto-scaling decisions. The service is scaled to zero if no request was received in during that time. (eg: 10s) --autoscale-window string Duration to look back for making auto-scaling decisions. The service is scaled to zero if no request was received in during that time. (eg: 10s)
--cmd string Specify command to be used as entrypoint instead of default one. Example: --cmd /app/start or --cmd /app/start --arg myArg to pass aditional arguments.
--concurrency-limit int Hard Limit of concurrent requests to be processed by a single replica. --concurrency-limit int Hard Limit of concurrent requests to be processed by a single replica.
--concurrency-target int Recommendation for when to scale up based on the concurrent number of incoming request. Defaults to --concurrency-limit when given. --concurrency-target int Recommendation for when to scale up based on the concurrent number of incoming request. Defaults to --concurrency-limit when given.
-e, --env stringArray Environment variable to set. NAME=value; you may provide this flag any number of times to set multiple environment variables. To unset, specify the environment variable name followed by a "-" (e.g., NAME-). -e, --env stringArray Environment variable to set. NAME=value; you may provide this flag any number of times to set multiple environment variables. To unset, specify the environment variable name followed by a "-" (e.g., NAME-).

View File

@ -36,6 +36,9 @@ type ConfigurationEditFlags struct {
Mount []string Mount []string
Volume []string Volume []string
Command string
Arg []string
RequestsFlags, LimitsFlags ResourceFlags RequestsFlags, LimitsFlags ResourceFlags
MinScale int MinScale int
MaxScale int MaxScale int
@ -102,6 +105,16 @@ func (p *ConfigurationEditFlags) addSharedFlags(command *cobra.Command) {
"To unset a ConfigMap/Secret reference, append \"-\" to the name, e.g. --volume myvolume-.") "To unset a ConfigMap/Secret reference, append \"-\" to the name, e.g. --volume myvolume-.")
p.markFlagMakesRevision("volume") p.markFlagMakesRevision("volume")
command.Flags().StringVarP(&p.Command, "cmd", "", "",
"Specify command to be used as entrypoint instead of default one. "+
"Example: --cmd /app/start or --cmd /app/start --arg myArg to pass aditional arguments.")
p.markFlagMakesRevision("cmd")
command.Flags().StringArrayVarP(&p.Arg, "arg", "", []string{},
"Add argument to the container command. "+
"Example: --arg myArg1 --arg --myArg2 --arg myArg3=3. "+
"You can use this flag multiple times.")
p.markFlagMakesRevision("arg")
command.Flags().StringVar(&p.RequestsFlags.CPU, "requests-cpu", "", "The requested CPU (e.g., 250m).") command.Flags().StringVar(&p.RequestsFlags.CPU, "requests-cpu", "", "The requested CPU (e.g., 250m).")
p.markFlagMakesRevision("requests-cpu") p.markFlagMakesRevision("requests-cpu")
command.Flags().StringVar(&p.RequestsFlags.Memory, "requests-memory", "", "The requested memory (e.g., 64Mi).") command.Flags().StringVar(&p.RequestsFlags.Memory, "requests-memory", "", "The requested memory (e.g., 64Mi).")
@ -281,6 +294,20 @@ func (p *ConfigurationEditFlags) Apply(
return err return err
} }
if cmd.Flags().Changed("cmd") {
err = servinglib.UpdateContainerCommand(template, p.Command)
if err != nil {
return err
}
}
if cmd.Flags().Changed("arg") {
err = servinglib.UpdateContainerArg(template, p.Arg)
if err != nil {
return err
}
}
if cmd.Flags().Changed("port") { if cmd.Flags().Changed("port") {
err = servinglib.UpdateContainerPort(template, p.Port) err = servinglib.UpdateContainerPort(template, p.Port)
if err != nil { if err != nil {

View File

@ -21,6 +21,8 @@ import (
"strings" "strings"
"testing" "testing"
"gotest.tools/assert"
api_errors "k8s.io/apimachinery/pkg/api/errors" api_errors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/watch" "k8s.io/apimachinery/pkg/watch"
@ -156,6 +158,30 @@ func TestServiceCreateImageSync(t *testing.T) {
} }
} }
func TestServiceCreateCommand(t *testing.T) {
action, created, _, err := fakeServiceCreate([]string{
"service", "create", "foo", "--image", "gcr.io/foo/bar:baz", "--cmd", "/app/start", "--async"}, false, false)
assert.NilError(t, err)
assert.Assert(t, action.Matches("create", "services"))
template, err := servinglib.RevisionTemplateOfService(created)
assert.NilError(t, err)
assert.DeepEqual(t, template.Spec.Containers[0].Command, []string{"/app/start"})
}
func TestServiceCreateArg(t *testing.T) {
action, created, _, err := fakeServiceCreate([]string{
"service", "create", "foo", "--image", "gcr.io/foo/bar:baz", "--arg", "myArg1", "--arg", "--myArg2", "--arg", "--myArg3=3", "--async"}, false, false)
assert.NilError(t, err)
assert.Assert(t, action.Matches("create", "services"))
expectedArg := []string{"myArg1", "--myArg2", "--myArg3=3"}
template, err := servinglib.RevisionTemplateOfService(created)
assert.NilError(t, err)
assert.DeepEqual(t, template.Spec.Containers[0].Args, expectedArg)
}
func TestServiceCreateEnv(t *testing.T) { func TestServiceCreateEnv(t *testing.T) {
action, created, _, err := fakeServiceCreate([]string{ action, created, _, err := fakeServiceCreate([]string{
"service", "create", "foo", "--image", "gcr.io/foo/bar:baz", "-e", "A=DOGS", "--env", "B=WOLVES", "--env=EMPTY", "--async"}, false, false) "service", "create", "foo", "--image", "gcr.io/foo/bar:baz", "-e", "A=DOGS", "--env", "B=WOLVES", "--env=EMPTY", "--async"}, false, false)

View File

@ -203,6 +203,44 @@ func TestServiceUpdateImage(t *testing.T) {
} }
} }
func TestServiceUpdateCommand(t *testing.T) {
orig := newEmptyService()
origTemplate, err := servinglib.RevisionTemplateOfService(orig)
assert.NilError(t, err)
err = servinglib.UpdateContainerCommand(origTemplate, "./start")
assert.NilError(t, err)
action, updated, _, err := fakeServiceUpdate(orig, []string{
"service", "update", "foo", "--cmd", "/app/start", "--async"}, false)
assert.NilError(t, err)
assert.Assert(t, action.Matches("update", "services"))
updatedTemplate, err := servinglib.RevisionTemplateOfService(updated)
assert.NilError(t, err)
assert.DeepEqual(t, updatedTemplate.Spec.Containers[0].Command, []string{"/app/start"})
}
func TestServiceUpdateArg(t *testing.T) {
orig := newEmptyService()
origTemplate, err := servinglib.RevisionTemplateOfService(orig)
assert.NilError(t, err)
err = servinglib.UpdateContainerArg(origTemplate, []string{"myArg0"})
assert.NilError(t, err)
action, updated, _, err := fakeServiceUpdate(orig, []string{
"service", "update", "foo", "--arg", "myArg1", "--arg", "--myArg2", "--arg", "--myArg3=3", "--async"}, false)
assert.NilError(t, err)
assert.Assert(t, action.Matches("update", "services"))
updatedTemplate, err := servinglib.RevisionTemplateOfService(updated)
assert.NilError(t, err)
assert.DeepEqual(t, updatedTemplate.Spec.Containers[0].Args, []string{"myArg1", "--myArg2", "--myArg3=3"})
}
func TestServiceUpdateRevisionNameExplicit(t *testing.T) { func TestServiceUpdateRevisionNameExplicit(t *testing.T) {
orig := newEmptyServiceBetaAPIStyle() orig := newEmptyServiceBetaAPIStyle()

View File

@ -314,6 +314,26 @@ func FreezeImageToDigest(template *servingv1alpha1.RevisionTemplateSpec, baseRev
return nil return nil
} }
// UpdateContainerCommand updates container with a given argument
func UpdateContainerCommand(template *servingv1alpha1.RevisionTemplateSpec, command string) error {
container, err := ContainerOfRevisionTemplate(template)
if err != nil {
return err
}
container.Command = []string{command}
return nil
}
// UpdateContainerArg updates container with a given argument
func UpdateContainerArg(template *servingv1alpha1.RevisionTemplateSpec, arg []string) error {
container, err := ContainerOfRevisionTemplate(template)
if err != nil {
return err
}
container.Args = arg
return nil
}
// UpdateContainerPort updates container with a give port // UpdateContainerPort updates container with a give port
func UpdateContainerPort(template *servingv1alpha1.RevisionTemplateSpec, port int32) error { func UpdateContainerPort(template *servingv1alpha1.RevisionTemplateSpec, port int32) error {
container, err := ContainerOfRevisionTemplate(template) container, err := ContainerOfRevisionTemplate(template)

View File

@ -295,6 +295,28 @@ func checkContainerImage(t *testing.T, template *servingv1alpha1.RevisionTemplat
} }
} }
func TestUpdateContainerCommand(t *testing.T) {
template, _ := getV1alpha1RevisionTemplateWithOldFields()
err := UpdateContainerCommand(template, "/app/start")
assert.NilError(t, err)
assert.DeepEqual(t, template.Spec.GetContainer().Command, []string{"/app/start"})
err = UpdateContainerCommand(template, "/app/latest")
assert.NilError(t, err)
assert.DeepEqual(t, template.Spec.GetContainer().Command, []string{"/app/latest"})
}
func TestUpdateContainerArg(t *testing.T) {
template, _ := getV1alpha1RevisionTemplateWithOldFields()
err := UpdateContainerArg(template, []string{"--myArg"})
assert.NilError(t, err)
assert.DeepEqual(t, template.Spec.GetContainer().Args, []string{"--myArg"})
err = UpdateContainerArg(template, []string{"myArg1", "--myArg2"})
assert.NilError(t, err)
assert.DeepEqual(t, template.Spec.GetContainer().Args, []string{"myArg1", "--myArg2"})
}
func TestUpdateContainerPort(t *testing.T) { func TestUpdateContainerPort(t *testing.T) {
template, _ := getV1alpha1Config() template, _ := getV1alpha1Config()
err := UpdateContainerPort(template, 8888) err := UpdateContainerPort(template, 8888)