cmd/cli: better error message when doing restart

In case of remote config validation error during start, it's likely that
there's problem with connecting to ControlD API. The ctrld daemon was
restarted in this case, but may not ready to receive requests yet.

This commit changes the error message to explicitly state that instead
of a mis-leading "could not complete service restart".
This commit is contained in:
Cuong Manh Le
2025-02-11 19:27:25 +07:00
committed by Cuong Manh Le
parent 60e65a37a6
commit 5007a87d3a
2 changed files with 27 additions and 10 deletions
+10 -3
View File
@@ -1478,6 +1478,12 @@ func removeOrgFlagsFromArgs(sc *service.Config) {
// newSocketControlClient returns new control client after control server was started. // newSocketControlClient returns new control client after control server was started.
func newSocketControlClient(ctx context.Context, s service.Service, dir string) *controlClient { func newSocketControlClient(ctx context.Context, s service.Service, dir string) *controlClient {
return newSocketControlClientWithTimeout(ctx, s, dir, dialSocketControlServerTimeout)
}
// newSocketControlClientWithTimeout returns new control client after control server was started.
// The timeoutDuration controls how long to wait for the server.
func newSocketControlClientWithTimeout(ctx context.Context, s service.Service, dir string, timeoutDuration time.Duration) *controlClient {
// Return early if service is not running. // Return early if service is not running.
if status, err := s.Status(); err != nil || status != service.StatusRunning { if status, err := s.Status(); err != nil || status != service.StatusRunning {
return nil return nil
@@ -1486,7 +1492,7 @@ func newSocketControlClient(ctx context.Context, s service.Service, dir string)
bo.LogLongerThan = 10 * time.Second bo.LogLongerThan = 10 * time.Second
cc := newControlClient(filepath.Join(dir, ctrldControlUnixSock)) cc := newControlClient(filepath.Join(dir, ctrldControlUnixSock))
timeout := time.NewTimer(30 * time.Second) timeout := time.NewTimer(timeoutDuration)
defer timeout.Stop() defer timeout.Stop()
// The socket control server may not start yet, so attempt to ping // The socket control server may not start yet, so attempt to ping
@@ -1807,7 +1813,7 @@ func resetDnsTask(p *prog, s service.Service, isCtrldInstalled bool, ir *ifaceRe
} }
// doValidateCdRemoteConfig fetches and validates custom config for cdUID. // doValidateCdRemoteConfig fetches and validates custom config for cdUID.
func doValidateCdRemoteConfig(cdUID string, fatal bool) { func doValidateCdRemoteConfig(cdUID string, fatal bool) error {
rc, err := controld.FetchResolverConfig(cdUID, rootCmd.Version, cdDev) rc, err := controld.FetchResolverConfig(cdUID, rootCmd.Version, cdDev)
if err != nil { if err != nil {
logger := mainLog.Load().Fatal() logger := mainLog.Load().Fatal()
@@ -1816,7 +1822,7 @@ func doValidateCdRemoteConfig(cdUID string, fatal bool) {
} }
logger.Err(err).Err(err).Msgf("failed to fetch resolver uid: %s", cdUID) logger.Err(err).Err(err).Msgf("failed to fetch resolver uid: %s", cdUID)
if !fatal { if !fatal {
return return err
} }
} }
// validateCdRemoteConfig clobbers v, saving it here to restore later. // validateCdRemoteConfig clobbers v, saving it here to restore later.
@@ -1847,6 +1853,7 @@ func doValidateCdRemoteConfig(cdUID string, fatal bool) {
mainLog.Load().Warn().Msg("disregarding invalid custom config") mainLog.Load().Warn().Msg("disregarding invalid custom config")
} }
v = oldV v = oldV
return nil
} }
// uninstallInvalidCdUID performs self-uninstallation because the ControlD device does not exist. // uninstallInvalidCdUID performs self-uninstallation because the ControlD device does not exist.
+17 -7
View File
@@ -30,6 +30,9 @@ import (
"github.com/Control-D-Inc/ctrld/internal/router" "github.com/Control-D-Inc/ctrld/internal/router"
) )
// dialSocketControlServerTimeout is the default timeout to wait when ping control server.
const dialSocketControlServerTimeout = 30 * time.Second
func initLogCmd() *cobra.Command { func initLogCmd() *cobra.Command {
warnRuntimeLoggingNotEnabled := func() { warnRuntimeLoggingNotEnabled := func() {
mainLog.Load().Warn().Msg("runtime debug logging is not enabled") mainLog.Load().Warn().Msg("runtime debug logging is not enabled")
@@ -373,7 +376,7 @@ NOTE: running "ctrld start" without any arguments will start already installed c
} }
if cdUID != "" { if cdUID != "" {
doValidateCdRemoteConfig(cdUID, true) _ = doValidateCdRemoteConfig(cdUID, true)
} else if uid := cdUIDFromProvToken(); uid != "" { } else if uid := cdUIDFromProvToken(); uid != "" {
cdUID = uid cdUID = uid
mainLog.Load().Debug().Msg("using uid from provision token") mainLog.Load().Debug().Msg("using uid from provision token")
@@ -697,8 +700,9 @@ func initRestartCmd() *cobra.Command {
initInteractiveLogging() initInteractiveLogging()
var validateConfigErr error
if cdMode { if cdMode {
doValidateCdRemoteConfig(cdUID, false) validateConfigErr = doValidateCdRemoteConfig(cdUID, false)
} }
if ir := runningIface(s); ir != nil { if ir := runningIface(s); ir != nil {
@@ -752,12 +756,18 @@ func initRestartCmd() *cobra.Command {
if doRestart() { if doRestart() {
if dir, err := socketDir(); err == nil { if dir, err := socketDir(); err == nil {
cc := newSocketControlClient(context.TODO(), s, dir) timeout := dialSocketControlServerTimeout
if cc == nil { // If we failed to validate remote config above, it's likely that
mainLog.Load().Error().Msg("Could not complete service restart") // we are having problem with network connection. So using a shorter
os.Exit(1) // timeout than default one for better UX.
if validateConfigErr != nil {
timeout = 5 * time.Second
}
if cc := newSocketControlClientWithTimeout(context.TODO(), s, dir, timeout); cc != nil {
_, _ = cc.post(ifacePath, nil)
} else {
mainLog.Load().Warn().Err(err).Msg("Service was restarted, but ctrld process may not be ready yet")
} }
_, _ = cc.post(ifacePath, nil)
} else { } else {
mainLog.Load().Warn().Err(err).Msg("Service was restarted, but could not ping the control server") mainLog.Load().Warn().Err(err).Msg("Service was restarted, but could not ping the control server")
} }