in cache-config/t3c-apply/t3c-apply.go [90:373]
func Main() int {
var syncdsUpdate torequest.UpdateStatus
var lock util.FileLock
cfg, err := config.GetCfg(Version, GitRevision)
if err != nil {
log.Infoln(err)
log.Errorln(FailureExitMsg)
return ExitCodeConfigError
} else if cfg == (config.Cfg{}) { // user used the --help option
return ExitCodeSuccess
}
log.Infoln("Trying to acquire app lock")
for lockStart := time.Now(); !lock.GetLock(LockFilePath); {
if time.Since(lockStart) > LockFileRetryTimeout {
log.Errorf("Failed to get app lock after %v seconds, another instance is running, exiting without running\n", int(LockFileRetryTimeout/time.Second))
log.Infoln(FailureExitMsg)
return ExitCodeAlreadyRunning
}
log.Errorf("Unable to acquire app lock retrying in: %v ", LockFileRetryInterval)
time.Sleep(LockFileRetryInterval)
}
log.Infoln("Acquired app lock")
defer lock.Unlock()
// Note failing to load old metadata is not fatal!
// oldMetaData must always be checked for nil before usage!
oldMetaData, err := LoadMetaData(cfg)
if err != nil {
log.Errorln("Failed to load old metadata file, metadata-dependent functionality disabled: " + err.Error())
}
// Note we only write the metadata file after acquiring the app lock.
// We don't want to write a metadata file if we didn't run because another t3c-apply
// was already running.
metaData := t3cutil.NewApplyMetaData()
metaData.ServerHostName = cfg.CacheHostName
t3cutil.WriteActionLog(t3cutil.ActionLogActionApplyStart, t3cutil.ActionLogStatusSuccess, metaData)
if cfg.UseGit == config.UseGitYes {
triedMakingRepo, err := util.EnsureConfigDirIsGitRepo(cfg)
if err != nil {
log.Errorln("Ensuring config directory '" + cfg.TsConfigDir + "' is a git repo - config may not be a git repo! " + err.Error())
if triedMakingRepo {
t3cutil.WriteActionLog(t3cutil.ActionLogActionGitInit, t3cutil.ActionLogStatusFailure, metaData)
}
} else {
log.Infoln("Successfully ensured ATS config directory '" + cfg.TsConfigDir + "' is a git repo")
if triedMakingRepo {
t3cutil.WriteActionLog(t3cutil.ActionLogActionGitInit, t3cutil.ActionLogStatusSuccess, metaData)
}
}
} else {
log.Infoln("UseGit not 'yes', not creating git repo")
}
if cfg.UseGit == config.UseGitYes || cfg.UseGit == config.UseGitAuto {
//need to see if there is an old lock file laying around.
//older than 5 minutes
const gitMaxLockAgeMinutes = 5
const gitLock = ".git/index.lock"
gitLockFile := filepath.Join(cfg.TsConfigDir, gitLock)
oldLock, err := util.IsGitLockFileOld(gitLockFile, time.Now(), gitMaxLockAgeMinutes*time.Minute)
if err != nil {
log.Errorln("checking for git lock file: " + err.Error())
}
if oldLock {
log.Errorf("removing git lock file older than %dm", gitMaxLockAgeMinutes)
err := util.RemoveGitLock(gitLockFile)
if err != nil {
log.Errorf("couldn't remove git lock file: %v", err.Error())
}
}
log.Infoln("Checking git for safe directory config")
if err := util.GetGitConfigSafeDir(cfg); err != nil {
log.Warnln("error checking git for safe directory config: " + err.Error())
}
// commit anything someone else changed when we weren't looking,
// with a keyword indicating it wasn't our change
if err := util.MakeGitCommitAll(cfg, util.GitChangeNotSelf, true); err != nil {
log.Errorln("git committing existing changes, dir '" + cfg.TsConfigDir + "': " + err.Error())
t3cutil.WriteActionLog(t3cutil.ActionLogActionGitCommitInitial, t3cutil.ActionLogStatusFailure, metaData)
} else {
t3cutil.WriteActionLog(t3cutil.ActionLogActionGitCommitInitial, t3cutil.ActionLogStatusSuccess, metaData)
}
}
trops := torequest.NewTrafficOpsReq(cfg)
// if doing os checks, insure there is a 'systemctl' or 'service' and 'chkconfig' commands.
if !cfg.SkipOSCheck && cfg.SvcManagement == config.Unknown {
log.Errorln("OS checks are enabled and unable to find any know service management tools.")
}
// create and clean the config.TmpBase (/tmp/ort)
if !util.MkDir(config.TmpBase, cfg.ReportOnly) {
log.Errorln("mkdir TmpBase '" + config.TmpBase + "' failed, cannot continue")
log.Infoln(FailureExitMsg)
return ExitCodeGeneralFailure
} else if !util.CleanTmpDir(cfg) {
log.Errorln("CleanTmpDir failed, cannot continue")
log.Infoln(FailureExitMsg)
return ExitCodeGeneralFailure
}
log.Infoln(time.Now().Format(time.RFC3339))
if !util.CheckUser(cfg) {
lock.Unlock()
return ExitCodeUserCheckError
}
// if running in Revalidate mode, check to see if it's
// necessary to continue
if cfg.Files == t3cutil.ApplyFilesFlagReval {
syncdsUpdate, err = trops.CheckRevalidateState(false)
if err != nil {
log.Errorln("Checking revalidate state: " + err.Error())
return GitCommitAndExit(ExitCodeRevalidationError, FailureExitMsg, cfg, metaData, oldMetaData)
}
if syncdsUpdate == torequest.UpdateTropsNotNeeded {
log.Infoln("Checking revalidate state: returned UpdateTropsNotNeeded")
metaData.Succeeded = true
return GitCommitAndExit(ExitCodeRevalidationError, SuccessExitMsg, cfg, metaData, oldMetaData)
}
} else {
syncdsUpdate, err = trops.CheckSyncDSState(metaData, cfg)
if err != nil {
log.Errorln("Checking syncds state: " + err.Error())
return GitCommitAndExit(ExitCodeSyncDSError, FailureExitMsg, cfg, metaData, oldMetaData)
}
if !cfg.IgnoreUpdateFlag && cfg.Files == t3cutil.ApplyFilesFlagAll && syncdsUpdate == torequest.UpdateTropsNotNeeded {
// If touching remap.config fails, we want to still try to restart services
// But log a critical-post-config-failure, which needs logged right before exit.
postConfigFail := false
// check for maxmind db updates even if we have no other updates
if CheckMaxmindUpdate(cfg) {
// We updated the db so we should touch and reload
trops.RemapConfigReload = true
path := cfg.TsConfigDir + "/remap.config"
_, rc, err := util.ExecCommand("/usr/bin/touch", path)
if err != nil {
log.Errorf("failed to update the remap.config for reloading: %s\n", err.Error())
postConfigFail = true
} else if rc == 0 {
log.Infoln("updated the remap.config for reloading.")
}
if err := trops.StartServices(&syncdsUpdate, metaData, cfg); err != nil {
log.Errorln("failed to start services: " + err.Error())
metaData.PartialSuccess = true
return GitCommitAndExit(ExitCodeServicesError, PostConfigFailureExitMsg, cfg, metaData, oldMetaData)
}
}
finalMsg := SuccessExitMsg
if postConfigFail {
finalMsg = PostConfigFailureExitMsg
}
metaData.Succeeded = true
return GitCommitAndExit(ExitCodeSuccess, finalMsg, cfg, metaData, oldMetaData)
}
}
if cfg.Files != t3cutil.ApplyFilesFlagAll {
// make sure we got the data necessary to check packages
log.Infoln("======== Didn't get all files, no package processing needed or possible ========")
metaData.InstalledPackages = oldMetaData.InstalledPackages
} else if cfg.RpmDBOk {
log.Infoln("======== Start processing packages ========")
err = trops.ProcessPackages()
if err != nil {
log.Errorf("Error processing packages: %s\n", err)
return GitCommitAndExit(ExitCodePackagingError, FailureExitMsg, cfg, metaData, oldMetaData)
}
metaData.InstalledPackages = t3cutil.PackagesToMetaData(trops.Pkgs)
// check and make sure packages are enabled for startup
err = trops.CheckSystemServices()
if err != nil {
log.Errorf("Error verifying system services: %s\n", err.Error())
return GitCommitAndExit(ExitCodeServicesError, FailureExitMsg, cfg, metaData, oldMetaData)
}
} else {
log.Warnln("======== RPM DB checks failed, package processing not possible, using installed packages from metadata if available========")
trops.ProcessPackagesWithMetaData(oldMetaData.InstalledPackages)
}
log.Debugf("Preparing to fetch the config files for %s, files: %s, syncdsUpdate: %s\n", cfg.CacheHostName, cfg.Files, syncdsUpdate)
err = trops.GetConfigFileList()
if err != nil {
log.Errorf("Getting config file list: %s\n", err)
return GitCommitAndExit(ExitCodeConfigFilesError, FailureExitMsg, cfg, metaData, oldMetaData)
}
syncdsUpdate, err = trops.ProcessConfigFiles(metaData)
if err != nil {
log.Errorf("Error while processing config files: %s\n", err.Error())
t3cutil.WriteActionLog(t3cutil.ActionLogActionUpdateFilesAll, t3cutil.ActionLogStatusFailure, metaData)
} else {
t3cutil.WriteActionLog(t3cutil.ActionLogActionUpdateFilesAll, t3cutil.ActionLogStatusSuccess, metaData)
}
// check for maxmind db updates
// If we've updated also reload remap to reload the plugin and pick up the new database
if CheckMaxmindUpdate(cfg) {
trops.RemapConfigReload = true
}
if trops.RemapConfigReload == true {
cfg, ok := trops.GetConfigFile("remap.config")
_, rc, err := util.ExecCommand("/usr/bin/touch", cfg.Path)
if err != nil {
log.Errorf("failed to update the remap.config for reloading: %s\n", err.Error())
} else if rc == 0 && ok == true {
log.Infoln("updated the remap.config for reloading.")
}
}
if err := trops.StartServices(&syncdsUpdate, metaData, cfg); err != nil {
log.Errorln("failed to start services: " + err.Error())
metaData.PartialSuccess = true
return GitCommitAndExit(ExitCodeServicesError, PostConfigFailureExitMsg, cfg, metaData, oldMetaData)
}
// start 'teakd' if installed.
if trops.IsPackageInstalled("teakd") {
svcStatus, pid, err := util.GetServiceStatus("teakd")
if err != nil {
log.Errorf("not starting 'teakd', error getting 'teakd' run status: %s\n", err)
} else if svcStatus == util.SvcNotRunning {
running, err := util.ServiceStart("teakd", "start")
if err != nil {
log.Errorf("'teakd' was not started: %s\n", err)
} else if running {
log.Infoln("service 'teakd' started.")
} else if svcStatus == util.SvcRunning {
log.Infof("service 'teakd' was already running, pid: %v\n", pid)
}
}
}
if trops.HitchReload {
svcStatus, _, err := util.GetServiceStatus("hitch")
cmd := "start"
running := false
if err != nil {
log.Errorf("not starting 'hitch', error getting 'hitch' run status: %s\n", err)
} else if svcStatus != util.SvcNotRunning {
cmd = "reload"
}
running, err = util.ServiceStart("hitch", cmd)
if err != nil {
log.Errorf("'hitch' was not %sed: %s\n", cmd, err)
} else if running {
log.Infof("service 'hitch' %sed", cmd)
} else {
log.Infoln("service 'hitch' already running")
}
}
// reload sysctl
if trops.SysCtlReload == true {
runSysctl(cfg)
}
trops.PrintWarnings()
if err := trops.UpdateTrafficOps(&syncdsUpdate); err != nil {
log.Errorf("failed to update Traffic Ops: %s\n", err.Error())
}
metaData.Succeeded = true
if syncdsUpdate == torequest.UpdateTropsFailed {
return GitCommitAndExit(ExitCodeSuccess, CacheConfigFailureExitMsg, cfg, metaData, oldMetaData)
} else {
return GitCommitAndExit(ExitCodeSuccess, SuccessExitMsg, cfg, metaData, oldMetaData)
}
}