Skip to content

Commit

Permalink
Introduce Combustion type
Browse files Browse the repository at this point in the history
Signed-off-by: Atanas Dinov <[email protected]>
  • Loading branch information
atanasdinov committed May 21, 2024
1 parent 64ba3fb commit 2d92311
Show file tree
Hide file tree
Showing 12 changed files with 265 additions and 214 deletions.
19 changes: 10 additions & 9 deletions pkg/build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,32 @@ import (
"path/filepath"
"time"

"github.com/suse-edge/edge-image-builder/pkg/combustion"
"github.com/suse-edge/edge-image-builder/pkg/image"
"github.com/suse-edge/edge-image-builder/pkg/log"
)

type configureCombustion func(ctx *image.Context) error
type imageConfigurator interface {
Configure(ctx *image.Context) error
}

type Builder struct {
context *image.Context
configureCombustion configureCombustion
context *image.Context
imageConfigurator imageConfigurator
}

func NewBuilder(ctx *image.Context) *Builder {
func NewBuilder(ctx *image.Context, imageConfigurator imageConfigurator) *Builder {
return &Builder{
context: ctx,
configureCombustion: combustion.Configure,
context: ctx,
imageConfigurator: imageConfigurator,
}
}

func (b *Builder) Build() error {
log.Audit("Generating image customization components...")

if err := b.configureCombustion(b.context); err != nil {
if err := b.imageConfigurator.Configure(b.context); err != nil {
log.Audit("Error configuring customization components, check the logs under the build directory for more information.")
return fmt.Errorf("configuring combustion: %w", err)
return fmt.Errorf("configuring image: %w", err)
}

switch b.context.ImageDefinition.Image.ImageType {
Expand Down
34 changes: 18 additions & 16 deletions pkg/cli/build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,12 @@ func Run(_ *cli.Context) error {

appendHelm(ctx)

if cmdErr = bootstrapDependencyServices(ctx, rootBuildDir); cmdErr != nil {
combustionClient := &combustion.Combustion{
NetworkConfigGenerator: network.ConfigGenerator{},
NetworkConfiguratorInstaller: network.ConfiguratorInstaller{},
}

if cmdErr = bootstrapDependencyServices(ctx, rootBuildDir, combustionClient); cmdErr != nil {
cmd.LogError(cmdErr, checkBuildLogMessage)
os.Exit(1)
}
Expand All @@ -97,7 +102,7 @@ func Run(_ *cli.Context) error {
}
}()

builder := build.NewBuilder(ctx)
builder := build.NewBuilder(ctx, combustionClient)
if err = builder.Build(); err != nil {
zap.S().Fatalf("An error occurred building the image: %s", err)
}
Expand Down Expand Up @@ -154,13 +159,11 @@ func parseImageDefinition(configDir, definitionFile string) (*image.Definition,
// Assembles the image build context with user-provided values and implementation defaults.
func buildContext(buildDir, combustionDir, artefactsDir, configDir string, imageDefinition *image.Definition) *image.Context {
ctx := &image.Context{
ImageConfigDir: configDir,
BuildDir: buildDir,
CombustionDir: combustionDir,
ArtefactsDir: artefactsDir,
ImageDefinition: imageDefinition,
NetworkConfigGenerator: network.ConfigGenerator{},
NetworkConfiguratorInstaller: network.ConfiguratorInstaller{},
ImageConfigDir: configDir,
BuildDir: buildDir,
CombustionDir: combustionDir,
ArtefactsDir: artefactsDir,
ImageDefinition: imageDefinition,
}
return ctx
}
Expand Down Expand Up @@ -242,7 +245,7 @@ func appendHelm(ctx *image.Context) {
}

// If the image definition requires it, starts the necessary services, returning an error in the event of failure.
func bootstrapDependencyServices(ctx *image.Context, rootDir string) *cmd.Error {
func bootstrapDependencyServices(ctx *image.Context, rootDir string, combustionClient *combustion.Combustion) *cmd.Error {
if !combustion.SkipRPMComponent(ctx) {
p, err := podman.New(ctx.BuildDir)
if err != nil {
Expand All @@ -256,14 +259,13 @@ func bootstrapDependencyServices(ctx *image.Context, rootDir string) *cmd.Error
imgType := ctx.ImageDefinition.Image.ImageType
baseBuilder := resolver.NewTarballBuilder(ctx.BuildDir, imgPath, imgType, p)

rpmResolver := resolver.New(ctx.BuildDir, p, baseBuilder, "")
ctx.RPMResolver = rpmResolver
ctx.RPMRepoCreator = rpm.NewRepoCreator(ctx.BuildDir)
combustionClient.RPMResolver = resolver.New(ctx.BuildDir, p, baseBuilder, "")
combustionClient.RPMRepoCreator = rpm.NewRepoCreator(ctx.BuildDir)
}

if combustion.IsEmbeddedArtifactRegistryConfigured(ctx) {
certsDir := filepath.Join(ctx.ImageConfigDir, combustion.K8sDir, combustion.HelmDir, combustion.CertsDir)
ctx.HelmClient = helm.New(ctx.BuildDir, certsDir)
combustionClient.HelmClient = helm.New(ctx.BuildDir, certsDir)
}

if ctx.ImageDefinition.Kubernetes.Version != "" {
Expand All @@ -275,8 +277,8 @@ func bootstrapDependencyServices(ctx *image.Context, rootDir string) *cmd.Error
}
}

ctx.KubernetesScriptDownloader = kubernetes.ScriptDownloader{}
ctx.KubernetesArtefactDownloader = kubernetes.ArtefactDownloader{
combustionClient.KubernetesScriptDownloader = kubernetes.ScriptDownloader{}
combustionClient.KubernetesArtefactDownloader = kubernetes.ArtefactDownloader{
Cache: c,
}
}
Expand Down
46 changes: 41 additions & 5 deletions pkg/combustion/combustion.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package combustion
import (
"errors"
"fmt"
"io"
"io/fs"
"os"
"path/filepath"
Expand All @@ -21,9 +22,44 @@ import (
// Result can also be an empty slice or nil if this is not necessary.
type configureComponent func(context *image.Context) ([]string, error)

type networkConfigGenerator interface {
GenerateNetworkConfig(configDir, outputDir string, outputWriter io.Writer) error
}

type networkConfiguratorInstaller interface {
InstallConfigurator(sourcePath, installPath string) error
}

type kubernetesScriptDownloader interface {
DownloadInstallScript(distribution, destinationPath string) (string, error)
}

type kubernetesArtefactDownloader interface {
DownloadRKE2Artefacts(arch image.Arch, version, cni string, multusEnabled bool, installPath, imagesPath string) error
DownloadK3sArtefacts(arch image.Arch, version, installPath, imagesPath string) error
}

type rpmResolver interface {
Resolve(packages *image.Packages, localRPMConfig *image.LocalRPMConfig, outputDir string) (rpmDirPath string, pkgList []string, err error)
}

type rpmRepoCreator interface {
Create(path string) error
}

type Combustion struct {
NetworkConfigGenerator networkConfigGenerator
NetworkConfiguratorInstaller networkConfiguratorInstaller
KubernetesScriptDownloader kubernetesScriptDownloader
KubernetesArtefactDownloader kubernetesArtefactDownloader
RPMResolver rpmResolver
RPMRepoCreator rpmRepoCreator
HelmClient image.HelmClient
}

// Configure iterates over all separate Combustion components and configures them independently.
// If all of those are successful, the Combustion script is assembled and written to the file system.
func Configure(ctx *image.Context) error {
func (c *Combustion) Configure(ctx *image.Context) error {
var combustionScripts []string

// EIB Combustion script prefix ranges:
Expand Down Expand Up @@ -59,7 +95,7 @@ func Configure(ctx *image.Context) error {
},
{
name: networkComponentName,
runnable: configureNetwork,
runnable: c.configureNetwork,
},
{
name: groupsComponentName,
Expand All @@ -75,7 +111,7 @@ func Configure(ctx *image.Context) error {
},
{
name: rpmComponentName,
runnable: configureRPMs,
runnable: c.configureRPMs,
},
{
name: systemdComponentName,
Expand All @@ -91,15 +127,15 @@ func Configure(ctx *image.Context) error {
},
{
name: registryComponentName,
runnable: configureRegistry,
runnable: c.configureRegistry,
},
{
name: keymapComponentName,
runnable: configureKeymap,
},
{
name: k8sComponentName,
runnable: configureKubernetes,
runnable: c.configureKubernetes,
},
{
name: certsComponentName,
Expand Down
34 changes: 17 additions & 17 deletions pkg/combustion/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,15 @@ var (
k8sVIPManifest string
)

func configureKubernetes(ctx *image.Context) ([]string, error) {
func (c *Combustion) configureKubernetes(ctx *image.Context) ([]string, error) {
version := ctx.ImageDefinition.Kubernetes.Version

if version == "" {
log.AuditComponentSkipped(k8sComponentName)
return nil, nil
}

configureFunc := kubernetesConfigurator(version)
configureFunc := c.kubernetesConfigurator(version)
if configureFunc == nil {
log.AuditComponentFailed(k8sComponentName)
return nil, fmt.Errorf("cannot configure kubernetes version: %s", version)
Expand Down Expand Up @@ -102,37 +102,37 @@ func configureKubernetes(ctx *image.Context) ([]string, error) {
return []string{script}, nil
}

func kubernetesConfigurator(version string) func(*image.Context, *kubernetes.Cluster) (string, error) {
func (c *Combustion) kubernetesConfigurator(version string) func(*image.Context, *kubernetes.Cluster) (string, error) {
switch {
case strings.Contains(version, image.KubernetesDistroRKE2):
return configureRKE2
return c.configureRKE2
case strings.Contains(version, image.KubernetesDistroK3S):
return configureK3S
return c.configureK3S
default:
return nil
}
}

func downloadKubernetesInstallScript(ctx *image.Context, distribution string) (string, error) {
func (c *Combustion) downloadKubernetesInstallScript(ctx *image.Context, distribution string) (string, error) {
path := kubernetesArtefactsPath(ctx)

installScript, err := ctx.KubernetesScriptDownloader.DownloadInstallScript(distribution, path)
installScript, err := c.KubernetesScriptDownloader.DownloadInstallScript(distribution, path)
if err != nil {
return "", fmt.Errorf("downloading install script: %w", err)
}

return prependArtefactPath(filepath.Join(K8sDir, installScript)), nil
}

func configureK3S(ctx *image.Context, cluster *kubernetes.Cluster) (string, error) {
func (c *Combustion) configureK3S(ctx *image.Context, cluster *kubernetes.Cluster) (string, error) {
zap.S().Info("Configuring K3s cluster")

installScript, err := downloadKubernetesInstallScript(ctx, image.KubernetesDistroK3S)
installScript, err := c.downloadKubernetesInstallScript(ctx, image.KubernetesDistroK3S)
if err != nil {
return "", fmt.Errorf("downloading k3s install script: %w", err)
}

binaryPath, imagesPath, err := downloadK3sArtefacts(ctx)
binaryPath, imagesPath, err := c.downloadK3sArtefacts(ctx)
if err != nil {
return "", fmt.Errorf("downloading k3s artefacts: %w", err)
}
Expand Down Expand Up @@ -178,7 +178,7 @@ func configureK3S(ctx *image.Context, cluster *kubernetes.Cluster) (string, erro
return storeKubernetesInstaller(ctx, "multi-node-k3s", k3sMultiNodeInstaller, templateValues)
}

func downloadK3sArtefacts(ctx *image.Context) (binaryPath, imagesPath string, err error) {
func (c *Combustion) downloadK3sArtefacts(ctx *image.Context) (binaryPath, imagesPath string, err error) {
imagesPath = filepath.Join(K8sDir, k8sImagesDir)
imagesDestination := filepath.Join(ctx.ArtefactsDir, imagesPath)
if err = os.MkdirAll(imagesDestination, os.ModePerm); err != nil {
Expand All @@ -191,7 +191,7 @@ func downloadK3sArtefacts(ctx *image.Context) (binaryPath, imagesPath string, er
return "", "", fmt.Errorf("creating kubernetes install dir: %w", err)
}

if err = ctx.KubernetesArtefactDownloader.DownloadK3sArtefacts(
if err = c.KubernetesArtefactDownloader.DownloadK3sArtefacts(
ctx.ImageDefinition.Image.Arch,
ctx.ImageDefinition.Kubernetes.Version,
installDestination,
Expand Down Expand Up @@ -219,15 +219,15 @@ func downloadK3sArtefacts(ctx *image.Context) (binaryPath, imagesPath string, er
return prependArtefactPath(binaryPath), prependArtefactPath(imagesPath), nil
}

func configureRKE2(ctx *image.Context, cluster *kubernetes.Cluster) (string, error) {
func (c *Combustion) configureRKE2(ctx *image.Context, cluster *kubernetes.Cluster) (string, error) {
zap.S().Info("Configuring RKE2 cluster")

installScript, err := downloadKubernetesInstallScript(ctx, image.KubernetesDistroRKE2)
installScript, err := c.downloadKubernetesInstallScript(ctx, image.KubernetesDistroRKE2)
if err != nil {
return "", fmt.Errorf("downloading RKE2 install script: %w", err)
}

installPath, imagesPath, err := downloadRKE2Artefacts(ctx, cluster)
installPath, imagesPath, err := c.downloadRKE2Artefacts(ctx, cluster)
if err != nil {
return "", fmt.Errorf("downloading RKE2 artefacts: %w", err)
}
Expand Down Expand Up @@ -280,7 +280,7 @@ func storeKubernetesInstaller(ctx *image.Context, templateName, templateContents
return k8sInstallScript, nil
}

func downloadRKE2Artefacts(ctx *image.Context, cluster *kubernetes.Cluster) (installPath, imagesPath string, err error) {
func (c *Combustion) downloadRKE2Artefacts(ctx *image.Context, cluster *kubernetes.Cluster) (installPath, imagesPath string, err error) {
cni, multusEnabled, err := cluster.ExtractCNI()
if err != nil {
return "", "", fmt.Errorf("extracting CNI from cluster config: %w", err)
Expand All @@ -298,7 +298,7 @@ func downloadRKE2Artefacts(ctx *image.Context, cluster *kubernetes.Cluster) (ins
return "", "", fmt.Errorf("creating kubernetes install dir: %w", err)
}

if err = ctx.KubernetesArtefactDownloader.DownloadRKE2Artefacts(
if err = c.KubernetesArtefactDownloader.DownloadRKE2Artefacts(
ctx.ImageDefinition.Image.Arch,
ctx.ImageDefinition.Kubernetes.Version,
cni,
Expand Down
19 changes: 11 additions & 8 deletions pkg/combustion/kubernetes_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,17 @@ func TestConfigureKubernetes_SuccessfulRKE2ServerWithManifests(t *testing.T) {
APIHost: "api.cluster01.hosted.on.edge.suse.com",
},
}
ctx.KubernetesScriptDownloader = mockKubernetesScriptDownloader{
downloadScript: func(distribution, destPath string) (string, error) {
return "install-k8s.sh", nil

c := Combustion{
KubernetesScriptDownloader: mockKubernetesScriptDownloader{
downloadScript: func(distribution, destPath string) (string, error) {
return "install-k8s.sh", nil
},
},
}
ctx.KubernetesArtefactDownloader = mockKubernetesArtefactDownloader{
downloadRKE2Artefacts: func(arch image.Arch, version, cni string, multusEnabled bool, installPath, imagesPath string) error {
return nil
KubernetesArtefactDownloader: mockKubernetesArtefactDownloader{
downloadRKE2Artefacts: func(arch image.Arch, version, cni string, multusEnabled bool, installPath, imagesPath string) error {
return nil
},
},
}

Expand All @@ -84,7 +87,7 @@ func TestConfigureKubernetes_SuccessfulRKE2ServerWithManifests(t *testing.T) {
err := fileio.CopyFile(localSampleManifestPath, filepath.Join(localManifestsSrcDir, "sample-crd.yaml"), fileio.NonExecutablePerms)
require.NoError(t, err)

scripts, err := configureKubernetes(ctx)
scripts, err := c.configureKubernetes(ctx)
require.NoError(t, err)
require.Len(t, scripts, 1)

Expand Down
Loading

0 comments on commit 2d92311

Please sign in to comment.