e2e: add isAlreadyExistsCLIError to check known error

added isAlreadyExistsCLIError to check for known error.
if error is already exists we are considering it
as a success.

Signed-off-by: Madhu Rajanna <madhupr007@gmail.com>
(cherry picked from commit dd9fabf747)
This commit is contained in:
Madhu Rajanna 2021-07-28 08:45:43 +05:30 committed by mergify[bot]
parent 72a2b97be2
commit 9e84583063
3 changed files with 163 additions and 0 deletions

View File

@ -43,3 +43,71 @@ func isRetryableAPIError(err error) bool {
return false return false
} }
//nolint:lll // sample output cannot be split into multiple lines.
/*
getStdErr will extract the stderror and returns the actual error message
Sample kubectl output:
error running /usr/local/bin/kubectl --server=https://192.168.39.67:8443 --kubeconfig=***** --namespace=default create -f -:
Command stdout:
stderr:
Error from server (AlreadyExists): error when creating "STDIN": services "csi-rbdplugin-provisioner" already exists
Error from server (AlreadyExists): error when creating "STDIN": deployments.apps "csi-rbdplugin-provisioner" already exists
error:
exit status 1
Sample message returned from this function:
Error from server (AlreadyExists): error when creating "STDIN": services "csi-rbdplugin-provisioner" already exists
Error from server (AlreadyExists): error when creating "STDIN": deployments.apps "csi-rbdplugin-provisioner" already exists.
*/
func getStdErr(errString string) string {
stdErrStr := "stderr:\n"
errStr := "error:\n"
stdErrPosition := strings.Index(errString, stdErrStr)
if stdErrPosition == -1 {
return ""
}
errPosition := strings.Index(errString, errStr)
if errPosition == -1 {
return ""
}
stdErrPositionLength := stdErrPosition + len(stdErrStr)
if stdErrPositionLength >= errPosition {
return ""
}
return errString[stdErrPosition+len(stdErrStr) : errPosition]
}
// isAlreadyExistsCLIError checks for already exists error from kubectl CLI.
func isAlreadyExistsCLIError(err error) bool {
if err == nil {
return false
}
// if multiple resources already exists. each error is separated by newline
stdErr := getStdErr(err.Error())
if stdErr == "" {
return false
}
stdErrs := strings.Split(stdErr, "\n")
for _, s := range stdErrs {
// If the string is just a new line continue
if strings.TrimSuffix(s, "\n") == "" {
continue
}
// Resource already exists error message
if !strings.Contains(s, "Error from server (AlreadyExists)") {
return false
}
}
return true
}

89
e2e/errors_test.go Normal file
View File

@ -0,0 +1,89 @@
/*
Copyright 2020 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package e2e
import (
"fmt"
"testing"
)
// nolint:lll // error string cannot be split into multiple lines as is a
// output from kubectl.
func TestGetStdErr(t *testing.T) {
t.Parallel()
tests := []struct {
name string
errString string
expected string
isAlreadyExistError bool
}{
{
name: "stdErr output when error is found",
errString: `
error running /usr/local/bin/kubectl --server=https://192.168.39.67:8443 --kubeconfig=***** --namespace=default create -f -:
Command stdout:
stderr:
Error from server (AlreadyExists): error when creating "STDIN": services "csi-rbdplugin-provisioner" already exists
Error from server (AlreadyExists): error when creating "STDIN": deployments.apps "csi-rbdplugin-provisioner" already exists
error:
exit status 1`,
expected: `Error from server (AlreadyExists): error when creating "STDIN": services "csi-rbdplugin-provisioner" already exists
Error from server (AlreadyExists): error when creating "STDIN": deployments.apps "csi-rbdplugin-provisioner" already exists
`,
isAlreadyExistError: true,
},
{
name: "stdErr output when stderr: string is not found",
errString: `
error running /usr/local/bin/kubectl --server=https://192.168.39.67:8443 --kubeconfig=***** --namespace=default create -f -:
Command stdout:
error:
exit status 1`,
expected: "",
isAlreadyExistError: false,
},
{
name: "stdErr output when error: string is not found",
errString: `
error running /usr/local/bin/kubectl --server=https://192.168.39.67:8443 --kubeconfig=***** --namespace=default create -f -:
Command stdout:
stderr:
Error from server (AlreadyExists): error when creating "STDIN": services "csi-rbdplugin-provisioner" already exists
Error from server (AlreadyExists): error when creating "STDIN": deployments.apps "csi-rbdplugin-provisioner" already exists`,
expected: "",
isAlreadyExistError: false,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
if got := getStdErr(tt.errString); got != tt.expected {
t.Errorf("getStdErr() output = %v, expected %v", got, tt.expected)
}
if got := isAlreadyExistsCLIError(fmt.Errorf("%s", tt.errString)); got != tt.isAlreadyExistError {
t.Errorf("isAlreadyExistsCLIError() output = %v, expected %v", got, tt.isAlreadyExistError)
}
})
}
}

View File

@ -1238,6 +1238,9 @@ func retryKubectlInput(namespace string, action kubectlAction, data string, t in
if isRetryableAPIError(err) { if isRetryableAPIError(err) {
return false, nil return false, nil
} }
if isAlreadyExistsCLIError(err) {
return true, nil
}
e2elog.Logf( e2elog.Logf(
"will run kubectl (%s) again (%d seconds elapsed)", "will run kubectl (%s) again (%d seconds elapsed)",
action, action,
@ -1264,6 +1267,9 @@ func retryKubectlFile(namespace string, action kubectlAction, filename string, t
if isRetryableAPIError(err) { if isRetryableAPIError(err) {
return false, nil return false, nil
} }
if isAlreadyExistsCLIError(err) {
return true, nil
}
e2elog.Logf( e2elog.Logf(
"will run kubectl (%s -f %q) again (%d seconds elapsed)", "will run kubectl (%s -f %q) again (%d seconds elapsed)",
action, action,