mirror of
https://github.com/kairos-io/kairos-agent.git
synced 2025-09-19 09:12:37 +00:00
gear: Add c3os bundles
This commit is contained in:
committed by
Itxaka
parent
49e4bd9503
commit
9679421d20
220
internal/machine/bundles.go
Normal file
220
internal/machine/bundles.go
Normal file
@@ -0,0 +1,220 @@
|
|||||||
|
package machine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/c3os-io/c3os/internal/utils"
|
||||||
|
"github.com/hashicorp/go-multierror"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BundleConfig struct {
|
||||||
|
Target string
|
||||||
|
Repository string
|
||||||
|
DBPath string
|
||||||
|
RootPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
// bundles needs to ship only /config/... (etc) and /bin/... (will go to /usr/local/bin)
|
||||||
|
type BundleOption func(bc *BundleConfig) error
|
||||||
|
|
||||||
|
func (bc *BundleConfig) Apply(opts ...BundleOption) error {
|
||||||
|
for _, o := range opts {
|
||||||
|
if err := o(bc); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithDBHPath(r string) BundleOption {
|
||||||
|
return func(bc *BundleConfig) error {
|
||||||
|
bc.DBPath = r
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithRootFS(r string) BundleOption {
|
||||||
|
return func(bc *BundleConfig) error {
|
||||||
|
bc.RootPath = r
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithRepository(r string) BundleOption {
|
||||||
|
return func(bc *BundleConfig) error {
|
||||||
|
bc.Repository = r
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithTarget(p string) BundleOption {
|
||||||
|
return func(bc *BundleConfig) error {
|
||||||
|
bc.Target = p
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bc *BundleConfig) extractRepo() (string, string) {
|
||||||
|
s := strings.Split(bc.Repository, ":")
|
||||||
|
return s[0], s[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX: directly to rootfs ? or maybe better to /usr/local/.c3os/rootfs and handle symlinks?
|
||||||
|
func defaultConfig() *BundleConfig {
|
||||||
|
return &BundleConfig{
|
||||||
|
DBPath: "/usr/local/.c3os/db",
|
||||||
|
RootPath: "/",
|
||||||
|
Repository: "quay.io/c3os/packages",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type BundleInstaller interface {
|
||||||
|
Install(*BundleConfig) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// - Make provider consume bundles when bins are not detected in the rootfs
|
||||||
|
// - Default bundles preset in case of no binaries detected and version specified via config.
|
||||||
|
|
||||||
|
func RunBundles(bundles ...[]BundleOption) error {
|
||||||
|
var resErr error
|
||||||
|
for _, b := range bundles {
|
||||||
|
config := defaultConfig()
|
||||||
|
config.Apply(b...)
|
||||||
|
|
||||||
|
installer, err := NewBundleInstaller(*config)
|
||||||
|
if err != nil {
|
||||||
|
resErr = multierror.Append(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dat := strings.Split(config.Target, ":")
|
||||||
|
if len(dat) != 2 {
|
||||||
|
resErr = multierror.Append(fmt.Errorf("invalid target"))
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
config.Target = dat[1]
|
||||||
|
|
||||||
|
err = installer.Install(config)
|
||||||
|
if err != nil {
|
||||||
|
resErr = multierror.Append(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBundleInstaller(bc BundleConfig) (BundleInstaller, error) {
|
||||||
|
|
||||||
|
dat := strings.Split(bc.Target, ":")
|
||||||
|
if len(dat) != 2 {
|
||||||
|
return nil, fmt.Errorf("could not decode scheme")
|
||||||
|
}
|
||||||
|
switch strings.ToLower(dat[0]) {
|
||||||
|
case "container":
|
||||||
|
return &ContainerInstaller{}, nil
|
||||||
|
case "run":
|
||||||
|
return &ContainerRunner{}, nil
|
||||||
|
case "package":
|
||||||
|
return &LuetInstaller{}, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return &LuetInstaller{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// BundleInstall installs a bundle from a luet repo or a container image
|
||||||
|
type ContainerRunner struct{}
|
||||||
|
|
||||||
|
func (l *ContainerRunner) Install(config *BundleConfig) error {
|
||||||
|
|
||||||
|
tempDir, err := ioutil.TempDir("", "containerrunner")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tempDir)
|
||||||
|
|
||||||
|
out, err := utils.SH(
|
||||||
|
fmt.Sprintf(
|
||||||
|
`luet util unpack %s %s`,
|
||||||
|
config.Target,
|
||||||
|
tempDir,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not unpack container: %w - %s", err, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err = utils.SH(fmt.Sprintf("CONTAINERDIR=%s %s/run.sh", tempDir, tempDir))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not execute container: %w - %s", err, out)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ContainerInstaller struct{}
|
||||||
|
|
||||||
|
func (l *ContainerInstaller) Install(config *BundleConfig) error {
|
||||||
|
|
||||||
|
//mkdir -p test/etc/luet/repos.conf.d
|
||||||
|
_, err := utils.SH(
|
||||||
|
fmt.Sprintf(
|
||||||
|
`luet util unpack %s %s`,
|
||||||
|
config.Target,
|
||||||
|
config.RootPath,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not add repository: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type LuetInstaller struct{}
|
||||||
|
|
||||||
|
func (l *LuetInstaller) Install(config *BundleConfig) error {
|
||||||
|
|
||||||
|
t, repo := config.extractRepo()
|
||||||
|
//mkdir -p test/etc/luet/repos.conf.d
|
||||||
|
_, err := utils.SH(
|
||||||
|
fmt.Sprintf(
|
||||||
|
`LUET_CONFIG_FROM_HOST=false luet repo add --system-dbpath %s --system-target %s c3os-system -y --description "Automatically generated c3os-system" --url "%s" --type "%s"`,
|
||||||
|
config.DBPath,
|
||||||
|
config.RootPath,
|
||||||
|
repo,
|
||||||
|
t,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not add repository: %w", err)
|
||||||
|
}
|
||||||
|
_, err = utils.SH(
|
||||||
|
fmt.Sprintf(
|
||||||
|
`LUET_CONFIG_FROM_HOST=false luet repo update -f --system-dbpath %s --system-target %s`,
|
||||||
|
config.DBPath,
|
||||||
|
config.RootPath,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not sync repository: %w", err)
|
||||||
|
}
|
||||||
|
_, err = utils.SH(
|
||||||
|
fmt.Sprintf(
|
||||||
|
`LUET_CONFIG_FROM_HOST=false luet install -y --system-dbpath %s --system-target %s %s`,
|
||||||
|
config.DBPath,
|
||||||
|
config.RootPath,
|
||||||
|
config.Target,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not sync repository: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy bins to /usr/local/bin
|
||||||
|
return nil
|
||||||
|
}
|
@@ -2,6 +2,7 @@ package machine
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/c3os-io/c3os/internal/machine/openrc"
|
"github.com/c3os-io/c3os/internal/machine/openrc"
|
||||||
@@ -101,3 +102,14 @@ func UUID() string {
|
|||||||
hostname, _ := os.Hostname()
|
hostname, _ := os.Hostname()
|
||||||
return fmt.Sprintf("%s-%s", id, hostname)
|
return fmt.Sprintf("%s-%s", id, hostname)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CreateSentinel(f string) error {
|
||||||
|
return ioutil.WriteFile(fmt.Sprintf("/usr/local/.c3os/sentinel_%s", f), []byte{}, os.ModePerm)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SentinelExist(f string) bool {
|
||||||
|
if _, err := os.Stat(fmt.Sprintf("/usr/local/.c3os/sentinel_%s", f)); err == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
@@ -60,7 +60,11 @@ func (s ServiceUnit) WriteUnit() error {
|
|||||||
|
|
||||||
// TODO: This is too much k3s specific
|
// TODO: This is too much k3s specific
|
||||||
func (s ServiceUnit) OverrideCmd(cmd string) error {
|
func (s ServiceUnit) OverrideCmd(cmd string) error {
|
||||||
cmd = strings.ReplaceAll(cmd, "/usr/bin/k3s ", "")
|
k3sbin := utils.K3sBin()
|
||||||
|
if k3sbin == "" {
|
||||||
|
return fmt.Errorf("no k3s binary found (?)")
|
||||||
|
}
|
||||||
|
cmd = strings.ReplaceAll(cmd, k3sbin+" ", "")
|
||||||
svcDir := filepath.Join(s.rootdir, fmt.Sprintf("/etc/rancher/k3s/%s.env", s.name))
|
svcDir := filepath.Join(s.rootdir, fmt.Sprintf("/etc/rancher/k3s/%s.env", s.name))
|
||||||
|
|
||||||
return ioutil.WriteFile(svcDir, []byte(fmt.Sprintf(`command_args="%s >>/var/log/%s.log 2>&1"`, cmd, s.name)), 0600)
|
return ioutil.WriteFile(svcDir, []byte(fmt.Sprintf(`command_args="%s >>/var/log/%s.log 2>&1"`, cmd, s.name)), 0600)
|
||||||
|
@@ -37,6 +37,7 @@ func Bootstrap(e *pluggable.Event) pluggable.EventResponse {
|
|||||||
return pluggable.EventResponse{Error: fmt.Sprintf("Failed reading JSON input: %s input '%s'", err.Error(), cfg.Config)}
|
return pluggable.EventResponse{Error: fmt.Sprintf("Failed reading JSON input: %s input '%s'", err.Error(), cfg.Config)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: this belong to a systemd service that is started instead
|
||||||
utils.SH("sysctl -w net.core.rmem_max=2500000")
|
utils.SH("sysctl -w net.core.rmem_max=2500000")
|
||||||
|
|
||||||
tokenNotDefined := (c.C3OS == nil || c.C3OS.NetworkToken == "")
|
tokenNotDefined := (c.C3OS == nil || c.C3OS.NetworkToken == "")
|
||||||
@@ -188,7 +189,11 @@ func oneTimeBootstrap(l logging.StandardLogger, c *config.Config, vpnSetupFN fun
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := svc.OverrideCmd(fmt.Sprintf("/usr/bin/k3s %s %s", svcRole, strings.Join(k3sConfig.Args, " "))); err != nil {
|
k3sbin := utils.K3sBin()
|
||||||
|
if k3sbin == "" {
|
||||||
|
return fmt.Errorf("no k3s binary found (?)")
|
||||||
|
}
|
||||||
|
if err := svc.OverrideCmd(fmt.Sprintf("%s %s %s", k3sbin, svcRole, strings.Join(k3sConfig.Args, " "))); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -108,7 +108,12 @@ func Master(cc *config.Config) Role {
|
|||||||
args = append(args, k3sConfig.Args...)
|
args = append(args, k3sConfig.Args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := svc.OverrideCmd(fmt.Sprintf("/usr/bin/k3s server %s", strings.Join(args, " "))); err != nil {
|
k3sbin := utils.K3sBin()
|
||||||
|
if k3sbin == "" {
|
||||||
|
return fmt.Errorf("no k3s binary found (?)")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := svc.OverrideCmd(fmt.Sprintf("%s server %s", k3sbin, strings.Join(args, " "))); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -89,7 +89,11 @@ func Worker(cc *config.Config) Role {
|
|||||||
args = append(args, k3sConfig.Args...)
|
args = append(args, k3sConfig.Args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := svc.OverrideCmd(fmt.Sprintf("/usr/bin/k3s agent %s", strings.Join(args, " "))); err != nil {
|
k3sbin := utils.K3sBin()
|
||||||
|
if k3sbin == "" {
|
||||||
|
return fmt.Errorf("no k3s binary found (?)")
|
||||||
|
}
|
||||||
|
if err := svc.OverrideCmd(fmt.Sprintf("%s agent %s", k3sbin, strings.Join(args, " "))); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -3,6 +3,7 @@ package utils
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
@@ -27,7 +28,8 @@ func Version() string {
|
|||||||
release, _ := godotenv.Read("/etc/os-release")
|
release, _ := godotenv.Read("/etc/os-release")
|
||||||
v := release["VERSION"]
|
v := release["VERSION"]
|
||||||
v = strings.ReplaceAll(v, "+k3s1-c3OS", "-")
|
v = strings.ReplaceAll(v, "+k3s1-c3OS", "-")
|
||||||
return strings.ReplaceAll(v, "+k3s-c3OS", "-")
|
v = strings.ReplaceAll(v, "+k3s-c3OS", "-")
|
||||||
|
return strings.ReplaceAll(v, "c3OS", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func OSRelease(key string) (string, error) {
|
func OSRelease(key string) (string, error) {
|
||||||
@@ -80,3 +82,13 @@ func GetInterfaceIP(in string) string {
|
|||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func K3sBin() string {
|
||||||
|
for _, p := range []string{"/usr/bin/k3s"} {
|
||||||
|
if _, err := os.Stat(p); err == nil {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user