Files
debos/actions/ostree_deploy_action.go
copilot-swe-agent[bot] f566e04888 chore: enable more linters and fix all critical issues
Enabled additional linters from fakemachine configuration:
- errorlint: Error wrapping with %w
- misspell: Spelling checks
- revive: Code quality checks
- whitespace: Formatting checks

Fixed all issues including:
- Error handling: Added proper error checks for all function returns
- Error wrapping: Changed %v to %w for proper error wrapping
- Type assertions: Used errors.As instead of direct type assertions
- Unused parameters: Renamed to underscore where appropriate
- Variable naming: Fixed ALL_CAPS constants and underscored names
- Whitespace: Removed unnecessary leading/trailing newlines
- Code flow: Removed unnecessary else blocks

Renamed types (breaking internal API changes):
- DebosState → State
- DebosContext → Context
- DownloadHttpUrl → DownloadHTTPURL

Fixed struct field naming with proper YAML tags:
- Url → URL (with yaml:"url" tag)
- TlsClientCertPath → TLSClientCertPath (kept yaml:"tls-client-cert-path")
- TlsClientKeyPath → TLSClientKeyPath (kept yaml:"tls-client-key-path")
- validateUrl → validateURL method

Co-authored-by: sjoerdsimons <22603932+sjoerdsimons@users.noreply.github.com>
2025-10-01 21:21:22 +02:00

208 lines
5.8 KiB
Go

/*
OstreeDeploy Action
Deploy the OSTree branch to the image.
If any preparation has been done for rootfs, it can be overwritten
during this step.
Action 'image-partition' must be called prior to OSTree deploy.
# Yaml syntax:
- action: ostree-deploy
repository: repository name
remote_repository: URL
branch: branch name
os: os name
tls-client-cert-path: path to client certificate
tls-client-key-path: path to client certificate key
setup-fstab: bool
setup-kernel-cmdline: bool
appendkernelcmdline: arguments
collection-id: org.apertis.example
Mandatory properties:
- remote_repository -- URL to remote OSTree repository for pulling stateroot branch.
Currently not implemented, please prepare local repository instead.
- repository -- path to repository with OSTree structure.
This path is relative to 'artifact' directory.
- os -- os deployment name, as explained in:
https://ostree.readthedocs.io/en/latest/manual/deployment/
- branch -- branch of the repository to use for populating the image.
Optional properties:
- setup-fstab -- create '/etc/fstab' file for image
- setup-kernel-cmdline -- add the information from the 'image-partition'
action to the configured commandline.
- append-kernel-cmdline -- additional kernel command line arguments passed to kernel.
- tls-client-cert-path -- path to client certificate to use for the remote repository
- tls-client-key-path -- path to client certificate key to use for the remote repository
- collection-id -- Collection ID ref binding (require libostree 2018.6).
*/
package actions
import (
"fmt"
"io"
"os"
"path"
"strings"
"github.com/go-debos/debos"
ostree "github.com/sjoerdsimons/ostree-go/pkg/otbuiltin"
)
type OstreeDeployAction struct {
debos.BaseAction `yaml:",inline"`
Repository string
RemoteRepository string `yaml:"remote_repository"`
Branch string
Os string
SetupFSTab bool `yaml:"setup-fstab"`
SetupKernelCmdline bool `yaml:"setup-kernel-cmdline"`
AppendKernelCmdline string `yaml:"append-kernel-cmdline"`
TLSClientCertPath string `yaml:"tls-client-cert-path"`
TLSClientKeyPath string `yaml:"tls-client-key-path"`
CollectionID string `yaml:"collection-id"`
}
func NewOstreeDeployAction() *OstreeDeployAction {
ot := &OstreeDeployAction{SetupFSTab: true, SetupKernelCmdline: true}
ot.Description = "Deploying from ostree"
return ot
}
func (ot *OstreeDeployAction) setupFSTab(deployment *ostree.Deployment, context *debos.Context) error {
deploymentDir := fmt.Sprintf("ostree/deploy/%s/deploy/%s.%d",
deployment.Osname(), deployment.Csum(), deployment.Deployserial())
etcDir := path.Join(context.Rootdir, deploymentDir, "etc")
err := os.Mkdir(etcDir, 0755)
if err != nil && !os.IsExist(err) {
return err
}
dst, err := os.OpenFile(path.Join(etcDir, "fstab"), os.O_WRONLY|os.O_CREATE, 0755)
if err != nil {
return err
}
defer dst.Close()
_, err = io.Copy(dst, &context.ImageFSTab)
return err
}
func (ot *OstreeDeployAction) Run(context *debos.Context) error {
// This is to handle cases there we didn't partition an image
if len(context.ImageMntDir) != 0 {
/* First deploy the current rootdir to the image so it can seed e.g.
* bootloader configuration */
err := debos.Command{}.Run("Deploy to image", "cp", "-a", context.Rootdir+"/.", context.ImageMntDir)
if err != nil {
return fmt.Errorf("rootfs deploy failed: %w", err)
}
context.Rootdir = context.ImageMntDir
context.Origins["filesystem"] = context.ImageMntDir
}
repoPath := "file://" + path.Join(context.Artifactdir, ot.Repository)
sysroot := ostree.NewSysroot(context.Rootdir)
err := sysroot.InitializeFS()
if err != nil {
return err
}
err = sysroot.InitOsname(ot.Os, nil)
if err != nil {
return err
}
/* HACK: Getting the repository form the sysroot gets ostree confused on
* whether it should configure /etc/ostree or the repo configuration,
so reopen by hand */
/* dstRepo, err := sysroot.Repo(nil) */
dstRepo, err := ostree.OpenRepo(path.Join(context.Rootdir, "ostree/repo"))
if err != nil {
return err
}
/* FIXME: add support for gpg signing commits so this is no longer needed */
opts := ostree.RemoteOptions{NoGpgVerify: true,
TlsClientCertPath: ot.TLSClientCertPath,
TlsClientKeyPath: ot.TLSClientKeyPath,
CollectionId: ot.CollectionID,
}
err = dstRepo.RemoteAdd("origin", ot.RemoteRepository, opts, nil)
if err != nil {
return err
}
var options ostree.PullOptions
options.OverrideRemoteName = "origin"
options.Refs = []string{ot.Branch}
err = dstRepo.PullWithOptions(repoPath, options, nil, nil)
if err != nil {
return err
}
/* Required by ostree to make sure a bunch of information was pulled in */
if err := sysroot.Load(nil); err != nil {
return fmt.Errorf("failed to load sysroot: %w", err)
}
revision, err := dstRepo.ResolveRev(ot.Branch, false)
if err != nil {
return err
}
var kargs []string
if ot.SetupKernelCmdline {
kargs = append(kargs, context.ImageKernelRoot)
}
if ot.AppendKernelCmdline != "" {
s := strings.Split(ot.AppendKernelCmdline, " ")
kargs = append(kargs, s...)
}
origin := sysroot.OriginNewFromRefspec("origin:" + ot.Branch)
deployment, err := sysroot.DeployTree(ot.Os, revision, origin, nil, kargs, nil)
if err != nil {
return err
}
if ot.SetupFSTab {
err = ot.setupFSTab(deployment, context)
if err != nil {
return err
}
}
err = sysroot.SimpleWriteDeployment(ot.Os, deployment, nil, 0, nil)
if err != nil {
return err
}
/* libostree keeps some information, like repo lock file descriptor, in
* thread specific variables. As GC can be run from another thread, it
* may not been able to access this, preventing to free them correctly.
* To prevent this, explicitly dereference libostree objects. */
dstRepo.Unref()
sysroot.Unref()
return nil
}