applicationhealth-extension.../main/status.go

132 строки
3.4 KiB
Go
Исходник Обычный вид История

2018-06-26 22:45:05 +03:00
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"time"
)
type StatusReport []StatusItem
type StatusItem struct {
Version float64 `json:"version"`
TimestampUTC string `json:"timestampUTC"`
Status Status `json:"status"`
}
type StatusType string
const (
StatusTransitioning StatusType = "transitioning"
Bump to v2.0.8: Bootstrap VMWatch Process if vmWatchSettings present (#33) ## Overview This PR contains changes to support running VMWatch (amd64 and arm64) as an executable via goroutines and channels. > VMWatch is a standardized, lightweight, and open-sourced testing framework designed to enhance the monitoring and management of guest VMs on the Azure platform, including both 1P and 3P instances. VMWatch is engineered to collect vital health signals across multiple dimensions, which will be seamlessly integrated into Azure's quality systems. By leveraging these signals, VMWatch will enable Azure to swiftly detect and prevent regressions induced by platform updates or configuration changes, identify gaps in platform telemetry, and ultimately improve the guest experience for all Azure customers. ## Behavior VMWatch will run asynchronously as a separate process than ApplicationHealth, so the probing of application health will not be affected by the state of VMWatch. Depending on extension settings, VMWatch can be enabled/disabled, and also specify the test names and parameter overrides to VMWatch binary. The status of VMWatch will be displayed in the extension x.status files and also in GET VM Instance View. Main process will attempt to start VMWatch binary up to 3 times, after which VMWatch status will be set to failed. ## Process Leaks To ensure that VMWatch processes do not accumulate, applicationhealth-shim will be responsible for killing existing VMWatch processes by looking for processes running with the VMWatch binary names according to the architecture type. For unexpected process termination, if for some reason the main applicationhealth-extension process is terminated, we also ensure that the VMWatch process is also killed by subscribing to shutdown/termination signals in the main process, and killing the VMWatch based off process ID. ## Example Binary Execution Example execution from integration testing ` SIGNAL_FOLDER=/var/log/azure/Microsoft.ManagedServices.ApplicationHealthLinux/events VERBOSE_LOG_FILE_FULL_PATH=/var/log/azure/Microsoft.ManagedServices.ApplicationHealthLinux/VE.RS.ION/vmwatch.log ./var/lib/waagent/Extension/bin/VMWatch/vmwatch_linux_amd64 --config /var/lib/waagent/Extension/bin/VMWatch/vmwatch.conf --input-filter disk_io:outbound_connectivity ` ## Release/Packaging In addition to the arm64 or amd64 VMWatch binaries, `vmwatch.conf` will be expected to be present in the bin/VMWatch directory for VMWatch process to read. VMWatch will also be populating and sharing eventsFolder with ApplicationHealth, so events can be viewed in Kusto. The verbose logs of VMWatch will be written to `vmwatch.log`. --------- Co-authored-by: klugorosado <142627157+klugorosado@users.noreply.github.com>
2023-11-17 19:25:58 +03:00
StatusWarning StatusType = "warning"
2018-06-26 22:45:05 +03:00
StatusError StatusType = "error"
StatusSuccess StatusType = "success"
)
type Status struct {
Operation string `json:"operation"`
ConfigurationAppliedTimeUTC string `json:"configurationAppliedTime"`
Status StatusType `json:"status"`
FormattedMessage FormattedMessage `json:"formattedMessage"`
SubstatusList []SubstatusItem `json:"substatus,omitempty"`
}
2018-06-26 22:45:05 +03:00
type FormattedMessage struct {
Lang string `json:"lang"`
Message string `json:"message"`
}
type SubstatusItem struct {
Name string `json:"name"`
Status StatusType `json:"status"`
FormattedMessage FormattedMessage `json:"formattedMessage"`
2018-06-26 22:45:05 +03:00
}
func NewStatus(t StatusType, operation, message string) StatusReport {
now := time.Now().UTC().Format(time.RFC3339)
return []StatusItem{
{
Version: 1.0,
2018-06-26 22:45:05 +03:00
TimestampUTC: now,
Status: Status{
Operation: operation,
2018-06-26 22:45:05 +03:00
ConfigurationAppliedTimeUTC: now,
Status: t,
2018-06-26 22:45:05 +03:00
FormattedMessage: FormattedMessage{
Lang: "en",
Message: message,
},
2018-06-26 22:45:05 +03:00
},
},
}
}
func NewSubstatus(name string, t StatusType, message string) SubstatusItem {
return SubstatusItem{
Name: name,
Status: t,
FormattedMessage: FormattedMessage{
Lang: "en",
Message: message,
},
}
}
func (r StatusReport) AddSubstatus(t StatusType, name, message string, state HealthStatus) {
2018-06-26 22:45:05 +03:00
if len(r) > 0 {
substatusItem := SubstatusItem{
Name: name,
Status: t,
FormattedMessage: FormattedMessage{
Lang: "en",
Message: message,
2018-06-26 22:45:05 +03:00
},
}
r[0].Status.SubstatusList = append(r[0].Status.SubstatusList, substatusItem)
}
}
func (r StatusReport) AddSubstatusItem(substatus SubstatusItem) {
if len(r) > 0 {
r[0].Status.SubstatusList = append(r[0].Status.SubstatusList, substatus)
2018-06-26 22:45:05 +03:00
}
}
func (r StatusReport) marshal() ([]byte, error) {
return json.MarshalIndent(r, "", "\t")
}
// Save persists the status message to the specified status folder using the
// sequence number. The operation consists of writing to a temporary file in the
// same folder and moving it to the final destination for atomicity.
Implementing New Sequence Number Management and Fixing how we get the extension Sequence Number (#83) This pull request includes changes to the sequence number management and testing in the `main` and `internal/seqno` packages. The most important changes include the creation of a new `SequenceNumberManager` interface and `SeqNumManager` struct, the addition of a function to check if a sequence number has already been processed before enabling it, and the addition of tests for the new function. New sequence number management: * [`internal/seqno/seqno.go`](diffhunk://#diff-f671e4abbca7ae7b738bc8ef287fcbf3995062b2cc5e54ad666e3fa6f1b674dcR1-R101): Created a new `SequenceNumberManager` interface and `SeqNumManager` struct to manage sequence numbers. The `SeqNumManager` struct includes functions to get and set sequence numbers, and to find a sequence number from either the environment variable or the most recently used file under the config folder. Changes to `main` package: * [`main/cmds.go`](diffhunk://#diff-ace417b47e816a44cf3b6f6248e72453a46d9e6043f19aea9d39212e852cc373L32-R32): a new function `enablePre` has been added. This function, acting as the PreFunc for the enable command, verifies if the sequence number is ready for processing by comparing it with the last executed number from the `mrseq` file. This ensures orderly processing of sequence numbers. * [`main/main.go`](diffhunk://#diff-327181d0a8c5e6b164561d7910f4eeffd41442d55b2a2788fda2aa2692f17ec0L64-R68): Replaced the `FindSeqNum` function with `seqnoManager.FindSeqNum` to find the sequence number. * [`main/seqnum.go`](diffhunk://#diff-171d8d31093fac5a89b9bbe034fe628faf47dd12fad91b3205433ca95c56be52L1-L32): Removed the `FindSeqNum` function as it has been replaced by `seqnoManager.FindSeqNum`. New tests: * [`main/cmds_test.go`](diffhunk://#diff-bdb35e68cc43b04f7c8b572233a1472169052b84e0b471c6fe578fe049784223R36-R133): Added tests for the enablePre. --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-28 04:13:21 +03:00
func (r StatusReport) Save(statusFolder string, seqNum uint) error {
2018-06-26 22:45:05 +03:00
fn := fmt.Sprintf("%d.status", seqNum)
path := filepath.Join(statusFolder, fn)
tmpFile, err := ioutil.TempFile(statusFolder, fn)
if err != nil {
return fmt.Errorf("status: failed to create temporary file: %v", err)
}
tmpFile.Close()
b, err := r.marshal()
if err != nil {
return fmt.Errorf("status: failed to marshal into json: %v", err)
}
if err := ioutil.WriteFile(tmpFile.Name(), b, 0644); err != nil {
return fmt.Errorf("status: failed to write to path=%s error=%v", tmpFile.Name(), err)
2018-06-26 22:45:05 +03:00
}
if err := os.Rename(tmpFile.Name(), path); err != nil {
return fmt.Errorf("status: failed to move to path=%s error=%v", path, err)
}
return nil
}
func (r StatusReport) String() string {
report, _ := json.MarshalIndent(r, "", "\t")
return string(report)
}