mirror of https://github.com/knative/client.git
Add --user flag for service create and update (#679)
* add run as user flag #678 * add run as user flag #678 * add changelog for pr 679 * review comments for pr 679 * review comments for pr 679 * add test for config changes * add user flag
This commit is contained in:
parent
ab00cc2969
commit
66173059fc
|
|
@ -59,6 +59,10 @@
|
||||||
| 🧽
|
| 🧽
|
||||||
| Add `--wait` and `--no-wait` to service delete operation. Change service delete to wait by default.
|
| Add `--wait` and `--no-wait` to service delete operation. Change service delete to wait by default.
|
||||||
| https://github.com/knative/client/pull/682[#682]
|
| https://github.com/knative/client/pull/682[#682]
|
||||||
|
|
||||||
|
| 🎁
|
||||||
|
| Add `--user` flag for specifying the user id to run the container
|
||||||
|
| https://github.com/knative/client/pull/679[#679]
|
||||||
|===
|
|===
|
||||||
|
|
||||||
## v0.12.0 (2020-01-29)
|
## v0.12.0 (2020-01-29)
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,7 @@ kn service create NAME --image IMAGE [flags]
|
||||||
--requests-memory string The requested memory (e.g., 64Mi).
|
--requests-memory string 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}}")
|
--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}}")
|
||||||
--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.
|
--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.
|
||||||
|
--user int The user ID to run the container (e.g., 1001).
|
||||||
--volume stringArray Add a volume from a ConfigMap (prefix cm: or config-map:) or a Secret (prefix secret: or sc:). Example: --volume myvolume=cm:myconfigmap or --volume myvolume=secret:mysecret. You can use this flag multiple times. To unset a ConfigMap/Secret reference, append "-" to the name, e.g. --volume myvolume-.
|
--volume stringArray Add a volume from a ConfigMap (prefix cm: or config-map:) or a Secret (prefix secret: or sc:). Example: --volume myvolume=cm:myconfigmap or --volume myvolume=secret:mysecret. You can use this flag multiple times. To unset a ConfigMap/Secret reference, append "-" to the name, e.g. --volume myvolume-.
|
||||||
--wait-timeout int Seconds to wait before giving up on waiting for service to be ready. (default 600)
|
--wait-timeout int Seconds to wait before giving up on waiting for service to be ready. (default 600)
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,7 @@ kn service update NAME [flags]
|
||||||
--tag strings Set tag (format: --tag revisionRef=tagName) where revisionRef can be a revision or '@latest' string representing latest ready revision. This flag can be specified multiple times.
|
--tag strings Set tag (format: --tag revisionRef=tagName) where revisionRef can be a revision or '@latest' string representing latest ready revision. This flag can be specified multiple times.
|
||||||
--traffic strings Set traffic distribution (format: --traffic revisionRef=percent) where revisionRef can be a revision or a tag or '@latest' string representing latest ready revision. This flag can be given multiple times with percent summing up to 100%.
|
--traffic strings Set traffic distribution (format: --traffic revisionRef=percent) where revisionRef can be a revision or a tag or '@latest' string representing latest ready revision. This flag can be given multiple times with percent summing up to 100%.
|
||||||
--untag strings Untag revision (format: --untag tagName). This flag can be specified multiple times.
|
--untag strings Untag revision (format: --untag tagName). This flag can be specified multiple times.
|
||||||
|
--user int The user ID to run the container (e.g., 1001).
|
||||||
--volume stringArray Add a volume from a ConfigMap (prefix cm: or config-map:) or a Secret (prefix secret: or sc:). Example: --volume myvolume=cm:myconfigmap or --volume myvolume=secret:mysecret. You can use this flag multiple times. To unset a ConfigMap/Secret reference, append "-" to the name, e.g. --volume myvolume-.
|
--volume stringArray Add a volume from a ConfigMap (prefix cm: or config-map:) or a Secret (prefix secret: or sc:). Example: --volume myvolume=cm:myconfigmap or --volume myvolume=secret:mysecret. You can use this flag multiple times. To unset a ConfigMap/Secret reference, append "-" to the name, e.g. --volume myvolume-.
|
||||||
--wait-timeout int Seconds to wait before giving up on waiting for service to be ready. (default 600)
|
--wait-timeout int Seconds to wait before giving up on waiting for service to be ready. (default 600)
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ type ConfigurationEditFlags struct {
|
||||||
ServiceAccountName string
|
ServiceAccountName string
|
||||||
ImagePullSecrets string
|
ImagePullSecrets string
|
||||||
Annotations []string
|
Annotations []string
|
||||||
|
User int64
|
||||||
|
|
||||||
// Preferences about how to do the action.
|
// Preferences about how to do the action.
|
||||||
LockToDigest bool
|
LockToDigest bool
|
||||||
|
|
@ -189,6 +190,8 @@ func (p *ConfigurationEditFlags) addSharedFlags(command *cobra.Command) {
|
||||||
"",
|
"",
|
||||||
"Image pull secret to set. An empty argument (\"\") clears the pull secret. The referenced secret must exist in the service's namespace.")
|
"Image pull secret to set. An empty argument (\"\") clears the pull secret. The referenced secret must exist in the service's namespace.")
|
||||||
p.markFlagMakesRevision("pull-secret")
|
p.markFlagMakesRevision("pull-secret")
|
||||||
|
command.Flags().Int64VarP(&p.User, "user", "", 0, "The user ID to run the container (e.g., 1001).")
|
||||||
|
p.markFlagMakesRevision("user")
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddUpdateFlags adds the flags specific to update.
|
// AddUpdateFlags adds the flags specific to update.
|
||||||
|
|
@ -396,6 +399,10 @@ func (p *ConfigurationEditFlags) Apply(
|
||||||
servinglib.UpdateImagePullSecrets(template, p.ImagePullSecrets)
|
servinglib.UpdateImagePullSecrets(template, p.ImagePullSecrets)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cmd.Flags().Changed("user") {
|
||||||
|
servinglib.UpdateUser(template, p.User)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ import (
|
||||||
"knative.dev/client/pkg/wait"
|
"knative.dev/client/pkg/wait"
|
||||||
|
|
||||||
"knative.dev/client/pkg/util"
|
"knative.dev/client/pkg/util"
|
||||||
|
"knative.dev/pkg/ptr"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestServiceCreateImageMock(t *testing.T) {
|
func TestServiceCreateImageMock(t *testing.T) {
|
||||||
|
|
@ -385,6 +386,29 @@ func TestServiceCreateWithMountSecret(t *testing.T) {
|
||||||
r.Validate()
|
r.Validate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestServiceCreateWithUser(t *testing.T) {
|
||||||
|
client := knclient.NewMockKnServiceClient(t)
|
||||||
|
|
||||||
|
r := client.Recorder()
|
||||||
|
r.GetService("foo", nil, errors.NewNotFound(servingv1.Resource("service"), "foo"))
|
||||||
|
|
||||||
|
service := getService("foo")
|
||||||
|
|
||||||
|
template := &service.Spec.Template
|
||||||
|
template.Spec.Containers[0].SecurityContext = &corev1.SecurityContext{
|
||||||
|
RunAsUser: ptr.Int64(int64(1001)),
|
||||||
|
}
|
||||||
|
template.Spec.Containers[0].Image = "gcr.io/foo/bar:baz"
|
||||||
|
template.Annotations = map[string]string{servinglib.UserImageAnnotationKey: "gcr.io/foo/bar:baz"}
|
||||||
|
r.CreateService(service, nil)
|
||||||
|
|
||||||
|
output, err := executeServiceCommand(client, "create", "foo", "--image", "gcr.io/foo/bar:baz", "--user", "1001", "--no-wait", "--revision-name=")
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Assert(t, util.ContainsAll(output, "created", "foo", "default"))
|
||||||
|
|
||||||
|
r.Validate()
|
||||||
|
}
|
||||||
|
|
||||||
func getService(name string) *servingv1.Service {
|
func getService(name string) *servingv1.Service {
|
||||||
service := &servingv1.Service{
|
service := &servingv1.Service{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import (
|
||||||
clientserving "knative.dev/client/pkg/serving"
|
clientserving "knative.dev/client/pkg/serving"
|
||||||
clientservingv1 "knative.dev/client/pkg/serving/v1"
|
clientservingv1 "knative.dev/client/pkg/serving/v1"
|
||||||
"knative.dev/client/pkg/util"
|
"knative.dev/client/pkg/util"
|
||||||
|
"knative.dev/pkg/ptr"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestServiceUpdateEnvMock(t *testing.T) {
|
func TestServiceUpdateEnvMock(t *testing.T) {
|
||||||
|
|
@ -1427,3 +1428,48 @@ func TestServiceUpdateWithRemovingMount(t *testing.T) {
|
||||||
|
|
||||||
r.Validate()
|
r.Validate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestServiceUpdateUser(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"
|
||||||
|
template.Spec.Containers[0].SecurityContext = &corev1.SecurityContext{
|
||||||
|
RunAsUser: ptr.Int64(int64(1001)),
|
||||||
|
}
|
||||||
|
template.ObjectMeta.Annotations = map[string]string{
|
||||||
|
clientserving.UserImageAnnotationKey: "gcr.io/foo/bar:baz",
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedService := getService(svcName)
|
||||||
|
template = &updatedService.Spec.Template
|
||||||
|
template.Spec.Containers[0].Image = "gcr.io/foo/bar:baz"
|
||||||
|
template.Spec.Containers[0].SecurityContext = &corev1.SecurityContext{
|
||||||
|
RunAsUser: ptr.Int64(int64(1002)),
|
||||||
|
}
|
||||||
|
template.ObjectMeta.Annotations = map[string]string{
|
||||||
|
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",
|
||||||
|
"--user", "1001",
|
||||||
|
"--no-wait", "--revision-name=",
|
||||||
|
)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Assert(t, util.ContainsAll(output, "created", svcName, "default"))
|
||||||
|
|
||||||
|
output, err = executeServiceCommand(client,
|
||||||
|
"update", svcName,
|
||||||
|
"--user", "1002",
|
||||||
|
"--no-wait", "--revision-name=",
|
||||||
|
)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Assert(t, util.ContainsAll(output, "updated", svcName, "default"))
|
||||||
|
|
||||||
|
r.Validate()
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -337,6 +337,18 @@ func UpdateContainerPort(template *servingv1.RevisionTemplateSpec, port int32) e
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateRunAsUser updates container with a given user id
|
||||||
|
func UpdateUser(template *servingv1.RevisionTemplateSpec, user int64) error {
|
||||||
|
container, err := ContainerOfRevisionTemplate(template)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
container.SecurityContext = &corev1.SecurityContext{
|
||||||
|
RunAsUser: &user,
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateResources updates resources as requested
|
// UpdateResources updates resources as requested
|
||||||
func UpdateResources(template *servingv1.RevisionTemplateSpec, requestsResourceList corev1.ResourceList, limitsResourceList corev1.ResourceList) error {
|
func UpdateResources(template *servingv1.RevisionTemplateSpec, requestsResourceList corev1.ResourceList, limitsResourceList corev1.ResourceList) error {
|
||||||
container, err := ContainerOfRevisionTemplate(template)
|
container, err := ContainerOfRevisionTemplate(template)
|
||||||
|
|
|
||||||
|
|
@ -300,6 +300,10 @@ func checkPortUpdate(t *testing.T, template *servingv1.RevisionTemplateSpec, por
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkUserUpdate(t *testing.T, template *servingv1.RevisionTemplateSpec, user *int64) {
|
||||||
|
assert.DeepEqual(t, template.Spec.Containers[0].SecurityContext.RunAsUser, user)
|
||||||
|
}
|
||||||
|
|
||||||
func TestUpdateEnvVarsBoth(t *testing.T) {
|
func TestUpdateEnvVarsBoth(t *testing.T) {
|
||||||
template, container := getRevisionTemplate()
|
template, container := getRevisionTemplate()
|
||||||
container.Env = []corev1.EnvVar{
|
container.Env = []corev1.EnvVar{
|
||||||
|
|
@ -649,6 +653,20 @@ func TestGenerateVolumeName(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUpdateUser(t *testing.T) {
|
||||||
|
template, _ := getRevisionTemplate()
|
||||||
|
err := UpdateUser(template, int64(1001))
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
checkUserUpdate(t, template, ptr.Int64(int64(1001)))
|
||||||
|
|
||||||
|
template.Spec.Containers[0].SecurityContext.RunAsUser = ptr.Int64(int64(1002))
|
||||||
|
err = UpdateUser(template, int64(1002))
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
checkUserUpdate(t, template, ptr.Int64(int64(1002)))
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// =========================================================================================================
|
// =========================================================================================================
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue