This is an automated email from the ASF dual-hosted git repository.

ocket8888 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git


The following commit(s) were added to refs/heads/master by this push:
     new 2e324be2d8 Add t3c action log (#6924)
2e324be2d8 is described below

commit 2e324be2d85040b14ed43e988dadf9a11a21ae0f
Author: Robert O Butts <[email protected]>
AuthorDate: Fri Jul 29 09:13:55 2022 -0600

    Add t3c action log (#6924)
---
 cache-config/t3c-apply/t3c-apply.go                | 37 ++++++++-
 cache-config/t3c-apply/torequest/torequest.go      | 13 +++-
 cache-config/t3c-apply/util/gitutil.go             | 20 +++--
 cache-config/t3cutil/actionlog.go                  | 87 ++++++++++++++++++++++
 cache-config/t3cutil/t3cutil.go                    | 11 ++-
 ...etadata-file_test.go => t3c-action-log_test.go} | 35 +++------
 .../ort-tests/t3c-create-metadata-file_test.go     | 11 +++
 7 files changed, 173 insertions(+), 41 deletions(-)

diff --git a/cache-config/t3c-apply/t3c-apply.go 
b/cache-config/t3c-apply/t3c-apply.go
index afdfc12146..353e24a864 100644
--- a/cache-config/t3c-apply/t3c-apply.go
+++ b/cache-config/t3c-apply/t3c-apply.go
@@ -125,13 +125,22 @@ func Main() int {
 
        metaData.ServerHostName = cfg.CacheHostName
 
+       t3cutil.WriteActionLog(t3cutil.ActionLogActionApplyStart, 
t3cutil.ActionLogStatusSuccess, metaData)
+
        if cfg.UseGit == config.UseGitYes {
-               err := util.EnsureConfigDirIsGitRepo(cfg)
+               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")
        }
@@ -141,6 +150,9 @@ func Main() int {
                // 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)
                }
        }
 
@@ -207,7 +219,7 @@ func Main() int {
                                } else if rc == 0 {
                                        log.Infoln("updated the remap.config 
for reloading.")
                                }
-                               if err := trops.StartServices(&syncdsUpdate); 
err != nil {
+                               if err := trops.StartServices(&syncdsUpdate, 
metaData); err != nil {
                                        log.Errorln("failed to start services: 
" + err.Error())
                                        metaData.PartialSuccess = true
                                        return 
GitCommitAndExit(ExitCodeServicesError, PostConfigFailureExitMsg, cfg, 
metaData, oldMetaData)
@@ -250,6 +262,10 @@ func Main() int {
        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
@@ -268,7 +284,7 @@ func Main() int {
                }
        }
 
-       if err := trops.StartServices(&syncdsUpdate); err != nil {
+       if err := trops.StartServices(&syncdsUpdate, metaData); err != nil {
                log.Errorln("failed to start services: " + err.Error())
                metaData.PartialSuccess = true
                return GitCommitAndExit(ExitCodeServicesError, 
PostConfigFailureExitMsg, cfg, metaData, oldMetaData)
@@ -335,9 +351,24 @@ func GitCommitAndExit(exitCode int, exitMsg string, cfg 
config.Cfg, metaData *t3
        if cfg.UseGit == config.UseGitYes || cfg.UseGit == config.UseGitAuto {
                if err := util.MakeGitCommitAll(cfg, util.GitChangeIsSelf, 
success); err != nil {
                        log.Errorln("git committing existing changes, dir '" + 
cfg.TsConfigDir + "': " + err.Error())
+                       // nil metadata to prevent modifying the file after the 
final git commit
+                       
t3cutil.WriteActionLog(t3cutil.ActionLogActionGitCommitFinal, 
t3cutil.ActionLogStatusFailure, nil)
+               } else {
+                       // nil metadata to prevent modifying the file after the 
final git commit
+                       
t3cutil.WriteActionLog(t3cutil.ActionLogActionGitCommitFinal, 
t3cutil.ActionLogStatusSuccess, nil)
                }
        }
+
+       if metaData.Succeeded {
+               // nil metadata to prevent modifying the file after the final 
git commit
+               t3cutil.WriteActionLog(t3cutil.ActionLogActionApplyEnd, 
t3cutil.ActionLogStatusSuccess, nil)
+       } else {
+               // nil metadata to prevent modifying the file after the final 
git commit
+               t3cutil.WriteActionLog(t3cutil.ActionLogActionApplyEnd, 
t3cutil.ActionLogStatusFailure, nil)
+       }
+
        log.Infoln(exitMsg)
+
        return exitCode
 }
 
diff --git a/cache-config/t3c-apply/torequest/torequest.go 
b/cache-config/t3c-apply/torequest/torequest.go
index e0eef3f267..35cef6a396 100644
--- a/cache-config/t3c-apply/torequest/torequest.go
+++ b/cache-config/t3c-apply/torequest/torequest.go
@@ -1037,10 +1037,13 @@ func (r *TrafficOpsReq) 
RevalidateWhileSleeping(metaData *t3cutil.ApplyMetaData)
 
                updateStatus, err := r.ProcessConfigFiles(metaData)
                if err != nil {
+                       
t3cutil.WriteActionLog(t3cutil.ActionLogActionUpdateFilesReval, 
t3cutil.ActionLogStatusFailure, metaData)
                        return updateStatus, err
+               } else {
+                       
t3cutil.WriteActionLog(t3cutil.ActionLogActionUpdateFilesReval, 
t3cutil.ActionLogStatusSuccess, metaData)
                }
 
-               if err := r.StartServices(&updateStatus); err != nil {
+               if err := r.StartServices(&updateStatus, metaData); err != nil {
                        return updateStatus, errors.New("failed to start 
services: " + err.Error())
                }
 
@@ -1057,7 +1060,7 @@ func (r *TrafficOpsReq) RevalidateWhileSleeping(metaData 
*t3cutil.ApplyMetaData)
 // StartServices reloads, restarts, or starts ATS as necessary,
 // according to the changed config files and run mode.
 // Returns nil on success or any error.
-func (r *TrafficOpsReq) StartServices(syncdsUpdate *UpdateStatus) error {
+func (r *TrafficOpsReq) StartServices(syncdsUpdate *UpdateStatus, metaData 
*t3cutil.ApplyMetaData) error {
        serviceNeeds := t3cutil.ServiceNeedsNothing
        if r.Cfg.ServiceAction == t3cutil.ApplyServiceActionFlagRestart {
                serviceNeeds = t3cutil.ServiceNeedsRestart
@@ -1103,8 +1106,10 @@ func (r *TrafficOpsReq) StartServices(syncdsUpdate 
*UpdateStatus) error {
                        startStr = "start"
                }
                if _, err := util.ServiceStart("trafficserver", startStr); err 
!= nil {
+                       
t3cutil.WriteActionLog(t3cutil.ActionLogActionATSRestart, 
t3cutil.ActionLogStatusFailure, metaData)
                        return errors.New("failed to restart trafficserver")
                }
+               t3cutil.WriteActionLog(t3cutil.ActionLogActionATSRestart, 
t3cutil.ActionLogStatusSuccess, metaData)
                log.Infoln("trafficserver has been " + startStr + "ed")
                if *syncdsUpdate == UpdateTropsNeeded {
                        *syncdsUpdate = UpdateTropsSuccessful
@@ -1119,11 +1124,15 @@ func (r *TrafficOpsReq) StartServices(syncdsUpdate 
*UpdateStatus) error {
                } else if serviceNeeds == t3cutil.ServiceNeedsReload {
                        log.Infoln("ATS configuration has changed, Running 
'traffic_ctl config reload' now.")
                        if _, _, err := 
util.ExecCommand(config.TSHome+config.TrafficCtl, "config", "reload"); err != 
nil {
+                               
t3cutil.WriteActionLog(t3cutil.ActionLogActionATSReload, 
t3cutil.ActionLogStatusFailure, metaData)
+
                                if *syncdsUpdate == UpdateTropsNeeded {
                                        *syncdsUpdate = UpdateTropsFailed
                                }
                                return errors.New("ATS configuration has 
changed and 'traffic_ctl config reload' failed, check ATS logs: " + err.Error())
                        }
+                       
t3cutil.WriteActionLog(t3cutil.ActionLogActionATSReload, 
t3cutil.ActionLogStatusSuccess, metaData)
+
                        if *syncdsUpdate == UpdateTropsNeeded {
                                *syncdsUpdate = UpdateTropsSuccessful
                        }
diff --git a/cache-config/t3c-apply/util/gitutil.go 
b/cache-config/t3c-apply/util/gitutil.go
index 9dca3dbeca..3706c3be2a 100644
--- a/cache-config/t3c-apply/util/gitutil.go
+++ b/cache-config/t3c-apply/util/gitutil.go
@@ -32,31 +32,35 @@ import (
        "github.com/apache/trafficcontrol/cache-config/t3c-apply/config"
 )
 
-func EnsureConfigDirIsGitRepo(cfg config.Cfg) error {
+// EnsureConfigDirIsGitRepo ensures the ATS config directory is a git repo.
+// Returns whether it tried to create a git repo, and any error.
+// Note the return will be (false, nil) if a git repo already exists.
+// Note true and a non-nil error may be returned, if creating a git repo is 
necessary and attempted and fails.
+func EnsureConfigDirIsGitRepo(cfg config.Cfg) (bool, error) {
        cmd := exec.Command("git", "status")
        cmd.Dir = cfg.TsConfigDir
 
        errPipe, err := cmd.StderrPipe()
        if err != nil {
-               return errors.New("getting stderr pipe for command: " + 
err.Error())
+               return false, errors.New("getting stderr pipe for command: " + 
err.Error())
        }
 
        if err := cmd.Start(); err != nil {
                if _, ok := err.(*exec.ExitError); !ok {
                        // this means Go failed to run the command, not that 
the command returned an error.
-                       return errors.New("git status returned: " + err.Error())
+                       return false, errors.New("git status returned: " + 
err.Error())
                }
        }
 
        errOutput, err := ioutil.ReadAll(errPipe)
        if err != nil {
-               return errors.New("reading stderr: " + err.Error())
+               return false, errors.New("reading stderr: " + err.Error())
        }
 
        if err := cmd.Wait(); err != nil {
                if _, ok := err.(*exec.ExitError); !ok {
                        // this means Go failed to run the command, not that 
the command returned an error.
-                       return errors.New("waiting for git command: " + 
err.Error())
+                       return false, errors.New("waiting for git command: " + 
err.Error())
                }
        }
 
@@ -64,14 +68,14 @@ func EnsureConfigDirIsGitRepo(cfg config.Cfg) error {
 
        errOutput = bytes.ToLower(errOutput)
        if !bytes.Contains(errOutput, []byte(GitNotARepoMsgPrefix)) {
-               return nil // it's already a git repo
+               return false, nil // it's already a git repo
        }
 
        if err := makeConfigDirGitRepo(cfg); err != nil {
-               return errors.New("making config dir '" + cfg.TsConfigDir + "' 
a git repo: " + err.Error())
+               return true, errors.New("making config dir '" + cfg.TsConfigDir 
+ "' a git repo: " + err.Error())
        }
 
-       return nil
+       return true, nil
 }
 
 func makeConfigDirGitRepo(cfg config.Cfg) error {
diff --git a/cache-config/t3cutil/actionlog.go 
b/cache-config/t3cutil/actionlog.go
new file mode 100644
index 0000000000..908f4ea054
--- /dev/null
+++ b/cache-config/t3cutil/actionlog.go
@@ -0,0 +1,87 @@
+package t3cutil
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import (
+       "github.com/apache/trafficcontrol/lib/go-log"
+)
+
+// ActionLogAction is an action t3c performs which affects the state of the 
machine.
+// Things that don't affect the state of the machine are not considered 
actions.
+//
+// For example, requesting Traffic Ops is not an 'action',
+// but restarting ATS or modifying a config file is.
+//
+// Actions also include the t3c-apply run starting and finishing,
+// to help delineate the actions of different runs in the log.
+//
+type ActionLogAction string
+
+const (
+       // ActionLogActionApplyStart is the start of the t3c-apply run.
+       // The status of this should always be success.
+       ActionLogActionApplyStart = ActionLogAction("apply-start")
+
+       // ActionLogActionGitInit is creating a git repo in the ATS config 
directory.
+       ActionLogActionGitInit = ActionLogAction("git-init")
+
+       // ActionLogActionGitCommitInitial is the initial commit at the start 
of the run.
+       ActionLogActionGitCommitInitial = 
ActionLogAction("create-git-commit-initial")
+
+       // ActionLogActionGitCommitInitial is the final commit at the end of 
the run.
+       ActionLogActionGitCommitFinal = 
ActionLogAction("create-git-commit-final")
+
+       // ActionLogActionUpdateFilesAll is writing and updating ATS config 
files.
+       ActionLogActionUpdateFilesAll = ActionLogAction("update-files-all")
+
+       // ActionLogActionUpdateFilesReval is writing and updating only 
revalidate ATS config files.
+       ActionLogActionUpdateFilesReval = ActionLogAction("update-files-reval")
+
+       // ActionLogActionATSReload is calling service reload on ATS.
+       ActionLogActionATSReload = ActionLogAction("ats-reload")
+
+       // ActionLogActionATSReload is calling service restart on ATS.
+       ActionLogActionATSRestart = ActionLogAction("ats-restart")
+
+       // ActionLogActionApplyEnd is the end of the t3c-apply run.
+       ActionLogActionApplyEnd = ActionLogAction("apply-end")
+)
+
+type ActionLogStatus string
+
+const (
+       ActionLogStatusSuccess = ActionLogStatus("success")
+       ActionLogStatusFailure = ActionLogStatus("failure")
+)
+
+// WriteActionLog writes the given action and status to both the info log and 
the given metadata object.
+//
+// The metaData may be nil, and should be if this is being called after the 
final git commit,
+// to prevent modifying the file after the commit.
+//
+func WriteActionLog(action ActionLogAction, status ActionLogStatus, metaData 
*ApplyMetaData) {
+       if metaData != nil {
+               metaData.Actions = append(metaData.Actions, ApplyMetaDataAction{
+                       Action: string(action),
+                       Status: string(status),
+               })
+       }
+       log.Infoln(`ACTION='` + string(action) + `' STATUS='` + string(status) 
+ `'` + "\n")
+}
diff --git a/cache-config/t3cutil/t3cutil.go b/cache-config/t3cutil/t3cutil.go
index 8073285d9d..aa4ee70f42 100644
--- a/cache-config/t3cutil/t3cutil.go
+++ b/cache-config/t3cutil/t3cutil.go
@@ -258,8 +258,9 @@ func UserAgentStr(appName string, versionNum string, 
gitRevision string) string
 func NewApplyMetaData() *ApplyMetaData {
        return &ApplyMetaData{
                Version:           MetaDataVersion,
-               InstalledPackages: []string{}, // construct a slice, so JSON 
serializes '[]' not 'null'.
-               OwnedFilePaths:    []string{}, // construct a slice, so JSON 
serializes '[]' not 'null'.
+               InstalledPackages: []string{},              // construct a 
slice, so JSON serializes '[]' not 'null'.
+               OwnedFilePaths:    []string{},              // construct a 
slice, so JSON serializes '[]' not 'null'.
+               Actions:           []ApplyMetaDataAction{}, // construct a map, 
so JSON serializes '{}' not 'null'.
        }
 }
 
@@ -351,6 +352,12 @@ type ApplyMetaData struct {
        // are strongly encouraged to set alarms and read logs in the event it 
occurs,
        // to determine what was changed, what failed, and what actions need 
taken.
        PartialSuccess bool `json:"partial-success"`
+
+       Actions []ApplyMetaDataAction `json:"actions"`
+}
+type ApplyMetaDataAction struct {
+       Action string `json:"action"`
+       Status string `json:"status"`
 }
 
 // Format prints the ApplyMetaData in a format designed to be written to a 
file,
diff --git a/cache-config/testing/ort-tests/t3c-create-metadata-file_test.go 
b/cache-config/testing/ort-tests/t3c-action-log_test.go
similarity index 50%
copy from cache-config/testing/ort-tests/t3c-create-metadata-file_test.go
copy to cache-config/testing/ort-tests/t3c-action-log_test.go
index 745fd89650..3c1cfe8b20 100644
--- a/cache-config/testing/ort-tests/t3c-create-metadata-file_test.go
+++ b/cache-config/testing/ort-tests/t3c-action-log_test.go
@@ -15,17 +15,14 @@ package orttest
 */
 
 import (
-       "encoding/json"
-       "io/ioutil"
-       "path/filepath"
+       "strings"
        "testing"
 
+       "github.com/apache/trafficcontrol/cache-config/t3cutil"
        "github.com/apache/trafficcontrol/cache-config/testing/ort-tests/tcdata"
-       "github.com/apache/trafficcontrol/cache-config/testing/ort-tests/util"
 )
 
-func TestT3cCreateMetaDataFile(t *testing.T) {
-       // t3c should create a metadata file
+func TestT3cActionLog(t *testing.T) {
        tcd.WithObjs(t, []tcdata.TCObj{
                tcdata.CDNs, tcdata.Types, tcdata.Tenants, tcdata.Parameters,
                tcdata.Profiles, tcdata.ProfileParameters,
@@ -33,29 +30,15 @@ func TestT3cCreateMetaDataFile(t *testing.T) {
                tcdata.CacheGroups, tcdata.Servers, tcdata.Topologies,
                tcdata.DeliveryServices}, func() {
 
-               err := t3cUpdateCreateEmptyFile(DefaultCacheHostName, "badass")
-               if err != nil {
-                       t.Fatalf("t3c badass failed: %v", err)
+               stdErr, exitCode := t3cUpdateReload(DefaultCacheHostName, 
"badass")
+               if exitCode != 0 {
+                       t.Fatalf("t3c badass failed, code: %v", exitCode)
                }
 
-               const metaDataFileName = `t3c-apply-metadata.json`
-
-               filePath := filepath.Join(TestConfigDir, metaDataFileName)
-
-               if !util.FileExists(filePath) {
-                       t.Fatalf("missing metadata file '%s'", filePath)
+               startActionMsg := `ACTION='` + 
t3cutil.ActionLogActionApplyStart + `'`
+               if !strings.Contains(stdErr, string(startActionMsg)) {
+                       t.Errorf("expected log to contain action log message 
'%s', actual: %s", startActionMsg, string(stdErr))
                }
 
-               mdFileBts, err := ioutil.ReadFile(filePath)
-               if err != nil {
-                       t.Fatalf("reading file '%s': %v", filePath, err)
-               }
-
-               // Test that the file is a valid JSON object.
-               // Other than that, we don't want to assert any particular data.
-               mdObj := map[string]interface{}{}
-               if err := json.Unmarshal(mdFileBts, &mdObj); err != nil {
-                       t.Errorf("expected metadata file '%s' to be a json 
object, actual: %s", filePath, err)
-               }
        })
 }
diff --git a/cache-config/testing/ort-tests/t3c-create-metadata-file_test.go 
b/cache-config/testing/ort-tests/t3c-create-metadata-file_test.go
index 745fd89650..86c4e95893 100644
--- a/cache-config/testing/ort-tests/t3c-create-metadata-file_test.go
+++ b/cache-config/testing/ort-tests/t3c-create-metadata-file_test.go
@@ -18,8 +18,10 @@ import (
        "encoding/json"
        "io/ioutil"
        "path/filepath"
+       "strings"
        "testing"
 
+       "github.com/apache/trafficcontrol/cache-config/t3cutil"
        "github.com/apache/trafficcontrol/cache-config/testing/ort-tests/tcdata"
        "github.com/apache/trafficcontrol/cache-config/testing/ort-tests/util"
 )
@@ -57,5 +59,14 @@ func TestT3cCreateMetaDataFile(t *testing.T) {
                if err := json.Unmarshal(mdFileBts, &mdObj); err != nil {
                        t.Errorf("expected metadata file '%s' to be a json 
object, actual: %s", filePath, err)
                }
+
+               metaDataStr := string(mdFileBts)
+               if !strings.Contains(metaDataStr, `"actions":`) {
+                       t.Errorf("expected metadata file '%s' to contain action 
log, actual: %s", filePath, metaDataStr)
+               }
+               if !strings.Contains(metaDataStr, 
`"`+string(t3cutil.ActionLogActionApplyStart)+`"`) {
+                       t.Errorf("expected metadata file '%s' to contain action 
log apply start message '%v', actual: %s", filePath, 
t3cutil.ActionLogActionApplyStart, metaDataStr)
+               }
+
        })
 }

Reply via email to