Skip to content

Commit

Permalink
add containers log saver extension
Browse files Browse the repository at this point in the history
Signed-off-by: Anatoly Loskutnikov <anatoly.loskutnikov@gmail.com>
  • Loading branch information
Tiberivs committed Mar 15, 2021
1 parent 3847bff commit 3b85327
Show file tree
Hide file tree
Showing 6 changed files with 554 additions and 8 deletions.
18 changes: 13 additions & 5 deletions extensions/base/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,25 @@ package base

import (
"github.com/networkservicemesh/integration-tests/extensions/checkout"
"github.com/networkservicemesh/integration-tests/extensions/logs"
"github.com/networkservicemesh/integration-tests/extensions/multisuite"
)

// Suite is a base suite for generating tests. Contains extensions that can be used for assertion and automation goals.
type Suite struct {
checkout.Suite
// Add other extensions here
*multisuite.Suite
}

func (s *Suite) SetupSuite() {
s.Repository = "networkservicemesh/deployments-k8s"
s.Version = "25830bce"
s.Dir = "../" // Note: this should be synced with input parameters in gen.go file
// Add other extensions here
s.Suite.WithSuits(
logs.Suite{},
checkout.Suite{
Repository: "networkservicemesh/deployments-k8s",
Version: "25830bce",
Dir: "../", // Note: this should be synced with input parameters in gen.go file
})

s.Suite.SetT(s.T())
s.Suite.SetupSuite()
}
1 change: 1 addition & 0 deletions extensions/checkout/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
// Suite clones the repository if it is not presented on the running file system.
type Suite struct {
shell.Suite

Repository string
Dir string
Version string
Expand Down
132 changes: 132 additions & 0 deletions extensions/logs/suite.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// Copyright (c) 2021 Doc.ai and/or its affiliates.
//
// SPDX-License-Identifier: Apache-2.0
//
// 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 logs

import (
"context"
"flag"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"time"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"

"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
)

var logContextTimeoutFlag = flag.String("log-context-timeout", "15s",
"log context timeout")
var logDirFlag = flag.String("log-dir", "logs",
"container logs directory")
var ignoreNamespaceFlag = flag.String("ignore-k8s-ns", "kube-system,local-path-storage",
"comma separated list of ignored kubernetes namespaces")

type Suite struct {
suite.Suite

testStartTime time.Time
ctxTimeout time.Duration
kubeClient kubernetes.Interface
}

func (s *Suite) SetupSuite() {
var err error

s.ctxTimeout, err = time.ParseDuration(*logContextTimeoutFlag)
require.NoError(s.T(), err)
require.Greater(s.T(), s.ctxTimeout, 0)

s.kubeClient, err = newKubeClient()
require.NoError(s.T(), err)
}

func (s *Suite) SetupTest() {
s.testStartTime = time.Now()
}

func (s *Suite) AfterTest(suiteName, testName string) {
logPath := fmt.Sprintf("%s/%s/%s", *logDirFlag, suiteName, testName)
require.NoError(s.T(), os.MkdirAll(logPath, os.ModePerm))

logOptions := corev1.PodLogOptions{
Timestamps: true,
SinceTime: &metav1.Time{Time: s.testStartTime},
}

ctx, cancel := context.WithTimeout(context.Background(), s.ctxTimeout)
defer cancel()

list, err := s.kubeClient.CoreV1().Namespaces().List(ctx, metav1.ListOptions{})
require.NoError(s.T(), err)

for nsIdx := range list.Items {
ns := &list.Items[nsIdx]

if isIgnoredNamespace(ns.Name) {
continue
}

pods, err := s.kubeClient.CoreV1().Pods(ns.Name).List(ctx, metav1.ListOptions{})
require.NoError(s.T(), err)

for podIdx := range pods.Items {
pod := &pods.Items[podIdx]

data, err := s.kubeClient.CoreV1().Pods(ns.Name).GetLogs(pod.Name, &logOptions).DoRaw(ctx)
require.NoError(s.T(), err)

if len(data) > 0 {
logFile := fmt.Sprintf("%s/%s.log", logPath, pod.Name)
require.NoError(s.T(), ioutil.WriteFile(logFile, data, os.ModePerm))
}
}
}
}

// newKubeClient creates new k8s client
func newKubeClient() (kubernetes.Interface, error) {
path := os.Getenv("KUBECONFIG")

if path == "" {
path = filepath.Join(os.Getenv("HOME"), ".kube", "config")
}

config, err := clientcmd.BuildConfigFromFlags("", path)
if err != nil {
return nil, err
}

return kubernetes.NewForConfig(config)
}

func isIgnoredNamespace(ns string) bool {
ignoreList := strings.Split(*ignoreNamespaceFlag, `,`)
for _, ignored := range ignoreList {
if ns == ignored {
return true
}
}

return false
}
95 changes: 95 additions & 0 deletions extensions/multisuite/suite.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright (c) 2021 Doc.ai and/or its affiliates.
//
// SPDX-License-Identifier: Apache-2.0
//
// 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 multisuite

import (
"testing"

"github.com/stretchr/testify/suite"

"github.com/networkservicemesh/gotestmd/pkg/suites/shell"
)

type Suite struct {
shell.Suite

suits []interface{}
}

func (s *Suite) WithSuits(ifaces ...interface{}) {
s.suits = make([]interface{}, len(ifaces))
for i := range ifaces {
s.suits[i] = ifaces[i]
}
}

func (s *Suite) SetT(t *testing.T) {
s.Suite.SetT(t)
for _, p := range s.suits {
if v, ok := p.(suite.TestingSuite); ok {
v.SetT(t)
}
}
}

func (s *Suite) SetupSuite() {
for _, p := range s.suits {
if v, ok := p.(suite.SetupAllSuite); ok {
v.SetupSuite()
}
}
}

func (s *Suite) SetupTest() {
for _, p := range s.suits {
if v, ok := p.(suite.SetupTestSuite); ok {
v.SetupTest()
}
}
}

func (s *Suite) TearDownSuite() {
for _, p := range s.suits {
if v, ok := p.(suite.TearDownAllSuite); ok {
v.TearDownSuite()
}
}
}

func (s *Suite) TearDownTest() {
for _, p := range s.suits {
if v, ok := p.(suite.TearDownTestSuite); ok {
v.TearDownTest()
}
}
}

func (s *Suite) BeforeTest(suiteName, testName string) {
for _, p := range s.suits {
if v, ok := p.(suite.BeforeTest); ok {
v.BeforeTest(suiteName, testName)
}
}
}

func (s *Suite) AfterTest(suiteName, testName string) {
for _, p := range s.suits {
if v, ok := p.(suite.AfterTest); ok {
v.AfterTest(suiteName, testName)
}
}
}
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@ require (
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/stretchr/testify v1.6.1
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 // indirect
k8s.io/api v0.19.4
k8s.io/apimachinery v0.19.4
k8s.io/client-go v0.19.4
)
Loading

0 comments on commit 3b85327

Please sign in to comment.