Skip to content

Commit 289a6b0

Browse files
authored
add sudo_password to use sudo mod. (#2402)
* fix: graceful delete runtime dir. Signed-off-by: joyceliu <[email protected]> * fix: graceful delete runtime dir. Signed-off-by: joyceliu <[email protected]> * fix: add `sudo` and SHELL in connector. Signed-off-by: joyceliu <[email protected]> --------- Signed-off-by: joyceliu <[email protected]> Co-authored-by: joyceliu <[email protected]>
1 parent d1026e1 commit 289a6b0

File tree

6 files changed

+79
-27
lines changed

6 files changed

+79
-27
lines changed

pkg/connector/connector.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ const (
3636
connectedKubernetes = "kubernetes"
3737
)
3838

39-
var shell = commandShell()
39+
var localShell = commandShell()
4040

4141
// Connector is the interface for connecting to a remote host
4242
type Connector interface {

pkg/connector/kubernetes_connector.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ func (c *kubernetesConnector) PutFile(_ context.Context, src []byte, dst string,
114114
func (c *kubernetesConnector) FetchFile(ctx context.Context, src string, dst io.Writer) error {
115115
// add "--kubeconfig" to src command
116116
klog.V(5).InfoS("exec local command", "cmd", src)
117-
command := c.Cmd.CommandContext(ctx, "/bin/sh", "-c", src)
117+
command := c.Cmd.CommandContext(ctx, localShell, "-c", src)
118118
command.SetDir(c.homeDir)
119119
command.SetEnv([]string{"KUBECONFIG=" + filepath.Join(c.homeDir, kubeconfigRelPath)})
120120
command.SetStdout(dst)
@@ -127,7 +127,7 @@ func (c *kubernetesConnector) FetchFile(ctx context.Context, src string, dst io.
127127
func (c *kubernetesConnector) ExecuteCommand(ctx context.Context, cmd string) ([]byte, error) {
128128
// add "--kubeconfig" to src command
129129
klog.V(5).InfoS("exec local command", "cmd", cmd)
130-
command := c.Cmd.CommandContext(ctx, shell, "-c", cmd)
130+
command := c.Cmd.CommandContext(ctx, localShell, "-c", cmd)
131131
command.SetDir(c.homeDir)
132132
command.SetEnv([]string{"KUBECONFIG=" + filepath.Join(c.homeDir, kubeconfigRelPath)})
133133

pkg/connector/local_connector.go

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import (
2828

2929
"k8s.io/klog/v2"
3030
"k8s.io/utils/exec"
31-
"k8s.io/utils/ptr"
3231

3332
_const "github.com/kubesphere/kubekey/v4/pkg/const"
3433
"github.com/kubesphere/kubekey/v4/pkg/variable"
@@ -38,17 +37,16 @@ var _ Connector = &localConnector{}
3837
var _ GatherFacts = &localConnector{}
3938

4039
func newLocalConnector(connectorVars map[string]any) *localConnector {
41-
sudo, err := variable.BoolVar(nil, connectorVars, _const.VariableConnectorSudo)
40+
sudo, err := variable.StringVar(nil, connectorVars, _const.VariableConnectorSudoPassword)
4241
if err != nil {
43-
klog.InfoS("get connector sudo failed use default port 22", "error", err)
44-
sudo = ptr.To(true)
42+
klog.V(4).InfoS("get connector sudo password failed, execute command without sudo", "error", err)
4543
}
4644

47-
return &localConnector{Sudo: *sudo, Cmd: exec.New()}
45+
return &localConnector{Sudo: sudo, Cmd: exec.New()}
4846
}
4947

5048
type localConnector struct {
51-
Sudo bool
49+
Sudo string
5250
Cmd exec.Interface
5351
}
5452

@@ -97,11 +95,16 @@ func (c *localConnector) FetchFile(_ context.Context, src string, dst io.Writer)
9795
// ExecuteCommand in local host
9896
func (c *localConnector) ExecuteCommand(ctx context.Context, cmd string) ([]byte, error) {
9997
klog.V(5).InfoS("exec local command", "cmd", cmd)
100-
if c.Sudo {
101-
return c.Cmd.CommandContext(ctx, "sudo", "-E", shell, "-c", cmd).CombinedOutput()
98+
// find command interpreter in env. default /bin/bash
99+
100+
if c.Sudo != "" {
101+
command := c.Cmd.CommandContext(ctx, "sudo", "-E", localShell, "-c", cmd)
102+
command.SetStdin(bytes.NewBufferString(c.Sudo + "\n"))
103+
104+
return command.CombinedOutput()
102105
}
103106

104-
return c.Cmd.CommandContext(ctx, shell, "-c", cmd).CombinedOutput()
107+
return c.Cmd.CommandContext(ctx, localShell, "-c", cmd).CombinedOutput()
105108
}
106109

107110
// HostInfo for GatherFacts

pkg/connector/ssh_connector.go

Lines changed: 61 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"os"
2727
"os/user"
2828
"path/filepath"
29+
"strings"
2930
"time"
3031

3132
"github.com/pkg/sftp"
@@ -38,8 +39,9 @@ import (
3839
)
3940

4041
const (
41-
defaultSSHPort = 22
42-
defaultSSHUser = "root"
42+
defaultSSHPort = 22
43+
defaultSSHUser = "root"
44+
defaultSSHSHELL = "/bin/bash"
4345
)
4446

4547
var defaultSSHPrivateKey string
@@ -56,16 +58,15 @@ var _ Connector = &sshConnector{}
5658
var _ GatherFacts = &sshConnector{}
5759

5860
func newSSHConnector(host string, connectorVars map[string]any) *sshConnector {
59-
sudo, err := variable.BoolVar(nil, connectorVars, _const.VariableConnectorSudo)
61+
sudo, err := variable.StringVar(nil, connectorVars, _const.VariableConnectorSudoPassword)
6062
if err != nil {
61-
klog.InfoS("get connector sudo failed use default port 22", "error", err)
62-
sudo = ptr.To(true)
63+
klog.V(4).InfoS("get connector sudo password failed, execute command without sudo", "error", err)
6364
}
6465

6566
// get host in connector variable. if empty, set default host: host_name.
6667
hostParam, err := variable.StringVar(nil, connectorVars, _const.VariableConnectorHost)
6768
if err != nil {
68-
klog.InfoS("get connector host failed use current hostname", "error", err)
69+
klog.V(4).InfoS("get connector host failed use current hostname", "error", err)
6970
hostParam = host
7071
}
7172
// get port in connector variable. if empty, set default port: 22.
@@ -93,23 +94,27 @@ func newSSHConnector(host string, connectorVars map[string]any) *sshConnector {
9394
}
9495

9596
return &sshConnector{
96-
Sudo: *sudo,
97+
Sudo: sudo,
9798
Host: hostParam,
9899
Port: *portParam,
99100
User: userParam,
100101
Password: passwdParam,
101102
PrivateKey: keyParam,
103+
shell: defaultSSHSHELL,
102104
}
103105
}
104106

105107
type sshConnector struct {
106-
Sudo bool
108+
Sudo string
107109
Host string
108110
Port int
109111
User string
110112
Password string
111113
PrivateKey string
112-
client *ssh.Client
114+
115+
client *ssh.Client
116+
// shell to execute command
117+
shell string
113118
}
114119

115120
// Init connector, get ssh.Client
@@ -147,6 +152,22 @@ func (c *sshConnector) Init(context.Context) error {
147152
}
148153
c.client = sshClient
149154

155+
// get shell from env
156+
session, err := sshClient.NewSession()
157+
if err != nil {
158+
return fmt.Errorf("create session error: %w", err)
159+
}
160+
defer session.Close()
161+
162+
output, err := session.CombinedOutput("echo $SHELL")
163+
if err != nil {
164+
return fmt.Errorf("env command error: %w", err)
165+
}
166+
167+
if strings.TrimSuffix(string(output), "\n") != "" {
168+
c.shell = strings.TrimSuffix(string(output), "\n")
169+
}
170+
150171
return nil
151172
}
152173

@@ -231,11 +252,39 @@ func (c *sshConnector) ExecuteCommand(_ context.Context, cmd string) ([]byte, er
231252
}
232253
defer session.Close()
233254

234-
if c.Sudo {
235-
return session.CombinedOutput(fmt.Sprintf("sudo -E %s -c \"%q\"", shell, cmd))
255+
if c.Sudo != "" {
256+
cmd = fmt.Sprintf("sudo -E %s -c \"%q\"", c.shell, cmd)
257+
// get pipe from session
258+
stdin, _ := session.StdinPipe()
259+
stdout, _ := session.StdoutPipe()
260+
stderr, _ := session.StderrPipe()
261+
// Request a pseudo-terminal (required for sudo password input)
262+
if err := session.RequestPty("xterm", 80, 40, ssh.TerminalModes{}); err != nil {
263+
return nil, err
264+
}
265+
// Start the remote command
266+
if err := session.Start(cmd); err != nil {
267+
return nil, err
268+
}
269+
// Write sudo password to the standard input
270+
if _, err := io.WriteString(stdin, c.Sudo+"\n"); err != nil {
271+
return nil, err
272+
}
273+
// Read the command output
274+
output := make([]byte, 0)
275+
stdoutData, _ := io.ReadAll(stdout)
276+
stderrData, _ := io.ReadAll(stderr)
277+
output = append(output, stdoutData...)
278+
output = append(output, stderrData...)
279+
// Wait for the command to complete
280+
if err := session.Wait(); err != nil {
281+
return nil, err
282+
}
283+
284+
return output, nil
236285
}
237286

238-
return session.CombinedOutput(fmt.Sprintf("%s -c \"%q\"", shell, cmd))
287+
return session.CombinedOutput(fmt.Sprintf("%s -c \"%q\"", c.shell, cmd))
239288
}
240289

241290
// HostInfo for GatherFacts

pkg/const/common.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ const ( // === From inventory ===
3030
VariableConnector = "connector"
3131
// VariableConnectorType is connected type for VariableConnector.
3232
VariableConnectorType = "type"
33-
// VariableConnectorSudo is connected address for VariableConnector.
34-
VariableConnectorSudo = "sudo"
33+
// VariableConnectorSudoPassword is connected address for VariableConnector.
34+
VariableConnectorSudoPassword = "sudo_password"
3535
// VariableConnectorHost is connected address for VariableConnector.
3636
VariableConnectorHost = "host"
3737
// VariableConnectorPort is connected address for VariableConnector.

pkg/executor/pipeline_executor.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ func (e pipelineExecutor) execBatchHosts(ctx context.Context, play kkprojectv1.P
168168
option: e.option,
169169
hosts: serials,
170170
ignoreErrors: play.IgnoreErrors,
171-
blocks: play.Tasks,
171+
blocks: play.PostTasks,
172172
tags: play.Taggable,
173173
}.Exec(ctx)); err != nil {
174174
return fmt.Errorf("execute post-tasks error: %w", err)

0 commit comments

Comments
 (0)