@@ -3,14 +3,14 @@ package cmd
33import (
44 "context"
55 "errors"
6+ "fmt"
67 "os"
78 "os/exec"
89 "os/user"
910 "path/filepath"
1011 "strconv"
1112 "strings"
1213 "syscall"
13- "time"
1414
1515 "github.com/cybozu-go/cke"
1616 "github.com/cybozu-go/log"
@@ -26,51 +26,45 @@ func detectSSHNode(arg string) string {
2626 return nodeName
2727}
2828
29- func writeToFifo ( fifo string , data string ) {
30- f , err := os . OpenFile ( fifo , os . O_WRONLY , 0600 )
29+ func createFifo2 () ( string , error ) {
30+ usr , err := user . Current ( )
3131 if err != nil {
32- log .Error ("failed to open fifo" , map [string ]interface {}{
33- log .FnError : err ,
34- "fifo" : fifo ,
35- })
36- return
32+ return "" , err
3733 }
38- defer f .Close ()
3934
40- _ , err = f .WriteString (data )
41- if err != nil {
42- log .Error ("failed to write to fifo" , map [string ]interface {}{
43- log .FnError : err ,
44- "fifo" : fifo ,
45- })
35+ fifoFilePath := filepath .Join (usr .HomeDir , ".ssh" , "ckecli-ssh-key-" + strconv .Itoa (os .Getpid ()))
36+ _ , err = os .Stat (fifoFilePath )
37+ if os .IsExist (err ) {
38+ return fifoFilePath , nil
4639 }
47- }
48-
49- func sshPrivateKey (nodeName string ) (string , error ) {
50- usr , err := user .Current ()
51- if err != nil {
40+ if ! os .IsNotExist (err ) {
5241 return "" , err
5342 }
43+
5444 err = os .MkdirAll (filepath .Join (usr .HomeDir , ".ssh" ), 0700 )
5545 if err != nil {
5646 return "" , err
5747 }
58- fifo := filepath . Join ( usr . HomeDir , ".ssh" , "ckecli-ssh-key-" + strconv . Itoa ( os . Getpid ()))
59- err = syscall .Mkfifo (fifo , 0600 )
48+
49+ err = syscall .Mkfifo (fifoFilePath , 0600 )
6050 if err != nil {
6151 return "" , err
6252 }
6353
54+ return fifoFilePath , err
55+ }
56+
57+ func getPrivateKey (nodeName string ) ([]byte , error ) {
6458 vc , err := inf .Vault ()
6559 if err != nil {
66- return "" , err
60+ return nil , err
6761 }
6862 secret , err := vc .Logical ().Read (cke .SSHSecret )
6963 if err != nil {
70- return "" , err
64+ return nil , err
7165 }
7266 if secret == nil {
73- return "" , errors .New ("no ssh private keys" )
67+ return nil , errors .New ("no ssh private keys" )
7468 }
7569 privKeys := secret .Data
7670
@@ -79,31 +73,124 @@ func sshPrivateKey(nodeName string) (string, error) {
7973 mykey = privKeys ["" ]
8074 }
8175 if mykey == nil {
82- return "" , errors .New ("no ssh private key for " + nodeName )
76+ return nil , errors .New ("no ssh private key for " + nodeName )
8377 }
78+ /*
79+ go func() {
80+ // OpenSSH reads the private key file three times, it need to write key three times.
81+ writeToFifo(fifo, mykey.(string))
82+ time.Sleep(100 * time.Millisecond)
83+ writeToFifo(fifo, mykey.(string))
84+ time.Sleep(100 * time.Millisecond)
85+ writeToFifo(fifo, mykey.(string))
86+ }()
87+ */
88+ return mykey .([]byte ), nil
89+ }
8490
85- go func () {
86- // OpenSSH reads the private key file three times, it need to write key three times.
87- writeToFifo (fifo , mykey .(string ))
88- time .Sleep (100 * time .Millisecond )
89- writeToFifo (fifo , mykey .(string ))
90- time .Sleep (100 * time .Millisecond )
91- writeToFifo (fifo , mykey .(string ))
92- }()
91+ func sshAgent (ctx context.Context , privateKeyFile string ) (map [string ]string , error ) {
92+ myEnv := make (map [string ]string )
93+
94+ sshArgs := []string {
95+ "-s" ,
96+ }
97+ cmd := exec .CommandContext (ctx , "ssh-agent" , sshArgs ... )
98+ stdoutStderr , err := cmd .CombinedOutput ()
99+ if err != nil {
100+ return nil , err
101+ }
102+ line := strings .Split (string (stdoutStderr ), "\n " )
103+
104+ partOfLine := strings .Split (line [0 ], ";" )
105+ kvPair := strings .Split (partOfLine [0 ], "=" )
106+ myEnv [kvPair [0 ]] = kvPair [1 ]
107+ err = os .Setenv (kvPair [0 ], kvPair [1 ])
108+ if err != nil {
109+ return nil , err
110+ }
93111
94- return fifo , nil
112+ partOfLine = strings .Split (line [1 ], ";" )
113+ kvPair = strings .Split (partOfLine [0 ], "=" )
114+ myEnv [kvPair [0 ]] = kvPair [1 ]
115+ err = os .Setenv (kvPair [0 ], kvPair [1 ])
116+ if err != nil {
117+ return nil , err
118+ }
119+
120+ sshArgs2 := []string {
121+ privateKeyFile ,
122+ }
123+ cmd0 := exec .CommandContext (ctx , "ssh-add" , sshArgs2 ... )
124+ _ , err = cmd0 .CombinedOutput ()
125+ if err != nil {
126+ return nil , err
127+ }
128+
129+ return myEnv , nil
95130}
96131
97- func ssh (ctx context.Context , args []string ) error {
132+ func killSshAgent (ctx context.Context ) error {
133+ sshArgs := []string {
134+ "-k" ,
135+ }
136+ cmd := exec .CommandContext (ctx , "ssh-agent" , sshArgs ... )
137+ stdoutStderr , err := cmd .CombinedOutput ()
138+ if err != nil {
139+ fmt .Println ("Error ssh-agent -k " , err )
140+ return err
141+ }
142+ fmt .Println ("kill ssh agent :: output=" , string (stdoutStderr ))
143+ return nil
144+ }
145+
146+ func writeToFifo (fifo string , data []byte ) error {
147+ f , err := os .OpenFile (fifo , os .O_WRONLY | os .O_CREATE | os .O_APPEND , os .ModeNamedPipe )
148+ if err != nil {
149+ log .Error ("failed to open fifo" , map [string ]interface {}{
150+ log .FnError : err ,
151+ "fifo" : fifo ,
152+ })
153+ return err
154+ }
155+ defer f .Close ()
156+ if _ , err = f .Write (data ); err != nil {
157+ log .Error ("failed to write to fifo" , map [string ]interface {}{
158+ log .FnError : err ,
159+ "fifo" : fifo ,
160+ })
161+ return err
162+ }
163+ return nil
164+ }
165+
166+ func sshSubMain (ctx context.Context , args []string ) error {
167+ pipeFilename , err := createFifo2 ()
168+ if err != nil {
169+ return err
170+ }
171+
98172 node := detectSSHNode (args [0 ])
99- fifo , err := sshPrivateKey (node )
173+ pirvateKey , err := getPrivateKey (node )
100174 if err != nil {
101175 return err
102176 }
103- defer os .Remove (fifo )
104177
178+ go func () {
179+ if _ , err := sshAgent (ctx , pipeFilename ); err != nil {
180+ fmt .Println ("getPrivateKey err=" , err , "node=" , node )
181+ // ログ出力
182+ return
183+ }
184+ }()
185+
186+ if err = writeToFifo (pipeFilename , pirvateKey ); err != nil {
187+ return err
188+ }
189+ defer os .Remove (pipeFilename )
190+ defer killSshAgent (ctx )
191+
192+ //return ssh(ctx, args)
105193 sshArgs := []string {
106- "-i" , fifo ,
107194 "-o" , "UserKnownHostsFile=/dev/null" ,
108195 "-o" , "StrictHostKeyChecking=no" ,
109196 "-o" , "ConnectTimeout=60" ,
@@ -116,6 +203,22 @@ func ssh(ctx context.Context, args []string) error {
116203 return c .Run ()
117204}
118205
206+ /*
207+ func ssh(ctx context.Context, args []string) (error, string) {
208+ sshArgs := []string{
209+ "-o", "UserKnownHostsFile=/dev/null",
210+ "-o", "StrictHostKeyChecking=no",
211+ "-o", "ConnectTimeout=60",
212+ }
213+ sshArgs = append(sshArgs, args...)
214+ c := exec.CommandContext(ctx, "ssh", sshArgs...)
215+ c.Stdin = os.Stdin
216+ c.Stdout = os.Stdout
217+ c.Stderr = os.Stderr
218+ return c.Run(), "OK"
219+ }
220+ */
221+
119222// sshCmd represents the ssh command
120223var sshCmd = & cobra.Command {
121224 Use : "ssh [user@]NODE [COMMAND...]" ,
@@ -130,7 +233,7 @@ If COMMAND is specified, it will be executed on the node.
130233 Args : cobra .MinimumNArgs (1 ),
131234 RunE : func (cmd * cobra.Command , args []string ) error {
132235 well .Go (func (ctx context.Context ) error {
133- return ssh (ctx , args )
236+ return sshSubMain (ctx , args )
134237 })
135238 well .Stop ()
136239 return well .Wait ()
0 commit comments