Add recovery event

This commit is contained in:
mudler
2022-08-12 09:40:40 +02:00
committed by Ettore Di Giacinto
parent 33eb2d9a84
commit 5e1ba9265d
8 changed files with 185 additions and 118 deletions

8
go.mod
View File

@@ -3,18 +3,23 @@ module github.com/c3os-io/provider-c3os
go 1.18 go 1.18
replace github.com/c3os-io/c3os => /home/mudler/_git/c3os replace github.com/c3os-io/c3os => /home/mudler/_git/c3os
replace github.com/c3os-io/c3os/sdk => /home/mudler/_git/c3os/sdk replace github.com/c3os-io/c3os/sdk => /home/mudler/_git/c3os/sdk
require ( require (
github.com/c3os-io/c3os v0.0.0-00010101000000-000000000000 github.com/c3os-io/c3os v0.0.0-00010101000000-000000000000
github.com/c3os-io/c3os/sdk v0.0.0-20220810165607-7d6553114e1d github.com/c3os-io/c3os/sdk v0.0.0-20220810165607-7d6553114e1d
github.com/creack/pty v1.1.19-0.20220421211855-0d412c9fbeb1
github.com/gliderlabs/ssh v0.2.2
github.com/ipfs/go-log v1.0.5 github.com/ipfs/go-log v1.0.5
github.com/mudler/edgevpn v0.15.3 github.com/mudler/edgevpn v0.15.3
github.com/mudler/go-nodepair v0.0.0-20220507212557-7d47aa3cc1f1 github.com/mudler/go-nodepair v0.0.0-20220507212557-7d47aa3cc1f1
github.com/mudler/go-pluggable v0.0.0-20220716112424-189d463e3ff3 github.com/mudler/go-pluggable v0.0.0-20220716112424-189d463e3ff3
github.com/mudler/go-processmanager v0.0.0-20211226182900-899fbb0b97f6
github.com/mudler/yip v0.0.0-20220725150231-976737b2353c github.com/mudler/yip v0.0.0-20220725150231-976737b2353c
github.com/onsi/ginkgo/v2 v2.1.3 github.com/onsi/ginkgo/v2 v2.1.3
github.com/onsi/gomega v1.19.0 github.com/onsi/gomega v1.19.0
github.com/pterm/pterm v0.12.41
github.com/urfave/cli v1.22.9 github.com/urfave/cli v1.22.9
go.uber.org/zap v1.21.0 go.uber.org/zap v1.21.0
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0
@@ -23,6 +28,7 @@ require (
) )
require ( require (
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 // indirect
github.com/atomicgo/cursor v0.0.1 // indirect github.com/atomicgo/cursor v0.0.1 // indirect
github.com/avast/retry-go v3.0.0+incompatible // indirect github.com/avast/retry-go v3.0.0+incompatible // indirect
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect
@@ -124,7 +130,6 @@ require (
github.com/minio/sha256-simd v1.0.0 // indirect github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect github.com/mr-tron/base58 v1.2.0 // indirect
github.com/mudler/go-isterminal v0.0.0-20211031135732-5e4e06fc5a58 // indirect github.com/mudler/go-isterminal v0.0.0-20211031135732-5e4e06fc5a58 // indirect
github.com/mudler/go-processmanager v0.0.0-20211226182900-899fbb0b97f6 // indirect
github.com/multiformats/go-base32 v0.0.4 // indirect github.com/multiformats/go-base32 v0.0.4 // indirect
github.com/multiformats/go-base36 v0.1.0 // indirect github.com/multiformats/go-base36 v0.1.0 // indirect
github.com/multiformats/go-multiaddr v0.5.0 // indirect github.com/multiformats/go-multiaddr v0.5.0 // indirect
@@ -148,7 +153,6 @@ require (
github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.34.0 // indirect github.com/prometheus/common v0.34.0 // indirect
github.com/prometheus/procfs v0.7.3 // indirect github.com/prometheus/procfs v0.7.3 // indirect
github.com/pterm/pterm v0.12.41 // indirect
github.com/qeesung/image2ascii v1.0.1 // indirect github.com/qeesung/image2ascii v1.0.1 // indirect
github.com/raulk/clock v1.1.0 // indirect github.com/raulk/clock v1.1.0 // indirect
github.com/raulk/go-watchdog v1.2.0 // indirect github.com/raulk/go-watchdog v1.2.0 // indirect

7
go.sum
View File

@@ -74,6 +74,7 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
@@ -138,8 +139,6 @@ github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46f
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/c-robinson/iplib v1.0.3 h1:NG0UF0GoEsrC1/vyfX1Lx2Ss7CySWl3KqqXh3q4DdPU= github.com/c-robinson/iplib v1.0.3 h1:NG0UF0GoEsrC1/vyfX1Lx2Ss7CySWl3KqqXh3q4DdPU=
github.com/c-robinson/iplib v1.0.3/go.mod h1:i3LuuFL1hRT5gFpBRnEydzw8R6yhGkF4szNDIbF8pgo= github.com/c-robinson/iplib v1.0.3/go.mod h1:i3LuuFL1hRT5gFpBRnEydzw8R6yhGkF4szNDIbF8pgo=
github.com/c3os-io/c3os/sdk v0.0.0-20220810165607-7d6553114e1d h1:2M/zhLA6v0pt/GQ7+EqMYgqQDkAZWfxMQvTScEb5TcE=
github.com/c3os-io/c3os/sdk v0.0.0-20220810165607-7d6553114e1d/go.mod h1:yZVjsJTesh10MvO82nXoLJcN11faoZb2hfG06veCm1k=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/cavaliergopher/grab v2.0.0+incompatible/go.mod h1:6ICNRTQPwkMP0m2sKIDv/9XkhFJJwiEOQyZ+8E4H7Yg= github.com/cavaliergopher/grab v2.0.0+incompatible/go.mod h1:6ICNRTQPwkMP0m2sKIDv/9XkhFJJwiEOQyZ+8E4H7Yg=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
@@ -194,6 +193,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHH
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.19-0.20220421211855-0d412c9fbeb1 h1:Tw0uuY+3UWYiSbR0+wsrJ30vY3zMFZ4JNPkSp9XdFyA=
github.com/creack/pty v1.1.19-0.20220421211855-0d412c9fbeb1/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -250,6 +251,7 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ=
github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag=
@@ -270,6 +272,7 @@ github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5 h1:Y5Q2mEwfzjMt5+3u7
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5/go.mod h1:uF6rMu/1nvu+5DpiRLwusA6xB8zlkNoGzKn8lmYONUo= github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5/go.mod h1:uF6rMu/1nvu+5DpiRLwusA6xB8zlkNoGzKn8lmYONUo=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=

98
internal/cli/recovery.go Normal file
View File

@@ -0,0 +1,98 @@
package cli
import (
"context"
"fmt"
"io"
"os/exec"
"time"
config "github.com/c3os-io/c3os/pkg/config"
"github.com/ipfs/go-log"
"github.com/creack/pty"
"github.com/gliderlabs/ssh"
"github.com/mudler/edgevpn/pkg/logger"
"github.com/mudler/edgevpn/pkg/node"
"github.com/mudler/edgevpn/pkg/services"
"github.com/pterm/pterm"
)
func startRecoveryService(ctx context.Context, token, name, address, loglevel string) error {
nc := config.Network(token, "", loglevel, "c3osrecovery0")
lvl, err := log.LevelFromString(loglevel)
if err != nil {
lvl = log.LevelError
}
llger := logger.New(lvl)
o, _, err := nc.ToOpts(llger)
if err != nil {
llger.Fatal(err.Error())
}
o = append(o,
services.Alive(
time.Duration(20)*time.Second,
time.Duration(10)*time.Second,
time.Duration(10)*time.Second)...)
// opts, err := vpn.Register(vpnOpts...)
// if err != nil {
// return err
// }
o = append(o, services.RegisterService(llger, time.Duration(5*time.Second), name, address)...)
e, err := node.New(o...)
if err != nil {
return err
}
return e.Start(ctx)
}
func sshServer(listenAdddr, password string) {
ssh.Handle(func(s ssh.Session) {
cmd := exec.Command("bash")
ptyReq, winCh, isPty := s.Pty()
if isPty {
cmd.Env = append(cmd.Env, fmt.Sprintf("TERM=%s", ptyReq.Term))
f, err := pty.Start(cmd)
if err != nil {
pterm.Warning.Println("Failed reserving tty")
}
go func() {
for win := range winCh {
setWinsize(f, win.Width, win.Height)
}
}()
go func() {
io.Copy(f, s) //nolint:errcheck
}()
io.Copy(s, f) //nolint:errcheck
cmd.Wait() //nolint:errcheck
} else {
io.WriteString(s, "No PTY requested.\n") //nolint:errcheck
s.Exit(1) //nolint:errcheck
}
})
pterm.Info.Println(ssh.ListenAndServe(listenAdddr, nil, ssh.PasswordAuth(func(ctx ssh.Context, pass string) bool {
return pass == password
}),
))
}
func StartRecoveryService(tk, serviceUUID, generatedPassword, listenAddr string) error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
if err := startRecoveryService(ctx, tk, serviceUUID, listenAddr, "fatal"); err != nil {
return err
}
sshServer(listenAddr, generatedPassword)
return fmt.Errorf("should not return")
}

View File

@@ -1,4 +1,4 @@
package provider package cli
import ( import (
"os" "os"

View File

@@ -1,4 +1,4 @@
package provider package cli
import ( import (
"os" "os"

View File

@@ -30,6 +30,8 @@ var networkAPI = []cli.Flag{
}, },
} }
const recoveryAddr = "127.0.0.1:2222"
func Start() error { func Start() error {
app := &cli.App{ app := &cli.App{
Name: "c3os", Name: "c3os",
@@ -50,8 +52,38 @@ For all the example cases, see: https://docs.c3os.io .
`, `,
UsageText: ``, UsageText: ``,
Copyright: "Ettore Di Giacinto", Copyright: "Ettore Di Giacinto",
Commands: []cli.Command{ Commands: []cli.Command{
{
Name: "recovery-ssh-server",
UsageText: "recovery-ssh-server",
Usage: "Starts SSH recovery service",
Description: `
Spawn up a simple standalone ssh server over p2p
`,
ArgsUsage: "Spawn up a simple standalone ssh server over p2p",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "token",
EnvVar: "TOKEN",
},
&cli.StringFlag{
Name: "service",
EnvVar: "SERVICE",
},
&cli.StringFlag{
Name: "password",
EnvVar: "PASSWORD",
},
&cli.StringFlag{
Name: "listen",
EnvVar: "LISTEN",
Value: recoveryAddr,
},
},
Action: func(c *cli.Context) error {
return StartRecoveryService(c.String("token"), c.String("service"), c.String("password"), c.String("listen"))
},
},
{ {
Name: "register", Name: "register",
UsageText: "register --reboot --device /dev/sda /image/snapshot.png", UsageText: "register --reboot --device /dev/sda /image/snapshot.png",

View File

@@ -1,136 +1,64 @@
package agent package provider
import ( import (
"context"
"fmt" "fmt"
"io" "os"
"os/exec"
"time"
"github.com/c3os-io/c3os/internal/cmd"
config "github.com/c3os-io/c3os/pkg/config"
"github.com/c3os-io/c3os/pkg/utils" "github.com/c3os-io/c3os/pkg/utils"
"github.com/ipfs/go-log"
machine "github.com/c3os-io/c3os/pkg/machine"
"github.com/creack/pty"
"github.com/gliderlabs/ssh"
"github.com/mudler/edgevpn/pkg/logger"
"github.com/mudler/edgevpn/pkg/node"
"github.com/mudler/edgevpn/pkg/services"
nodepair "github.com/mudler/go-nodepair" nodepair "github.com/mudler/go-nodepair"
qr "github.com/mudler/go-nodepair/qrcode" "github.com/mudler/go-pluggable"
"github.com/pterm/pterm" process "github.com/mudler/go-processmanager"
) )
const recoveryAddr = "127.0.0.1:2222" const recoveryAddr = "127.0.0.1:2222"
const sshStateDir = "/tmp/.ssh_recovery"
func startRecoveryService(ctx context.Context, token, name, address, loglevel string) error { func Recovery(e *pluggable.Event) pluggable.EventResponse {
nc := config.Network(token, "", loglevel, "c3osrecovery0") resp := &pluggable.EventResponse{}
lvl, err := log.LevelFromString(loglevel)
if err != nil {
lvl = log.LevelError
}
llger := logger.New(lvl)
o, _, err := nc.ToOpts(llger)
if err != nil {
llger.Fatal(err.Error())
}
o = append(o,
services.Alive(
time.Duration(20)*time.Second,
time.Duration(10)*time.Second,
time.Duration(10)*time.Second)...)
// opts, err := vpn.Register(vpnOpts...)
// if err != nil {
// return err
// }
o = append(o, services.RegisterService(llger, time.Duration(5*time.Second), name, address)...)
e, err := node.New(o...)
if err != nil {
return err
}
return e.Start(ctx)
}
func Recovery() error {
cmd.PrintBranding(DefaultBanner)
agentConfig, err := LoadConfig()
if err != nil {
return err
}
tk := nodepair.GenerateToken() tk := nodepair.GenerateToken()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
serviceUUID := utils.RandStringRunes(10) serviceUUID := utils.RandStringRunes(10)
generatedPassword := utils.RandStringRunes(7) generatedPassword := utils.RandStringRunes(7)
resp.Data = utils.EncodeRecoveryToken(tk, serviceUUID, generatedPassword)
if err := startRecoveryService(ctx, tk, serviceUUID, recoveryAddr, "fatal"); err != nil { resp.State = fmt.Sprintf(
return err
}
cmd.PrintText(agentConfig.Branding.Recovery, "Recovery")
time.Sleep(5 * time.Second)
pterm.Info.Printfln(
"starting ssh server on '%s', password: '%s' service: '%s' ", recoveryAddr, generatedPassword, serviceUUID) "starting ssh server on '%s', password: '%s' service: '%s' ", recoveryAddr, generatedPassword, serviceUUID)
qr.Print(utils.EncodeRecoveryToken(tk, serviceUUID, generatedPassword)) // start ssh server in a separate process
go sshServer(recoveryAddr, generatedPassword) sshServer := process.New(
process.WithName(os.Args[0]),
process.WithArgs("recovery-ssh-server"),
process.WithEnvironment(
fmt.Sprintf("TOKEN=%s", tk),
fmt.Sprintf("SERVICE=%s", serviceUUID),
fmt.Sprintf("LISTEN=%s", recoveryAddr),
fmt.Sprintf("PASSWORD=%s", generatedPassword),
),
process.WithStateDir(sshStateDir),
)
// Wait for user input and go back to shell err := sshServer.Run()
utils.Prompt("") //nolint:errcheck
cancel()
// give tty1 back
svc, err := machine.Getty(1)
if err == nil {
svc.Start() //nolint:errcheck
}
return nil
}
func sshServer(listenAdddr, password string) {
ssh.Handle(func(s ssh.Session) {
cmd := exec.Command("bash")
ptyReq, winCh, isPty := s.Pty()
if isPty {
cmd.Env = append(cmd.Env, fmt.Sprintf("TERM=%s", ptyReq.Term))
f, err := pty.Start(cmd)
if err != nil { if err != nil {
pterm.Warning.Println("Failed reserving tty") resp.Error = err.Error()
} }
go func() { return *resp
for win := range winCh { }
setWinsize(f, win.Width, win.Height)
} func RecoveryStop(e *pluggable.Event) pluggable.EventResponse {
}() resp := &pluggable.EventResponse{}
go func() {
io.Copy(f, s) //nolint:errcheck sshServer := process.New(
}() process.WithStateDir(sshStateDir),
io.Copy(s, f) //nolint:errcheck )
cmd.Wait() //nolint:errcheck
} else { err := sshServer.Stop()
io.WriteString(s, "No PTY requested.\n") //nolint:errcheck if err != nil {
s.Exit(1) //nolint:errcheck resp.Error = err.Error()
} } else {
}) os.RemoveAll(sshStateDir)
}
pterm.Info.Println(ssh.ListenAndServe(listenAdddr, nil, ssh.PasswordAuth(func(ctx ssh.Context, pass string) bool { return *resp
return pass == password
}),
))
} }

View File

@@ -21,6 +21,8 @@ func Start() error {
// Expected output: string // Expected output: string
factory.Add(bus.EventChallenge, Challenge) factory.Add(bus.EventChallenge, Challenge)
return factory.Run(pluggable.EventType(os.Args[1]), os.Stdin, os.Stdout) factory.Add(bus.EventRecovery, Recovery)
factory.Add(bus.EventRecoveryStop, RecoveryStop)
return factory.Run(pluggable.EventType(os.Args[1]), os.Stdin, os.Stdout)
} }