-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #264 from SUSE/include_uptime_tracker
Integrating uptime-tracker ( https://github.com/SUSE/uptime-tracker/ )
- Loading branch information
Showing
9 changed files
with
284 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
[Unit] | ||
Description=Run SUSE uptime tracker | ||
Wants=suse-uptime-tracker.timer | ||
|
||
[Service] | ||
Type=oneshot | ||
ExecStart=/usr/bin/suse-uptime-tracker |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
[Unit] | ||
Description=Schedule uptime tracking every 15 minutes | ||
|
||
[Timer] | ||
# Run this timer every 15 minutes | ||
OnCalendar=*:0/15 | ||
RandomizedDelaySec=5m | ||
|
||
[Install] | ||
WantedBy=timers.target |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
Fri Sep 13 15:56:05 UTC 2024 - Miquel Sabate Sola <[email protected]> | ||
|
||
- IN PROGRESS: 1.13 | ||
- Integrating uptime-tracker | ||
|
||
------------------------------------------------------------------- | ||
Fri Sep 13 14:11:22 UTC 2024 - Miquel Sabate Sola <[email protected]> | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
Usage: suse-uptime-tracker [options] | ||
Keep track of system uptime. If no options are specified, it will update | ||
the uptime tracking log file with the current uptime. | ||
|
||
--version Print program version. | ||
-h, --help Show this message. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
package main | ||
|
||
import ( | ||
"bufio" | ||
_ "embed" | ||
"errors" | ||
"flag" | ||
"fmt" | ||
"os" | ||
"sort" | ||
"strings" | ||
"time" | ||
) | ||
|
||
var ( | ||
//go:embed version.txt | ||
version string | ||
//go:embed uptimeTrackerUsage.txt | ||
uptimeTrackerUsageText string | ||
) | ||
|
||
const ( | ||
uptimeCheckLogsFilePath = "/etc/zypp/suse-uptime.log" | ||
dateStringFormat = "2006-01-02" | ||
initUptimeHours = "000000000000000000000000" // initialize the uptime hours bit string with | ||
daysBeforePurge = 90 // purge all the records after this many days | ||
) | ||
|
||
func getShortenedVersion() string { | ||
return strings.Split(strings.TrimSpace(version), "~")[0] | ||
} | ||
|
||
func exitOnError(err error) { | ||
if err == nil { | ||
return | ||
} | ||
fmt.Println(err) | ||
os.Exit(1) | ||
} | ||
|
||
func displayUptimeVersion() { | ||
var ( | ||
version bool | ||
) | ||
|
||
flag.Usage = func() { | ||
fmt.Print(uptimeTrackerUsageText) | ||
} | ||
|
||
flag.BoolVar(&version, "version", false, "") | ||
|
||
flag.Parse() | ||
if version { | ||
fmt.Println(getShortenedVersion()) | ||
os.Exit(0) | ||
} | ||
} | ||
|
||
func readUptimeLogFile(uptimeLogsFilePath string) (map[string]string, error) { | ||
uptimeLogsFile, err := os.Open(uptimeLogsFilePath) | ||
if err != nil { | ||
if errors.Is(err, os.ErrNotExist) { | ||
// file doesn't exist, so don't error out | ||
return nil, nil | ||
} | ||
return nil, err | ||
} | ||
fileScanner := bufio.NewScanner(uptimeLogsFile) | ||
fileScanner.Split(bufio.ScanLines) | ||
var logEntries = make(map[string]string) | ||
|
||
var entry []string | ||
for fileScanner.Scan() { | ||
entryText := fileScanner.Text() | ||
entry = strings.Split(entryText, ":") | ||
if len(entry) != 2 { | ||
return nil, errors.New("Uptime log file is corrupted. Invalid log entry " + entryText) | ||
} | ||
logEntries[entry[0]] = entry[1] | ||
} | ||
err = uptimeLogsFile.Close() | ||
if err != nil { | ||
return nil, err | ||
} | ||
return logEntries, nil | ||
} | ||
|
||
func purgeOldUptimeLog(uptimeLogs map[string]string) (map[string]string, error) { | ||
now := time.Now().UTC() | ||
purgeBefore := now.AddDate(0, 0, -daysBeforePurge) | ||
var purgedLogs = make(map[string]string) | ||
for day, uptimeHours := range uptimeLogs { | ||
timestamp, err := time.Parse(dateStringFormat, day) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if timestamp.After(purgeBefore) { | ||
purgedLogs[day] = uptimeHours | ||
} | ||
} | ||
return purgedLogs, nil | ||
} | ||
|
||
func updateUptimeLog(uptimeLogs map[string]string) map[string]string { | ||
// NOTE: we are standardizing timezone to UTC | ||
now := time.Now().UTC() | ||
day := now.Format(dateStringFormat) | ||
hours, _, _ := now.Clock() | ||
_, ok := uptimeLogs[day] | ||
if !ok { | ||
uptimeLogs[day] = initUptimeHours | ||
} | ||
uptimeHoursMap := []rune(uptimeLogs[day]) | ||
uptimeHoursMap[hours] = '1' | ||
uptimeLogs[day] = string(uptimeHoursMap) | ||
|
||
return uptimeLogs | ||
} | ||
|
||
func writeUptimeLogsFile(uptimeLogsFilePath string, uptimeLogs map[string]string) error { | ||
uptimeLogsFile, err := os.OpenFile(uptimeLogsFilePath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644) | ||
if err != nil { | ||
return err | ||
} | ||
defer uptimeLogsFile.Close() | ||
|
||
// sort the keys | ||
keys := make([]string, 0, len(uptimeLogs)) | ||
for day := range uptimeLogs { | ||
keys = append(keys, day) | ||
} | ||
sort.Strings(keys) | ||
|
||
for _, day := range keys { | ||
_, err = uptimeLogsFile.WriteString(day + ":" + uptimeLogs[day] + "\n") | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func main() { | ||
displayUptimeVersion() | ||
uptimeLogs, err := readUptimeLogFile(uptimeCheckLogsFilePath) | ||
exitOnError(err) | ||
uptimeLogs, err = purgeOldUptimeLog(uptimeLogs) | ||
exitOnError(err) | ||
uptimeLogs = updateUptimeLog(uptimeLogs) | ||
err = writeUptimeLogsFile(uptimeCheckLogsFilePath, uptimeLogs) | ||
exitOnError(err) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
package main | ||
|
||
import ( | ||
"io/ioutil" | ||
"os" | ||
"testing" | ||
"time" | ||
|
||
"github.com/google/uuid" | ||
) | ||
|
||
const ( | ||
DDMMYYYY = "2006-01-02" | ||
) | ||
|
||
func createTestUptimeLogFileWithContent(content string) (string, error) { | ||
tempFile, err := ioutil.TempFile("", "testUptimeLog") | ||
if err != nil { | ||
return "", err | ||
} | ||
tempFilePath := tempFile.Name() | ||
if _, err := tempFile.WriteString(content); err != nil { | ||
os.Remove(tempFilePath) | ||
return "", err | ||
} | ||
if err := tempFile.Close(); err != nil { | ||
os.Remove(tempFilePath) | ||
return "", err | ||
} | ||
|
||
return tempFilePath, nil | ||
} | ||
|
||
func TestUptimeLogFileDoesNotExist(t *testing.T) { | ||
bogusUptimeLogsFilePath := uuid.New().String() | ||
uptimeLog, err := readUptimeLogFile(bogusUptimeLogsFilePath) | ||
if uptimeLog != nil || err != nil { | ||
t.Fatalf("Expected err and uptimeLog to be nil if uptime log file does not exist") | ||
} | ||
} | ||
|
||
func TestCorruptedUptimeLog(t *testing.T) { | ||
corruptedUptimeLog := `2024-01-18:000000000000001000110000 | ||
2024-01-13000000000000000000010000` | ||
tempFilePath, err := createTestUptimeLogFileWithContent(corruptedUptimeLog) | ||
if err != nil { | ||
t.Fatalf("Failed to create temp uptime log file for testing") | ||
} | ||
_, err = readUptimeLogFile(tempFilePath) | ||
if err == nil { | ||
t.Fatalf("Expected an error for corrupted uptime logs entry") | ||
} | ||
defer os.Remove(tempFilePath) | ||
} | ||
|
||
func TestPurgeOldUptimeLog(t *testing.T) { | ||
datetime := time.Now().UTC() | ||
currdate := string((datetime.Format(DDMMYYYY))) | ||
olddatetime := datetime.AddDate(-1, 0, 0) | ||
olddate := string((olddatetime.Format(DDMMYYYY))) | ||
PurgeOldUptimeLog := currdate + ":000000000000001000110000\n" + olddate + ":000000000000000000010000\n" | ||
tempFilePath, err := createTestUptimeLogFileWithContent(PurgeOldUptimeLog) | ||
if err != nil { | ||
t.Fatalf("Failed to populate old uptime logs content for testing") | ||
} | ||
uptimelog, _ := readUptimeLogFile(tempFilePath) | ||
purgelog, _ := purgeOldUptimeLog(uptimelog) | ||
if len(purgelog) != 1 { | ||
t.Fatalf("Failed to purge old uptime logs entry") | ||
} | ||
defer os.Remove(tempFilePath) | ||
} | ||
|
||
func TestUpdateuptimeLog(t *testing.T) { | ||
datetime := time.Now().UTC() | ||
hour, _, _ := datetime.Clock() | ||
strhour := rune(hour) | ||
currdate := string((datetime.Format(DDMMYYYY))) | ||
PopulateUptimeLog := currdate + ":000000000000000000000000\n" | ||
tempFilePath, err := createTestUptimeLogFileWithContent(PopulateUptimeLog) | ||
if err != nil { | ||
t.Fatalf("Failed to populate uptime logs content for testing") | ||
} | ||
uptimelog, _ := readUptimeLogFile(tempFilePath) | ||
uptimelog = updateUptimeLog(uptimelog) | ||
timeupd := string(uptimelog[currdate]) | ||
activehr := timeupd[strhour : strhour+1] | ||
if activehr != "1" { | ||
t.Fatalf("Failed to update uptime hour ") | ||
} | ||
defer os.Remove(tempFilePath) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
1.0.0 |