Skip to content

Commit

Permalink
Add core handler to binding (openconfig#2296)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcushines authored Oct 27, 2023
1 parent ab521c8 commit f36af19
Show file tree
Hide file tree
Showing 5 changed files with 773 additions and 10 deletions.
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ require (
cloud.google.com/go/iam v1.1.2 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903 // indirect
github.com/acomagu/bufpipe v1.0.4 // indirect
github.com/aristanetworks/arista-ceoslab-operator/v2 v2.0.1 // indirect
github.com/aristanetworks/arista-ceoslab-operator/v2 v2.0.2 // indirect
github.com/carlmontanari/difflibgo v0.0.0-20210718194309-31b9e131c298 // indirect
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
github.com/cloudflare/circl v1.3.3 // indirect
Expand Down Expand Up @@ -99,7 +99,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/networkop/meshnet-cni v0.3.1-0.20230525201116-d7c306c635cf // indirect
github.com/open-traffic-generator/ixia-c-operator v0.3.4 // indirect
github.com/open-traffic-generator/ixia-c-operator v0.3.6 // indirect
github.com/openconfig/grpctunnel v0.0.0-20220819142823-6f5422b8ca70 // indirect
github.com/openconfig/lemming/operator v0.2.0 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
Expand All @@ -110,7 +110,7 @@ require (
github.com/rogpeppe/go-internal v1.9.0 // indirect
github.com/sagikazarmark/locafero v0.3.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/scrapli/scrapligo v1.1.7 // indirect
github.com/scrapli/scrapligo v1.1.11 // indirect
github.com/scrapli/scrapligocfg v1.0.0 // indirect
github.com/sergi/go-diff v1.1.0 // indirect
github.com/sirikothe/gotextfsm v1.0.1-0.20200816110946-6aa2cfd355e4 // indirect
Expand Down
11 changes: 6 additions & 5 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -755,8 +755,8 @@ github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0I
github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI=
github.com/apache/arrow/go/v12 v12.0.0/go.mod h1:d+tV/eHZZ7Dz7RPrFKtPK02tpr+c9/PEd/zm8mDS9Vg=
github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU=
github.com/aristanetworks/arista-ceoslab-operator/v2 v2.0.1 h1:lOGhvrrxc/bzUMJI4kYmZh/N1a87Vnsk/TENZt5kCoc=
github.com/aristanetworks/arista-ceoslab-operator/v2 v2.0.1/go.mod h1:/mvSt2fEmlVEU7dppip3UNz/MUt380f50dFsZRGn83o=
github.com/aristanetworks/arista-ceoslab-operator/v2 v2.0.2 h1:KQL1evr4NM4ZQOLRs1bbmD0kYPmLRAMqvRrNSpYAph4=
github.com/aristanetworks/arista-ceoslab-operator/v2 v2.0.2/go.mod h1:/mvSt2fEmlVEU7dppip3UNz/MUt380f50dFsZRGn83o=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
Expand Down Expand Up @@ -1132,8 +1132,8 @@ github.com/onsi/ginkgo/v2 v2.6.0 h1:9t9b9vRUbFq3C4qKFCGkVuq/fIHji802N1nrtkh1mNc=
github.com/onsi/ginkgo/v2 v2.6.0/go.mod h1:63DOGlLAH8+REH8jUGdL3YpCpu7JODesutUjdENfUAc=
github.com/onsi/gomega v1.24.1 h1:KORJXNNTzJXzu4ScJWssJfJMnJ+2QJqhoQSRwNlze9E=
github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM=
github.com/open-traffic-generator/ixia-c-operator v0.3.4 h1:xH0hLVWf2wuVUT9ovFdh/WwwBf1oGkBu5YEWD61igck=
github.com/open-traffic-generator/ixia-c-operator v0.3.4/go.mod h1:Q+ZXCinXxUKcnrJf5PJC1Q7JxUQc5ZPZA85jwVAqIRQ=
github.com/open-traffic-generator/ixia-c-operator v0.3.6 h1:dablUs6FAToVDFaoIo2M+Z9UCa93KAwlj7HJqNwLwTQ=
github.com/open-traffic-generator/ixia-c-operator v0.3.6/go.mod h1:Q+ZXCinXxUKcnrJf5PJC1Q7JxUQc5ZPZA85jwVAqIRQ=
github.com/open-traffic-generator/snappi/gosnappi v0.13.0 h1:RdlbT+CIlVum6xbhiFr/IzTvQee5bMa3V4oBWa79UBw=
github.com/open-traffic-generator/snappi/gosnappi v0.13.0/go.mod h1:QjB939WFJqUq6V7RQqkY/LFCgRRzKrybHHFp7F7xdWA=
github.com/openconfig/entity-naming v0.0.0-20230912181021-7ac806551a31 h1:K/9O+J20+liIof8WjquMydnebD0N1U9ItjhJYF6H4hg=
Expand Down Expand Up @@ -1242,8 +1242,9 @@ github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/scrapli/scrapligo v1.0.0/go.mod h1:jvRMdb90MNnswMiku8UNXj8JZaOIPhwhcqqFwr9qeoY=
github.com/scrapli/scrapligo v1.1.7 h1:xc0/bTDT+BfLkjJ3B4X6/8lxuzW7tgB8BMg8Tzn1yHQ=
github.com/scrapli/scrapligo v1.1.7/go.mod h1:rRx/rT2oNPYztiT3/ik0FRR/Ro7AdzN/eR9AtF8A81Y=
github.com/scrapli/scrapligo v1.1.11 h1:ATvpF2LDoxnd/HlfSj5A0IiJDro75D6nuCx8m6S44vU=
github.com/scrapli/scrapligo v1.1.11/go.mod h1:XrSom4Gd87B110QkyTaTkuL2EbzEVOlgCJGKIZa6wns=
github.com/scrapli/scrapligocfg v1.0.0 h1:540SuGqqM6rKN87SLCfR54IageQ6s3a/ZOycGRgbbak=
github.com/scrapli/scrapligocfg v1.0.0/go.mod h1:9+6k9dQeIqEZEg6EK5YXEjuVb7h+nvvel26CY1RGjy4=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
Expand Down
266 changes: 266 additions & 0 deletions internal/core/core.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,266 @@
// Copyright 2023 Google LLC
//
// Licensed 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.

// Package core provides a validator for being able to
// check for core files on DUT's before and after test
// modules runs.
package core

import (
"bytes"
"context"
"fmt"
"regexp"
"sync"
"text/template"
"time"

"github.com/golang/glog"
"github.com/openconfig/ondatra"
"github.com/openconfig/ondatra/binding"
"github.com/openconfig/ondatra/eventlis"
"google.golang.org/grpc"

fpb "github.com/openconfig/gnoi/file"
opb "github.com/openconfig/ondatra/proto"
)

var (
vendorCoreFilePath = map[opb.Device_Vendor]string{
opb.Device_JUNIPER: "/var/core/",
opb.Device_CISCO: "/misc/disk1/",
opb.Device_NOKIA: "/var/core/",
opb.Device_ARISTA: "/var/core/",
}
vendorCoreFileNamePattern = map[opb.Device_Vendor]*regexp.Regexp{
opb.Device_JUNIPER: regexp.MustCompile(".*.tar.gz"),
opb.Device_CISCO: regexp.MustCompile("/misc/disk1/.*core.*"),
opb.Device_NOKIA: regexp.MustCompile("/var/core/coredump-.*"),
opb.Device_ARISTA: regexp.MustCompile("/var/core/core.*"),
}
)

var (
validator validatorImpl
)

type fileInfo struct {
Name string
Path string
Modified uint64
}

type dutCoreFiles struct {
DUT string
Files coreFiles
Status string
}

type coreFiles map[string]fileInfo

type checker struct {
dut binding.DUT
fileClient fpb.FileClient

mu sync.Mutex
startTime time.Time
endTime time.Time
prevCores coreFiles
}

func newChecker(dut binding.DUT) (*checker, error) {
dutVendor := dut.Vendor()
// vendorCoreFilePath and vendorCoreProcName should be provided to fetch core file on dut.
if _, ok := vendorCoreFilePath[dutVendor]; !ok {
return nil, fmt.Errorf("add support for vendor %v in var vendorCoreFilePath", dutVendor)
}
if _, ok := vendorCoreFileNamePattern[dutVendor]; !ok {
return nil, fmt.Errorf("add support for vendor %v in var vendorCoreFileNamePattern", dutVendor)
}
gClients, err := dut.DialGNOI(context.Background(), grpc.WithBlock())
if err != nil {
return nil, err
}
return &checker{
dut: dut,
fileClient: gClients.File(),
prevCores: coreFiles{},
startTime: time.Now(),
}, nil
}

func (c *checker) check() (coreFiles, error) {
c.mu.Lock()
defer c.mu.Unlock()
cores, err := c.checkCores()
if err != nil {
return nil, err
}
delta := coreFiles{}
for k, v := range cores {
if _, ok := c.prevCores[k]; !ok {
delta[k] = v
}
}
c.prevCores = cores
return delta, nil
}

type validatorImpl struct {
mu sync.Mutex
duts map[string]*checker
}

func (v *validatorImpl) check() map[string]dutCoreFiles {
var wg sync.WaitGroup
var mu sync.Mutex
dutCores := map[string]dutCoreFiles{}
for _, c := range v.duts {
wg.Add(1)
go func(c *checker) {
defer wg.Done()
cores, err := c.check()
status := "OK"
if err != nil {
status = fmt.Sprintf("DUT %q failed to check cores: %v", c.dut.Name(), err)
glog.Warning(status)
}
mu.Lock()
defer mu.Unlock()
dutCores[c.dut.Name()] = dutCoreFiles{
DUT: c.dut.Name(),
Files: cores,
Status: status,
}
}(c)
}
wg.Wait()
return dutCores
}

// start starts a core file watcher for the provided DUT.
func (v *validatorImpl) start(duts map[string]binding.DUT) map[string]dutCoreFiles {
v.mu.Lock()
defer v.mu.Unlock()
for k, dut := range duts {
glog.Infof("Registering core file checking for DUT %q", k)
c, err := newChecker(dut)
if err != nil {
glog.Warningf("Failed to register core file checking for DUT %q: %v", k, err)
continue
}
v.duts[k] = c
}
return v.check()
}

// Stop ends the validator and returns a list of all DUTs that
// found core files.
func (v *validatorImpl) stop() map[string]dutCoreFiles {
v.mu.Lock()
defer v.mu.Unlock()
return v.check()
}

func registerBefore(e *eventlis.BeforeTestsEvent) error {
cores := validator.start(e.Reservation.DUTs)
ondatra.Report().AddSuiteProperty("validator.core", "enabled")
report := createReport(cores)
ondatra.Report().AddSuiteProperty("validator.core.initial", report)
return nil
}

const (
coreFmt = `
Delta Core Files by DUT:{{range $key, $dut := .}}
DUT: {{$key}}{{ range $key, $cores := $dut.Files }}
{{ $key }}{{ end }}{{ end }}`
)

var coreTemplate = template.Must(template.New("errorMsg").Parse(coreFmt))

func createReport(d map[string]dutCoreFiles) string {
b := new(bytes.Buffer)
if err := coreTemplate.Execute(b, d); err != nil {
b.Reset()
fmt.Fprintf(b, "parse error on retrieving core files: %v", err)
}
return b.String()
}

func registerAfter(e *eventlis.AfterTestsEvent) error {
cores := validator.stop()
foundCores := false
for _, files := range cores {
if len(files.Files) > 0 {
foundCores = true
break
}
}
report := createReport(cores)
msg := fmt.Sprintf("core file check found cores:\n%s", report)
glog.Infof(msg)
ondatra.Report().AddSuiteProperty("validator.core.end", report)
if foundCores {
return fmt.Errorf(msg)
}
return nil
}

// Register will register core file watcher with the caller.
// This will allow the event listener to fire on test module start and end.
// All DUTs in the reservation will be monitored.
func Register() {
validator = validatorImpl{
duts: map[string]*checker{},
}
ondatra.EventListener().AddBeforeTestsCallback(registerBefore)
ondatra.EventListener().AddAfterTestsCallback(registerAfter)
}

// coreFileCheck function is used to check if cores are found on the DUT.
func (c *checker) checkCores() (coreFiles, error) {
dutVendor := c.dut.Vendor()
corePath := vendorCoreFilePath[dutVendor]
fileMatch := vendorCoreFileNamePattern[dutVendor]
in := &fpb.StatRequest{
Path: corePath,
}
validResponse, err := c.fileClient.Stat(context.Background(), in)
if err != nil {
return nil, fmt.Errorf("DUT %q: %w", corePath, err)
}
cores := coreFiles{}
// Check cores creation time is greater than test start time.
for _, fileStatsInfo := range validResponse.GetStats() {
// Get the exact file.
in = &fpb.StatRequest{
Path: fileStatsInfo.GetPath(),
}
validResponse, err := c.fileClient.Stat(context.Background(), in)
if err != nil {
return nil, fmt.Errorf("DUT %q: unable to stat file %q, %v", c.dut.Name(), fileStatsInfo.GetPath(), err)
}
for _, filesMatched := range validResponse.GetStats() {
coreFileName := filesMatched.GetPath()
if fileMatch.MatchString(coreFileName) {
cores[coreFileName] = fileInfo{
Name: coreFileName,
Modified: fileStatsInfo.GetLastModified(),
}
}
}
}
return cores, nil
}
Loading

0 comments on commit f36af19

Please sign in to comment.