Skip to content

Commit

Permalink
Add install.sh script for CIs, add --poweroff to register
Browse files Browse the repository at this point in the history
  • Loading branch information
mudler committed Feb 11, 2022
1 parent 04332f0 commit b7c4539
Show file tree
Hide file tree
Showing 6 changed files with 241 additions and 104 deletions.
86 changes: 86 additions & 0 deletions install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#!/bin/bash
set -e

: ${BINARY_NAME:="c3os"}
: ${INSTALL_DIR:="/usr/local/bin"}
: ${USE_SUDO:="true"}
: ${INSTALL_K3S:="true"}
: ${INSTALL_EDGEVPN:="true"}
: ${DOWNLOADER:="curl"}

install_k3s() {
export INSTALL_K3S_VERSION=${K3S_VERSION}
export INSTALL_K3S_BIN_DIR="/usr/bin"
export INSTALL_K3S_SKIP_START="true"
export INSTALL_K3S_SKIP_ENABLE="true"
curl -sfL https://get.k3s.io | sh -
}

c3os_github_version() {
set +e
curl -s https://api.github.com/repos/mudler/c3os/releases/latest | \
grep tag_name | \
awk '{ print $2 }' | \
sed -e 's/\"//g' -e 's/,//g' || echo "v0.8.5"
set -e
}

install_edgevpn() {
curl -sfL https://raw.githubusercontent.com/mudler/edgevpn/master/install.sh | sh -
}

download() {
[ $# -eq 2 ] || fatal 'download needs exactly 2 arguments'

case $DOWNLOADER in
curl)
curl -o $1 -sfL $2
;;
wget)
wget -qO $1 $2
;;
*)
fatal "Incorrect executable '$DOWNLOADER'"
;;
esac

# Abort if download command failed
[ $? -eq 0 ] || fatal 'Download failed'
}

SUDO=sudo
if [ $(id -u) -eq 0 ]; then
SUDO=
fi

c3os_version="${C3OS_VERSION:-$(c3os_github_version)}"

echo "Downloading c3os $c3os_version"

if [ "${INSTALL_EDGEVPN}" == "true" ]; then
install_edgevpn
fi

if [ "${INSTALL_K3S}" == "true" ]; then
install_k3s
fi

TMP_DIR=$(mktemp -d -t c3os-install.XXXXXXXXXX)

download $TMP_DIR/out.tar.gz https://github.com/mudler/c3os/releases/download/$c3os_version/c3os-$c3os_version-Linux-x86_64.tar.gz

# TODO verify w/ checksum
tar xvf $TMP_DIR/out.tar.gz -C $TMP_DIR

$SUDO cp -rf $TMP_DIR/c3os $INSTALL_DIR/

# TODO trap
rm -rf $TMP_DIR

if [ ! -d "/etc/systemd/system.conf.d/" ]; then
$SUDO mkdir -p /etc/systemd/system.conf.d
fi

if [ ! -d "/etc/sysconfig" ]; then
$SUDO mkdir -p /etc/sysconfig
fi
1 change: 1 addition & 0 deletions installer/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type C3OSConfig struct {
Offline bool `yaml:"offline"`
Reboot bool `yaml:"reboot"`
Device string `yaml:"device"`
Poweroff bool `yaml:"poweroff"`
}

type Config struct {
Expand Down
85 changes: 82 additions & 3 deletions installer/installer.go
Original file line number Diff line number Diff line change
@@ -1,26 +1,100 @@
package main

import (
"context"
"errors"
"fmt"
"io/ioutil"
"os"
"os/exec"
"time"

systemd "github.com/mudler/c3os/installer/systemd"
nodepair "github.com/mudler/go-nodepair"
qr "github.com/mudler/go-nodepair/qrcode"
"github.com/pterm/pterm"
"gopkg.in/yaml.v2"
)

func optsToArgs(options map[string]string) (res []string) {
for k, v := range options {
if k != "device" && k != "cc" && k != "reboot" {
if k != "device" && k != "cc" && k != "reboot" && k != "poweroff" {
res = append(res, fmt.Sprintf("--%s", k))
res = append(res, fmt.Sprintf("%s", v))
}
}
return
}

func install(dir string) error {
// Reads config, and if present and offline is defined,
// runs the installation
cc, err := ScanConfig(dir)
if err == nil && cc.C3OS != nil && cc.C3OS.Offline {
runInstall(map[string]string{
"device": cc.C3OS.Device,
"cc": cc.cloudFileContent,
})

svc, err := systemd.Getty(1)
if err == nil {
svc.Start()
}

return nil
}

printBanner(banner)
tk := nodepair.GenerateToken()

pterm.DefaultBox.WithTitle("Installation").WithTitleBottomRight().WithRightPadding(0).WithBottomPadding(0).Println(
`Welcome to c3os!
p2p device installation enrollment is starting.
A QR code will be displayed below.
In another machine, run "c3os register" with the QR code visible on screen,
or "c3os register <file>" to register the machine from a photo.
IF the qrcode is not displaying correctly,
try booting with another vga option from the boot cmdline (e.g. vga=791).`)

pterm.Info.Println("Starting in 5 seconds...")
pterm.Print("\n\n") // Add two new lines as spacer.

time.Sleep(5 * time.Second)

qr.Print(tk)

r := map[string]string{}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

go func() {
prompt("Waiting for registration, press any key to abort pairing. To restart run 'c3os install'.")
// give tty1 back
svc, err := systemd.Getty(1)
if err == nil {
svc.Start()
}
cancel()
}()

if err := nodepair.Receive(ctx, &r, nodepair.WithToken(tk)); err != nil {
return err
}

if len(r) == 0 {
return errors.New("no configuration, stopping installation")
}

pterm.Info.Println("Starting installation")

runInstall(r)

pterm.Info.Println("Installation completed, press enter to go back to the shell.")

return nil
}

func runInstall(options map[string]string) {
fmt.Println("Running install", options)
f, _ := ioutil.TempFile("", "xxxx")

device, ok := options["device"]
Expand All @@ -39,6 +113,7 @@ func runInstall(options map[string]string) {
yaml.Unmarshal([]byte(cloudInit), c)

_, reboot := options["reboot"]
_, poweroff := options["poweroff"]

ioutil.WriteFile(f.Name(), []byte(cloudInit), os.ModePerm)
args := []string{}
Expand All @@ -55,7 +130,11 @@ func runInstall(options map[string]string) {
os.Exit(1)
}

if reboot || c.C3OS.Reboot {
if reboot || c.C3OS != nil && c.C3OS.Reboot {
Reboot()
}

if poweroff || c.C3OS != nil && c.C3OS.Poweroff {
PowerOFF()
}
}
123 changes: 22 additions & 101 deletions installer/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,17 @@ package main
import (
//"fmt"

"context"
"encoding/base64"
"errors"
"fmt"
"io/ioutil"
"os"
"strconv"
"strings"
"time"

"github.com/mudler/c3os/installer/systemd"
edgeVPNClient "github.com/mudler/edgevpn/api/client"
service "github.com/mudler/edgevpn/api/client/service"
"github.com/mudler/edgevpn/pkg/node"
nodepair "github.com/mudler/go-nodepair"
qr "github.com/mudler/go-nodepair/qrcode"
"github.com/pterm/pterm"
"github.com/urfave/cli"
"gopkg.in/yaml.v2"
)

func main() {
Expand All @@ -46,6 +39,9 @@ func main() {
&cli.BoolFlag{
Name: "reboot",
},
&cli.BoolFlag{
Name: "poweroff",
},
},
Action: func(c *cli.Context) error {
args := c.Args()
Expand All @@ -54,34 +50,24 @@ func main() {
ref = args[0]
}

b, _ := ioutil.ReadFile(c.String("config"))
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": c.String("device"),
"cc": string(b),
}

if c.Bool("reboot") {
config["reboot"] = ""
}

err := nodepair.Send(
ctx,
config,
nodepair.WithReader(qr.Reader),
nodepair.WithToken(ref),
)
if err != nil {
return err
return register(ref, c.String("config"), c.String("device"), c.Bool("reboot"), c.Bool("poweroff"))
},
},
{
Name: "create-config",
Aliases: []string{"c"},
UsageText: "Create a config with a generated network token",
Action: func(c *cli.Context) error {
l := int(^uint(0) >> 1)
args := c.Args()
if len(args) > 0 {
if i, err := strconv.Atoi(args[0]); err == nil {
l = i
}
}

fmt.Println("Payload sent, installation will start on the machine briefly")

cc := &Config{C3OS: &C3OSConfig{NetworkToken: node.GenerateNewConnectionData(l).Base64()}}
y, _ := yaml.Marshal(cc)
fmt.Println(string(y))
return nil
},
},
Expand Down Expand Up @@ -138,72 +124,7 @@ func main() {
Name: "install",
Aliases: []string{"i"},
Action: func(c *cli.Context) error {

// Reads config, and if present and offline is defined,
// runs the installation
cc, err := ScanConfig("/oem")
if err == nil && cc.C3OS != nil && cc.C3OS.Offline {
runInstall(map[string]string{
"device": cc.C3OS.Device,
"cc": cc.cloudFileContent,
})
if cc.C3OS.Reboot {
Reboot()
} else {
svc, err := systemd.Getty(1)
if err == nil {
svc.Start()
}
}
return nil
}

printBanner(banner)
tk := nodepair.GenerateToken()

pterm.DefaultBox.WithTitle("Installation").WithTitleBottomRight().WithRightPadding(0).WithBottomPadding(0).Println(
`Welcome to c3os!
p2p device installation enrollment is starting.
A QR code will be displayed below.
In another machine, run "c3os register" with the QR code visible on screen,
or "c3os register <file>" to register the machine from a photo.
IF the qrcode is not displaying correctly,
try booting with another vga option from the boot cmdline (e.g. vga=791).`)

pterm.Info.Println("Starting in 5 seconds...")
pterm.Print("\n\n") // Add two new lines as spacer.

time.Sleep(5 * time.Second)

qr.Print(tk)

r := map[string]string{}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

go func() {
prompt("Waiting for registration, press any key to abort pairing. To restart run 'c3os install'.")
// give tty1 back
svc, err := systemd.Getty(1)
if err == nil {
svc.Start()
}
cancel()
}()

if err := nodepair.Receive(ctx, &r, nodepair.WithToken(tk)); err != nil {
return err
}

if len(r) == 0 {
return errors.New("no configuration, stopping installation")
}

pterm.Info.Println("Starting installation")
runInstall(r)

pterm.Info.Println("Installation completed, press enter to go back to the shell.")
return nil
return install("/oem")
},
},
},
Expand Down
Loading

0 comments on commit b7c4539

Please sign in to comment.