mirror of
https://github.com/kairos-io/provider-kairos.git
synced 2025-09-24 20:47:27 +00:00
✨ Add recovery event
This commit is contained in:
committed by
Ettore Di Giacinto
parent
33eb2d9a84
commit
5e1ba9265d
8
go.mod
8
go.mod
@@ -3,18 +3,23 @@ module github.com/c3os-io/provider-c3os
|
||||
go 1.18
|
||||
|
||||
replace github.com/c3os-io/c3os => /home/mudler/_git/c3os
|
||||
|
||||
replace github.com/c3os-io/c3os/sdk => /home/mudler/_git/c3os/sdk
|
||||
|
||||
require (
|
||||
github.com/c3os-io/c3os v0.0.0-00010101000000-000000000000
|
||||
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/mudler/edgevpn v0.15.3
|
||||
github.com/mudler/go-nodepair v0.0.0-20220507212557-7d47aa3cc1f1
|
||||
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/onsi/ginkgo/v2 v2.1.3
|
||||
github.com/onsi/gomega v1.19.0
|
||||
github.com/pterm/pterm v0.12.41
|
||||
github.com/urfave/cli v1.22.9
|
||||
go.uber.org/zap v1.21.0
|
||||
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0
|
||||
@@ -23,6 +28,7 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 // indirect
|
||||
github.com/atomicgo/cursor v0.0.1 // indirect
|
||||
github.com/avast/retry-go v3.0.0+incompatible // 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/mr-tron/base58 v1.2.0 // 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-base36 v0.1.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/common v0.34.0 // 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/raulk/clock v1.1.0 // indirect
|
||||
github.com/raulk/go-watchdog v1.2.0 // indirect
|
||||
|
7
go.sum
7
go.sum
@@ -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-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
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/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=
|
||||
@@ -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/c-robinson/iplib v1.0.3 h1:NG0UF0GoEsrC1/vyfX1Lx2Ss7CySWl3KqqXh3q4DdPU=
|
||||
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/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=
|
||||
@@ -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/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.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 v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
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/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/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/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ=
|
||||
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/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.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
|
||||
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-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
|
98
internal/cli/recovery.go
Normal file
98
internal/cli/recovery.go
Normal 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")
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
package provider
|
||||
package cli
|
||||
|
||||
import (
|
||||
"os"
|
@@ -1,4 +1,4 @@
|
||||
package provider
|
||||
package cli
|
||||
|
||||
import (
|
||||
"os"
|
@@ -30,6 +30,8 @@ var networkAPI = []cli.Flag{
|
||||
},
|
||||
}
|
||||
|
||||
const recoveryAddr = "127.0.0.1:2222"
|
||||
|
||||
func Start() error {
|
||||
app := &cli.App{
|
||||
Name: "c3os",
|
||||
@@ -50,8 +52,38 @@ For all the example cases, see: https://docs.c3os.io .
|
||||
`,
|
||||
UsageText: ``,
|
||||
Copyright: "Ettore Di Giacinto",
|
||||
|
||||
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",
|
||||
UsageText: "register --reboot --device /dev/sda /image/snapshot.png",
|
||||
|
@@ -1,136 +1,64 @@
|
||||
package agent
|
||||
package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os/exec"
|
||||
"time"
|
||||
"os"
|
||||
|
||||
"github.com/c3os-io/c3os/internal/cmd"
|
||||
config "github.com/c3os-io/c3os/pkg/config"
|
||||
"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"
|
||||
qr "github.com/mudler/go-nodepair/qrcode"
|
||||
"github.com/pterm/pterm"
|
||||
"github.com/mudler/go-pluggable"
|
||||
process "github.com/mudler/go-processmanager"
|
||||
)
|
||||
|
||||
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")
|
||||
|
||||
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
|
||||
}
|
||||
resp := &pluggable.EventResponse{}
|
||||
|
||||
tk := nodepair.GenerateToken()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
serviceUUID := utils.RandStringRunes(10)
|
||||
generatedPassword := utils.RandStringRunes(7)
|
||||
|
||||
if err := startRecoveryService(ctx, tk, serviceUUID, recoveryAddr, "fatal"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd.PrintText(agentConfig.Branding.Recovery, "Recovery")
|
||||
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
pterm.Info.Printfln(
|
||||
resp.Data = utils.EncodeRecoveryToken(tk, serviceUUID, generatedPassword)
|
||||
resp.State = fmt.Sprintf(
|
||||
"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
|
||||
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)
|
||||
err := sshServer.Run()
|
||||
if err != nil {
|
||||
pterm.Warning.Println("Failed reserving tty")
|
||||
resp.Error = err.Error()
|
||||
}
|
||||
go func() {
|
||||
for win := range winCh {
|
||||
setWinsize(f, win.Width, win.Height)
|
||||
return *resp
|
||||
}
|
||||
}()
|
||||
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 RecoveryStop(e *pluggable.Event) pluggable.EventResponse {
|
||||
resp := &pluggable.EventResponse{}
|
||||
|
||||
sshServer := process.New(
|
||||
process.WithStateDir(sshStateDir),
|
||||
)
|
||||
|
||||
err := sshServer.Stop()
|
||||
if err != nil {
|
||||
resp.Error = err.Error()
|
||||
} else {
|
||||
os.RemoveAll(sshStateDir)
|
||||
}
|
||||
return *resp
|
||||
}
|
||||
|
@@ -21,6 +21,8 @@ func Start() error {
|
||||
// Expected output: string
|
||||
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)
|
||||
}
|
||||
|
Reference in New Issue
Block a user