mirror of
https://github.com/kairos-io/kairos-agent.git
synced 2025-08-17 15:57:46 +00:00
art: Drop CLI from c3os codebase
Part of: https://github.com/c3os-io/c3os/issues/68
This commit is contained in:
parent
c2721eb53c
commit
cb7d203a86
@ -10,13 +10,10 @@ import (
|
|||||||
agent "github.com/c3os-io/c3os/internal/agent"
|
agent "github.com/c3os-io/c3os/internal/agent"
|
||||||
"github.com/c3os-io/c3os/internal/bus"
|
"github.com/c3os-io/c3os/internal/bus"
|
||||||
|
|
||||||
cmd "github.com/c3os-io/c3os/internal/cmd"
|
|
||||||
providerConfig "github.com/c3os-io/c3os/internal/provider/config"
|
|
||||||
machine "github.com/c3os-io/c3os/pkg/machine"
|
machine "github.com/c3os-io/c3os/pkg/machine"
|
||||||
bundles "github.com/c3os-io/c3os/sdk/bundles"
|
bundles "github.com/c3os-io/c3os/sdk/bundles"
|
||||||
|
|
||||||
"github.com/c3os-io/c3os/internal/github"
|
"github.com/c3os-io/c3os/internal/github"
|
||||||
config "github.com/c3os-io/c3os/pkg/config"
|
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
@ -183,70 +180,6 @@ E.g. c3os-agent install-bundle container:quay.io/c3os/c3os...
|
|||||||
return bundles.RunBundles([]bundles.BundleOption{bundles.WithRepository(c.String("repository")), bundles.WithTarget(args[0])})
|
return bundles.RunBundles([]bundles.BundleOption{bundles.WithRepository(c.String("repository")), bundles.WithTarget(args[0])})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Name: "rotate",
|
|
||||||
Usage: "Rotate a c3os node network configuration via CLI",
|
|
||||||
Description: `
|
|
||||||
|
|
||||||
Updates a c3os node VPN configuration.
|
|
||||||
|
|
||||||
For example, to update the network token in a node:
|
|
||||||
$ c3os rotate --network-token XXX
|
|
||||||
`,
|
|
||||||
Aliases: []string{"r"},
|
|
||||||
Flags: []cli.Flag{
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "restart",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "network-token",
|
|
||||||
EnvVar: "NETWORK_TOKEN",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "api",
|
|
||||||
Value: "127.0.0.1:8080",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "root-dir",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
UsageText: "Rotate network token manually in the node",
|
|
||||||
Action: func(c *cli.Context) error {
|
|
||||||
dirs := []string{"/oem", "/usr/local/cloud-config"}
|
|
||||||
args := c.Args()
|
|
||||||
if len(args) > 0 {
|
|
||||||
dirs = args
|
|
||||||
}
|
|
||||||
|
|
||||||
return agent.RotateToken(dirs, c.String("network-token"), c.String("api"), c.String("root-dir"), c.Bool("restart"))
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
Name: "get-network-token",
|
|
||||||
Description: "Print network token from local configuration",
|
|
||||||
Usage: "Print network token from local configuration",
|
|
||||||
Action: func(c *cli.Context) error {
|
|
||||||
dirs := []string{"/oem", "/usr/local/cloud-config"}
|
|
||||||
args := c.Args()
|
|
||||||
if len(args) > 0 {
|
|
||||||
dirs = args
|
|
||||||
}
|
|
||||||
cc, err := config.Scan(config.Directories(dirs...))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
providerCfg := &providerConfig.Config{}
|
|
||||||
err = cc.Unmarshal(providerCfg)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Print(providerCfg.C3OS.NetworkToken)
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Name: "uuid",
|
Name: "uuid",
|
||||||
Usage: "Prints the local UUID",
|
Usage: "Prints the local UUID",
|
||||||
@ -352,7 +285,7 @@ For all the example cases, see: https://docs.c3os.io .
|
|||||||
UsageText: ``,
|
UsageText: ``,
|
||||||
Copyright: "Ettore Di Giacinto",
|
Copyright: "Ettore Di Giacinto",
|
||||||
|
|
||||||
Commands: cmd.CommonCommand(cmds...),
|
Commands: cmds,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := app.Run(os.Args)
|
err := app.Run(os.Args)
|
||||||
|
@ -1,118 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/c3os-io/c3os/pkg/config"
|
|
||||||
"github.com/c3os-io/c3os/pkg/utils"
|
|
||||||
"github.com/ipfs/go-log"
|
|
||||||
"github.com/mudler/edgevpn/api"
|
|
||||||
"github.com/mudler/edgevpn/pkg/logger"
|
|
||||||
"github.com/mudler/edgevpn/pkg/node"
|
|
||||||
"github.com/mudler/edgevpn/pkg/services"
|
|
||||||
"github.com/mudler/edgevpn/pkg/vpn"
|
|
||||||
qr "github.com/mudler/go-nodepair/qrcode"
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
// bridge is just starting a VPN with edgevpn to the given network token.
|
|
||||||
func bridge(c *cli.Context) error {
|
|
||||||
qrCodePath := ""
|
|
||||||
fromQRCode := false
|
|
||||||
var serviceUUID, sshPassword string
|
|
||||||
|
|
||||||
if c.String("qr-code-image") != "" {
|
|
||||||
qrCodePath = c.String("qr-code-image")
|
|
||||||
fromQRCode = true
|
|
||||||
}
|
|
||||||
if c.Bool("qr-code-snapshot") {
|
|
||||||
qrCodePath = ""
|
|
||||||
fromQRCode = true
|
|
||||||
}
|
|
||||||
|
|
||||||
token := c.String("network-token")
|
|
||||||
|
|
||||||
if fromQRCode {
|
|
||||||
recoveryToken := qr.Reader(qrCodePath)
|
|
||||||
data := utils.DecodeRecoveryToken(recoveryToken)
|
|
||||||
if len(data) != 3 {
|
|
||||||
fmt.Println("Token not decoded correctly")
|
|
||||||
return fmt.Errorf("invalid token")
|
|
||||||
}
|
|
||||||
token = data[0]
|
|
||||||
serviceUUID = data[1]
|
|
||||||
sshPassword = data[2]
|
|
||||||
if serviceUUID == "" || sshPassword == "" || token == "" {
|
|
||||||
return fmt.Errorf("decoded invalid values")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
nc := config.Network(token, c.String("address"), c.String("log-level"), "c3os0")
|
|
||||||
|
|
||||||
lvl, err := log.LevelFromString(nc.LogLevel)
|
|
||||||
if err != nil {
|
|
||||||
lvl = log.LevelError
|
|
||||||
}
|
|
||||||
llger := logger.New(lvl)
|
|
||||||
|
|
||||||
o, vpnOpts, err := nc.ToOpts(llger)
|
|
||||||
if err != nil {
|
|
||||||
llger.Fatal(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
opts := []node.Option{}
|
|
||||||
|
|
||||||
if !fromQRCode {
|
|
||||||
// We just connect to a VPN token
|
|
||||||
o = append(o,
|
|
||||||
services.Alive(
|
|
||||||
time.Duration(20)*time.Second,
|
|
||||||
time.Duration(10)*time.Second,
|
|
||||||
time.Duration(10)*time.Second)...)
|
|
||||||
|
|
||||||
if c.Bool("dhcp") {
|
|
||||||
// Adds DHCP server
|
|
||||||
address, _, err := net.ParseCIDR(c.String("address"))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
nodeOpts, vO := vpn.DHCP(llger, 15*time.Minute, c.String("lease-dir"), address.String())
|
|
||||||
o = append(o, nodeOpts...)
|
|
||||||
vpnOpts = append(vpnOpts, vO...)
|
|
||||||
}
|
|
||||||
|
|
||||||
opts, err = vpn.Register(vpnOpts...)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// We hook into a service
|
|
||||||
llger.Info("Connecting to service", serviceUUID)
|
|
||||||
llger.Info("SSH access password is", sshPassword)
|
|
||||||
llger.Info("SSH server reachable at 127.0.0.1:2200")
|
|
||||||
opts = append(opts, node.WithNetworkService(
|
|
||||||
services.ConnectNetworkService(
|
|
||||||
30*time.Second,
|
|
||||||
serviceUUID,
|
|
||||||
"127.0.0.1:2200",
|
|
||||||
),
|
|
||||||
))
|
|
||||||
llger.Info("To connect, keep this terminal open and run in another terminal 'ssh 127.0.0.1 -p 2200' the password is ", sshPassword)
|
|
||||||
llger.Info("Note: the connection might not be available instantly and first attempts will likely fail.")
|
|
||||||
llger.Info(" Few attempts might be required before establishing a tunnel to the host.")
|
|
||||||
}
|
|
||||||
|
|
||||||
e, err := node.New(append(o, opts...)...)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
go api.API(ctx, c.String("api"), 5*time.Second, 20*time.Second, e, nil, false) //nolint:errcheck
|
|
||||||
|
|
||||||
return e.Start(ctx)
|
|
||||||
}
|
|
179
cmd/cli/main.go
179
cmd/cli/main.go
@ -1,179 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
cmd "github.com/c3os-io/c3os/internal/cmd"
|
|
||||||
|
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
var cliCmd = []cli.Command{
|
|
||||||
{
|
|
||||||
Name: "register",
|
|
||||||
UsageText: "register --reboot --device /dev/sda /image/snapshot.png",
|
|
||||||
Usage: "Registers and bootstraps a node",
|
|
||||||
Description: `
|
|
||||||
Bootstraps a node which is started in pairing mode. It can send over a configuration file used to install the c3os node.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
$ c3os register --config config.yaml --device /dev/sda ~/Downloads/screenshot.png
|
|
||||||
|
|
||||||
will decode the QR code from ~/Downloads/screenshot.png and bootstrap the node remotely.
|
|
||||||
|
|
||||||
If the image is omitted, a screenshot will be taken and used to decode the QR code.
|
|
||||||
|
|
||||||
See also https://docs.c3os.io/installation/device_pairing/ for documentation.
|
|
||||||
`,
|
|
||||||
ArgsUsage: "Register optionally accepts an image. If nothing is passed will take a screenshot of the screen and try to decode the QR code",
|
|
||||||
Flags: []cli.Flag{
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "config",
|
|
||||||
Usage: "C3OS YAML configuration file",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "device",
|
|
||||||
Usage: "Device used for the installation target",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "reboot",
|
|
||||||
Usage: "Reboot node after installation",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "poweroff",
|
|
||||||
Usage: "Shutdown node after installation",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "log-level",
|
|
||||||
Usage: "Set log level",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
Action: func(c *cli.Context) error {
|
|
||||||
args := c.Args()
|
|
||||||
var ref string
|
|
||||||
if len(args) == 1 {
|
|
||||||
ref = args[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
return register(c.String("log-level"), ref, c.String("config"), c.String("device"), c.Bool("reboot"), c.Bool("poweroff"))
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "bridge",
|
|
||||||
UsageText: "bridge --network-token XXX",
|
|
||||||
Usage: "Connect to a c3os VPN network",
|
|
||||||
Description: `
|
|
||||||
Starts a bridge with a c3os network or a node.
|
|
||||||
|
|
||||||
# With a network
|
|
||||||
|
|
||||||
By default, "bridge" will create a VPN network connection to the node with the token supplied, thus it requires elevated permissions in order to work.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
$ sudo c3os bridge --network-token <TOKEN>
|
|
||||||
|
|
||||||
Will start a VPN, which local ip is fixed to 10.1.0.254 (tweakable with --address).
|
|
||||||
|
|
||||||
The API will also be accessible at http://127.0.0.1:8080
|
|
||||||
|
|
||||||
# With a node
|
|
||||||
|
|
||||||
"c3os bridge" can be used also to connect over to a node in recovery mode. When operating in this modality c3os bridge requires no specific permissions, indeed a tunnel
|
|
||||||
will be created locally to connect to the machine remotely.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
$ c3os bridge --qr-code-image /path/to/image.png
|
|
||||||
|
|
||||||
Will scan the QR code in the image and connect over. Further instructions on how to connect over will be printed out to the screen.
|
|
||||||
|
|
||||||
See also: https://docs.c3os.io/after_install/troubleshooting/#connect-to-the-cluster-network and https://docs.c3os.io/after_install/recovery_mode/
|
|
||||||
|
|
||||||
`,
|
|
||||||
Flags: []cli.Flag{
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "network-token",
|
|
||||||
Required: false,
|
|
||||||
EnvVar: "NETWORK_TOKEN",
|
|
||||||
Usage: "Network token to connect over",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "log-level",
|
|
||||||
Required: false,
|
|
||||||
EnvVar: "LOGLEVEL",
|
|
||||||
Value: "info",
|
|
||||||
Usage: "Bridge log level",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "qr-code-snapshot",
|
|
||||||
Required: false,
|
|
||||||
Usage: "Bool to take a local snapshot instead of reading from an image file for recovery",
|
|
||||||
EnvVar: "QR_CODE_SNAPSHOT",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "qr-code-image",
|
|
||||||
Usage: "Path to an image containing a valid QR code for recovery mode",
|
|
||||||
Required: false,
|
|
||||||
EnvVar: "QR_CODE_IMAGE",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "api",
|
|
||||||
Value: "127.0.0.1:8080",
|
|
||||||
Usage: "Listening API url",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "dhcp",
|
|
||||||
EnvVar: "DHCP",
|
|
||||||
Usage: "Enable DHCP",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Value: "10.1.0.254/24",
|
|
||||||
Name: "address",
|
|
||||||
EnvVar: "ADDRESS",
|
|
||||||
Usage: "Specify an address for the bridge",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Value: "/tmp/c3os",
|
|
||||||
Name: "lease-dir",
|
|
||||||
EnvVar: "lease-dir",
|
|
||||||
Usage: "DHCP Lease directory",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Action: bridge,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
|
|
||||||
app := &cli.App{
|
|
||||||
Name: "c3os",
|
|
||||||
Version: "0.1",
|
|
||||||
Author: "Ettore Di Giacinto",
|
|
||||||
Usage: "c3os CLI to bootstrap, upgrade, connect and manage a c3os network",
|
|
||||||
Description: `
|
|
||||||
The c3os CLI can be used to manage a c3os box and perform all day-two tasks, like:
|
|
||||||
- register a node
|
|
||||||
- connect to a node in recovery mode
|
|
||||||
- to establish a VPN connection
|
|
||||||
- set, list roles
|
|
||||||
- interact with the network API
|
|
||||||
|
|
||||||
and much more.
|
|
||||||
|
|
||||||
For all the example cases, see: https://docs.c3os.io .
|
|
||||||
`,
|
|
||||||
UsageText: ``,
|
|
||||||
Copyright: "Ettore Di Giacinto",
|
|
||||||
|
|
||||||
Commands: cmd.CommonCommand(cliCmd...),
|
|
||||||
}
|
|
||||||
|
|
||||||
err := app.Run(os.Args)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
|
|
||||||
nodepair "github.com/mudler/go-nodepair"
|
|
||||||
qr "github.com/mudler/go-nodepair/qrcode"
|
|
||||||
)
|
|
||||||
|
|
||||||
func register(loglevel, arg, configFile, device string, reboot, poweroff bool) error {
|
|
||||||
b, _ := ioutil.ReadFile(configFile)
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
// dmesg -D to suppress tty ev
|
|
||||||
fmt.Println("Sending registration payload, please wait")
|
|
||||||
|
|
||||||
config := map[string]string{
|
|
||||||
"device": device,
|
|
||||||
"cc": string(b),
|
|
||||||
}
|
|
||||||
|
|
||||||
if reboot {
|
|
||||||
config["reboot"] = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
if poweroff {
|
|
||||||
config["poweroff"] = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
err := nodepair.Send(
|
|
||||||
ctx,
|
|
||||||
config,
|
|
||||||
nodepair.WithReader(qr.Reader),
|
|
||||||
nodepair.WithToken(arg),
|
|
||||||
nodepair.WithLogLevel(loglevel),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Payload sent, installation will start on the machine briefly")
|
|
||||||
return nil
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user