mirror of
https://github.com/kubernetes/kubectl.git
synced 2026-06-08 16:23:21 -04:00
Merge pull request #101669 from carlory/fix-kubectl-1042
fix kubectl set env or resources not working for initcontainers Kubernetes-commit: 8634bc61c635717dec93128f8908ffd20774e66f
This commit is contained in:
commit
d005bb9a51
7 changed files with 227 additions and 15 deletions
6
Godeps/Godeps.json
generated
6
Godeps/Godeps.json
generated
|
|
@ -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",
|
||||
|
|
|
|||
12
go.mod
12
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
|
||||
)
|
||||
|
|
|
|||
12
go.sum
12
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=
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue