Skip to content

Commit

Permalink
feat: Add logic to mark config changes and display message
Browse files Browse the repository at this point in the history
  • Loading branch information
mattevans committed Dec 20, 2024
1 parent 6a4e7d9 commit 734c169
Show file tree
Hide file tree
Showing 7 changed files with 319 additions and 31 deletions.
55 changes: 44 additions & 11 deletions cmd/cli/commands/config/config_contributoor.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
package config

import (
"runtime"

"github.com/ethpandaops/contributoor-installer/internal/sidecar"
"github.com/ethpandaops/contributoor-installer/internal/tui"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
"github.com/sirupsen/logrus"
)

// Available run modes.
var runModes = []string{
sidecar.RunMethodDocker,
sidecar.RunMethodSystemd,
sidecar.RunMethodBinary,
}

// ContributoorSettingsPage is a page that allows the user to configure core contributoor settings.
type ContributoorSettingsPage struct {
display *ConfigDisplay
Expand Down Expand Up @@ -68,13 +77,6 @@ func (p *ContributoorSettingsPage) initPage() {
logrus.ErrorLevel.String(),
}

// Available run modes
runModes := []string{
sidecar.RunMethodDocker,
sidecar.RunMethodSystemd,
sidecar.RunMethodBinary,
}

// Find current log level index
currentLogLevel := p.display.sidecarCfg.Get().LogLevel
currentLogLevelIndex := 2 // Default to info
Expand All @@ -99,16 +101,27 @@ func (p *ContributoorSettingsPage) initPage() {
}
}

// Create display labels that show launchd on macOS
runModeLabels := make([]string, len(runModes))

for i, mode := range runModes {
if mode == sidecar.RunMethodSystemd {
runModeLabels[i] = getServiceManagerLabel()
} else {
runModeLabels[i] = mode
}
}

// Add our form fields.
form.AddDropDown("Log Level", logLevels, currentLogLevelIndex, func(option string, index int) {
p.description.SetText("Set the logging verbosity level. Debug and Trace provide more detailed output.")
})

form.AddDropDown("Run Mode", runModes, currentRunModeIndex, func(option string, index int) {
form.AddDropDown("Run Mode", runModeLabels, currentRunModeIndex, func(option string, index int) {
if option == sidecar.RunMethodDocker {
p.description.SetText("Run using Docker containers (recommended)")
} else if option == sidecar.RunMethodSystemd {
p.description.SetText("Run using systemd")
} else if runModes[index] == sidecar.RunMethodSystemd {
p.description.SetText(getServiceManagerDescription())
} else {
p.description.SetText("Run directly as a binary on your system")
}
Expand Down Expand Up @@ -198,7 +211,8 @@ func validateAndUpdateContributoor(p *ContributoorSettingsPage) {
runMode, _ := p.form.GetFormItem(1).(*tview.DropDown)

_, logLevelText := logLevel.GetCurrentOption()
_, runModeText := runMode.GetCurrentOption()
runModeIndex, _ := runMode.GetCurrentOption()
runModeText := runModes[runModeIndex]

if err := p.display.sidecarCfg.Update(func(cfg *sidecar.Config) {
cfg.LogLevel = logLevelText
Expand All @@ -209,6 +223,7 @@ func validateAndUpdateContributoor(p *ContributoorSettingsPage) {
return
}

p.display.markConfigChanged()
p.display.setPage(p.display.homePage)
}

Expand All @@ -222,3 +237,21 @@ func (p *ContributoorSettingsPage) openErrorModal(err error) {
},
), true)
}

// getServiceManagerLabel returns the appropriate label based on platform.
func getServiceManagerLabel() string {
if runtime.GOOS == "darwin" {
return "launchd"
}

return "systemd"
}

// getServiceManagerDescription returns the appropriate description based on platform.
func getServiceManagerDescription() string {
if runtime.GOOS == "darwin" {
return "Run using macOS launchd service manager"
}

return "Run using Linux systemd service manager"
}
11 changes: 6 additions & 5 deletions cmd/cli/commands/config/config_network.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,7 @@ func (p *NetworkConfigPage) initPage() {
// Add a save button and ensure we validate the input.
saveButton := tview.NewButton(tui.ButtonSaveSettings)
saveButton.SetSelectedFunc(func() {
beaconNodeAddress, _ := form.GetFormItem(1).(*tview.InputField)
validateAndUpdate(p, beaconNodeAddress)
validateAndUpdateNetwork(p)
})
saveButton.SetBackgroundColorActivated(tui.ColorButtonActivated)
saveButton.SetLabelColorActivated(tui.ColorButtonText)
Expand Down Expand Up @@ -169,21 +168,23 @@ func (p *NetworkConfigPage) initPage() {
p.content = mainFlex
}

func validateAndUpdate(p *NetworkConfigPage, input *tview.InputField) {
if err := validate.ValidateBeaconNodeAddress(input.GetText()); err != nil {
func validateAndUpdateNetwork(p *NetworkConfigPage) {
if err := validate.ValidateBeaconNodeAddress(p.display.sidecarCfg.Get().BeaconNodeAddress); err != nil {
p.openErrorModal(err)

return
}

if err := p.display.sidecarCfg.Update(func(cfg *sidecar.Config) {
cfg.BeaconNodeAddress = input.GetText()
cfg.NetworkName = p.display.sidecarCfg.Get().NetworkName
cfg.BeaconNodeAddress = p.display.sidecarCfg.Get().BeaconNodeAddress
}); err != nil {
p.openErrorModal(err)

return
}

p.display.markConfigChanged()
p.display.setPage(p.display.homePage)
}

Expand Down
1 change: 1 addition & 0 deletions cmd/cli/commands/config/config_output_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ func validateAndUpdateOutputServer(p *OutputServerConfigPage) {
return
}

p.display.markConfigChanged()
p.display.setPage(p.display.homePage)
}

Expand Down
30 changes: 15 additions & 15 deletions cmd/cli/commands/config/display.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package config

import (
"fmt"

"github.com/ethpandaops/contributoor-installer/internal/sidecar"
"github.com/ethpandaops/contributoor-installer/internal/tui"
"github.com/gdamore/tcell/v2"
Expand All @@ -24,6 +26,7 @@ type ConfigDisplay struct {
networkConfigPage *NetworkConfigPage
outputServerConfigPage *OutputServerConfigPage
settingsPage *ContributoorSettingsPage
hasChanges bool
}

// NewConfigDisplay creates a new Configtui.
Expand Down Expand Up @@ -96,21 +99,7 @@ func (d *ConfigDisplay) setupGrid() {

// setPage sets the current page and updates the frame.
func (d *ConfigDisplay) setPage(page *tui.Page) {
d.frame.Clear()

frame := tui.CreatePageFrame(tui.PageFrameOptions{
Content: d.pages,
Title: page.Title,
HelpType: tui.HelpSettings,
OnEsc: func() {
if d.pages.HasPage("config-home") {
d.setPage(d.homePage)
}
},
})

d.frame = frame
d.app.SetRoot(frame, true)
d.app.SetRoot(d.frame, true)
d.pages.SwitchToPage(page.ID)
}

Expand Down Expand Up @@ -200,6 +189,12 @@ func (d *ConfigDisplay) initPage() {
// Define the action for the close button.
closeButton.SetSelectedFunc(func() {
d.app.Stop()

if d.hasChanges {
fmt.Printf("%sConfiguration updated successfully%s\n", tui.TerminalColorGreen, tui.TerminalColorReset)
fmt.Printf("For these changes to take effect, you must restart the service:\n")
fmt.Printf(" contributoor restart\n")
}
})

// Layout everything in a flex container.
Expand All @@ -223,3 +218,8 @@ func (d *ConfigDisplay) initPage() {

d.content = flex
}

// markConfigChanged tracks that config has been modified.
func (d *ConfigDisplay) markConfigChanged() {
d.hasChanges = true
}
100 changes: 100 additions & 0 deletions cmd/cli/commands/restart/restart.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package restart

import (
"fmt"

"github.com/ethpandaops/contributoor-installer/cmd/cli/options"
"github.com/ethpandaops/contributoor-installer/internal/sidecar"
"github.com/ethpandaops/contributoor-installer/internal/tui"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
)

func RegisterCommands(app *cli.App, opts *options.CommandOpts) {
app.Commands = append(app.Commands, cli.Command{
Name: opts.Name(),
Aliases: opts.Aliases(),
Usage: "Restart Contributoor",
UsageText: "contributoor restart [options]",
Action: func(c *cli.Context) error {
var (
log = opts.Logger()
installerCfg = opts.InstallerConfig()
)

sidecarCfg, err := sidecar.NewConfigService(log, c.GlobalString("config-path"))
if err != nil {
return fmt.Errorf("error loading config: %w", err)
}

dockerSidecar, err := sidecar.NewDockerSidecar(log, sidecarCfg, installerCfg)
if err != nil {
return fmt.Errorf("error creating docker sidecar service: %w", err)
}

systemdSidecar, err := sidecar.NewSystemdSidecar(log, sidecarCfg, installerCfg)
if err != nil {
return fmt.Errorf("error creating systemd sidecar service: %w", err)
}

binarySidecar, err := sidecar.NewBinarySidecar(log, sidecarCfg, installerCfg)
if err != nil {
return fmt.Errorf("error creating binary sidecar service: %w", err)
}

return restartContributoor(c, log, sidecarCfg, dockerSidecar, systemdSidecar, binarySidecar)
},
})
}

func restartContributoor(
c *cli.Context,
log *logrus.Logger,
config sidecar.ConfigManager,
docker sidecar.DockerSidecar,
systemd sidecar.SystemdSidecar,
binary sidecar.BinarySidecar,
) error {
var (
runner sidecar.SidecarRunner
cfg = config.Get()
)

fmt.Printf("%sRestarting Contributoor%s\n", tui.TerminalColorLightBlue, tui.TerminalColorReset)

// Determine which runner to use
switch cfg.RunMethod {
case sidecar.RunMethodDocker:
runner = docker
case sidecar.RunMethodSystemd:
runner = systemd
case sidecar.RunMethodBinary:
runner = binary
default:
return fmt.Errorf("invalid sidecar run method: %s", cfg.RunMethod)
}

// Check if running
running, err := runner.IsRunning()
if err != nil {
log.Errorf("could not check sidecar status: %v", err)

return err
}

// Stop if running
if running {
if err := runner.Stop(); err != nil {
return fmt.Errorf("failed to stop service: %w", err)
}
} else {
fmt.Printf("%sContributoor is not running, starting contributoor%s\n", tui.TerminalColorYellow, tui.TerminalColorReset)
}

// Start the service.
if err := runner.Start(); err != nil {
return fmt.Errorf("failed to start service: %w", err)
}

return nil
}
Loading

0 comments on commit 734c169

Please sign in to comment.