mirror of
https://github.com/Control-D-Inc/ctrld.git
synced 2026-02-03 22:18:39 +00:00
fix upgrade flow
set service on new run, fix duplicate args set service on new run, fix duplicate args revert startCmd in upgrade flow due to pin compat issues make restart reset DNS like upgrade, add debugging to uninstall method debugging debugging debugging debugging debugging WMI remove stackexchange lib, use ms wmi pkg debugging debugging set correct class fix os reolver init issues fix netadapter class use os resolver instead of fetching default nameservers while already running remove debug lines fix lookup IP fix lookup IP fix lookup IP fix lookup IP fix dns namserver retries when not needed
This commit is contained in:
@@ -56,10 +56,12 @@ func getActiveDirectoryDomain() (string, error) {
|
||||
defer log.SetOutput(os.Stderr)
|
||||
whost := host.NewWmiLocalHost()
|
||||
cs, err := hh.GetComputerSystem(whost)
|
||||
if cs != nil {
|
||||
defer cs.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer cs.Close()
|
||||
pod, err := cs.GetPropertyPartOfDomain()
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
||||
@@ -126,7 +126,7 @@ func initCLI() {
|
||||
rootCmd.CompletionOptions.HiddenDefaultCmd = true
|
||||
|
||||
initRunCmd()
|
||||
startCmd, startCmdAlias := initStartCmd()
|
||||
startCmd := initStartCmd()
|
||||
stopCmd := initStopCmd()
|
||||
restartCmd := initRestartCmd()
|
||||
reloadCmd := initReloadCmd(restartCmd)
|
||||
@@ -135,7 +135,7 @@ func initCLI() {
|
||||
interfacesCmd := initInterfacesCmd()
|
||||
initServicesCmd(startCmd, stopCmd, restartCmd, reloadCmd, statusCmd, uninstallCmd, interfacesCmd)
|
||||
initClientsCmd()
|
||||
initUpgradeCmd(startCmdAlias)
|
||||
initUpgradeCmd()
|
||||
initLogCmd()
|
||||
}
|
||||
|
||||
@@ -243,10 +243,6 @@ func run(appCallback *AppCallback, stopCh chan struct{}) {
|
||||
if err := s.Run(); err != nil {
|
||||
mainLog.Load().Error().Err(err).Msg("failed to start service")
|
||||
}
|
||||
// Configure Windows service failure actions
|
||||
if err := ConfigureWindowsServiceFailureActions(ctrldServiceName); err != nil {
|
||||
mainLog.Load().Error().Err(err).Msgf("failed to configure Windows service %s failure actions", ctrldServiceName)
|
||||
}
|
||||
}()
|
||||
}
|
||||
writeDefaultConfig := !noConfigStart && configBase64 == ""
|
||||
@@ -394,6 +390,8 @@ func run(appCallback *AppCallback, stopCh chan struct{}) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Configure Windows service failure actions
|
||||
_ = ConfigureWindowsServiceFailureActions(ctrldServiceName)
|
||||
})
|
||||
p.onStopped = append(p.onStopped, func() {
|
||||
for _, lc := range p.cfg.Listener {
|
||||
@@ -1615,22 +1613,27 @@ var errRequiredDeactivationPin = errors.New("deactivation pin is required to sto
|
||||
|
||||
// checkDeactivationPin validates if the deactivation pin matches one in ControlD config.
|
||||
func checkDeactivationPin(s service.Service, stopCh chan struct{}) error {
|
||||
mainLog.Load().Debug().Msg("Checking deactivation pin")
|
||||
dir, err := socketDir()
|
||||
if err != nil {
|
||||
mainLog.Load().Err(err).Msg("could not check deactivation pin")
|
||||
return err
|
||||
}
|
||||
mainLog.Load().Debug().Msg("Creating control client")
|
||||
var cc *controlClient
|
||||
if s == nil {
|
||||
cc = newSocketControlClientMobile(dir, stopCh)
|
||||
} else {
|
||||
cc = newSocketControlClient(context.TODO(), s, dir)
|
||||
}
|
||||
mainLog.Load().Debug().Msg("Control client done")
|
||||
if cc == nil {
|
||||
return nil // ctrld is not running.
|
||||
}
|
||||
data, _ := json.Marshal(&deactivationRequest{Pin: deactivationPin})
|
||||
resp, _ := cc.post(deactivationPath, bytes.NewReader(data))
|
||||
mainLog.Load().Debug().Msg("Posting deactivation request")
|
||||
resp, err := cc.post(deactivationPath, bytes.NewReader(data))
|
||||
mainLog.Load().Debug().Msg("Posting deactivation request done")
|
||||
if resp != nil {
|
||||
switch resp.StatusCode {
|
||||
case http.StatusBadRequest:
|
||||
@@ -1694,7 +1697,7 @@ func curCdUID() string {
|
||||
if s, _ := newService(&prog{}, svcConfig); s != nil {
|
||||
// Configure Windows service failure actions
|
||||
if err := ConfigureWindowsServiceFailureActions(ctrldServiceName); err != nil {
|
||||
mainLog.Load().Error().Err(err).Msgf("failed to configure Windows service %s failure actions", ctrldServiceName)
|
||||
mainLog.Load().Debug().Err(err).Msgf("failed to configure Windows service %s failure actions", ctrldServiceName)
|
||||
}
|
||||
if dir, _ := socketDir(); dir != "" {
|
||||
cc := newSocketControlClient(context.TODO(), s, dir)
|
||||
@@ -1777,6 +1780,7 @@ func resetDnsNoLog(p *prog) {
|
||||
func resetDnsTask(p *prog, s service.Service, isCtrldInstalled bool, ir *ifaceResponse) task {
|
||||
return task{func() error {
|
||||
if iface == "" {
|
||||
mainLog.Load().Debug().Msg("no iface, skipping resetDnsTask")
|
||||
return nil
|
||||
}
|
||||
// Always reset DNS first, ensuring DNS setting is in a good state.
|
||||
|
||||
@@ -164,7 +164,7 @@ func initRunCmd() *cobra.Command {
|
||||
return runCmd
|
||||
}
|
||||
|
||||
func initStartCmd() (*cobra.Command, *cobra.Command) {
|
||||
func initStartCmd() *cobra.Command {
|
||||
startCmd := &cobra.Command{
|
||||
PreRun: func(cmd *cobra.Command, args []string) {
|
||||
checkHasElevatedPrivilege()
|
||||
@@ -391,7 +391,7 @@ NOTE: running "ctrld start" without any arguments will start already installed c
|
||||
|
||||
tasks := []task{
|
||||
{s.Stop, false, "Stop"},
|
||||
{func() error { return doGenerateNextDNSConfig(nextdns) }, true, "Generate NextDNS config"},
|
||||
{func() error { return doGenerateNextDNSConfig(nextdns) }, true, "Checking config"},
|
||||
{func() error { return ensureUninstall(s) }, false, "Ensure uninstall"},
|
||||
resetDnsTask(p, s, isCtrldInstalled, currentIface),
|
||||
{func() error {
|
||||
@@ -534,7 +534,7 @@ NOTE: running "ctrld start" without any arguments will start already installed c
|
||||
startCmdAlias.Flags().AddFlagSet(startCmd.Flags())
|
||||
rootCmd.AddCommand(startCmdAlias)
|
||||
|
||||
return startCmd, startCmdAlias
|
||||
return startCmd
|
||||
}
|
||||
|
||||
func initStopCmd() *cobra.Command {
|
||||
@@ -647,6 +647,15 @@ func initRestartCmd() *cobra.Command {
|
||||
mainLog.Load().Warn().Msg("service not installed")
|
||||
return
|
||||
}
|
||||
if iface == "" {
|
||||
iface = "auto"
|
||||
}
|
||||
p.preRun()
|
||||
if ir := runningIface(s); ir != nil {
|
||||
p.runningIface = ir.Name
|
||||
p.requiredMultiNICsConfig = ir.All
|
||||
}
|
||||
|
||||
initLogging()
|
||||
|
||||
if cdMode {
|
||||
@@ -656,11 +665,53 @@ func initRestartCmd() *cobra.Command {
|
||||
if ir := runningIface(s); ir != nil {
|
||||
iface = ir.Name
|
||||
}
|
||||
tasks := []task{
|
||||
{s.Stop, false, "Stop"},
|
||||
{s.Start, true, "Start"},
|
||||
|
||||
doRestart := func() bool {
|
||||
tasks := []task{
|
||||
{s.Stop, true, "Stop"},
|
||||
{func() error {
|
||||
p.router.Cleanup()
|
||||
p.resetDNS()
|
||||
return nil
|
||||
}, false, "Cleanup"},
|
||||
{func() error {
|
||||
time.Sleep(time.Second * 1)
|
||||
return nil
|
||||
}, false, "Waiting for service to stop"},
|
||||
}
|
||||
if doTasks(tasks) {
|
||||
|
||||
if router.WaitProcessExited() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
|
||||
defer cancel()
|
||||
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
mainLog.Load().Error().Msg("timeout while waiting for service to stop")
|
||||
break loop
|
||||
default:
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
if status, _ := s.Status(); status == service.StatusStopped {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
|
||||
tasks = []task{
|
||||
{s.Start, true, "Start"},
|
||||
}
|
||||
|
||||
return doTasks(tasks)
|
||||
|
||||
}
|
||||
if doTasks(tasks) {
|
||||
|
||||
if doRestart() {
|
||||
dir, err := socketDir()
|
||||
if err != nil {
|
||||
mainLog.Load().Warn().Err(err).Msg("Service was restarted, but could not ping the control server")
|
||||
@@ -668,11 +719,13 @@ func initRestartCmd() *cobra.Command {
|
||||
}
|
||||
cc := newSocketControlClient(context.TODO(), s, dir)
|
||||
if cc == nil {
|
||||
mainLog.Load().Notice().Msg("Service was not restarted")
|
||||
mainLog.Load().Error().Msg("Could not complete service restart")
|
||||
os.Exit(1)
|
||||
}
|
||||
_, _ = cc.post(ifacePath, nil)
|
||||
mainLog.Load().Notice().Msg("Service restarted")
|
||||
} else {
|
||||
mainLog.Load().Error().Msg("Service restart failed")
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -1049,7 +1102,7 @@ func initClientsCmd() *cobra.Command {
|
||||
return clientsCmd
|
||||
}
|
||||
|
||||
func initUpgradeCmd(startCmd *cobra.Command) *cobra.Command {
|
||||
func initUpgradeCmd() *cobra.Command {
|
||||
const (
|
||||
upgradeChannelDev = "dev"
|
||||
upgradeChannelProd = "prod"
|
||||
@@ -1087,6 +1140,14 @@ func initUpgradeCmd(startCmd *cobra.Command) *cobra.Command {
|
||||
mainLog.Load().Error().Msg(err.Error())
|
||||
return
|
||||
}
|
||||
if iface == "" {
|
||||
iface = "auto"
|
||||
}
|
||||
p.preRun()
|
||||
if ir := runningIface(s); ir != nil {
|
||||
p.runningIface = ir.Name
|
||||
p.requiredMultiNICsConfig = ir.All
|
||||
}
|
||||
|
||||
svcInstalled := true
|
||||
if _, err := s.Status(); errors.Is(err, service.ErrNotInstalled) {
|
||||
@@ -1121,23 +1182,56 @@ func initUpgradeCmd(startCmd *cobra.Command) *cobra.Command {
|
||||
mainLog.Load().Fatal().Err(err).Msg("failed to update current binary")
|
||||
}
|
||||
|
||||
// we run the actual commands to make sure all the logic we want is executed
|
||||
doRestart := func() bool {
|
||||
|
||||
// run the start command so that we reinit the service
|
||||
// this is to fix the non restarting options on windows for existing clients
|
||||
// we have to reset os.Args, since other commands use it.
|
||||
curCdUID := curCdUID()
|
||||
startArgs := []string{}
|
||||
os.Args = []string{"ctrld", "start"}
|
||||
if curCdUID != "" {
|
||||
startArgs = append(startArgs, fmt.Sprintf("--cd=%s", curCdUID))
|
||||
os.Args = append(os.Args, fmt.Sprintf("--cd=%s", curCdUID))
|
||||
if !svcInstalled {
|
||||
return true
|
||||
}
|
||||
startCmd.Run(startCmd, startArgs)
|
||||
tasks := []task{
|
||||
{s.Stop, true, "Stop"},
|
||||
{func() error {
|
||||
p.router.Cleanup()
|
||||
p.resetDNS()
|
||||
return nil
|
||||
}, false, "Cleanup"},
|
||||
{func() error {
|
||||
time.Sleep(time.Second * 1)
|
||||
return nil
|
||||
}, false, "Waiting for service to stop"},
|
||||
}
|
||||
if doTasks(tasks) {
|
||||
|
||||
return true
|
||||
if router.WaitProcessExited() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
|
||||
defer cancel()
|
||||
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
mainLog.Load().Error().Msg("timeout while waiting for service to stop")
|
||||
break loop
|
||||
default:
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
if status, _ := s.Status(); status == service.StatusStopped {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks = []task{
|
||||
{s.Start, true, "Start"},
|
||||
}
|
||||
if doTasks(tasks) {
|
||||
if dir, err := socketDir(); err == nil {
|
||||
if cc := newSocketControlClient(context.TODO(), s, dir); cc != nil {
|
||||
_, _ = cc.post(ifacePath, nil)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
if svcInstalled {
|
||||
mainLog.Load().Debug().Msg("Restarting ctrld service using new binary")
|
||||
|
||||
@@ -40,11 +40,13 @@ func validInterfaces() []string {
|
||||
whost := host.NewWmiLocalHost()
|
||||
q := query.NewWmiQuery("MSFT_NetAdapter")
|
||||
instances, err := instance.GetWmiInstancesFromHost(whost, string(constant.StadardCimV2), q)
|
||||
if instances != nil {
|
||||
defer instances.Close()
|
||||
}
|
||||
if err != nil {
|
||||
mainLog.Load().Warn().Err(err).Msg("failed to get wmi network adapter")
|
||||
return nil
|
||||
}
|
||||
defer instances.Close()
|
||||
var adapters []string
|
||||
for _, i := range instances {
|
||||
adapter, err := netadapter.NewNetworkAdapter(i)
|
||||
|
||||
@@ -792,6 +792,7 @@ func (p *prog) dnsWatchdog(iface *net.Interface, nameservers []string, allIfaces
|
||||
|
||||
func (p *prog) resetDNS() {
|
||||
if p.runningIface == "" {
|
||||
mainLog.Load().Debug().Msg("no running interface, skipping resetDNS")
|
||||
return
|
||||
}
|
||||
// See corresponding comments in (*prog).setDNS function.
|
||||
|
||||
@@ -52,7 +52,21 @@ func ConfigureWindowsServiceFailureActions(serviceName string) error {
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
// restart 3 times with a delay of 2 seconds
|
||||
// 1. Retrieve the current config
|
||||
cfg, err := s.Config()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 2. Update the Description
|
||||
cfg.Description = "A highly configurable, multi-protocol DNS forwarding proxy"
|
||||
|
||||
// 3. Apply the updated config
|
||||
if err := s.UpdateConfig(cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Then proceed with existing actions, e.g. setting failure actions
|
||||
actions := []mgr.RecoveryAction{
|
||||
{Type: mgr.ServiceRestart, Delay: time.Second * 2}, // 2 seconds
|
||||
{Type: mgr.ServiceRestart, Delay: time.Second * 2}, // 2 seconds
|
||||
|
||||
Reference in New Issue
Block a user