diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 9dbd01563..1bf60f777 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -1040,11 +1040,11 @@ }, { "ImportPath": "k8s.io/api", - "Rev": "020341df4dc8" + "Rev": "929601b97a81" }, { "ImportPath": "k8s.io/apimachinery", - "Rev": "96c076bf1d97" + "Rev": "4c2cee4b928c" }, { "ImportPath": "k8s.io/cli-runtime", @@ -1060,7 +1060,7 @@ }, { "ImportPath": "k8s.io/component-base", - "Rev": "44faecbf614e" + "Rev": "18af7a2c44df" }, { "ImportPath": "k8s.io/component-helpers", diff --git a/go.mod b/go.mod index 05158a050..dc2f77830 100644 --- a/go.mod +++ b/go.mod @@ -32,11 +32,11 @@ require ( github.com/stretchr/testify v1.6.1 golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073 gopkg.in/yaml.v2 v2.4.0 - k8s.io/api v0.0.0-20210518101613-020341df4dc8 - k8s.io/apimachinery v0.0.0-20210518100457-96c076bf1d97 + k8s.io/api v0.0.0-20210518101620-929601b97a81 + k8s.io/apimachinery v0.0.0-20210518100458-4c2cee4b928c k8s.io/cli-runtime v0.0.0-20210518124924-2b12152cfa0d k8s.io/client-go v0.0.0-20210518102931-3cca9d72c140 - k8s.io/component-base v0.0.0-20210518111232-44faecbf614e + k8s.io/component-base v0.0.0-20210518111236-18af7a2c44df k8s.io/component-helpers v0.0.0-20210518112016-d2cb76f2050a k8s.io/klog/v2 v2.8.0 k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e @@ -48,12 +48,12 @@ require ( ) replace ( - k8s.io/api => k8s.io/api v0.0.0-20210518101613-020341df4dc8 - k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20210518100457-96c076bf1d97 + k8s.io/api => k8s.io/api v0.0.0-20210518101620-929601b97a81 + k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20210518100458-4c2cee4b928c k8s.io/cli-runtime => k8s.io/cli-runtime v0.0.0-20210518124924-2b12152cfa0d k8s.io/client-go => k8s.io/client-go v0.0.0-20210518102931-3cca9d72c140 k8s.io/code-generator => k8s.io/code-generator v0.0.0-20210518095634-f57bba428cbd - k8s.io/component-base => k8s.io/component-base v0.0.0-20210518111232-44faecbf614e + k8s.io/component-base => k8s.io/component-base v0.0.0-20210518111236-18af7a2c44df k8s.io/component-helpers => k8s.io/component-helpers v0.0.0-20210518112016-d2cb76f2050a k8s.io/metrics => k8s.io/metrics v0.0.0-20210518124134-efe7adfc18ed ) diff --git a/go.sum b/go.sum index 9f56cbc42..74eb0218b 100644 --- a/go.sum +++ b/go.sum @@ -731,17 +731,17 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.0.0-20210518101613-020341df4dc8 h1:ZRnEhwbQkikrh5x6TweXojo/X728NYotNn0j+tvQMfM= -k8s.io/api v0.0.0-20210518101613-020341df4dc8/go.mod h1:mfjSaVjQka7B+LlvX2q/KG3mXhs8HgdQT3ipatqYfU0= -k8s.io/apimachinery v0.0.0-20210518100457-96c076bf1d97 h1:hKyy5Pr8MoGjcqM5AYHQjpizciRmC8dz4N3XG4LZwuQ= -k8s.io/apimachinery v0.0.0-20210518100457-96c076bf1d97/go.mod h1:fBRSkoylGO2QUTae8Wb2wac6pZ83/r+tL6HFSXGbzfs= +k8s.io/api v0.0.0-20210518101620-929601b97a81 h1:HNRijF8MROYeNc8pUar2jkVz5vjJYD6ITNzWvdETjD4= +k8s.io/api v0.0.0-20210518101620-929601b97a81/go.mod h1:y+gvByfVKNWO6mErcyYTqghJvmW73GJQPxjlYKfOuio= +k8s.io/apimachinery v0.0.0-20210518100458-4c2cee4b928c h1:4cylLlCjbU4MC+jV8O68gmICP2kk8agE4tceRMAljVs= +k8s.io/apimachinery v0.0.0-20210518100458-4c2cee4b928c/go.mod h1:fBRSkoylGO2QUTae8Wb2wac6pZ83/r+tL6HFSXGbzfs= k8s.io/cli-runtime v0.0.0-20210518124924-2b12152cfa0d h1:RFVr7FWdCdM4VFNKGXOLiPTJ/J1JVdBbTKY+ZPMIWXA= k8s.io/cli-runtime v0.0.0-20210518124924-2b12152cfa0d/go.mod h1:YJCKepg/QD72rmBybA7hshzZfcAtjpbcMerf6dyv29g= k8s.io/client-go v0.0.0-20210518102931-3cca9d72c140 h1:GY3mSlGtHMBhojVkVlvYMRGBFJPznw4duMxd8fMQvvg= k8s.io/client-go v0.0.0-20210518102931-3cca9d72c140/go.mod h1:sGoh5eJ2yx5LuKX3C3Wj5zkHlcfHoueMPwbNP2qyRD8= k8s.io/code-generator v0.0.0-20210518095634-f57bba428cbd/go.mod h1:tHNeGA58jE3nJvZLDN0c/5k7P3NlYdjbWuJYK9QiU3s= -k8s.io/component-base v0.0.0-20210518111232-44faecbf614e h1:+LvsEqL+o2/s3SNrTdZm22miglZOm3TPof8oO5pa2F8= -k8s.io/component-base v0.0.0-20210518111232-44faecbf614e/go.mod h1:VYU6k+gXEg7lXm+XCubCKvSlHHI9l+JHRJ0Hw4nrjug= +k8s.io/component-base v0.0.0-20210518111236-18af7a2c44df h1:Qz7sUwbLJpc/VUuBtxZb3seTfKV1hDTx1yAVPI7jnJI= +k8s.io/component-base v0.0.0-20210518111236-18af7a2c44df/go.mod h1:hPm8b9lzwMCIUcu2WyNo0MxrfZcmt+tMkH0FuhUs1Zo= k8s.io/component-helpers v0.0.0-20210518112016-d2cb76f2050a h1:8/j0qwWx0p2tkFBK+URPu6ANIqp1MrZumZvlvfM7FwA= k8s.io/component-helpers v0.0.0-20210518112016-d2cb76f2050a/go.mod h1:h0T3Vxhshgu1I5OuwwqkDdxOM7E3qsIDOA+hnvgxI7M= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= diff --git a/pkg/cmd/set/set_env.go b/pkg/cmd/set/set_env.go index 9c90f3f34..82a96cb27 100644 --- a/pkg/cmd/set/set_env.go +++ b/pkg/cmd/set/set_env.go @@ -365,7 +365,9 @@ func (o *EnvOptions) RunEnv() error { patches := CalculatePatches(infos, scheme.DefaultJSONEncoder(), func(obj runtime.Object) ([]byte, error) { _, err := o.updatePodSpecForObject(obj, func(spec *v1.PodSpec) error { resolutionErrorsEncountered := false + initContainers, _ := selectContainers(spec.InitContainers, o.ContainerSelector) containers, _ := selectContainers(spec.Containers, o.ContainerSelector) + containers = append(containers, initContainers...) objName, err := meta.NewAccessor().Name(obj) if err != nil { return err diff --git a/pkg/cmd/set/set_env_test.go b/pkg/cmd/set/set_env_test.go index ba610207b..baa1a0188 100644 --- a/pkg/cmd/set/set_env_test.go +++ b/pkg/cmd/set/set_env_test.go @@ -666,3 +666,102 @@ func TestSetEnvFromResource(t *testing.T) { }) } } + +func TestSetEnvRemoteWithSpecificContainers(t *testing.T) { + inputs := []struct { + name string + args []string + selector string + + expectedContainers int + }{ + { + name: "all containers", + args: []string{"deployments", "redis", "env=prod"}, + selector: "*", + expectedContainers: 2, + }, + { + name: "use wildcards to select some containers", + args: []string{"deployments", "redis", "env=prod"}, + selector: "red*", + expectedContainers: 1, + }, + { + name: "single container", + args: []string{"deployments", "redis", "env=prod"}, + selector: "redis", + expectedContainers: 1, + }, + } + + for _, input := range inputs { + mockDeployment := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "redis", + Namespace: "test", + }, + Spec: appsv1.DeploymentSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + InitContainers: []corev1.Container{ + { + Name: "init", + Image: "redis", + }, + }, + Containers: []corev1.Container{ + { + Name: "redis", + Image: "redis", + }, + }, + }, + }, + }, + } + t.Run(input.name, func(t *testing.T) { + tf := cmdtesting.NewTestFactory().WithNamespace("test") + defer tf.Cleanup() + tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Version: ""}}} + tf.Client = &fake.RESTClient{ + GroupVersion: schema.GroupVersion{Group: "", Version: "v1"}, + NegotiatedSerializer: scheme.Codecs.WithoutConversion(), + Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { + switch p, m := req.URL.Path, req.Method; { + case p == "/namespaces/test/deployments/redis" && m == http.MethodGet: + return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: objBody(mockDeployment)}, nil + case p == "/namespaces/test/deployments/redis" && m == http.MethodPatch: + stream, err := req.GetBody() + if err != nil { + return nil, err + } + bytes, err := ioutil.ReadAll(stream) + if err != nil { + return nil, err + } + updated := strings.Count(string(bytes), `"value":`+`"`+"prod"+`"`) + if updated != input.expectedContainers { + t.Errorf("expected %d containers to be selected but got %d \n", input.expectedContainers, updated) + } + return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: objBody(mockDeployment)}, nil + default: + t.Errorf("%s: unexpected request: %#v\n%#v", input.name, req.URL, req) + return nil, nil + } + }), + } + streams := genericclioptions.NewTestIOStreamsDiscard() + opts := &EnvOptions{ + PrintFlags: genericclioptions.NewPrintFlags("").WithDefaultOutput("yaml").WithTypeSetter(scheme.Scheme), + ContainerSelector: input.selector, + Overwrite: true, + IOStreams: streams, + } + err := opts.Complete(tf, NewCmdEnv(tf, streams), input.args) + assert.NoError(t, err) + err = opts.RunEnv() + assert.NoError(t, err) + }) + } +} diff --git a/pkg/cmd/set/set_resources.go b/pkg/cmd/set/set_resources.go index 45c3c109c..04dcfafce 100644 --- a/pkg/cmd/set/set_resources.go +++ b/pkg/cmd/set/set_resources.go @@ -232,7 +232,9 @@ func (o *SetResourcesOptions) Run() error { patches := CalculatePatches(o.Infos, scheme.DefaultJSONEncoder(), func(obj runtime.Object) ([]byte, error) { transformed := false _, err := o.UpdatePodSpecForObject(obj, func(spec *v1.PodSpec) error { + initContainers, _ := selectContainers(spec.InitContainers, o.ContainerSelector) containers, _ := selectContainers(spec.Containers, o.ContainerSelector) + containers = append(containers, initContainers...) if len(containers) != 0 { for i := range containers { if len(o.Limits) != 0 && len(containers[i].Resources.Limits) == 0 { diff --git a/pkg/cmd/set/set_resources_test.go b/pkg/cmd/set/set_resources_test.go index 0fe25d349..d667c4d09 100644 --- a/pkg/cmd/set/set_resources_test.go +++ b/pkg/cmd/set/set_resources_test.go @@ -516,3 +516,112 @@ func TestSetResourcesRemote(t *testing.T) { }) } } + +func TestSetResourcesRemoteWithSpecificContainers(t *testing.T) { + inputs := []struct { + name string + selector string + args []string + + expectedContainers int + }{ + { + name: "all containers", + args: []string{"deployments", "redis"}, + selector: "*", + expectedContainers: 2, + }, + { + name: "use wildcards to select some containers", + args: []string{"deployments", "redis"}, + selector: "red*", + expectedContainers: 1, + }, + { + name: "single container", + args: []string{"deployments", "redis"}, + selector: "redis", + expectedContainers: 1, + }, + } + + for _, input := range inputs { + mockDeployment := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "redis", + Namespace: "test", + }, + Spec: appsv1.DeploymentSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + InitContainers: []corev1.Container{ + { + Name: "init", + Image: "redis", + }, + }, + Containers: []corev1.Container{ + { + Name: "redis", + Image: "redis", + }, + }, + }, + }, + }, + } + t.Run(input.name, func(t *testing.T) { + tf := cmdtesting.NewTestFactory().WithNamespace("test") + defer tf.Cleanup() + tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Version: ""}}} + tf.Client = &fake.RESTClient{ + GroupVersion: schema.GroupVersion{Group: "", Version: "v1"}, + NegotiatedSerializer: scheme.Codecs.WithoutConversion(), + Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { + switch p, m := req.URL.Path, req.Method; { + case p == "/namespaces/test/deployments/redis" && m == http.MethodGet: + return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: objBody(mockDeployment)}, nil + case p == "/namespaces/test/deployments/redis" && m == http.MethodPatch: + stream, err := req.GetBody() + if err != nil { + return nil, err + } + bytes, err := ioutil.ReadAll(stream) + if err != nil { + return nil, err + } + updated := strings.Count(string(bytes), "200m") + if updated != input.expectedContainers { + t.Errorf("expected %d containers to be selected but got %d \n", input.expectedContainers, updated) + } + return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: objBody(mockDeployment)}, nil + default: + t.Errorf("%s: unexpected request: %#v\n%#v", input.name, req.URL, req) + return nil, nil + } + }), + } + + outputFormat := "yaml" + + streams := genericclioptions.NewTestIOStreamsDiscard() + cmd := NewCmdResources(tf, streams) + cmd.Flags().Set("output", outputFormat) + opts := SetResourcesOptions{ + PrintFlags: genericclioptions.NewPrintFlags("").WithDefaultOutput(outputFormat).WithTypeSetter(scheme.Scheme), + + Limits: "cpu=200m,memory=512Mi", + ContainerSelector: input.selector, + IOStreams: streams, + } + err := opts.Complete(tf, cmd, input.args) + if err == nil { + err = opts.Validate() + } + if err == nil { + err = opts.Run() + } + assert.NoError(t, err) + }) + } +}