mirror of
https://github.com/ceph/ceph-csi.git
synced 2024-11-22 14:20:19 +00:00
util: make ExecComand return stdout and stderr as string
Most consumers of util.ExecCommand() need to convert the returned []byte format of stdout and/or stderr to string. By having util.ExecCommand() return strings instead, the code gets a little simpler. A few commands return JSON that needs to be parsed. These commands will be replaced by go-ceph implementations later on. For now, convert the strings back to []byte when needed. Signed-off-by: Niels de Vos <ndevos@redhat.com>
This commit is contained in:
parent
ddac66d76b
commit
36469b87e2
@ -41,7 +41,7 @@ func execCommandJSON(ctx context.Context, v interface{}, program string, args ..
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = json.Unmarshal(stdout, v); err != nil {
|
if err = json.Unmarshal([]byte(stdout), v); err != nil {
|
||||||
return fmt.Errorf("failed to unmarshal JSON for %s %v: %s: %w", program, util.StripSecretInArgs(args), stdout, err)
|
return fmt.Errorf("failed to unmarshal JSON for %s %v: %s: %w", program, util.StripSecretInArgs(args), stdout, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,16 +67,15 @@ func getVolumeRootPathCeph(ctx context.Context, volOptions *volumeOptions, cr *u
|
|||||||
"--keyfile="+cr.KeyFile)
|
"--keyfile="+cr.KeyFile)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
stdErrString := string(stderr)
|
klog.Errorf(util.Log(ctx, "failed to get the rootpath for the vol %s(%s) stdError %s"), string(volID), err, stderr)
|
||||||
klog.Errorf(util.Log(ctx, "failed to get the rootpath for the vol %s(%s) stdError %s"), string(volID), err, stdErrString)
|
|
||||||
|
|
||||||
if strings.HasPrefix(stdErrString, errNotFoundString) {
|
if strings.HasPrefix(stderr, errNotFoundString) {
|
||||||
return "", util.JoinErrors(ErrVolumeNotFound, err)
|
return "", util.JoinErrors(ErrVolumeNotFound, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return strings.TrimSuffix(string(stdout), "\n"), nil
|
return strings.TrimSuffix(stdout, "\n"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type localClusterState struct {
|
type localClusterState struct {
|
||||||
|
@ -176,7 +176,7 @@ func mountFuse(ctx context.Context, mountPoint string, cr *util.Credentials, vol
|
|||||||
// We need "starting fuse" meaning the mount is ok
|
// We need "starting fuse" meaning the mount is ok
|
||||||
// and PID of the ceph-fuse daemon for unmount
|
// and PID of the ceph-fuse daemon for unmount
|
||||||
|
|
||||||
match := fusePidRx.FindSubmatch(stderr)
|
match := fusePidRx.FindSubmatch([]byte(stderr))
|
||||||
// validMatchLength is set to 2 as match is expected
|
// validMatchLength is set to 2 as match is expected
|
||||||
// to have 2 items, starting fuse and PID of the fuse daemon
|
// to have 2 items, starting fuse and PID of the fuse daemon
|
||||||
const validMatchLength = 2
|
const validMatchLength = 2
|
||||||
|
@ -90,9 +90,9 @@ func rbdGetDeviceList(ctx context.Context, accessType string) ([]rbdDeviceInfo,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if accessType == accessTypeKRbd {
|
if accessType == accessTypeKRbd {
|
||||||
err = json.Unmarshal(stdout, &rbdDeviceList)
|
err = json.Unmarshal([]byte(stdout), &rbdDeviceList)
|
||||||
} else {
|
} else {
|
||||||
err = json.Unmarshal(stdout, &nbdDeviceList)
|
err = json.Unmarshal([]byte(stdout), &nbdDeviceList)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error to parse JSON output of device list for devices of type (%s): (%v)", accessType, err)
|
return nil, fmt.Errorf("error to parse JSON output of device list for devices of type (%s): (%v)", accessType, err)
|
||||||
@ -231,7 +231,7 @@ func createPath(ctx context.Context, volOpt *rbdVolume, cr *util.Credentials) (s
|
|||||||
// Execute map
|
// Execute map
|
||||||
stdout, stderr, err := util.ExecCommand(ctx, rbd, mapOptions...)
|
stdout, stderr, err := util.ExecCommand(ctx, rbd, mapOptions...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Warningf(util.Log(ctx, "rbd: map error %v, rbd output: %s"), err, string(stderr))
|
klog.Warningf(util.Log(ctx, "rbd: map error %v, rbd output: %s"), err, stderr)
|
||||||
// unmap rbd image if connection timeout
|
// unmap rbd image if connection timeout
|
||||||
if strings.Contains(err.Error(), rbdMapConnectionTimeout) {
|
if strings.Contains(err.Error(), rbdMapConnectionTimeout) {
|
||||||
detErr := detachRBDImageOrDeviceSpec(ctx, imagePath, true, isNbd, volOpt.Encrypted, volOpt.VolID)
|
detErr := detachRBDImageOrDeviceSpec(ctx, imagePath, true, isNbd, volOpt.Encrypted, volOpt.VolID)
|
||||||
@ -239,9 +239,9 @@ func createPath(ctx context.Context, volOpt *rbdVolume, cr *util.Credentials) (s
|
|||||||
klog.Warningf(util.Log(ctx, "rbd: %s unmap error %v"), imagePath, detErr)
|
klog.Warningf(util.Log(ctx, "rbd: %s unmap error %v"), imagePath, detErr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "", fmt.Errorf("rbd: map failed %v, rbd output: %s", err, string(stderr))
|
return "", fmt.Errorf("rbd: map failed with error %v, rbd error output: %s", err, stderr)
|
||||||
}
|
}
|
||||||
devicePath := strings.TrimSuffix(string(stdout), "\n")
|
devicePath := strings.TrimSuffix(stdout, "\n")
|
||||||
|
|
||||||
return devicePath, nil
|
return devicePath, nil
|
||||||
}
|
}
|
||||||
@ -311,13 +311,13 @@ func detachRBDImageOrDeviceSpec(ctx context.Context, imageOrDeviceSpec string, i
|
|||||||
// Messages for krbd and nbd differ, hence checking either of them for missing mapping
|
// Messages for krbd and nbd differ, hence checking either of them for missing mapping
|
||||||
// This is not applicable when a device path is passed in
|
// This is not applicable when a device path is passed in
|
||||||
if isImageSpec &&
|
if isImageSpec &&
|
||||||
(strings.Contains(string(stderr), fmt.Sprintf(rbdUnmapCmdkRbdMissingMap, imageOrDeviceSpec)) ||
|
(strings.Contains(stderr, fmt.Sprintf(rbdUnmapCmdkRbdMissingMap, imageOrDeviceSpec)) ||
|
||||||
strings.Contains(string(stderr), fmt.Sprintf(rbdUnmapCmdNbdMissingMap, imageOrDeviceSpec))) {
|
strings.Contains(stderr, fmt.Sprintf(rbdUnmapCmdNbdMissingMap, imageOrDeviceSpec))) {
|
||||||
// Devices found not to be mapped are treated as a successful detach
|
// Devices found not to be mapped are treated as a successful detach
|
||||||
util.TraceLog(ctx, "image or device spec (%s) not mapped", imageOrDeviceSpec)
|
util.TraceLog(ctx, "image or device spec (%s) not mapped", imageOrDeviceSpec)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return fmt.Errorf("rbd: unmap for spec (%s) failed (%v): (%s)", imageOrDeviceSpec, err, string(stderr))
|
return fmt.Errorf("rbd: unmap for spec (%s) failed (%v): (%s)", imageOrDeviceSpec, err, stderr)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -307,11 +307,11 @@ func addRbdManagerTask(ctx context.Context, pOpts *rbdVolume, arg []string) (boo
|
|||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch {
|
switch {
|
||||||
case strings.Contains(string(stderr), rbdTaskRemoveCmdInvalidString1) &&
|
case strings.Contains(stderr, rbdTaskRemoveCmdInvalidString1) &&
|
||||||
strings.Contains(string(stderr), rbdTaskRemoveCmdInvalidString2):
|
strings.Contains(stderr, rbdTaskRemoveCmdInvalidString2):
|
||||||
klog.Warningf(util.Log(ctx, "cluster with cluster ID (%s) does not support Ceph manager based rbd commands (minimum ceph version required is v14.2.3)"), pOpts.ClusterID)
|
klog.Warningf(util.Log(ctx, "cluster with cluster ID (%s) does not support Ceph manager based rbd commands (minimum ceph version required is v14.2.3)"), pOpts.ClusterID)
|
||||||
supported = false
|
supported = false
|
||||||
case strings.HasPrefix(string(stderr), rbdTaskRemoveCmdAccessDeniedMessage):
|
case strings.HasPrefix(stderr, rbdTaskRemoveCmdAccessDeniedMessage):
|
||||||
klog.Warningf(util.Log(ctx, "access denied to Ceph MGR-based rbd commands on cluster ID (%s)"), pOpts.ClusterID)
|
klog.Warningf(util.Log(ctx, "access denied to Ceph MGR-based rbd commands on cluster ID (%s)"), pOpts.ClusterID)
|
||||||
supported = false
|
supported = false
|
||||||
default:
|
default:
|
||||||
@ -883,17 +883,17 @@ func (rv *rbdVolume) updateVolWithImageInfo(cr *util.Credentials) error {
|
|||||||
"info", rv.String())
|
"info", rv.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf("failed getting information for image (%s): (%s)", rv, err)
|
klog.Errorf("failed getting information for image (%s): (%s)", rv, err)
|
||||||
if strings.Contains(string(stderr), "rbd: error opening image "+rv.RbdImageName+
|
if strings.Contains(stderr, "rbd: error opening image "+rv.RbdImageName+
|
||||||
": (2) No such file or directory") {
|
": (2) No such file or directory") {
|
||||||
return util.JoinErrors(ErrImageNotFound, err)
|
return util.JoinErrors(ErrImageNotFound, err)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = json.Unmarshal(stdout, &imgInfo)
|
err = json.Unmarshal([]byte(stdout), &imgInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf("failed to parse JSON output of image info (%s): (%s)", rv, err)
|
klog.Errorf("failed to parse JSON output of image info (%s): (%s)", rv, err)
|
||||||
return fmt.Errorf("unmarshal failed: %+v. raw buffer response: %s", err, string(stdout))
|
return fmt.Errorf("unmarshal failed: %+v. raw buffer response: %s", err, stdout)
|
||||||
}
|
}
|
||||||
|
|
||||||
rv.VolSize = imgInfo.Size
|
rv.VolSize = imgInfo.Size
|
||||||
@ -1051,7 +1051,7 @@ func resizeRBDImage(rbdVol *rbdVolume, cr *util.Credentials) error {
|
|||||||
_, stderr, err := util.ExecCommand(context.TODO(), "rbd", args...)
|
_, stderr, err := util.ExecCommand(context.TODO(), "rbd", args...)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to resize rbd image (%w), command output: %s", err, string(stderr))
|
return fmt.Errorf("failed to resize rbd image (%w), command output: %s", err, stderr)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -1129,17 +1129,17 @@ func (rv *rbdVolume) listSnapshots(ctx context.Context, cr *util.Credentials) ([
|
|||||||
"--all", rv.String())
|
"--all", rv.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf(util.Log(ctx, "failed getting information for image (%s): (%s)"), rv, err)
|
klog.Errorf(util.Log(ctx, "failed getting information for image (%s): (%s)"), rv, err)
|
||||||
if strings.Contains(string(stderr), "rbd: error opening image "+rv.RbdImageName+
|
if strings.Contains(stderr, "rbd: error opening image "+rv.RbdImageName+
|
||||||
": (2) No such file or directory") {
|
": (2) No such file or directory") {
|
||||||
return snapInfo, util.JoinErrors(ErrImageNotFound, err)
|
return snapInfo, util.JoinErrors(ErrImageNotFound, err)
|
||||||
}
|
}
|
||||||
return snapInfo, err
|
return snapInfo, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = json.Unmarshal(stdout, &snapInfo)
|
err = json.Unmarshal([]byte(stdout), &snapInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf(util.Log(ctx, "failed to parse JSON output of snapshot info (%s)"), err)
|
klog.Errorf(util.Log(ctx, "failed to parse JSON output of snapshot info (%s)"), err)
|
||||||
return snapInfo, fmt.Errorf("unmarshal failed: %w. raw buffer response: %s", err, string(stdout))
|
return snapInfo, fmt.Errorf("unmarshal failed: %w. raw buffer response: %s", err, stdout)
|
||||||
}
|
}
|
||||||
return snapInfo, nil
|
return snapInfo, nil
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ const InvalidPoolID int64 = -1
|
|||||||
// ExecCommand executes passed in program with args and returns separate stdout
|
// ExecCommand executes passed in program with args and returns separate stdout
|
||||||
// and stderr streams. In case ctx is not set to context.TODO(), the command
|
// and stderr streams. In case ctx is not set to context.TODO(), the command
|
||||||
// will be logged after it was executed.
|
// will be logged after it was executed.
|
||||||
func ExecCommand(ctx context.Context, program string, args ...string) (stdout, stderr []byte, err error) {
|
func ExecCommand(ctx context.Context, program string, args ...string) (string, string, error) {
|
||||||
var (
|
var (
|
||||||
cmd = exec.Command(program, args...) // #nosec:G204, commands executing not vulnerable.
|
cmd = exec.Command(program, args...) // #nosec:G204, commands executing not vulnerable.
|
||||||
sanitizedArgs = StripSecretInArgs(args)
|
sanitizedArgs = StripSecretInArgs(args)
|
||||||
@ -44,19 +44,23 @@ func ExecCommand(ctx context.Context, program string, args ...string) (stdout, s
|
|||||||
cmd.Stdout = &stdoutBuf
|
cmd.Stdout = &stdoutBuf
|
||||||
cmd.Stderr = &stderrBuf
|
cmd.Stderr = &stderrBuf
|
||||||
|
|
||||||
if err := cmd.Run(); err != nil {
|
err := cmd.Run()
|
||||||
|
stdout := stdoutBuf.String()
|
||||||
|
stderr := stderrBuf.String()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
err = fmt.Errorf("an error (%w) occurred while running %s args: %v", err, program, sanitizedArgs)
|
err = fmt.Errorf("an error (%w) occurred while running %s args: %v", err, program, sanitizedArgs)
|
||||||
if ctx != context.TODO() {
|
if ctx != context.TODO() {
|
||||||
UsefulLog(ctx, "%s", err)
|
UsefulLog(ctx, "%s", err)
|
||||||
}
|
}
|
||||||
return stdoutBuf.Bytes(), stderrBuf.Bytes(), err
|
return stdout, stderr, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx != context.TODO() {
|
if ctx != context.TODO() {
|
||||||
UsefulLog(ctx, "command succeeded: %s %v", program, sanitizedArgs)
|
UsefulLog(ctx, "command succeeded: %s %v", program, sanitizedArgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
return stdoutBuf.Bytes(), nil, nil
|
return stdout, stderr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPoolID fetches the ID of the pool that matches the passed in poolName
|
// GetPoolID fetches the ID of the pool that matches the passed in poolName
|
||||||
|
Loading…
Reference in New Issue
Block a user