From 864e94f8c3ead75195575405fff76de5e3b216fe Mon Sep 17 00:00:00 2001 From: xinyangli Date: Fri, 20 Dec 2024 19:20:45 +0800 Subject: [PATCH] introduce executor abstraction --- cmd/build.go | 9 +-- cmd/eval.go | 7 +- cmd/list.go | 6 +- cmd/run.go | 12 +++- go.mod | 2 +- go.sum | 4 +- internal/executor/executor.go | 16 +++++ internal/executor/nix.go | 76 ++++++++++++++++++++++ internal/{nix/nix.go => executor/utils.go} | 58 ++--------------- nix/package.nix | 2 +- 10 files changed, 122 insertions(+), 70 deletions(-) create mode 100644 internal/executor/executor.go create mode 100644 internal/executor/nix.go rename internal/{nix/nix.go => executor/utils.go} (78%) diff --git a/cmd/build.go b/cmd/build.go index 88088b1..fa6c120 100644 --- a/cmd/build.go +++ b/cmd/build.go @@ -3,7 +3,7 @@ package cmd import ( "context" - "github.com/nlewo/comin/internal/nix" + "github.com/nlewo/comin/internal/executor" "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -15,19 +15,20 @@ var buildCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { ctx := context.TODO() hosts := make([]string, 1) + executor, _ := executor.NewNixExecutor() if hostname != "" { hosts[0] = hostname } else { - hosts, _ = nix.List(flakeUrl) + hosts, _ = executor.List(flakeUrl) } for _, host := range hosts { logrus.Infof("Building the NixOS configuration of machine '%s'", host) - drvPath, _, err := nix.ShowDerivation(ctx, flakeUrl, host) + drvPath, _, err := executor.ShowDerivation(ctx, flakeUrl, host) if err != nil { logrus.Errorf("Failed to evaluate the configuration '%s': '%s'", host, err) } - err = nix.Build(ctx, drvPath) + err = executor.Build(ctx, drvPath) if err != nil { logrus.Errorf("Failed to build the configuration '%s': '%s'", host, err) } diff --git a/cmd/eval.go b/cmd/eval.go index 2719f9f..d50b3bb 100644 --- a/cmd/eval.go +++ b/cmd/eval.go @@ -3,7 +3,7 @@ package cmd import ( "context" - "github.com/nlewo/comin/internal/nix" + "github.com/nlewo/comin/internal/executor" "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -15,14 +15,15 @@ var evalCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { hosts := make([]string, 1) ctx := context.TODO() + executor, _ := executor.NewNixExecutor() if hostname != "" { hosts[0] = hostname } else { - hosts, _ = nix.List(flakeUrl) + hosts, _ = executor.List(flakeUrl) } for _, host := range hosts { logrus.Infof("Evaluating the NixOS configuration of machine '%s'", host) - _, _, err := nix.ShowDerivation(ctx, flakeUrl, host) + _, _, err := executor.ShowDerivation(ctx, flakeUrl, host) if err != nil { logrus.Errorf("Failed to eval the configuration '%s': '%s'", host, err) } diff --git a/cmd/list.go b/cmd/list.go index f852429..21c293f 100644 --- a/cmd/list.go +++ b/cmd/list.go @@ -2,7 +2,8 @@ package cmd import ( "fmt" - "github.com/nlewo/comin/internal/nix" + + "github.com/nlewo/comin/internal/executor" "github.com/spf13/cobra" ) @@ -11,7 +12,8 @@ var listCmd = &cobra.Command{ Short: "List hosts of the local repository", Args: cobra.MinimumNArgs(0), Run: func(cmd *cobra.Command, args []string) { - hosts, _ := nix.List(flakeUrl) + executor, _ := executor.NewNixExecutor() + hosts, _ := executor.List(flakeUrl) for _, host := range hosts { fmt.Println(host) } diff --git a/cmd/run.go b/cmd/run.go index 7cfa949..a4a9778 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -8,10 +8,10 @@ import ( "github.com/nlewo/comin/internal/builder" "github.com/nlewo/comin/internal/config" "github.com/nlewo/comin/internal/deployer" + "github.com/nlewo/comin/internal/executor" "github.com/nlewo/comin/internal/fetcher" "github.com/nlewo/comin/internal/http" "github.com/nlewo/comin/internal/manager" - "github.com/nlewo/comin/internal/nix" "github.com/nlewo/comin/internal/prometheus" "github.com/nlewo/comin/internal/repository" "github.com/nlewo/comin/internal/scheduler" @@ -67,8 +67,14 @@ var runCmd = &cobra.Command{ sched := scheduler.New() sched.FetchRemotes(fetcher, cfg.Remotes) - builder := builder.New(gitConfig.Path, gitConfig.Dir, cfg.Hostname, 5*time.Minute, nix.Eval, 30*time.Minute, nix.Build) - deployer := deployer.New(nix.Deploy, lastDeployment) + executor, err := executor.New() + if err != nil { + logrus.Error("Failed to create executor") + return + } + + builder := builder.New(gitConfig.Path, gitConfig.Dir, cfg.Hostname, 30*time.Minute, executor.Eval, 30*time.Minute, executor.Build) + deployer := deployer.New(executor.Deploy, lastDeployment) manager := manager.New(store, metrics, sched, fetcher, builder, deployer, machineId) diff --git a/go.mod b/go.mod index 1c3ffdc..051fba8 100644 --- a/go.mod +++ b/go.mod @@ -47,7 +47,7 @@ require ( golang.org/x/mod v0.18.0 // indirect golang.org/x/net v0.26.0 // indirect golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.21.0 // indirect + golang.org/x/sys v0.22.0 // indirect golang.org/x/tools v0.22.0 // indirect google.golang.org/protobuf v1.32.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect diff --git a/go.sum b/go.sum index 6b888f2..27a3626 100644 --- a/go.sum +++ b/go.sum @@ -122,8 +122,8 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= diff --git a/internal/executor/executor.go b/internal/executor/executor.go new file mode 100644 index 0000000..f886219 --- /dev/null +++ b/internal/executor/executor.go @@ -0,0 +1,16 @@ +package executor + +import ( + "context" +) + +type Executor interface { + Eval(ctx context.Context, flakeUrl, hostname string) (drvPath string, outPath string, machineId string, err error) + Build(ctx context.Context, drvPath string) (err error) + Deploy(ctx context.Context, outPath, operation string) (needToRestartComin bool, profilePath string, err error) +} + +func New() (e Executor, err error) { + e, err = NewNixExecutor() + return +} diff --git a/internal/executor/nix.go b/internal/executor/nix.go new file mode 100644 index 0000000..044fe0c --- /dev/null +++ b/internal/executor/nix.go @@ -0,0 +1,76 @@ +package executor + +import ( + "bytes" + "context" + "encoding/json" + "os" +) + +type NixLocal struct{} + +func NewNixExecutor() (*NixLocal, error) { + return &NixLocal{}, nil +} + +func (n *NixLocal) ShowDerivation(ctx context.Context, flakeUrl, hostname string) (drvPath string, outPath string, err error) { + return showDerivation(ctx, flakeUrl, hostname) +} + +func (n *NixLocal) Eval(ctx context.Context, flakeUrl, hostname string) (drvPath string, outPath string, machineId string, err error) { + drvPath, outPath, err = showDerivation(ctx, flakeUrl, hostname) + if err != nil { + return + } + machineId, err = getExpectedMachineId(flakeUrl, hostname) + return +} + +func (n *NixLocal) Build(ctx context.Context, drvPath string) (err error) { + return build(ctx, drvPath) +} + +func (n *NixLocal) Deploy(ctx context.Context, outPath, operation string) (needToRestartComin bool, profilePath string, err error) { + return deploy(ctx, outPath, operation) +} + +type Path struct { + Path string `json:"path"` +} + +type Output struct { + Out Path `json:"out"` +} + +type Derivation struct { + Outputs Output `json:"outputs"` +} + +type Show struct { + NixosConfigurations map[string]struct{} `json:"nixosConfigurations"` +} + +func (n *NixLocal) List(flakeUrl string) (hosts []string, err error) { + args := []string{ + "flake", + "show", + "--json", + flakeUrl, + } + var stdout bytes.Buffer + err = runNixCommand(args, &stdout, os.Stderr) + if err != nil { + return + } + + var output Show + err = json.Unmarshal(stdout.Bytes(), &output) + if err != nil { + return + } + hosts = make([]string, 0, len(output.NixosConfigurations)) + for key := range output.NixosConfigurations { + hosts = append(hosts, key) + } + return +} diff --git a/internal/nix/nix.go b/internal/executor/utils.go similarity index 78% rename from internal/nix/nix.go rename to internal/executor/utils.go index c8d6230..13db81f 100644 --- a/internal/nix/nix.go +++ b/internal/executor/utils.go @@ -1,4 +1,4 @@ -package nix +package executor import ( "bytes" @@ -61,16 +61,7 @@ func runNixCommand(args []string, stdout, stderr io.Writer) (err error) { return nil } -func Eval(ctx context.Context, flakeUrl, hostname string) (drvPath string, outPath string, machineId string, err error) { - drvPath, outPath, err = ShowDerivation(ctx, flakeUrl, hostname) - if err != nil { - return - } - machineId, err = getExpectedMachineId(flakeUrl, hostname) - return -} - -func ShowDerivation(ctx context.Context, flakeUrl, hostname string) (drvPath string, outPath string, err error) { +func showDerivation(ctx context.Context, flakeUrl, hostname string) (drvPath string, outPath string, err error) { installable := fmt.Sprintf("%s#nixosConfigurations.%s.config.system.build.toplevel", flakeUrl, hostname) args := []string{ "show-derivation", @@ -100,48 +91,7 @@ func ShowDerivation(ctx context.Context, flakeUrl, hostname string) (drvPath str return } -type Path struct { - Path string `json:"path"` -} - -type Output struct { - Out Path `json:"out"` -} - -type Derivation struct { - Outputs Output `json:"outputs"` -} - -type Show struct { - NixosConfigurations map[string]struct{} `json:"nixosConfigurations"` -} - -func List(flakeUrl string) (hosts []string, err error) { - args := []string{ - "flake", - "show", - "--json", - flakeUrl, - } - var stdout bytes.Buffer - err = runNixCommand(args, &stdout, os.Stderr) - if err != nil { - return - } - - var output Show - err = json.Unmarshal(stdout.Bytes(), &output) - if err != nil { - return - } - hosts = make([]string, 0, len(output.NixosConfigurations)) - for key := range output.NixosConfigurations { - hosts = append(hosts, key) - } - return -} - -func Build(ctx context.Context, drvPath string) (err error) { +func build(ctx context.Context, drvPath string) (err error) { args := []string{ "build", fmt.Sprintf("%s^*", drvPath), @@ -187,7 +137,7 @@ func switchToConfiguration(operation string, outPath string, dryRun bool) error return nil } -func Deploy(ctx context.Context, outPath, operation string) (needToRestartComin bool, profilePath string, err error) { +func deploy(ctx context.Context, outPath, operation string) (needToRestartComin bool, profilePath string, err error) { // FIXME: this check doesn't have to be here. It should be // done by the manager. beforeCominUnitFileHash := cominUnitFileHash() diff --git a/nix/package.nix b/nix/package.nix index 659bd2a..e78ea37 100644 --- a/nix/package.nix +++ b/nix/package.nix @@ -36,7 +36,7 @@ buildGoModule rec { ../main.go ]; }; - vendorHash = "sha256-8RkxEDnPZJAWOo9uITELewc2UfoJ86DMGUi+Mi801/g="; + vendorHash = "sha256-IE2yxFIIqbjjzBamwJg5vS36MMOkD7TJ4A5PKx3CRH4="; ldflags = [ "-X github.com/nlewo/comin/cmd.version=${version}" ];