From 4579674d3a6ea880d11a2c8fb9c5af1de10ce492 Mon Sep 17 00:00:00 2001 From: Pradeep Hegde Date: Thu, 3 Feb 2022 11:39:09 +0530 Subject: [PATCH 1/2] Util for powershell scripts --- pkg/os/disk/api.go | 31 ++++++++------------ pkg/os/filesystem/api.go | 9 +++--- pkg/os/iscsi/api.go | 62 +++++++++++----------------------------- pkg/os/smb/api.go | 34 +++++++--------------- pkg/os/system/api.go | 28 +++++++----------- pkg/os/volume/api.go | 55 +++++++++++++---------------------- pkg/utils/utils.go | 25 ++++++++++++++++ 7 files changed, 99 insertions(+), 145 deletions(-) diff --git a/pkg/os/disk/api.go b/pkg/os/disk/api.go index 7707dd96..70cc4a9c 100644 --- a/pkg/os/disk/api.go +++ b/pkg/os/disk/api.go @@ -4,7 +4,6 @@ import ( "encoding/hex" "encoding/json" "fmt" - "os/exec" "regexp" "strconv" "strings" @@ -12,6 +11,7 @@ import ( "unsafe" shared "github.com/kubernetes-csi/csi-proxy/pkg/shared/disk" + "github.com/kubernetes-csi/csi-proxy/pkg/utils" "k8s.io/klog/v2" ) @@ -64,13 +64,6 @@ func New() DiskAPI { return DiskAPI{} } -func runExec(command string) ([]byte, error) { - cmd := exec.Command("powershell", "/c", command) - klog.V(4).Infof("Executing command: %q", cmd.String()) - out, err := cmd.CombinedOutput() - return out, err -} - // ListDiskLocations - constructs a map with the disk number as the key and the DiskLocation structure // as the value. The DiskLocation struct has various fields like the Adapter, Bus, Target and LUNID. func (DiskAPI) ListDiskLocations() (map[uint32]shared.DiskLocation, error) { @@ -80,7 +73,7 @@ func (DiskAPI) ListDiskLocations() (map[uint32]shared.DiskLocation, error) { // "location": "PCI Slot 3 : Adapter 0 : Port 0 : Target 1 : LUN 0" // }, ...] cmd := fmt.Sprintf("ConvertTo-Json @(Get-Disk | select Number, Location)") - out, err := runExec(cmd) + out, err := utils.RunPowershellCmd(cmd) if err != nil { return nil, fmt.Errorf("failed to list disk location. cmd: %q, output: %q, err %v", cmd, string(out), err) } @@ -128,7 +121,7 @@ func (DiskAPI) ListDiskLocations() (map[uint32]shared.DiskLocation, error) { func (DiskAPI) Rescan() error { cmd := "Update-HostStorageCache" - out, err := runExec(cmd) + out, err := utils.RunPowershellCmd(cmd) if err != nil { return fmt.Errorf("error updating host storage cache output: %q, err: %v", string(out), err) } @@ -137,7 +130,7 @@ func (DiskAPI) Rescan() error { func (DiskAPI) IsDiskInitialized(diskNumber uint32) (bool, error) { cmd := fmt.Sprintf("Get-Disk -Number %d | Where partitionstyle -eq 'raw'", diskNumber) - out, err := runExec(cmd) + out, err := utils.RunPowershellCmd(cmd) if err != nil { return false, fmt.Errorf("error checking initialized status of disk %d: %v, %v", diskNumber, out, err) } @@ -150,7 +143,7 @@ func (DiskAPI) IsDiskInitialized(diskNumber uint32) (bool, error) { func (DiskAPI) InitializeDisk(diskNumber uint32) error { cmd := fmt.Sprintf("Initialize-Disk -Number %d -PartitionStyle GPT", diskNumber) - out, err := runExec(cmd) + out, err := utils.RunPowershellCmd(cmd) if err != nil { return fmt.Errorf("error initializing disk %d: %v, %v", diskNumber, out, err) } @@ -159,7 +152,7 @@ func (DiskAPI) InitializeDisk(diskNumber uint32) error { func (DiskAPI) BasicPartitionsExist(diskNumber uint32) (bool, error) { cmd := fmt.Sprintf("Get-Partition | Where DiskNumber -eq %d | Where Type -ne Reserved", diskNumber) - out, err := runExec(cmd) + out, err := utils.RunPowershellCmd(cmd) if err != nil { return false, fmt.Errorf("error checking presence of partitions on disk %d: %v, %v", diskNumber, out, err) } @@ -172,7 +165,7 @@ func (DiskAPI) BasicPartitionsExist(diskNumber uint32) (bool, error) { func (DiskAPI) CreateBasicPartition(diskNumber uint32) error { cmd := fmt.Sprintf("New-Partition -DiskNumber %d -UseMaximumSize", diskNumber) - out, err := runExec(cmd) + out, err := utils.RunPowershellCmd(cmd) if err != nil { return fmt.Errorf("error creating parition on disk %d: %v, %v", diskNumber, out, err) } @@ -238,7 +231,7 @@ func (DiskAPI) GetDiskPage83ID(disk syscall.Handle) (string, error) { func (imp DiskAPI) GetDiskNumberWithID(page83ID string) (uint32, error) { cmd := "ConvertTo-Json @(Get-Disk | Select Path)" - out, err := runExec(cmd) + out, err := utils.RunPowershellCmd(cmd) if err != nil { return 0, fmt.Errorf("Could not query disk paths") } @@ -298,7 +291,7 @@ func (imp DiskAPI) ListDiskIDs() (map[uint32]shared.DiskIDs, error) { // "SerialNumber": null // }, ] cmd := "ConvertTo-Json @(Get-Disk | Select Path, SerialNumber)" - out, err := runExec(cmd) + out, err := utils.RunPowershellCmd(cmd) if err != nil { return nil, fmt.Errorf("Could not query disk paths") } @@ -329,7 +322,7 @@ func (imp DiskAPI) ListDiskIDs() (map[uint32]shared.DiskIDs, error) { func (imp DiskAPI) GetDiskStats(diskNumber uint32) (int64, error) { cmd := fmt.Sprintf("(Get-Disk -Number %d).Size", diskNumber) - out, err := runExec(cmd) + out, err := utils.RunPowershellCmd(cmd) if err != nil || len(out) == 0 { return -1, fmt.Errorf("error getting size of disk. cmd: %s, output: %s, error: %v", cmd, string(out), err) } @@ -351,7 +344,7 @@ func (imp DiskAPI) GetDiskStats(diskNumber uint32) (int64, error) { func (imp DiskAPI) SetDiskState(diskNumber uint32, isOnline bool) error { cmd := fmt.Sprintf("(Get-Disk -Number %d) | Set-Disk -IsOffline $%t", diskNumber, !isOnline) - out, err := runExec(cmd) + out, err := utils.RunPowershellCmd(cmd) if err != nil { return fmt.Errorf("error setting disk attach state. cmd: %s, output: %s, error: %v", cmd, string(out), err) } @@ -361,7 +354,7 @@ func (imp DiskAPI) SetDiskState(diskNumber uint32, isOnline bool) error { func (imp DiskAPI) GetDiskState(diskNumber uint32) (bool, error) { cmd := fmt.Sprintf("(Get-Disk -Number %d) | Select-Object -ExpandProperty IsOffline", diskNumber) - out, err := runExec(cmd) + out, err := utils.RunPowershellCmd(cmd) if err != nil { return false, fmt.Errorf("error getting disk state. cmd: %s, output: %s, error: %v", cmd, string(out), err) } diff --git a/pkg/os/filesystem/api.go b/pkg/os/filesystem/api.go index 7a033b63..dfbe5f0a 100644 --- a/pkg/os/filesystem/api.go +++ b/pkg/os/filesystem/api.go @@ -3,9 +3,10 @@ package filesystem import ( "fmt" "os" - "os/exec" "path/filepath" "strings" + + "github.com/kubernetes-csi/csi-proxy/pkg/utils" ) // Implements the Filesystem OS API calls. All code here should be very simple @@ -49,9 +50,9 @@ func (filesystemAPI) PathExists(path string) (bool, error) { } func pathValid(path string) (bool, error) { - cmd := exec.Command("powershell", "/c", `Test-Path $Env:remotepath`) - cmd.Env = append(os.Environ(), fmt.Sprintf("remotepath=%s", path)) - output, err := cmd.CombinedOutput() + cmd := `Test-Path $Env:remotepath` + cmdEnv := fmt.Sprintf("remotepath=%s", path) + output, err := utils.RunPowershellCmdWithEnv(cmd, cmdEnv) if err != nil { return false, fmt.Errorf("returned output: %s, error: %v", string(output), err) } diff --git a/pkg/os/iscsi/api.go b/pkg/os/iscsi/api.go index 7515bbdf..d2749720 100644 --- a/pkg/os/iscsi/api.go +++ b/pkg/os/iscsi/api.go @@ -3,8 +3,8 @@ package iscsi import ( "encoding/json" "fmt" - "os" - "os/exec" + + "github.com/kubernetes-csi/csi-proxy/pkg/utils" ) // Implements the iSCSI OS API calls. All code here should be very simple @@ -22,12 +22,8 @@ func (APIImplementor) AddTargetPortal(portal *TargetPortal) error { cmdLine := fmt.Sprintf( `New-IscsiTargetPortal -TargetPortalAddress ${Env:iscsi_tp_address} ` + `-TargetPortalPortNumber ${Env:iscsi_tp_port}`) - cmd := exec.Command("powershell.exe", "/c", cmdLine) - cmd.Env = append(os.Environ(), - fmt.Sprintf("iscsi_tp_address=%s", portal.Address), - fmt.Sprintf("iscsi_tp_port=%d", portal.Port)) - - out, err := cmd.CombinedOutput() + out, err := utils.RunPowershellCmdWithEnvs(cmdLine, []string{fmt.Sprintf("iscsi_tp_address=%s", portal.Address), + fmt.Sprintf("iscsi_tp_port=%d", portal.Port)}) if err != nil { return fmt.Errorf("error adding target portal. cmd %s, output: %s, err: %v", cmdLine, string(out), err) } @@ -42,12 +38,8 @@ func (APIImplementor) DiscoverTargetPortal(portal *TargetPortal) ([]string, erro `ConvertTo-Json -InputObject @(Get-IscsiTargetPortal -TargetPortalAddress ` + `${Env:iscsi_tp_address} -TargetPortalPortNumber ${Env:iscsi_tp_port} | ` + `Get-IscsiTarget | Select-Object -ExpandProperty NodeAddress)`) - cmd := exec.Command("powershell.exe", "/c", cmdLine) - cmd.Env = append(os.Environ(), - fmt.Sprintf("iscsi_tp_address=%s", portal.Address), - fmt.Sprintf("iscsi_tp_port=%d", portal.Port)) - - out, err := cmd.CombinedOutput() + out, err := utils.RunPowershellCmdWithEnvs(cmdLine, []string{fmt.Sprintf("iscsi_tp_address=%s", portal.Address), + fmt.Sprintf("iscsi_tp_port=%d", portal.Port)}) if err != nil { return nil, fmt.Errorf("error discovering target portal. cmd: %s, output: %s, err: %w", cmdLine, string(out), err) } @@ -66,8 +58,7 @@ func (APIImplementor) ListTargetPortals() ([]TargetPortal, error) { `ConvertTo-Json -InputObject @(Get-IscsiTargetPortal | ` + `Select-Object TargetPortalAddress, TargetPortalPortNumber)`) - cmd := exec.Command("powershell.exe", "/c", cmdLine) - out, err := cmd.CombinedOutput() + out, err := utils.RunPowershellCmd(cmdLine) if err != nil { return nil, fmt.Errorf("error listing target portals. cmd %s, output: %s, err: %w", cmdLine, string(out), err) } @@ -87,12 +78,8 @@ func (APIImplementor) RemoveTargetPortal(portal *TargetPortal) error { `-TargetPortalPortNumber ${Env:iscsi_tp_port} | Remove-IscsiTargetPortal ` + `-Confirm:$false`) - cmd := exec.Command("powershell.exe", "/c", cmdLine) - cmd.Env = append(os.Environ(), - fmt.Sprintf("iscsi_tp_address=%s", portal.Address), - fmt.Sprintf("iscsi_tp_port=%d", portal.Port)) - - out, err := cmd.CombinedOutput() + out, err := utils.RunPowershellCmdWithEnvs(cmdLine, []string{fmt.Sprintf("iscsi_tp_address=%s", portal.Address), + fmt.Sprintf("iscsi_tp_port=%d", portal.Port)}) if err != nil { return fmt.Errorf("error removing target portal. cmd %s, output: %s, err: %w", cmdLine, string(out), err) } @@ -118,17 +105,12 @@ func (APIImplementor) ConnectTarget(portal *TargetPortal, iqn string, cmdLine += fmt.Sprintf(` -ChapSecret ${Env:iscsi_chap_secret}`) } - cmd := exec.Command("powershell.exe", "/c", cmdLine) - cmd.Env = append(os.Environ(), - fmt.Sprintf("iscsi_tp_address=%s", portal.Address), + out, err := utils.RunPowershellCmdWithEnvs(cmdLine, []string{fmt.Sprintf("iscsi_tp_address=%s", portal.Address), fmt.Sprintf("iscsi_tp_port=%d", portal.Port), fmt.Sprintf("iscsi_target_iqn=%s", iqn), fmt.Sprintf("iscsi_auth_type=%s", authType), fmt.Sprintf("iscsi_chap_user=%s", chapUser), - fmt.Sprintf("iscsi_chap_secret=%s", chapSecret), - ) - - out, err := cmd.CombinedOutput() + fmt.Sprintf("iscsi_chap_secret=%s", chapSecret)}) if err != nil { return fmt.Errorf("error connecting to target portal. cmd %s, output: %s, err: %w", cmdLine, string(out), err) } @@ -144,13 +126,9 @@ func (APIImplementor) DisconnectTarget(portal *TargetPortal, iqn string) error { ` | Get-IscsiTarget | Where-Object { $_.NodeAddress -eq ${Env:iscsi_target_iqn} }) ` + `-Confirm:$false`) - cmd := exec.Command("powershell.exe", "/c", cmdLine) - cmd.Env = append(os.Environ(), - fmt.Sprintf("iscsi_tp_address=%s", portal.Address), + out, err := utils.RunPowershellCmdWithEnvs(cmdLine, []string{fmt.Sprintf("iscsi_tp_address=%s", portal.Address), fmt.Sprintf("iscsi_tp_port=%d", portal.Port), - fmt.Sprintf("iscsi_target_iqn=%s", iqn)) - - out, err := cmd.CombinedOutput() + fmt.Sprintf("iscsi_target_iqn=%s", iqn)}) if err != nil { return fmt.Errorf("error disconnecting from target portal. cmd %s, output: %s, err: %w", cmdLine, string(out), err) } @@ -169,13 +147,9 @@ func (APIImplementor) GetTargetDisks(portal *TargetPortal, iqn string) ([]string `$ids = $c | Get-Disk | Select -ExpandProperty Number | Out-String -Stream; ` + `ConvertTo-Json -InputObject @($ids)`) - cmd := exec.Command("powershell.exe", "/c", cmdLine) - cmd.Env = append(os.Environ(), - fmt.Sprintf("iscsi_tp_address=%s", portal.Address), + out, err := utils.RunPowershellCmdWithEnvs(cmdLine, []string{fmt.Sprintf("iscsi_tp_address=%s", portal.Address), fmt.Sprintf("iscsi_tp_port=%d", portal.Port), - fmt.Sprintf("iscsi_target_iqn=%s", iqn)) - - out, err := cmd.CombinedOutput() + fmt.Sprintf("iscsi_target_iqn=%s", iqn)}) if err != nil { return nil, fmt.Errorf("error getting target disks. cmd %s, output: %s, err: %w", cmdLine, string(out), err) } @@ -192,11 +166,7 @@ func (APIImplementor) GetTargetDisks(portal *TargetPortal, iqn string) ([]string func (APIImplementor) SetMutualChapSecret(mutualChapSecret string) error { cmdLine := fmt.Sprintf( `Set-IscsiChapSecret -ChapSecret ${Env:iscsi_mutual_chap_secret}`) - cmd := exec.Command("powershell.exe", "/c", cmdLine) - cmd.Env = append(os.Environ(), - fmt.Sprintf("iscsi_mutual_chap_secret=%s", mutualChapSecret)) - - out, err := cmd.CombinedOutput() + out, err := utils.RunPowershellCmdWithEnvs(cmdLine, []string{fmt.Sprintf("iscsi_mutual_chap_secret=%s", mutualChapSecret)}) if err != nil { return fmt.Errorf("error setting mutual chap secret. cmd %s,"+ " output: %s, err: %v", cmdLine, string(out), err) diff --git a/pkg/os/smb/api.go b/pkg/os/smb/api.go index 3bec8eb0..dbf983d1 100644 --- a/pkg/os/smb/api.go +++ b/pkg/os/smb/api.go @@ -2,9 +2,9 @@ package smb import ( "fmt" - "os" - "os/exec" "strings" + + "github.com/kubernetes-csi/csi-proxy/pkg/utils" ) type API interface { @@ -23,12 +23,9 @@ func New() SmbAPI { } func (SmbAPI) IsSmbMapped(remotePath string) (bool, error) { - cmdLine := fmt.Sprintf(`$(Get-SmbGlobalMapping -RemotePath $Env:smbremotepath -ErrorAction Stop).Status `) - cmd := exec.Command("powershell", "/c", cmdLine) - cmd.Env = append(os.Environ(), - fmt.Sprintf("smbremotepath=%s", remotePath)) - - out, err := cmd.CombinedOutput() + cmdLine := `$(Get-SmbGlobalMapping -RemotePath $Env:smbremotepath -ErrorAction Stop).Status ` + cmdEnv := fmt.Sprintf("smbremotepath=%s", remotePath) + out, err := utils.RunPowershellCmdWithEnv(cmdLine, cmdEnv) if err != nil { return false, fmt.Errorf("error checking smb mapping. cmd %s, output: %s, err: %v", remotePath, string(out), err) } @@ -54,13 +51,8 @@ func (SmbAPI) NewSmbLink(remotePath, localPath string) error { remotePath = remotePath + "\\" } - cmdLine := fmt.Sprintf(`New-Item -ItemType SymbolicLink $Env:smblocalPath -Target $Env:smbremotepath`) - cmd := exec.Command("powershell", "/c", cmdLine) - cmd.Env = append(os.Environ(), - fmt.Sprintf("smbremotepath=%s", remotePath), - fmt.Sprintf("smblocalpath=%s", localPath), - ) - output, err := cmd.CombinedOutput() + cmdLine := `New-Item -ItemType SymbolicLink $Env:smblocalPath -Target $Env:smbremotepath` + output, err := utils.RunPowershellCmdWithEnvs(cmdLine, []string{fmt.Sprintf("smbremotepath=%s", remotePath), fmt.Sprintf("smblocalpath=%s", localPath)}) if err != nil { return fmt.Errorf("error linking %s to %s. output: %s, err: %v", remotePath, localPath, string(output), err) } @@ -75,21 +67,17 @@ func (SmbAPI) NewSmbGlobalMapping(remotePath, username, password string) error { `;$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $Env:smbuser, $PWord` + `;New-SmbGlobalMapping -RemotePath $Env:smbremotepath -Credential $Credential -RequirePrivacy $true`) - cmd := exec.Command("powershell", "/c", cmdLine) - cmd.Env = append(os.Environ(), - fmt.Sprintf("smbuser=%s", username), + if output, err := utils.RunPowershellCmdWithEnvs(cmdLine, []string{fmt.Sprintf("smbuser=%s", username), fmt.Sprintf("smbpassword=%s", password), - fmt.Sprintf("smbremotepath=%s", remotePath)) - if output, err := cmd.CombinedOutput(); err != nil { + fmt.Sprintf("smbremotepath=%s", remotePath)}); err != nil { return fmt.Errorf("NewSmbGlobalMapping failed. output: %q, err: %v", string(output), err) } return nil } func (SmbAPI) RemoveSmbGlobalMapping(remotePath string) error { - cmd := exec.Command("powershell", "/c", `Remove-SmbGlobalMapping -RemotePath $Env:smbremotepath -Force`) - cmd.Env = append(os.Environ(), fmt.Sprintf("smbremotepath=%s", remotePath)) - if output, err := cmd.CombinedOutput(); err != nil { + cmd := `Remove-SmbGlobalMapping -RemotePath $Env:smbremotepath -Force` + if output, err := utils.RunPowershellCmdWithEnvs(cmd, []string{fmt.Sprintf("smbremotepath=%s", remotePath)}); err != nil { return fmt.Errorf("UnmountSmbShare failed. output: %q, err: %v", string(output), err) } return nil diff --git a/pkg/os/system/api.go b/pkg/os/system/api.go index 062f1cb4..12a7dfdb 100644 --- a/pkg/os/system/api.go +++ b/pkg/os/system/api.go @@ -3,9 +3,10 @@ package system import ( "encoding/json" "fmt" - "os" "os/exec" "strings" + + "github.com/kubernetes-csi/csi-proxy/pkg/utils" ) // Implements the System OS API calls. All code here should be very simple @@ -54,12 +55,10 @@ func (APIImplementor) GetBIOSSerialNumber() (string, error) { func (APIImplementor) GetService(name string) (*ServiceInfo, error) { script := `Get-Service -Name $env:ServiceName | Select-Object DisplayName, Status, StartType | ` + `ConvertTo-JSON` - cmd := exec.Command("powershell", "/c", script) - cmd.Env = append(os.Environ(), fmt.Sprintf("ServiceName=%s", name)) - - out, err := cmd.CombinedOutput() + cmdEnv := fmt.Sprintf("ServiceName=%s", name) + out, err := utils.RunPowershellCmdWithEnv(script, cmdEnv) if err != nil { - return nil, fmt.Errorf("error querying service name=%s. cmd: %s, output: %s, error: %v", name, cmd, string(out), err) + return nil, fmt.Errorf("error querying service name=%s. cmd: %s, output: %s, error: %v", name, script, string(out), err) } var serviceInfo ServiceInfo @@ -73,12 +72,10 @@ func (APIImplementor) GetService(name string) (*ServiceInfo, error) { func (APIImplementor) StartService(name string) error { script := `Start-Service -Name $env:ServiceName` - cmd := exec.Command("powershell", "/c", script) - cmd.Env = append(os.Environ(), fmt.Sprintf("ServiceName=%s", name)) - - out, err := cmd.CombinedOutput() + cmdEnv := fmt.Sprintf("ServiceName=%s", name) + out, err := utils.RunPowershellCmdWithEnv(script, cmdEnv) if err != nil { - return fmt.Errorf("error starting service name=%s. cmd: %s, output: %s, error: %v", name, cmd, string(out), err) + return fmt.Errorf("error starting service name=%s. cmd: %s, output: %s, error: %v", name, script, string(out), err) } return nil @@ -86,14 +83,9 @@ func (APIImplementor) StartService(name string) error { func (APIImplementor) StopService(name string, force bool) error { script := `Stop-Service -Name $env:ServiceName -Force:$([System.Convert]::ToBoolean($env:Force))` - cmd := exec.Command("powershell", "/c", script) - cmd.Env = append(os.Environ(), - fmt.Sprintf("ServiceName=%s", name), - fmt.Sprintf("Force=%t", force)) - - out, err := cmd.CombinedOutput() + out, err := utils.RunPowershellCmdWithEnvs(script, []string{fmt.Sprintf("ServiceName=%s", name), fmt.Sprintf("Force=%t", force)}) if err != nil { - return fmt.Errorf("error stopping service name=%s. cmd: %s, output: %s, error: %v", name, cmd, string(out), err) + return fmt.Errorf("error stopping service name=%s. cmd: %s, output: %s, error: %v", name, script, string(out), err) } return nil diff --git a/pkg/os/volume/api.go b/pkg/os/volume/api.go index c62a5897..ee59f8d4 100644 --- a/pkg/os/volume/api.go +++ b/pkg/os/volume/api.go @@ -1,16 +1,15 @@ package volume import ( - "bytes" "encoding/json" "fmt" "os" - "os/exec" "path/filepath" "regexp" "strconv" "strings" + "github.com/kubernetes-csi/csi-proxy/pkg/utils" "k8s.io/klog/v2" ) @@ -62,16 +61,9 @@ func New() VolumeAPI { return VolumeAPI{} } -func runExec(command string) ([]byte, error) { - cmd := exec.Command("powershell", "/c", command) - klog.V(4).Infof("Executing command: %q", cmd.String()) - out, err := cmd.CombinedOutput() - return out, err -} - func getVolumeSize(volumeID string) (int64, error) { cmd := fmt.Sprintf("(Get-Volume -UniqueId \"%s\" | Get-partition).Size", volumeID) - out, err := runExec(cmd) + out, err := utils.RunPowershellCmd(cmd) if err != nil || len(out) == 0 { return -1, fmt.Errorf("error getting size of the partition from mount. cmd %s, output: %s, error: %v", cmd, string(out), err) @@ -95,7 +87,7 @@ func (VolumeAPI) ListVolumesOnDisk(diskNumber uint32, partitionNumber uint32) (v } else { cmd = fmt.Sprintf("(Get-Disk -Number %d | Get-Partition -PartitionNumber %d | Get-Volume).UniqueId", diskNumber, partitionNumber) } - out, err := runExec(cmd) + out, err := utils.RunPowershellCmd(cmd) if err != nil { return []string{}, fmt.Errorf("error list volumes on disk. cmd: %s, output: %s, error: %v", cmd, string(out), err) } @@ -107,7 +99,7 @@ func (VolumeAPI) ListVolumesOnDisk(diskNumber uint32, partitionNumber uint32) (v // FormatVolume - Formats a volume with the NTFS format. func (VolumeAPI) FormatVolume(volumeID string) (err error) { cmd := fmt.Sprintf("Get-Volume -UniqueId \"%s\" | Format-Volume -FileSystem ntfs -Confirm:$false", volumeID) - out, err := runExec(cmd) + out, err := utils.RunPowershellCmd(cmd) if err != nil { return fmt.Errorf("error formatting volume. cmd: %s, output: %s, error: %v", cmd, string(out), err) } @@ -123,7 +115,7 @@ func (VolumeAPI) WriteVolumeCache(volumeID string) (err error) { // IsVolumeFormatted - Check if the volume is formatted with the pre specified filesystem(typically ntfs). func (VolumeAPI) IsVolumeFormatted(volumeID string) (bool, error) { cmd := fmt.Sprintf("(Get-Volume -UniqueId \"%s\" -ErrorAction Stop).FileSystemType", volumeID) - out, err := runExec(cmd) + out, err := utils.RunPowershellCmd(cmd) if err != nil { return false, fmt.Errorf("error checking if volume is formatted. cmd: %s, output: %s, error: %v", cmd, string(out), err) } @@ -137,7 +129,7 @@ func (VolumeAPI) IsVolumeFormatted(volumeID string) (bool, error) { // MountVolume - mounts a volume to a path. This is done using the Add-PartitionAccessPath for presenting the volume via a path. func (VolumeAPI) MountVolume(volumeID, path string) error { cmd := fmt.Sprintf("Get-Volume -UniqueId \"%s\" | Get-Partition | Add-PartitionAccessPath -AccessPath %s", volumeID, path) - out, err := runExec(cmd) + out, err := utils.RunPowershellCmd(cmd) if err != nil { return fmt.Errorf("error mount volume to path. cmd: %s, output: %s, error: %v", cmd, string(out), err) } @@ -150,7 +142,7 @@ func (VolumeAPI) UnmountVolume(volumeID, path string) error { return err } cmd := fmt.Sprintf("Get-Volume -UniqueId \"%s\" | Get-Partition | Remove-PartitionAccessPath -AccessPath %s", volumeID, path) - out, err := runExec(cmd) + out, err := utils.RunPowershellCmd(cmd) if err != nil { return fmt.Errorf("error getting driver letter to mount volume. cmd: %s, output: %s,error: %v", cmd, string(out), err) } @@ -167,7 +159,7 @@ func (VolumeAPI) ResizeVolume(volumeID string, size int64) error { var outString string if size == 0 { cmd = fmt.Sprintf("Get-Volume -UniqueId \"%s\" | Get-partition | Get-PartitionSupportedSize | Select SizeMax | ConvertTo-Json", volumeID) - out, err = runExec(cmd) + out, err := utils.RunPowershellCmd(cmd) if err != nil || len(out) == 0 { return fmt.Errorf("error getting sizemin,sizemax from mount. cmd: %s, output: %s, error: %v", cmd, string(out), err) @@ -199,7 +191,7 @@ func (VolumeAPI) ResizeVolume(volumeID string, size int64) error { } cmd = fmt.Sprintf("Get-Volume -UniqueId \"%s\" | Get-Partition | Resize-Partition -Size %d", volumeID, finalSize) - out, err = runExec(cmd) + out, err = utils.RunPowershellCmd(cmd) if err != nil { return fmt.Errorf("error resizing volume. cmd: %s, output: %s size:%v, finalSize %v, error: %v", cmd, string(out), size, finalSize, err) } @@ -210,7 +202,7 @@ func (VolumeAPI) ResizeVolume(volumeID string, size int64) error { func (VolumeAPI) GetVolumeStats(volumeID string) (int64, int64, error) { // get the size and sizeRemaining for the volume cmd := fmt.Sprintf("(Get-Volume -UniqueId \"%s\" | Select SizeRemaining,Size) | ConvertTo-Json", volumeID) - out, err := runExec(cmd) + out, err := utils.RunPowershellCmd(cmd) if err != nil { return -1, -1, fmt.Errorf("error getting capacity and used size of volume. cmd: %s, output: %s, error: %v", cmd, string(out), err) @@ -236,7 +228,7 @@ func (VolumeAPI) GetVolumeStats(volumeID string) (int64, int64, error) { func (VolumeAPI) GetDiskNumberFromVolumeID(volumeID string) (uint32, error) { // get the size and sizeRemaining for the volume cmd := fmt.Sprintf("(Get-Volume -UniqueId \"%s\" | Get-Partition).DiskNumber", volumeID) - out, err := runExec(cmd) + out, err := utils.RunPowershellCmd(cmd) if err != nil || len(out) == 0 { return 0, fmt.Errorf("error getting disk number. cmd: %s, output: %s, error: %v", cmd, string(out), err) @@ -270,7 +262,7 @@ func (VolumeAPI) GetVolumeIDFromTargetPath(mount string) (string, error) { func getTarget(mount string) (string, error) { cmd := fmt.Sprintf("(Get-Item -Path %s).Target", mount) - out, err := runExec(cmd) + out, err := utils.RunPowershellCmd(cmd) if err != nil || len(out) == 0 { return "", fmt.Errorf("error getting volume from mount. cmd: %s, output: %s, error: %v", cmd, string(out), err) } @@ -360,18 +352,12 @@ func ensureVolumePrefix(volume string) string { // dereferenceSymlink dereferences the symlink `path` and returns the stdout. func dereferenceSymlink(path string) (string, error) { - cmd := exec.Command("powershell", "/c", fmt.Sprintf(`(Get-Item -Path %s).Target`, path)) - klog.V(8).Infof("About to execute: %q", cmd.String()) - var outbuf, errbuf bytes.Buffer - cmd.Stderr = &errbuf - cmd.Stdout = &outbuf - if err := cmd.Run(); err != nil { + cmd := fmt.Sprintf(`(Get-Item -Path %s).Target`, path) + out, err := utils.RunPowershellCmd(cmd) + if err != nil { return "", err } - if len(errbuf.String()) != 0 { - return "", fmt.Errorf("Unexpected stderr output in command=%v stdeerr=%v", cmd.String(), errbuf.String()) - } - output := strings.TrimSpace(outbuf.String()) + output := strings.TrimSpace(string(out)) klog.V(8).Infof("Stdout: %s", output) return output, nil } @@ -382,20 +368,19 @@ func getVolumeForDriveLetter(path string) (string, error) { return "", fmt.Errorf("The path=%s is not a valid DriverLetter", path) } - cmd := exec.Command("powershell", "/c", fmt.Sprintf(`(Get-Partition -DriveLetter %s | Get-Volume).UniqueId`, path)) - klog.V(8).Infof("About to execute: %q", cmd.String()) - targetb, err := cmd.Output() + cmd := fmt.Sprintf(`(Get-Partition -DriveLetter %s | Get-Volume).UniqueId`, path) + out, err := utils.RunPowershellCmd(cmd) if err != nil { return "", err } - output := strings.TrimSpace(string(targetb)) + output := strings.TrimSpace(string(out)) klog.V(8).Infof("Stdout: %s", output) return output, nil } func writeCache(volumeID string) error { cmd := fmt.Sprintf("Get-Volume -UniqueId \"%s\" | Write-Volumecache", volumeID) - out, err := runExec(cmd) + out, err := utils.RunPowershellCmd(cmd) if err != nil { return fmt.Errorf("error writing volume cache. cmd: %s, output: %s, error: %v", cmd, string(out), err) } diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 6dde526f..e5e71a80 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -1,3 +1,28 @@ package utils +import ( + "os" + "os/exec" + + "k8s.io/klog/v2" +) + const MaxPathLengthWindows = 260 + +func RunPowershellCmd(command string) ([]byte, error) { + return RunPowershellCmdWithEnvs(command, nil) +} + +func RunPowershellCmdWithEnv(command string, env string) ([]byte, error) { + return RunPowershellCmdWithEnvs(command, []string{env}) +} + +func RunPowershellCmdWithEnvs(command string, envs []string) ([]byte, error) { + cmd := exec.Command("powershell", "-Mta", "-NoProfile", "-Command", command) + if envs != nil { + cmd.Env = append(os.Environ(), envs...) + } + klog.V(8).Infof("Executing command: %q", cmd.String()) + out, err := cmd.CombinedOutput() + return out, err +} From 1d95f0900d9ee5b1f6439c4e7a9504af68ceb71b Mon Sep 17 00:00:00 2001 From: Pradeep Hegde Date: Fri, 4 Feb 2022 10:09:24 +0530 Subject: [PATCH 2/2] Use variadic function --- pkg/os/filesystem/api.go | 2 +- pkg/os/iscsi/api.go | 33 ++++++++++++++++----------------- pkg/os/smb/api.go | 10 +++++----- pkg/os/system/api.go | 6 +++--- pkg/utils/utils.go | 14 ++------------ 5 files changed, 27 insertions(+), 38 deletions(-) diff --git a/pkg/os/filesystem/api.go b/pkg/os/filesystem/api.go index dfbe5f0a..2f9ba524 100644 --- a/pkg/os/filesystem/api.go +++ b/pkg/os/filesystem/api.go @@ -52,7 +52,7 @@ func (filesystemAPI) PathExists(path string) (bool, error) { func pathValid(path string) (bool, error) { cmd := `Test-Path $Env:remotepath` cmdEnv := fmt.Sprintf("remotepath=%s", path) - output, err := utils.RunPowershellCmdWithEnv(cmd, cmdEnv) + output, err := utils.RunPowershellCmd(cmd, cmdEnv) if err != nil { return false, fmt.Errorf("returned output: %s, error: %v", string(output), err) } diff --git a/pkg/os/iscsi/api.go b/pkg/os/iscsi/api.go index d2749720..559ed3b5 100644 --- a/pkg/os/iscsi/api.go +++ b/pkg/os/iscsi/api.go @@ -22,8 +22,8 @@ func (APIImplementor) AddTargetPortal(portal *TargetPortal) error { cmdLine := fmt.Sprintf( `New-IscsiTargetPortal -TargetPortalAddress ${Env:iscsi_tp_address} ` + `-TargetPortalPortNumber ${Env:iscsi_tp_port}`) - out, err := utils.RunPowershellCmdWithEnvs(cmdLine, []string{fmt.Sprintf("iscsi_tp_address=%s", portal.Address), - fmt.Sprintf("iscsi_tp_port=%d", portal.Port)}) + out, err := utils.RunPowershellCmd(cmdLine, fmt.Sprintf("iscsi_tp_address=%s", portal.Address), + fmt.Sprintf("iscsi_tp_port=%d", portal.Port)) if err != nil { return fmt.Errorf("error adding target portal. cmd %s, output: %s, err: %v", cmdLine, string(out), err) } @@ -38,8 +38,8 @@ func (APIImplementor) DiscoverTargetPortal(portal *TargetPortal) ([]string, erro `ConvertTo-Json -InputObject @(Get-IscsiTargetPortal -TargetPortalAddress ` + `${Env:iscsi_tp_address} -TargetPortalPortNumber ${Env:iscsi_tp_port} | ` + `Get-IscsiTarget | Select-Object -ExpandProperty NodeAddress)`) - out, err := utils.RunPowershellCmdWithEnvs(cmdLine, []string{fmt.Sprintf("iscsi_tp_address=%s", portal.Address), - fmt.Sprintf("iscsi_tp_port=%d", portal.Port)}) + out, err := utils.RunPowershellCmd(cmdLine, fmt.Sprintf("iscsi_tp_address=%s", portal.Address), + fmt.Sprintf("iscsi_tp_port=%d", portal.Port)) if err != nil { return nil, fmt.Errorf("error discovering target portal. cmd: %s, output: %s, err: %w", cmdLine, string(out), err) } @@ -78,8 +78,8 @@ func (APIImplementor) RemoveTargetPortal(portal *TargetPortal) error { `-TargetPortalPortNumber ${Env:iscsi_tp_port} | Remove-IscsiTargetPortal ` + `-Confirm:$false`) - out, err := utils.RunPowershellCmdWithEnvs(cmdLine, []string{fmt.Sprintf("iscsi_tp_address=%s", portal.Address), - fmt.Sprintf("iscsi_tp_port=%d", portal.Port)}) + out, err := utils.RunPowershellCmd(cmdLine, fmt.Sprintf("iscsi_tp_address=%s", portal.Address), + fmt.Sprintf("iscsi_tp_port=%d", portal.Port)) if err != nil { return fmt.Errorf("error removing target portal. cmd %s, output: %s, err: %w", cmdLine, string(out), err) } @@ -98,19 +98,19 @@ func (APIImplementor) ConnectTarget(portal *TargetPortal, iqn string, ` -AuthenticationType ${Env:iscsi_auth_type}`) if chapUser != "" { - cmdLine += fmt.Sprintf(` -ChapUsername ${Env:iscsi_chap_user}`) + cmdLine += ` -ChapUsername ${Env:iscsi_chap_user}` } if chapSecret != "" { - cmdLine += fmt.Sprintf(` -ChapSecret ${Env:iscsi_chap_secret}`) + cmdLine += ` -ChapSecret ${Env:iscsi_chap_secret}` } - out, err := utils.RunPowershellCmdWithEnvs(cmdLine, []string{fmt.Sprintf("iscsi_tp_address=%s", portal.Address), + out, err := utils.RunPowershellCmd(cmdLine, fmt.Sprintf("iscsi_tp_address=%s", portal.Address), fmt.Sprintf("iscsi_tp_port=%d", portal.Port), fmt.Sprintf("iscsi_target_iqn=%s", iqn), fmt.Sprintf("iscsi_auth_type=%s", authType), fmt.Sprintf("iscsi_chap_user=%s", chapUser), - fmt.Sprintf("iscsi_chap_secret=%s", chapSecret)}) + fmt.Sprintf("iscsi_chap_secret=%s", chapSecret)) if err != nil { return fmt.Errorf("error connecting to target portal. cmd %s, output: %s, err: %w", cmdLine, string(out), err) } @@ -126,9 +126,9 @@ func (APIImplementor) DisconnectTarget(portal *TargetPortal, iqn string) error { ` | Get-IscsiTarget | Where-Object { $_.NodeAddress -eq ${Env:iscsi_target_iqn} }) ` + `-Confirm:$false`) - out, err := utils.RunPowershellCmdWithEnvs(cmdLine, []string{fmt.Sprintf("iscsi_tp_address=%s", portal.Address), + out, err := utils.RunPowershellCmd(cmdLine, fmt.Sprintf("iscsi_tp_address=%s", portal.Address), fmt.Sprintf("iscsi_tp_port=%d", portal.Port), - fmt.Sprintf("iscsi_target_iqn=%s", iqn)}) + fmt.Sprintf("iscsi_target_iqn=%s", iqn)) if err != nil { return fmt.Errorf("error disconnecting from target portal. cmd %s, output: %s, err: %w", cmdLine, string(out), err) } @@ -147,9 +147,9 @@ func (APIImplementor) GetTargetDisks(portal *TargetPortal, iqn string) ([]string `$ids = $c | Get-Disk | Select -ExpandProperty Number | Out-String -Stream; ` + `ConvertTo-Json -InputObject @($ids)`) - out, err := utils.RunPowershellCmdWithEnvs(cmdLine, []string{fmt.Sprintf("iscsi_tp_address=%s", portal.Address), + out, err := utils.RunPowershellCmd(cmdLine, fmt.Sprintf("iscsi_tp_address=%s", portal.Address), fmt.Sprintf("iscsi_tp_port=%d", portal.Port), - fmt.Sprintf("iscsi_target_iqn=%s", iqn)}) + fmt.Sprintf("iscsi_target_iqn=%s", iqn)) if err != nil { return nil, fmt.Errorf("error getting target disks. cmd %s, output: %s, err: %w", cmdLine, string(out), err) } @@ -164,9 +164,8 @@ func (APIImplementor) GetTargetDisks(portal *TargetPortal, iqn string) ([]string } func (APIImplementor) SetMutualChapSecret(mutualChapSecret string) error { - cmdLine := fmt.Sprintf( - `Set-IscsiChapSecret -ChapSecret ${Env:iscsi_mutual_chap_secret}`) - out, err := utils.RunPowershellCmdWithEnvs(cmdLine, []string{fmt.Sprintf("iscsi_mutual_chap_secret=%s", mutualChapSecret)}) + cmdLine := `Set-IscsiChapSecret -ChapSecret ${Env:iscsi_mutual_chap_secret}` + out, err := utils.RunPowershellCmd(cmdLine, fmt.Sprintf("iscsi_mutual_chap_secret=%s", mutualChapSecret)) if err != nil { return fmt.Errorf("error setting mutual chap secret. cmd %s,"+ " output: %s, err: %v", cmdLine, string(out), err) diff --git a/pkg/os/smb/api.go b/pkg/os/smb/api.go index dbf983d1..f7535e38 100644 --- a/pkg/os/smb/api.go +++ b/pkg/os/smb/api.go @@ -25,7 +25,7 @@ func New() SmbAPI { func (SmbAPI) IsSmbMapped(remotePath string) (bool, error) { cmdLine := `$(Get-SmbGlobalMapping -RemotePath $Env:smbremotepath -ErrorAction Stop).Status ` cmdEnv := fmt.Sprintf("smbremotepath=%s", remotePath) - out, err := utils.RunPowershellCmdWithEnv(cmdLine, cmdEnv) + out, err := utils.RunPowershellCmd(cmdLine, cmdEnv) if err != nil { return false, fmt.Errorf("error checking smb mapping. cmd %s, output: %s, err: %v", remotePath, string(out), err) } @@ -52,7 +52,7 @@ func (SmbAPI) NewSmbLink(remotePath, localPath string) error { } cmdLine := `New-Item -ItemType SymbolicLink $Env:smblocalPath -Target $Env:smbremotepath` - output, err := utils.RunPowershellCmdWithEnvs(cmdLine, []string{fmt.Sprintf("smbremotepath=%s", remotePath), fmt.Sprintf("smblocalpath=%s", localPath)}) + output, err := utils.RunPowershellCmd(cmdLine, fmt.Sprintf("smbremotepath=%s", remotePath), fmt.Sprintf("smblocalpath=%s", localPath)) if err != nil { return fmt.Errorf("error linking %s to %s. output: %s, err: %v", remotePath, localPath, string(output), err) } @@ -67,9 +67,9 @@ func (SmbAPI) NewSmbGlobalMapping(remotePath, username, password string) error { `;$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $Env:smbuser, $PWord` + `;New-SmbGlobalMapping -RemotePath $Env:smbremotepath -Credential $Credential -RequirePrivacy $true`) - if output, err := utils.RunPowershellCmdWithEnvs(cmdLine, []string{fmt.Sprintf("smbuser=%s", username), + if output, err := utils.RunPowershellCmd(cmdLine, fmt.Sprintf("smbuser=%s", username), fmt.Sprintf("smbpassword=%s", password), - fmt.Sprintf("smbremotepath=%s", remotePath)}); err != nil { + fmt.Sprintf("smbremotepath=%s", remotePath)); err != nil { return fmt.Errorf("NewSmbGlobalMapping failed. output: %q, err: %v", string(output), err) } return nil @@ -77,7 +77,7 @@ func (SmbAPI) NewSmbGlobalMapping(remotePath, username, password string) error { func (SmbAPI) RemoveSmbGlobalMapping(remotePath string) error { cmd := `Remove-SmbGlobalMapping -RemotePath $Env:smbremotepath -Force` - if output, err := utils.RunPowershellCmdWithEnvs(cmd, []string{fmt.Sprintf("smbremotepath=%s", remotePath)}); err != nil { + if output, err := utils.RunPowershellCmd(cmd, fmt.Sprintf("smbremotepath=%s", remotePath)); err != nil { return fmt.Errorf("UnmountSmbShare failed. output: %q, err: %v", string(output), err) } return nil diff --git a/pkg/os/system/api.go b/pkg/os/system/api.go index 12a7dfdb..2a2740b9 100644 --- a/pkg/os/system/api.go +++ b/pkg/os/system/api.go @@ -56,7 +56,7 @@ func (APIImplementor) GetService(name string) (*ServiceInfo, error) { script := `Get-Service -Name $env:ServiceName | Select-Object DisplayName, Status, StartType | ` + `ConvertTo-JSON` cmdEnv := fmt.Sprintf("ServiceName=%s", name) - out, err := utils.RunPowershellCmdWithEnv(script, cmdEnv) + out, err := utils.RunPowershellCmd(script, cmdEnv) if err != nil { return nil, fmt.Errorf("error querying service name=%s. cmd: %s, output: %s, error: %v", name, script, string(out), err) } @@ -73,7 +73,7 @@ func (APIImplementor) GetService(name string) (*ServiceInfo, error) { func (APIImplementor) StartService(name string) error { script := `Start-Service -Name $env:ServiceName` cmdEnv := fmt.Sprintf("ServiceName=%s", name) - out, err := utils.RunPowershellCmdWithEnv(script, cmdEnv) + out, err := utils.RunPowershellCmd(script, cmdEnv) if err != nil { return fmt.Errorf("error starting service name=%s. cmd: %s, output: %s, error: %v", name, script, string(out), err) } @@ -83,7 +83,7 @@ func (APIImplementor) StartService(name string) error { func (APIImplementor) StopService(name string, force bool) error { script := `Stop-Service -Name $env:ServiceName -Force:$([System.Convert]::ToBoolean($env:Force))` - out, err := utils.RunPowershellCmdWithEnvs(script, []string{fmt.Sprintf("ServiceName=%s", name), fmt.Sprintf("Force=%t", force)}) + out, err := utils.RunPowershellCmd(script, fmt.Sprintf("ServiceName=%s", name), fmt.Sprintf("Force=%t", force)) if err != nil { return fmt.Errorf("error stopping service name=%s. cmd: %s, output: %s, error: %v", name, script, string(out), err) } diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index e5e71a80..87c50339 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -9,19 +9,9 @@ import ( const MaxPathLengthWindows = 260 -func RunPowershellCmd(command string) ([]byte, error) { - return RunPowershellCmdWithEnvs(command, nil) -} - -func RunPowershellCmdWithEnv(command string, env string) ([]byte, error) { - return RunPowershellCmdWithEnvs(command, []string{env}) -} - -func RunPowershellCmdWithEnvs(command string, envs []string) ([]byte, error) { +func RunPowershellCmd(command string, envs ...string) ([]byte, error) { cmd := exec.Command("powershell", "-Mta", "-NoProfile", "-Command", command) - if envs != nil { - cmd.Env = append(os.Environ(), envs...) - } + cmd.Env = append(os.Environ(), envs...) klog.V(8).Infof("Executing command: %q", cmd.String()) out, err := cmd.CombinedOutput() return out, err