mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 10:33:35 +00:00
util: add support for the nsenter
add support to run rbd map and mount -t commands with the nsenter. complete design of pod/multus network is added here https://github.com/rook/rook/ blob/master/design/ceph/multus-network.md#csi-pods Signed-off-by: Madhu Rajanna <madhupr007@gmail.com>
This commit is contained in:
committed by
mergify[bot]
parent
6333c4b1e6
commit
7b2aef0d81
@ -21,6 +21,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"time"
|
||||
|
||||
@ -32,6 +33,47 @@ import (
|
||||
// InvalidPoolID used to denote an invalid pool.
|
||||
const InvalidPoolID int64 = -1
|
||||
|
||||
// ExecuteCommandWithNSEnter executes passed in program with args with nsenter
|
||||
// and returns separate stdout and stderr streams. In case ctx is not set to
|
||||
// context.TODO(), the command will be logged after it was executed.
|
||||
func ExecuteCommandWithNSEnter(ctx context.Context, netPath, program string, args ...string) (string, string, error) {
|
||||
var (
|
||||
sanitizedArgs = StripSecretInArgs(args)
|
||||
stdoutBuf bytes.Buffer
|
||||
stderrBuf bytes.Buffer
|
||||
)
|
||||
|
||||
// check netPath exists
|
||||
if _, err := os.Stat(netPath); err != nil {
|
||||
return "", "", fmt.Errorf("failed to get stat for %s %w", netPath, err)
|
||||
}
|
||||
// nsenter --net=%s -- <program> <args>
|
||||
args = append([]string{fmt.Sprintf("--net=%s", netPath), "--", program}, args...)
|
||||
cmd := exec.Command("nsenter", args...) // #nosec:G204, commands executing not vulnerable.
|
||||
|
||||
cmd.Stdout = &stdoutBuf
|
||||
cmd.Stderr = &stderrBuf
|
||||
|
||||
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)
|
||||
if ctx != context.TODO() {
|
||||
log.UsefulLog(ctx, "%s", err)
|
||||
}
|
||||
|
||||
return stdout, stderr, err
|
||||
}
|
||||
|
||||
if ctx != context.TODO() {
|
||||
log.UsefulLog(ctx, "command succeeded: %s %v", program, sanitizedArgs)
|
||||
}
|
||||
|
||||
return stdout, stderr, nil
|
||||
}
|
||||
|
||||
// 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
|
||||
// will be logged after it was executed.
|
||||
|
@ -49,6 +49,8 @@ type ClusterInfo struct {
|
||||
// SubvolumeGroup contains the name of the SubvolumeGroup for CSI volumes
|
||||
SubvolumeGroup string `json:"subvolumeGroup"`
|
||||
} `json:"cephFS"`
|
||||
// symlink filepath for the network namespace where we need to execute commands.
|
||||
NetNamespaceFilePath string `json:"netNamespaceFilePath"`
|
||||
}
|
||||
|
||||
// Expected JSON structure in the passed in config file is,
|
||||
@ -161,3 +163,12 @@ func GetClusterID(options map[string]string) (string, error) {
|
||||
|
||||
return clusterID, nil
|
||||
}
|
||||
|
||||
func GetNetNamespaceFilePath(pathToConfig, clusterID string) (string, error) {
|
||||
cluster, err := readClusterInfo(pathToConfig, clusterID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return cluster.NetNamespaceFilePath, nil
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
||||
package util
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
@ -138,3 +139,69 @@ func TestCSIConfig(t *testing.T) {
|
||||
t.Errorf("Test setup error %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetNetNamespaceFilePath(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := []struct {
|
||||
name string
|
||||
clusterID string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "get NetNamespaceFilePath for cluster-1",
|
||||
clusterID: "cluster-1",
|
||||
want: "/var/lib/kubelet/plugins/rbd.ceph.csi.com/cluster1-net",
|
||||
},
|
||||
{
|
||||
name: "get NetNamespaceFilePath for cluster-2",
|
||||
clusterID: "cluster-2",
|
||||
want: "/var/lib/kubelet/plugins/rbd.ceph.csi.com/cluster2-net",
|
||||
},
|
||||
{
|
||||
name: "when NetNamespaceFilePath is empty",
|
||||
clusterID: "cluster-3",
|
||||
want: "",
|
||||
},
|
||||
}
|
||||
|
||||
csiConfig := []ClusterInfo{
|
||||
{
|
||||
ClusterID: "cluster-1",
|
||||
Monitors: []string{"ip-1", "ip-2"},
|
||||
NetNamespaceFilePath: "/var/lib/kubelet/plugins/rbd.ceph.csi.com/cluster1-net",
|
||||
},
|
||||
{
|
||||
ClusterID: "cluster-2",
|
||||
Monitors: []string{"ip-3", "ip-4"},
|
||||
NetNamespaceFilePath: "/var/lib/kubelet/plugins/rbd.ceph.csi.com/cluster2-net",
|
||||
},
|
||||
{
|
||||
ClusterID: "cluster-3",
|
||||
Monitors: []string{"ip-5", "ip-6"},
|
||||
},
|
||||
}
|
||||
csiConfigFileContent, err := json.Marshal(csiConfig)
|
||||
if err != nil {
|
||||
t.Errorf("failed to marshal csi config info %v", err)
|
||||
}
|
||||
tmpConfPath := t.TempDir() + "/ceph-csi.json"
|
||||
err = os.WriteFile(tmpConfPath, csiConfigFileContent, 0o600)
|
||||
if err != nil {
|
||||
t.Errorf("failed to write %s file content: %v", CsiConfigFile, err)
|
||||
}
|
||||
for _, tt := range tests {
|
||||
ts := tt
|
||||
t.Run(ts.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
got, err := GetNetNamespaceFilePath(tmpConfPath, ts.clusterID)
|
||||
if err != nil {
|
||||
t.Errorf("GetNetNamespaceFilePath() error = %v", err)
|
||||
|
||||
return
|
||||
}
|
||||
if got != ts.want {
|
||||
t.Errorf("GetNetNamespaceFilePath() = %v, want %v", got, ts.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user