Skip to content

Commit

Permalink
feat: change dnf repo provisioner to include apt repos
Browse files Browse the repository at this point in the history
  • Loading branch information
femnad committed Dec 16, 2023
1 parent ada38f5 commit 2b18e27
Show file tree
Hide file tree
Showing 10 changed files with 246 additions and 38 deletions.
1 change: 1 addition & 0 deletions base/fup.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type Config struct {
file string
isRemote bool
AcceptHostKeys []string `yaml:"accept_host_keys"`
AptRepos []entity.AptRepo `yaml:"apt_repos"`
Archives []Archive `yaml:"archives"`
Binaries []entity.Binary `yaml:"binaries"`
Cargo []CargoPkg `yaml:"rust"`
Expand Down
142 changes: 142 additions & 0 deletions entity/aptrepo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package entity

import (
"fmt"
"github.com/femnad/fup/base/settings"
"github.com/femnad/fup/internal"
"github.com/femnad/fup/precheck"
"github.com/femnad/fup/precheck/unless"
"github.com/femnad/fup/remote"
marecmd "github.com/femnad/mare/cmd"
"io"
"os/exec"
"path"
)

const (
keyRingsDir = "/etc/apt/keyrings"
sourcesDir = "/etc/apt/sources.list.d"
)

type AptRepo struct {
GPGKey string `yaml:"gpg_key"`
RepoName string `yaml:"name"`
Repo string `yaml:"repo"`
When string `yaml:"when"`
}

func (a AptRepo) DefaultVersionCmd() string {
return ""
}

func (a AptRepo) GetUnless() unless.Unless {
return unless.Unless{
Stat: path.Join(sourcesDir, fmt.Sprintf("%s.list", a.RepoName)),
}
}

func (AptRepo) GetVersion() string {
return ""
}

func (AptRepo) HasPostProc() bool {
return false
}

func (a AptRepo) Name() string {
return a.RepoName
}

func (a AptRepo) RunWhen() string {
return a.When
}

func (AptRepo) UpdateCmd() string {
return "apt update"
}

func (AptRepo) ensureKeyFile(keyUrl, keyRingFile string) error {
key, err := remote.ReadResponseBytes(keyUrl)
if err != nil {
return err
}

gpgCmd := exec.Command("gpg", "--dearmor", "-o", keyRingFile)
stdin, err := gpgCmd.StdinPipe()
if err != nil {
return err
}
defer stdin.Close()

stdout, err := gpgCmd.StdoutPipe()
if err != nil {
return err
}
defer stdout.Close()

if err = gpgCmd.Start(); err != nil {
return err
}

_, err = stdin.Write(key)
if err != nil {
return err
}
stdin.Close()

out, err := io.ReadAll(stdout)
if err != nil {
return err
}

if err = gpgCmd.Wait(); err != nil {
return err
}

_, err = internal.WriteContent(internal.ManagedFile{
Content: string(out),
Path: keyRingFile,
Mode: 0o644,
User: "root",
Group: "root",
})
return err
}

func (a AptRepo) Install() error {
err := internal.EnsureDir(keyRingsDir)
if err != nil {
return err
}
keyRingFile := path.Join(keyRingsDir, fmt.Sprintf("%s.gpg", a.RepoName))

err = a.ensureKeyFile(a.Repo, keyRingFile)
if err != nil {
return err
}

out, err := marecmd.RunFormatError(marecmd.Input{Command: "dpkg --print-architecture"})
if err != nil {
return err
}
architecture := out.Stdout

versionCodename, err := precheck.GetOSVersionCodename()
if err != nil {
return err
}

content := fmt.Sprintf("deb [arch=${architecture} signed-by=%s] %s ${codename} stable", keyRingFile, a.Repo)
content = settings.Expand(content, map[string]string{
"architecture": architecture,
"codename": versionCodename,
})
repoFile := path.Join(sourcesDir, fmt.Sprintf("%s.list", a.RepoName))

_, err = internal.WriteContent(internal.ManagedFile{
Content: content,
Path: repoFile,
})

return err
}
6 changes: 5 additions & 1 deletion entity/dnfrepo.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ func (d DnfRepo) RunWhen() string {
return d.When
}

func (DnfRepo) UpdateCmd() string {
return ""
}

func (i installer) installCorePlugins() error {
cmd := fmt.Sprintf("dnf install -y %s", pluginsCore)
return i.runMaybeSudo(cmd)
Expand Down Expand Up @@ -115,7 +119,7 @@ func (d DnfRepo) Install() error {
}

if len(d.Packages) > 0 {
osId, err := precheck.GetOsId()
osId, err := precheck.GetOSId()
if err != nil {
return err
}
Expand Down
13 changes: 13 additions & 0 deletions entity/osrepo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package entity

import (
"github.com/femnad/fup/precheck/unless"
"github.com/femnad/fup/precheck/when"
)

type OSRepo interface {
unless.Unlessable
when.Whenable
Install() error
UpdateCmd() string
}
2 changes: 1 addition & 1 deletion precheck/fact.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ func isOk(cap string) (bool, error) {
}

func isOs(osId string) (bool, error) {
foundOsId, err := GetOsId()
foundOsId, err := GetOSId()
if err != nil {
return false, fmt.Errorf("error getting OS ID %v", err)
}
Expand Down
17 changes: 13 additions & 4 deletions precheck/os.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import (
)

const (
osReleaseFile = "/etc/os-release"
osIdField = "ID"
osReleaseFile = "/etc/os-release"
osIdField = "ID"
versionCodenameField = "VERSION_CODENAME"
)

func GetOsId() (string, error) {
func getOSReleaseField(f string) (string, error) {
file, err := os.Open(osReleaseFile)
if err != nil {
return "", err
Expand All @@ -37,11 +38,19 @@ func GetOsId() (string, error) {
}

field, value := fields[0], fields[1]
if field != osIdField {
if field != f {
continue
}
return value, nil
}

return "", fmt.Errorf("unable to locate OS ID line in %s", osReleaseFile)
}

func GetOSVersionCodename() (string, error) {
return getOSReleaseField(versionCodenameField)
}

func GetOSId() (string, error) {
return getOSReleaseField(osIdField)
}
27 changes: 0 additions & 27 deletions provision/dnfrepo.go

This file was deleted.

66 changes: 66 additions & 0 deletions provision/osrepo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package provision

import (
"errors"
marecmd "github.com/femnad/mare/cmd"

mapset "github.com/deckarep/golang-set/v2"

"github.com/femnad/fup/base"
"github.com/femnad/fup/entity"
"github.com/femnad/fup/internal"
"github.com/femnad/fup/precheck/unless"
"github.com/femnad/fup/precheck/when"
)

func runUpdateCmds(cmds mapset.Set[string]) []error {
var errs []error

isRoot, err := internal.IsUserRoot()
if err != nil {
return []error{err}
}

cmds.Each(func(cmd string) bool {
input := marecmd.Input{Command: cmd, Sudo: !isRoot}
_, err = marecmd.RunFormatError(input)
errs = append(errs, err)
return false
})

return errs
}

func addRepos(config base.Config) error {
var errs []error

var repos []entity.OSRepo
for _, repo := range config.AptRepos {
repos = append(repos, repo)
}
for _, repo := range config.DnfRepos {
repos = append(repos, repo)
}

updateCmds := mapset.NewSet[string]()
for _, repo := range repos {
if !when.ShouldRun(repo) {
continue
}

if unless.ShouldSkip(repo, config.Settings) {
continue
}

err := repo.Install()
if err == nil && repo.UpdateCmd() != "" {
updateCmds.Add(repo.UpdateCmd())
}
errs = append(errs, err)
}

updateErrs := runUpdateCmds(updateCmds)
errs = append(errs, updateErrs...)

return errors.Join(errs...)
}
2 changes: 1 addition & 1 deletion provision/packages.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ type determiner struct {

func newDeterminer() (determiner, error) {
var d determiner
osId, err := precheck.GetOsId()
osId, err := precheck.GetOSId()
if err != nil {
return d, fmt.Errorf("error determining OS: %v", err)
}
Expand Down
8 changes: 4 additions & 4 deletions provision/provision.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func NewProvisioner(cfg base.Config, filter []string) (Provisioner, error) {

all := []provisionFn{
{"preflight", p.runPreflightTasks},
{"dnf-repo", p.AddDnfRepos},
{"repo", p.AddOSRepos},
{"archive", p.extractArchives},
{"binary", p.downloadBinaries},
{"package", p.installPackages},
Expand Down Expand Up @@ -111,10 +111,10 @@ func (p Provisioner) Apply() error {
return p.provisioners.apply()
}

func (p Provisioner) AddDnfRepos() error {
internal.Log.Notice("Adding DNF repos")
func (p Provisioner) AddOSRepos() error {
internal.Log.Notice("Adding OS repos")

return addDnfRepos(p.Config, p.Config.DnfRepos)
return addRepos(p.Config)
}

func (p Provisioner) extractArchives() error {
Expand Down

0 comments on commit 2b18e27

Please sign in to comment.