agent/session/plugin/ssh/ssh.go (93 lines of code) (raw):
// Copyright (c) 2009-present, Alibaba Cloud All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ssh
import (
"fmt"
"os"
"os/signal"
"strconv"
"strings"
"syscall"
"github.com/aliyun/aliyun_assist_client/agent/session/plugin/cli"
"github.com/aliyun/aliyun_assist_client/agent/session/plugin/client"
"github.com/aliyun/aliyun_assist_client/agent/session/plugin/config"
"github.com/aliyun/aliyun_assist_client/agent/session/plugin/log"
"github.com/aliyun/aliyun_assist_client/agent/session/plugin/session"
"github.com/aliyun/aliyun_assist_client/agent/session/plugin/i18n"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
)
func NewSshCommand() *cli.Command {
c := &cli.Command{
Name: "ssh",
Short: i18n.T(
"use ssh proxy devops aliyun ecs instance",
"使用ssh proxy运维阿里云实例"),
Usage: "ssh --instance {instance_id} --port {port}",
Run: func(ctx *cli.Context, args []string) error {
if len(args) > 0 {
return cli.NewInvalidCommandError(args[0], ctx)
}
instance_id, _ := config.InstanceFlag(ctx.Flags()).GetValue()
wss_url, _ := config.WssUrlFlag(ctx.Flags()).GetValue()
return doSession(ctx, instance_id, wss_url)
},
}
return c
}
func doSession(ctx *cli.Context, instance_id string, wss_url string) error {
session.CheckSessionEnabled(ctx)
var websocket_url string
if instance_id != "" {
client, err := session.GetEcsClient(ctx)
if err != nil {
fmt.Print(err.Error())
log.GetLogger().Errorln(err)
return fmt.Errorf("get ecs client err:%v", err)
}
request := ecs.CreateStartTerminalSessionRequest()
request.Scheme = "https"
request.InstanceId = &[]string{instance_id}
port_val, _ := config.PortNumberFlag(ctx.Flags()).GetValue()
if port_val == "" {
port_val = "22"
}
port_i, _ := strconv.Atoi(port_val)
request.PortNumber = requests.NewInteger(port_i)
response, err := client.StartTerminalSession(request)
if err != nil {
log.GetLogger().Errorln(err, response)
fmt.Print(err.Error())
}
log.GetLogger().Infof("response is %#v\n", response)
websocket_url = response.WebSocketUrl
} else {
websocket_url = wss_url
}
log.GetLogger().Infoln("wss url:", websocket_url)
url := websocket_url
url = strings.Replace(url, "sessionid", "sessionId", 1)
log.GetLogger().Infoln("websocket url:", url)
client, err := client.NewClient(url, os.Stdin, os.Stdout, false, "", true, config.VerboseFlag(ctx.Flags()).IsAssigned(), 0)
// recvive signal from ssh, avoid killing by ssh
done := make(chan bool, 1)
go waitSignals(done)
if err = client.Loop(); err != nil {
log.GetLogger().Fatalf("Communication error: %v", err)
}
done <- true
return nil
}
func waitSignals(done chan bool) error {
sigChan := make(chan os.Signal, 1)
signal.Notify(
sigChan,
syscall.SIGHUP,
)
select {
case s := <-sigChan:
log.GetLogger().Infoln("recv signal: ", s)
break
case <-done:
break
}
log.GetLogger().Infoln("waitSignals return")
return nil
}