1ba991379Sopenharmony_ci/* 2ba991379Sopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd. 3ba991379Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4ba991379Sopenharmony_ci * you may not use this file except in compliance with the License. 5ba991379Sopenharmony_ci * You may obtain a copy of the License at 6ba991379Sopenharmony_ci * 7ba991379Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8ba991379Sopenharmony_ci * 9ba991379Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10ba991379Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11ba991379Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12ba991379Sopenharmony_ci * See the License for the specific language governing permissions and 13ba991379Sopenharmony_ci * limitations under the License. 14ba991379Sopenharmony_ci */ 15ba991379Sopenharmony_ci 16ba991379Sopenharmony_cipackage utils 17ba991379Sopenharmony_ci 18ba991379Sopenharmony_ciimport ( 19ba991379Sopenharmony_ci "context" 20ba991379Sopenharmony_ci "errors" 21ba991379Sopenharmony_ci "fmt" 22ba991379Sopenharmony_ci "github.com/pkg/sftp" 23ba991379Sopenharmony_ci "github.com/sirupsen/logrus" 24ba991379Sopenharmony_ci "golang.org/x/crypto/ssh" 25ba991379Sopenharmony_ci "io" 26ba991379Sopenharmony_ci "os" 27ba991379Sopenharmony_ci "path/filepath" 28ba991379Sopenharmony_ci "time" 29ba991379Sopenharmony_ci) 30ba991379Sopenharmony_ci 31ba991379Sopenharmony_cifunc newSSHClient(addr string, user string, passwd string) (*ssh.Client, error) { 32ba991379Sopenharmony_ci config := &ssh.ClientConfig{ 33ba991379Sopenharmony_ci User: user, 34ba991379Sopenharmony_ci Auth: []ssh.AuthMethod{ssh.Password(passwd)}, 35ba991379Sopenharmony_ci HostKeyCallback: ssh.InsecureIgnoreHostKey(), 36ba991379Sopenharmony_ci } 37ba991379Sopenharmony_ci config.SetDefaults() 38ba991379Sopenharmony_ci return ssh.Dial("tcp", addr, config) 39ba991379Sopenharmony_ci} 40ba991379Sopenharmony_ci 41ba991379Sopenharmony_cifunc RunCmdViaSSHContext(ctx context.Context, addr string, user string, passwd string, cmd string) (err error) { 42ba991379Sopenharmony_ci ctx, fn := context.WithTimeout(ctx, 6*time.Hour) 43ba991379Sopenharmony_ci defer fn() 44ba991379Sopenharmony_ci if err := RunCmdViaSSHContextNoRetry(ctx, addr, user, passwd, cmd); err != nil { 45ba991379Sopenharmony_ci if errors.Is(err, context.Canceled) { 46ba991379Sopenharmony_ci return err 47ba991379Sopenharmony_ci } 48ba991379Sopenharmony_ci logrus.Errorf("exec cmd via SSH at %s failed: %v, try again...", addr, err) 49ba991379Sopenharmony_ci return RunCmdViaSSHContextNoRetry(ctx, addr, user, passwd, cmd) 50ba991379Sopenharmony_ci } 51ba991379Sopenharmony_ci return nil 52ba991379Sopenharmony_ci} 53ba991379Sopenharmony_ci 54ba991379Sopenharmony_cifunc RunCmdViaSSHContextNoRetry(ctx context.Context, addr string, user string, passwd string, cmd string) (err error) { 55ba991379Sopenharmony_ci exit := make(chan struct{}) 56ba991379Sopenharmony_ci client, err := newSSHClient(addr, user, passwd) 57ba991379Sopenharmony_ci if err != nil { 58ba991379Sopenharmony_ci logrus.Errorf("new SSH client to %s err: %v", addr, err) 59ba991379Sopenharmony_ci return err 60ba991379Sopenharmony_ci } 61ba991379Sopenharmony_ci defer client.Close() 62ba991379Sopenharmony_ci session, err := client.NewSession() 63ba991379Sopenharmony_ci if err != nil { 64ba991379Sopenharmony_ci return err 65ba991379Sopenharmony_ci } 66ba991379Sopenharmony_ci defer func() { 67ba991379Sopenharmony_ci select { 68ba991379Sopenharmony_ci case <-ctx.Done(): 69ba991379Sopenharmony_ci err = ctx.Err() 70ba991379Sopenharmony_ci default: 71ba991379Sopenharmony_ci } 72ba991379Sopenharmony_ci }() 73ba991379Sopenharmony_ci defer close(exit) 74ba991379Sopenharmony_ci go func() { 75ba991379Sopenharmony_ci select { 76ba991379Sopenharmony_ci case <-ctx.Done(): 77ba991379Sopenharmony_ci case <-exit: 78ba991379Sopenharmony_ci } 79ba991379Sopenharmony_ci session.Close() 80ba991379Sopenharmony_ci }() 81ba991379Sopenharmony_ci logrus.Infof("run at %s: %s", addr, cmd) 82ba991379Sopenharmony_ci stdin, err := session.StdinPipe() 83ba991379Sopenharmony_ci if err != nil { 84ba991379Sopenharmony_ci return err 85ba991379Sopenharmony_ci } 86ba991379Sopenharmony_ci defer stdin.Close() 87ba991379Sopenharmony_ci stdout, err := session.StdoutPipe() 88ba991379Sopenharmony_ci if err != nil { 89ba991379Sopenharmony_ci return err 90ba991379Sopenharmony_ci } 91ba991379Sopenharmony_ci stderr, err := session.StderrPipe() 92ba991379Sopenharmony_ci if err != nil { 93ba991379Sopenharmony_ci return err 94ba991379Sopenharmony_ci } 95ba991379Sopenharmony_ci if err := session.Shell(); err != nil { 96ba991379Sopenharmony_ci return err 97ba991379Sopenharmony_ci } 98ba991379Sopenharmony_ci cmd = fmt.Sprintf("%s\nexit $?\n", cmd) 99ba991379Sopenharmony_ci go stdin.Write([]byte(cmd)) 100ba991379Sopenharmony_ci go io.Copy(os.Stdout, stdout) 101ba991379Sopenharmony_ci go io.Copy(os.Stderr, stderr) 102ba991379Sopenharmony_ci fmt.Printf("[%s] exec at %s %s :\n", time.Now(), addr, cmd) 103ba991379Sopenharmony_ci return session.Wait() 104ba991379Sopenharmony_ci} 105ba991379Sopenharmony_ci 106ba991379Sopenharmony_citype Direct string 107ba991379Sopenharmony_ci 108ba991379Sopenharmony_ciconst ( 109ba991379Sopenharmony_ci Download Direct = "download" 110ba991379Sopenharmony_ci Upload Direct = "upload" 111ba991379Sopenharmony_ci) 112ba991379Sopenharmony_ci 113ba991379Sopenharmony_cifunc TransFileViaSSH(verb Direct, addr string, user string, passwd string, remoteFile string, localFile string) error { 114ba991379Sopenharmony_ci c, err := newSSHClient(addr, user, passwd) 115ba991379Sopenharmony_ci if err != nil { 116ba991379Sopenharmony_ci logrus.Errorf("new SSH client to %s err: %v", addr, err) 117ba991379Sopenharmony_ci return err 118ba991379Sopenharmony_ci } 119ba991379Sopenharmony_ci defer c.Close() 120ba991379Sopenharmony_ci client, err := sftp.NewClient(c) 121ba991379Sopenharmony_ci if err != nil { 122ba991379Sopenharmony_ci logrus.Errorf("new SFTP client to %s err: %v", addr, err) 123ba991379Sopenharmony_ci return err 124ba991379Sopenharmony_ci } 125ba991379Sopenharmony_ci defer client.Close() 126ba991379Sopenharmony_ci var prep string 127ba991379Sopenharmony_ci var src, dst io.ReadWriteCloser 128ba991379Sopenharmony_ci if verb == Download { 129ba991379Sopenharmony_ci prep = "to" 130ba991379Sopenharmony_ci if src, err = client.Open(remoteFile); err != nil { 131ba991379Sopenharmony_ci return fmt.Errorf("open remote file %s at %s err: %v", remoteFile, addr, err) 132ba991379Sopenharmony_ci } 133ba991379Sopenharmony_ci defer src.Close() 134ba991379Sopenharmony_ci os.RemoveAll(localFile) 135ba991379Sopenharmony_ci os.MkdirAll(filepath.Dir(localFile), 0755) 136ba991379Sopenharmony_ci if dst, err = os.Create(localFile); err != nil { 137ba991379Sopenharmony_ci return fmt.Errorf("create local file err: %v", err) 138ba991379Sopenharmony_ci } 139ba991379Sopenharmony_ci defer dst.Close() 140ba991379Sopenharmony_ci } else { 141ba991379Sopenharmony_ci prep = "from" 142ba991379Sopenharmony_ci if src, err = os.Open(localFile); err != nil { 143ba991379Sopenharmony_ci return fmt.Errorf("open local file err: %v", err) 144ba991379Sopenharmony_ci } 145ba991379Sopenharmony_ci defer src.Close() 146ba991379Sopenharmony_ci client.Remove(remoteFile) 147ba991379Sopenharmony_ci client.MkdirAll(filepath.Dir(remoteFile)) 148ba991379Sopenharmony_ci if dst, err = client.Create(remoteFile); err != nil { 149ba991379Sopenharmony_ci return fmt.Errorf("create remote file %s at %s err: %v", remoteFile, addr, err) 150ba991379Sopenharmony_ci } 151ba991379Sopenharmony_ci defer dst.Close() 152ba991379Sopenharmony_ci } 153ba991379Sopenharmony_ci logrus.Infof("%sing %s at %s %s %s...", verb, remoteFile, addr, prep, localFile) 154ba991379Sopenharmony_ci t1 := time.Now() 155ba991379Sopenharmony_ci n, err := io.CopyBuffer(dst, src, make([]byte, 32*1024*1024)) 156ba991379Sopenharmony_ci if err != nil { 157ba991379Sopenharmony_ci logrus.Errorf("%s %s at %s %s %s err: %v", verb, remoteFile, addr, prep, localFile, err) 158ba991379Sopenharmony_ci return err 159ba991379Sopenharmony_ci } 160ba991379Sopenharmony_ci t2 := time.Now() 161ba991379Sopenharmony_ci cost := t2.Sub(t1).Seconds() 162ba991379Sopenharmony_ci logrus.Infof("%s %s at %s %s %s done, size: %d cost: %.2fs speed: %.2fMB/s", verb, remoteFile, addr, prep, localFile, n, cost, float64(n)/cost/1024/1024) 163ba991379Sopenharmony_ci return nil 164ba991379Sopenharmony_ci} 165