Skip to content

Commit

Permalink
Merge pull request #76 from kairos-io/add-commands-interface
Browse files Browse the repository at this point in the history
Add commands interface
  • Loading branch information
jimmykarily authored Oct 25, 2024
2 parents e00af29 + 4508bcf commit 1073599
Show file tree
Hide file tree
Showing 5 changed files with 369 additions and 249 deletions.
94 changes: 41 additions & 53 deletions deployer/deployer.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package deployer

import (
"context"
"io/ioutil"
"os"

"github.com/hashicorp/go-multierror"
Expand All @@ -13,60 +11,22 @@ import (
"gopkg.in/yaml.v3"
)

func LoadByte(b []byte) (*schema.Config, *schema.ReleaseArtifact, error) {
config := &schema.Config{}
release := &schema.ReleaseArtifact{}

if err := yaml.Unmarshal(b, config); err != nil {
return nil, nil, err
}

if err := yaml.Unmarshal(b, release); err != nil {
return nil, nil, err
}

return config, release, nil
type Deployer struct {
*herd.Graph
Config schema.Config
Artifact schema.ReleaseArtifact
}

// LoadFile loads a configuration file and returns the AuroraBoot configuration
// and release artifact information
func LoadFile(file string) (*schema.Config, *schema.ReleaseArtifact, error) {
func NewDeployer(c schema.Config, a schema.ReleaseArtifact, opts ...herd.GraphOption) *Deployer {
d := &Deployer{Config: c, Artifact: a}
d.Graph = herd.DAG(opts...)

dat, err := os.ReadFile(file)
if err != nil {
return nil, nil, err
}

return LoadByte(dat)
return d
}

// Start starts the auroraboot deployer
func Start(config *schema.Config, release *schema.ReleaseArtifact) error {

f, err := ioutil.TempFile("", "auroraboot-dat")
if err != nil {
return err
}

_, err = f.WriteString(config.CloudConfig)
if err != nil {
return err
}

// Have a dag for our ops
g := herd.DAG(herd.CollectOrphans)

Register(g, *release, *config, f.Name())

writeDag(g.Analyze())

ctx := context.Background()
err = g.Run(ctx)
if err != nil {
return err
}

for _, layer := range g.Analyze() {
func (d *Deployer) CollectErrors() error {
var err error
for _, layer := range d.Analyze() {
for _, op := range layer {
if op.Error != nil {
err = multierror.Append(err, op.Error)
Expand All @@ -77,8 +37,9 @@ func Start(config *schema.Config, release *schema.ReleaseArtifact) error {
return err
}

func writeDag(d [][]herd.GraphEntry) {
for i, layer := range d {
func (d *Deployer) WriteDag() {
graph := d.Analyze()
for i, layer := range graph {
log.Printf("%d.", (i + 1))
for _, op := range layer {
if !op.Ignored {
Expand All @@ -92,3 +53,30 @@ func writeDag(d [][]herd.GraphEntry) {
log.Print("")
}
}

func LoadByte(b []byte) (*schema.Config, *schema.ReleaseArtifact, error) {
config := &schema.Config{}
release := &schema.ReleaseArtifact{}

if err := yaml.Unmarshal(b, config); err != nil {
return nil, nil, err
}

if err := yaml.Unmarshal(b, release); err != nil {
return nil, nil, err
}

return config, release, nil
}

// LoadFile loads a configuration file and returns the AuroraBoot configuration
// and release artifact information
func LoadFile(file string) (*schema.Config, *schema.ReleaseArtifact, error) {

dat, err := os.ReadFile(file)
if err != nil {
return nil, nil, err
}

return LoadByte(dat)
}
212 changes: 36 additions & 176 deletions deployer/register.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
package deployer

import (
"context"
"fmt"
"io"
"os"
"path/filepath"
"strings"

"github.com/kairos-io/AuroraBoot/pkg/ops"
"github.com/kairos-io/AuroraBoot/pkg/schema"

"github.com/spectrocloud-labs/herd"
)

const (
Expand Down Expand Up @@ -47,175 +39,43 @@ const (
kairosDefaultArtifactName = "kairos"
)

// Register register the op dag based on the configuration and the artifact wanted.
func Register(g *herd.Graph, artifact schema.ReleaseArtifact, c schema.Config, cloudConfigFile string) {
dst := c.StateDir("build")
dstNetboot := c.StateDir("netboot")

listenAddr := ":8080"
if c.ListenAddr != "" {
listenAddr = c.ListenAddr
}

netbootPort := "8090"
if c.NetBootHTTPPort != "" {
netbootPort = c.NetBootHTTPPort
}
address := "0.0.0.0"
if c.NetBootListenAddr != "" {
netbootPort = c.NetBootListenAddr
}

// squashfs, kernel, and initrd names are tied to the output of /netboot.sh (op.ExtractNetboot)
squashFSfile := filepath.Join(dstNetboot, "kairos.squashfs")
kernelFile := filepath.Join(dstNetboot, "kairos-kernel")
initrdFile := filepath.Join(dstNetboot, "kairos-initrd")
isoFile := filepath.Join(dst, "kairos.iso")
tmpRootfs := c.StateDir("temp-rootfs")
fromImage := artifact.ContainerImage != ""
fromImageOption := func() bool { return fromImage }
isoOption := func() bool { return !fromImage }
netbootOption := func() bool { return !c.DisableNetboot }
netbootReleaseOption := func() bool { return !c.DisableNetboot && !fromImage }
rawDiskIsSet := c.Disk.VHD || c.Disk.RAW || c.Disk.GCE

// Pull locak docker daemon if container image starts with docker://
containerImage := artifact.ContainerImage
if strings.HasPrefix(containerImage, "docker://") {
containerImage = strings.ReplaceAll(containerImage, "docker://", "")
}

// Preparation steps
g.Add(opPreparetmproot, herd.WithCallback(
func(ctx context.Context) error {
return os.MkdirAll(dstNetboot, 0700)
},
))

g.Add(opPrepareNetboot, herd.WithCallback(
func(ctx context.Context) error {
return os.MkdirAll(dstNetboot, 0700)
},
))

g.Add(opPrepareISO, herd.WithCallback(func(ctx context.Context) error {
return os.MkdirAll(dst, 0700)
}))

g.Add(opCopyCloudConfig,
herd.WithDeps(opPrepareISO),
herd.WithCallback(func(ctx context.Context) error {
_, err := copy(cloudConfigFile, filepath.Join(dst, "config.yaml"))
// RegisterAll registers the op dag based on the configuration and the artifact wanted.
// This registers all steps for the top level Auroraboot command.
func RegisterAll(d *Deployer) error {
for _, step := range []func() error{
d.StepPrepTmpRootDir,
d.StepPrepNetbootDir,
d.StepPrepISODir,
d.StepCopyCloudConfig,
d.StepPullContainer,
d.StepGenISO,
d.StepExtractNetboot,
//TODO: add Validate step
// Ops to download from releases
d.StepDownloadInitrd,
d.StepDownloadKernel,
d.StepDownloadSquashFS,
d.StepDownloadISO,
// Ops to generate disk images
d.StepExtractSquashFS,
d.StepGenRawDisk,
d.StepGenMBRRawDisk,
d.StepConvertGCE,
d.StepConvertVHD,
// ARM
d.StepGenARMImages,
d.StepPrepareARMImages,
// Inject the data into the ISO
d.StepInjectCC,
// Start servers
d.StepStartHTTPServer,
d.StepStartNetboot,
} {
if err := step(); err != nil {
return err
}))

// Ops to generate from container image
g.Add(opContainerPull,
herd.EnableIf(fromImageOption),
herd.WithDeps(opPreparetmproot), herd.WithCallback(ops.PullContainerImage(containerImage, tmpRootfs)))
g.Add(opGenISO,
herd.EnableIf(func() bool { return fromImage && !rawDiskIsSet && c.Disk.ARM == nil }),
herd.WithDeps(opContainerPull, opCopyCloudConfig), herd.WithCallback(ops.GenISO(kairosDefaultArtifactName, tmpRootfs, dst, c.ISO)))
g.Add(opExtractNetboot,
herd.EnableIf(func() bool { return fromImage && !c.DisableNetboot }),
herd.WithDeps(opGenISO), herd.WithCallback(ops.ExtractNetboot(isoFile, dstNetboot, kairosDefaultArtifactName)))

//TODO: add Validate step
// Ops to download from releases
g.Add(opDownloadInitrd,
herd.EnableIf(netbootReleaseOption),
herd.WithDeps(opPrepareNetboot), herd.WithCallback(ops.DownloadArtifact(artifact.InitrdURL(), initrdFile)))
g.Add(opDownloadKernel,
herd.EnableIf(netbootReleaseOption),
herd.WithDeps(opPrepareNetboot), herd.WithCallback(ops.DownloadArtifact(artifact.KernelURL(), kernelFile)))
g.Add(opDownloadSquashFS,
herd.EnableIf(func() bool {
return !c.DisableNetboot && !fromImage || rawDiskIsSet && !fromImage || !fromImage && c.Disk.ARM != nil
}),
herd.WithDeps(opPrepareNetboot), herd.WithCallback(ops.DownloadArtifact(artifact.SquashFSURL(), squashFSfile)))
g.Add(opDownloadISO,
herd.EnableIf(isoOption),
herd.WithCallback(ops.DownloadArtifact(artifact.ISOUrl(), isoFile)))

// Ops to generate disk images

// Extract SquashFS from released asset to build the raw disk image if needed
g.Add(opExtractSquashFS,
herd.EnableIf(func() bool { return rawDiskIsSet && !fromImage }),
herd.WithDeps(opDownloadSquashFS), herd.WithCallback(ops.ExtractSquashFS(squashFSfile, tmpRootfs)))

imageOrSquashFS := herd.IfElse(fromImage, herd.WithDeps(opContainerPull), herd.WithDeps(opExtractSquashFS))

g.Add(opGenRawDisk,
herd.EnableIf(func() bool { return rawDiskIsSet && c.Disk.ARM == nil && !c.Disk.MBR }),
imageOrSquashFS,
herd.WithCallback(ops.GenEFIRawDisk(tmpRootfs, filepath.Join(dst, "disk.raw"))))

g.Add(opGenMBRRawDisk,
herd.EnableIf(func() bool { return c.Disk.ARM == nil && c.Disk.MBR }),
herd.IfElse(isoOption(),
herd.WithDeps(opDownloadISO), herd.WithDeps(opGenISO),
),
herd.IfElse(isoOption(),
herd.WithCallback(
ops.GenBIOSRawDisk(c, isoFile, filepath.Join(dst, "disk.raw"))),
herd.WithCallback(
ops.GenBIOSRawDisk(c, isoFile, filepath.Join(dst, "disk.raw"))),
),
)

g.Add(opConvertGCE,
herd.EnableIf(func() bool { return c.Disk.GCE }),
herd.WithDeps(opGenRawDisk),
herd.WithCallback(ops.ConvertRawDiskToGCE(filepath.Join(dst, "disk.raw"), filepath.Join(dst, "disk.raw.gce"))))

g.Add(opConvertVHD,
herd.EnableIf(func() bool { return c.Disk.VHD }),
herd.WithDeps(opGenRawDisk),
herd.WithCallback(ops.ConvertRawDiskToVHD(filepath.Join(dst, "disk.raw"), filepath.Join(dst, "disk.raw.vhd"))))

// ARM

g.Add(opGenARMImages,
herd.EnableIf(func() bool { return c.Disk.ARM != nil && !c.Disk.ARM.PrepareOnly }),
imageOrSquashFS,
herd.WithCallback(ops.GenArmDisk(tmpRootfs, filepath.Join(dst, "disk.img"), c)))

g.Add(opPrepareARMImages,
herd.EnableIf(func() bool { return c.Disk.ARM != nil && c.Disk.ARM.PrepareOnly }),
imageOrSquashFS,
herd.WithCallback(ops.PrepareArmPartitions(tmpRootfs, dst, c)))

// Inject the data into the ISO
g.Add(opInjectCC,
herd.EnableIf(isoOption),
herd.WithDeps(opCopyCloudConfig),
herd.ConditionalOption(isoOption, herd.WithDeps(opDownloadISO)),
herd.WithCallback(ops.InjectISO(dst, isoFile, c.ISO)))

// Start servers
g.Add(
opStartHTTPServer,
herd.Background,
herd.EnableIf(func() bool { return !c.DisableISOboot && !c.DisableHTTPServer }),
herd.IfElse(
fromImage,
herd.WithDeps(opGenISO, opCopyCloudConfig),
herd.WithDeps(opDownloadISO, opCopyCloudConfig, opInjectCC),
),
herd.WithCallback(ops.ServeArtifacts(listenAddr, dst)),
)

g.Add(
opStartNetboot,
herd.EnableIf(netbootOption),
herd.ConditionalOption(isoOption, herd.WithDeps(opDownloadInitrd, opDownloadKernel, opDownloadSquashFS)),
herd.ConditionalOption(fromImageOption, herd.WithDeps(opExtractNetboot)),
herd.Background,
herd.WithCallback(
ops.StartPixiecore(cloudConfigFile, squashFSfile, address, netbootPort, initrdFile, kernelFile, c.NetBoot),
),
)
}
}
return nil
}

func copy(src, dst string) (int64, error) {
Expand Down
Loading

0 comments on commit 1073599

Please sign in to comment.