Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ jobs:
go-version: 1.19

- name: Static analysis of code for errors
run: make analyze
env:
PM_LOG_DIR: ${{ github.workspace }}/test-logs
run: |
mkdir -p ${{ github.workspace }}/test-logs
make analyze

# - name: Build
# run: go build -v ./...
Expand All @@ -30,10 +34,12 @@ jobs:
- name: Test - go test
env:
PM_CONF_FILE: ${{ github.workspace }}/sample/pm.config.yaml
PM_LOG_DIR: ${{ github.workspace }}/test-logs
INTEGRATION_TEST: START
INTEG_TEST_BIN: ${{ github.workspace }}
run: |
mkdir -p ${{ github.workspace }}/cover
mkdir -p ${{ github.workspace }}/test-logs
go test -mod=vendor -v ./...

# - name: Test - make test
Expand Down
16 changes: 12 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Copyright (c) 2023 Veritas Technologies LLC. All rights reserved. IP63-2828-7171-04-15-9
# Copyright (c) 2024 Veritas Technologies LLC. All rights reserved. IP63-2828-7171-04-15-9

# A Self-Documenting Makefile: http://marmelab.com/blog/2016/02/29/auto-documented-makefile.html
.DEFAULT_GOAL := help
.PHONY: help
help: ## Display this help message.
@grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
@grep -Eh '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'

TOP=$(CURDIR)
include $(TOP)/Makefile.conf
Expand All @@ -29,8 +29,7 @@ clean: ## Clean Plugin Manager go build & test artifacts
cd $(GOSRC); \
go clean -i -mod=vendor ./...;
@echo "Cleaning Go test artifacts... ";
-@rm $(GOSRC)/{,.}*{dot,html,log,svg,xml};
-@rm $(GOSRC)/cmd/pm/{,.}*{dot,log,svg};
-@find $(GOSRC) -name "*.dot" -o -name "*.html" -o -name "*.log" -o -name "*.svg" -o -name "*.xml" | xargs -i rm -f {}
-@rm -rf $(GOSRC)/plugins/
-@rm -rf $(GOCOVERDIR);

Expand Down Expand Up @@ -113,4 +112,13 @@ go-race: ## Run Go tests with race detector enabled
export PM_CONF_FILE=$(GOSRC)/sample/pm.config.yaml; \
go test -mod=vendor -v -race ./...;

.PHONY: update-go-tools
update-go-tools: ## Update Go thirdparty tools to current go version
export GOBIN=$(GOTOOLSBIN); \
go install github.com/axw/gocov/gocov@latest; \
go install github.com/AlekSi/gocov-xml@latest; \
go install github.com/matm/gocov-html/cmd/gocov-html@latest; \
go install github.com/jstemmer/go-junit-report/v2@latest; \
go install golang.org/x/lint/golint@latest

.NOTPARALLEL:
27 changes: 2 additions & 25 deletions cmd/pm/pm.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
package main

import (
"fmt"
"os"
"path/filepath"

Expand All @@ -18,7 +17,7 @@ import (
var (
buildDate string
// Version of the Plugin Manager (PM) command.
version = "4.2"
version = "4.4"
// progname is name of my binary/program/executable.
progname = filepath.Base(os.Args[0])
)
Expand All @@ -28,29 +27,7 @@ func init() {
config.EnvConfFile = "PM_CONF_FILE"
// DefaultConfigPath is default path for config file used when EnvConfFile is not set.
config.DefaultConfigPath = "/opt/veritas/appliance/asum/pm.config.yaml"
// DefaultLogPath is default path for log file.
config.DefaultLogPath = "./pm.log"
// Use syslog until the config file is read.
// If syslog initialization fails, file logging will be used.
useFileLog := true
if logger.IsSysLogConfigPresent() {
err := logger.InitSysLogger("pm-main", logger.DefaultLogLevel)
if err != nil {
fmt.Printf("Failed to initialize SysLog for logging [%#v]. Proceeding with FileLog...\n", err)
useFileLog = false
}
}
if useFileLog {
// NOTE: while running tests, the path of binary would be in `/tmp/<go-build*>`,
// so, using relative logging path w.r.t. binary wouldn't be accessible on Jenkins.
// So, use absolute path which also has write permissions (like current source directory).
err := logger.InitFileLogger(config.DefaultLogPath, logger.DefaultLogLevel)
if err != nil {
fmt.Printf("Failed to initialize file logger [%#v].\n", err)
os.Exit(1)
}
}

logger.InitLogging()
}

func main() {
Expand Down
2 changes: 0 additions & 2 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ var (
EnvConfFile string
// DefaultConfigPath is default path for config file used when EnvConfFile is not set.
DefaultConfigPath string
// DefaultLogPath is default path for log file.
DefaultLogPath string
)

// GetLogDir provides location for storing logs.
Expand Down
5 changes: 1 addition & 4 deletions graph_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import (
"reflect"
"sort"
"testing"

logger "github.com/VeritasOS/plugin-manager/utils/log"
)

func Test_getStatusColor(t *testing.T) {
Expand Down Expand Up @@ -199,8 +197,7 @@ func Test_initGraph(t *testing.T) {
wantErr: false,
},
}
// Set log file name to "test", so that cleaning becomes easier.
logger.InitFileLogger("test.log", "INFO")

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := initGraph(tt.args.pluginType, tt.args.pluginsInfo); (err != nil) != tt.wantErr {
Expand Down
67 changes: 53 additions & 14 deletions plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package pm

import (
"bufio"
"encoding/json"
"errors"
"flag"
Expand All @@ -29,7 +30,7 @@ import (

var (
// Version of the Plugin Manager (PM).
version = "4.8"
version = "4.9"
)

// Status of plugin execution used for displaying to user on console.
Expand All @@ -48,15 +49,16 @@ type Plugin struct {
RequiredBy []string
Requires []string
Status string
StdOutErr string
StdOutErr []string
}

// Plugins is a list of plugins' info.
type Plugins []Plugin

// RunStatus is the pm run status.
type RunStatus struct {
Type string
Type string
Library string
// TODO: Add Percentage to get no. of pending vs. completed run of plugins.
Plugins Plugins `yaml:",omitempty"`
Status string
Expand Down Expand Up @@ -158,10 +160,13 @@ func getPluginsInfoFromJSONStrOrFile(strOrFile string) (RunStatus, error) {
jsonFormat = false
}
}
// INFO: Use RunStatus to unmarshal to keep input consistent with current
// output json, so that rerun failed could be done using result json.
var pluginsData RunStatus
if jsonFormat {
err = json.Unmarshal([]byte(rawData), &pluginsInfo)
err = json.Unmarshal([]byte(rawData), &pluginsData)
} else {
err = yaml.Unmarshal([]byte(rawData), &pluginsInfo)
err = yaml.Unmarshal([]byte(rawData), &pluginsData)
}
if err != nil {
logger.Error.Printf("Failed to call Unmarshal(%s, %v); err=%#v",
Expand All @@ -170,7 +175,7 @@ func getPluginsInfoFromJSONStrOrFile(strOrFile string) (RunStatus, error) {
logger.ConsoleError.PrintNReturnError(
"Plugins is not in expected format. Error: %s", err.Error())
}
return pluginsInfo, nil
return pluginsData, nil
}

func getPluginsInfoFromLibrary(pluginType, library string) (Plugins, error) {
Expand Down Expand Up @@ -411,7 +416,6 @@ func executePluginCmd(statusCh chan<- map[string]*Plugin, pInfo Plugin, failedDe
updateGraph(getPluginType(p), p, dStatusStart, "")
logger.ConsoleInfo.Printf("%s: %s", pInfo.Description, dStatusStart)
pluginLogFile := ""
// Create chLog, by default it will use syslog, if user specified logFile, then use previous defined log generator
var chLog *log.Logger
if !logger.IsFileLogger() {
var logTag string
Expand Down Expand Up @@ -496,21 +500,45 @@ func executePluginCmd(statusCh chan<- map[string]*Plugin, pInfo Plugin, failedDe
cmdParams := cmdParam[1:]
cmd := exec.Command(cmdStr, cmdParams...)
cmd.Env = envList
stdOutErr, err := cmd.CombinedOutput()
iostdout, err := cmd.StdoutPipe()
if err != nil {
pInfo.Status = dStatusFail
logger.Error.Printf("Failed to execute plugin %s. Error: %s\n", pInfo.Name, err.Error())
pInfo.StdOutErr = []string{err.Error()}
logger.ConsoleInfo.Printf("%s: %s\n", pInfo.Description, pInfo.Status)
statusCh <- map[string]*Plugin{p: &pInfo}
return
}
cmd.Stderr = cmd.Stdout

chLog.Println("Executing command:", pInfo.ExecStart)
err = cmd.Start()
var stdOutErr []string
if err == nil {
scanner := bufio.NewScanner(iostdout)
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
iobytes := scanner.Text()
chLog.Println(string(iobytes))
stdOutErr = append(stdOutErr, iobytes)
}
err = cmd.Wait()
// chLog.Printf("command exited with code: %+v", err)
}

func() {
chLog.Printf("INFO: Plugin(%s): Executing command: %s", p, pInfo.ExecStart)
if err != nil {
chLog.Printf("ERROR: Plugin(%s): Failed to execute command, err=%s", p, err.Error())
updateGraph(getPluginType(p), p, dStatusFail, pluginLogFile)
} else {
chLog.Printf("INFO: Plugin(%s): Stdout & Stderr: %s", p, string(stdOutErr))
chLog.Printf("INFO: Plugin(%s): Stdout & Stderr: %v", p, stdOutErr)
updateGraph(getPluginType(p), p, dStatusOk, pluginLogFile)
}
}()

logger.Debug.Println("Stdout & Stderr:", string(stdOutErr))
pStatus := Plugin{StdOutErr: string(stdOutErr)}
logger.Debug.Println("Stdout & Stderr:", stdOutErr)
pStatus := Plugin{StdOutErr: stdOutErr}
if err != nil {
pStatus.Status = dStatusFail
logger.Error.Printf("Failed to execute plugin %s. err=%s\n", p, err.Error())
Expand Down Expand Up @@ -760,9 +788,20 @@ func RunFromJSONStrOrFile(result *RunStatus, jsonStrOrFile string, runOptions Ru
result.StdOutErr = err.Error()
return err
}
result.Plugins = pluginsInfo.Plugins
result.Type = pluginsInfo.Type

result.Library = pluginsInfo.Library
result.Plugins = pluginsInfo.Plugins
// INFO: Override values of json/file with explicitly passed cmdline parameter. Else, set runOptions type from json/file.
if runOptions.Type != "" {
result.Type = runOptions.Type
} else {
runOptions.Type = pluginsInfo.Type
}
if runOptions.Library != "" {
result.Library = runOptions.Library
} else {
runOptions.Library = pluginsInfo.Library
}
return run(result, runOptions)
}

Expand Down Expand Up @@ -903,7 +942,7 @@ func ScanCommandOptions(options map[string]interface{}) error {
// but only extensions (i.e., they get created as hidden files).
config.SetPMLogFile(tLogFile)
myLogFile += config.GetPMLogFile()
if myLogFile != config.DefaultLogPath {
if myLogFile != logger.DefaultLogPath {
myLogFile := filepath.Clean(myLogFile)
logger.Info.Println("Logging to specified log file:", myLogFile)
errList := logger.DeInitLogger()
Expand Down
Loading