Skip to content

Commit

Permalink
fix: Upgrade to Go 1.21, test Kubernetes 1.25-1.28, refine engine & CLI
Browse files Browse the repository at this point in the history
* Perform compatibility tests with Kubernetes versions 1.25 to 1.28
* Transition to using Go version 1.21
* Update end-to-end tests for the latest GKE and EKS versions, including various CNIs
* Rectify a critical bug in the engine which led to delays post parent context cancellation
* Refactor CLI for precise association of command line flags with their intended subcommands
  • Loading branch information
prit342 committed Nov 26, 2023
1 parent 19cfdf9 commit 1db0f06
Show file tree
Hide file tree
Showing 34 changed files with 5,307 additions and 181 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
- name: Run golangci-lint
uses: reviewdog/action-golangci-lint@v2
with:
go_version: "1.20"
go_version: "1.21"
build:
runs-on: ubuntu-latest
needs: lint
Expand All @@ -31,7 +31,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v3
with:
go-version: '1.20.x'
go-version: '1.21.x'

- name: Install dependencies
run: go get ./...
Expand Down
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,19 @@ All notable changes to this project will be documented in this file.

## Table of Contents

- [2.0.3](#203)
- [2.0.2](#202)
- [2.0.1](#201)
- [2.0.0](#200)
- [0.1.0](#010)

---

## `2.0.3`

- test with latest version of Kubernetes and update to Go 1.21
- update e2e tests with latest version of EKS and GKE and Calico CNI

## `2.0.2`

- integrate e2e tests with network policies
Expand All @@ -31,4 +37,4 @@ All notable changes to this project will be documented in this file.
## `0.1.0`

- initial release
- no artifacts available
- no artifacts available
51 changes: 31 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,13 @@ The [`sniffer`](https://github.com/controlplaneio/netassertv2-packet-sniffer) an

## Installation

Download the latest stable version of `NetAssert` from the [releases](https://github.com/controlplaneio/netassert/releases) page
- Please download the latest stable version of `NetAssert` from [releases](https://github.com/controlplaneio/netassert/releases) page. The binary is available for Linux, MacOS and Windows platforms.

- If you are on Unix/Linux, you can also use the [download.sh](./download.sh) script to download the latest version of `NetAssert` into the current path:

```bash
curl -sL https://raw.githubusercontent.com/controlplaneio/netassert/master/download.sh | bash
```

## Test specification

Expand Down Expand Up @@ -257,37 +263,42 @@ All the tests are read from an YAML file or a directory (step **1**) and the res
statefulset.apps/web created
```

- Run the netassert binary pointing it to the test cases:
- Run the netassert binary pointing it to the test cases, one of the test cases will fail and this is by design:

```bash
❯ ./netassert run --input-file cmd/netassert/cli/test-cases.yaml
## if you have Go installed, you can build the binary using the the following command
❯ just build ## from the root of the project
go build -ldflags="-X 'main.appName=NetAssert' -X 'main.version=2.0.0-dev'" -o bin/netassert cmd/netassert/cli/*.go

❯ cat results.tap
1..4
❯ bin/netassert run --input-file ./sample-tests/test-cases/test-cases.yaml

❯ cat results.tap
TAP version 14
1..6
ok 1 - busybox-deploy-to-echoserver-deploy
ok 2 - busybox-deploy-to-core-dns
ok 3 - test-from-busybox-to-web-statefulset
not ok 4 - test-from-busybox-to-host
ok 2 - busybox-deploy-to-echoserver-deploy-2
ok 3 - busybox-deploy-to-web-statefulset
ok 4 - busybox-deploy-to-control-plane-dot-io
ok 5 - test-from-pod1-to-pod2
not ok 6 - busybox-deploy-to-fake-host
---
reason: ephemeral container netassertv2-client-u8dqy3qwo exit code for test test-from-busybox-to-host
reason: ephemeral container netassertv2-client-7y16ra1f9 exit code for test busybox-deploy-to-fake-host
is 1 instead of 0
...


```

## Compatibility

Netassert has been tested with the following flavours of Kubernetes:
NetAssert is architected for compatibility with Kubernetes versions that offer support for ephemeral containers. We have thoroughly tested NetAssert with Kubernetes versions 1.25 to 1.28, confirming compatibility and performance stability.

For broader validation, our team has also executed comprehensive [end-to-end tests](./e2e/README.md) against various Kubernetes distributions and CNIs which is detailed below:

| K8s Distribution | Version | CNI | Working |
|------------------|---------|---------------------------------|---------|
| AWS EKS | 1.25 | AWS VPC CNI | Yes |
| AWS EKS | 1.24 | AWS VPC CNI | Yes |
| AWS EKS | 1.25 | Calico Version 3.25 | Yes |
| AWS EKS | 1.24 | Calico version 3.25 | Yes |
| GCP GKE | 1.24 | GCP VPC CNI | Yes |
| GCP GKE | 1.24 | GCP Cilium 1.11 (Dataplane v2) | Yes |
| Kubernetes Distribution | Supported Version | Container Network Interface (CNI) |
|-------------------------|-------------------|------------------------------------
| Amazon EKS | 1.25 and higher | AWS VPC CNI |
| Amazon EKS | 1.25 and higher | Calico (Version 3.25 or later) |
| Google GKE | 1.24 and higher | Google Cloud Platform VPC CNI |
| Google GKE | 1.24 and higher | Google Cloud Dataplane V2 |

## Checking for ephemeral container support

Expand Down
11 changes: 6 additions & 5 deletions cmd/netassert/cli/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import (

"github.com/controlplaneio/netassert/v2/internal/data"
"github.com/controlplaneio/netassert/v2/internal/kubeops"
"github.com/hashicorp/go-hclog"
)

// loadTestCases - Reads test from a file or Directory
func loadTestCases() (data.Tests, error) {
func loadTestCases(testCasesFile, testCasesDir string) (data.Tests, error) {
if testCasesFile == "" && testCasesDir == "" {
return nil, errors.New("either an input file or an input dir containing the tests must be provided using " +
"flags (--input-file or --input-dir)")
Expand All @@ -35,11 +36,11 @@ func loadTestCases() (data.Tests, error) {
}

// createService - creates a new kubernetes operations service
func createService() (*kubeops.Service, error) {
func createService(kubeconfigPath string, l hclog.Logger) (*kubeops.Service, error) {
// if the user has supplied a kubeConfig file location then
if kubeConfig != "" {
return kubeops.NewServiceFromKubeConfigFile(kubeConfig, lg)
if kubeconfigPath != "" {
return kubeops.NewServiceFromKubeConfigFile(kubeconfigPath, l)
}

return kubeops.NewDefaultService(lg)
return kubeops.NewDefaultService(l)
}
6 changes: 4 additions & 2 deletions cmd/netassert/cli/gen_result.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import (
"fmt"
"os"

"github.com/hashicorp/go-hclog"

"github.com/controlplaneio/netassert/v2/internal/data"
)

// genResult - Prints results to Stdout and writes it to a Tap file
func genResult(testCases data.Tests) error {
func genResult(testCases data.Tests, tapFile string, lg hclog.Logger) error {
failedTestCases := 0

for _, v := range testCases {
Expand All @@ -35,7 +37,7 @@ func genResult(testCases data.Tests) error {
return fmt.Errorf("unable to close tap file %q: %w", tapFile, err)
}

lg.Info("✍ Wrote TAP File", "fileName", tapFile)
lg.Info("✍ Wrote test result in a TAP File", "fileName", tapFile)

if failedTestCases > 0 {
return fmt.Errorf("total %v test cases have failed", failedTestCases)
Expand Down
45 changes: 33 additions & 12 deletions cmd/netassert/cli/ping.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,51 @@ package main

import (
"context"
"fmt"
"os"
"time"

"github.com/spf13/cobra"

"github.com/controlplaneio/netassert/v2/internal/logger"
)

const (
apiServerHealthEndpoint = `/healthz` // health endpoint for the K8s server
)

// health endpoint for the K8s server
var apiServerHealthEndpoint = `/healthz`
type pingCmdConfig struct {
KubeConfig string
PingTimeout time.Duration
}

var pingCmdCfg = pingCmdConfig{}

var pingCmd = &cobra.Command{
Use: "ping",
Short: "pings the K8s API server over HTTP to see if it is alive and also checks if the server has support for " +
"ephemeral containers",
Long: "pings the K8s API server over HTTP to see if it is alive and also checks if the server has support for " +
"ephemeral/debug containers",
Short: "pings the K8s API server over HTTP(S) to see if it is alive and also checks if the server has support for " +
"ephemeral containers.",
Long: "pings the K8s API server over HTTP(S) to see if it is alive and also checks if the server has support for " +
"ephemeral/debug containers.",
Run: func(cmd *cobra.Command, args []string) {
ping()
ctx, cancel := context.WithTimeout(context.Background(), pingCmdCfg.PingTimeout)
defer cancel()
ping(ctx)
},
Version: rootCmd.Version,
}

// checkEphemeralContainerSupport checks to see if ephemeral containers are supported by the K8s server
func ping() {
k8sSvc, err := createService()
func ping(ctx context.Context) {
lg := logger.NewHCLogger("info", fmt.Sprintf("%s-%s", appName, version), os.Stdout)

k8sSvc, err := createService(pingCmdCfg.KubeConfig, lg)

if err != nil {
lg.Error("Failed to build K8s Client", "error", err)
lg.Error("Ping failed, unable to build K8s Client", "error", err)
os.Exit(1)
}

ctx := context.Background()

if err := k8sSvc.PingHealthEndpoint(ctx, apiServerHealthEndpoint); err != nil {
lg.Error("Ping failed", "error", err)
os.Exit(1)
Expand All @@ -47,3 +62,9 @@ func ping() {

lg.Info("✅ Ephemeral containers are supported by the Kubernetes server")
}

func init() {
pingCmd.Flags().DurationVarP(&pingCmdCfg.PingTimeout, "timeout", "t", 60*time.Second,
"Timeout for the ping command")
pingCmd.Flags().StringVarP(&pingCmdCfg.KubeConfig, "kubeconfig", "k", "", "path to kubeconfig file")
}
29 changes: 5 additions & 24 deletions cmd/netassert/cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,30 @@ package main

import (
"fmt"
"os"

"github.com/controlplaneio/netassert/v2/internal/logger"
"github.com/hashicorp/go-hclog"
"github.com/spf13/cobra"
)

var (
logLevel string // our log leve
lg hclog.Logger // command logger
kubeConfig string // location of kubeconfig file
testCasesFile string // location of test cases file
testCasesDir string // location of directory containing the test cases
version = "v2.0.0-dev" // netassert version
appName = "NetAssert" // name of the application
gitHash = "" // the git hash of the build
buildDate = "" // build date, will be injected by the build system
version = "v2.0.0-dev" // netassert version
appName = "NetAssert" // name of the application
gitHash = "" // the git hash of the build
buildDate = "" // build date, will be injected by the build system
)

var rootCmd = &cobra.Command{
Use: "netassert",
Short: "NetAssert is a command line utility to test network connectivity between kubernetes objects",
Long: "NetAssert is a command line utility to test network connectivity between kubernetes objects. " +
"It currently supports Deployment, Pod, Statefulset and Daemonset. You can check the traffic flow between these objects or from these " +
"objects to a remote host or an IP address",
"objects to a remote host or an IP address.",

PersistentPreRun: initCommon,
Version: fmt.Sprintf("\nNetAssert by control-plane.io\n"+
"Version: %s\nCommit Hash: %s\nBuild Date: %s\n",
version, gitHash, buildDate),
}

// init the logger and log basic app info
func initCommon(cmd *cobra.Command, args []string) {
lg = logger.NewHCLogger(logLevel, fmt.Sprintf("%s-%s", appName, version), os.Stdout)
}

func init() {
rootCmd.PersistentFlags().StringVarP(&kubeConfig, "kubeconfig", "k", kubeConfig, "kubeconfig path")
rootCmd.PersistentFlags().StringVarP(&testCasesFile, "input-file", "f", "", "input test file that contains a list of netassert tests")
rootCmd.PersistentFlags().StringVarP(&testCasesDir, "input-dir", "d", "", "input test directory that contains a list of netassert test files")
rootCmd.PersistentFlags().StringVarP(&logLevel, "log-level", "l", "info", "set log level (info, debug or trace)")

// add our subcommands
rootCmd.AddCommand(runCmd)
rootCmd.AddCommand(validateCmd)
Expand Down
Loading

0 comments on commit 1db0f06

Please sign in to comment.