7
.prow.sh
Executable file
7
.prow.sh
Executable file
@@ -0,0 +1,7 @@
|
||||
#! /bin/bash -e
|
||||
#
|
||||
# This is for testing csi-release-tools itself in Prow. All other
|
||||
# repos use prow.sh for that, but as csi-release-tools isn't a normal
|
||||
# repo with some Go code in it, it has a custom Prow test script.
|
||||
|
||||
./verify-shellcheck.sh "$(pwd)"
|
45
README.md
45
README.md
@@ -61,3 +61,48 @@ errors shell scripts, like missing quotation marks. The default
|
||||
`test-shellcheck` target in [build.make](./build.make) only checks the
|
||||
scripts in this directory. Components can add more directories to
|
||||
`TEST_SHELLCHECK_DIRS` to check also other scripts.
|
||||
|
||||
End-to-end testing
|
||||
------------------
|
||||
|
||||
A repo that wants to opt into testing via Prow must set up a top-level
|
||||
`.prow.sh`. Typically that will source `prow.sh` and then transfer
|
||||
control to it:
|
||||
|
||||
``` bash
|
||||
#! /bin/bash -e
|
||||
|
||||
. release-tools/prow.sh
|
||||
main
|
||||
```
|
||||
|
||||
All Kubernetes-CSI repos are expected to switch to Prow. For details
|
||||
on what is enabled in Prow, see
|
||||
https://github.com/kubernetes/test-infra/tree/master/config/jobs/kubernetes-csi
|
||||
|
||||
Test results for periodic jobs are visible in
|
||||
https://testgrid.k8s.io/sig-storage-csi
|
||||
|
||||
It is possible to reproduce the Prow testing locally on a suitable machine:
|
||||
- Linux host
|
||||
- Docker installed
|
||||
- code to be tested checkout out in `$GOPATH/src/<import path>`
|
||||
- `cd $GOPATH/src/<import path> && ./.prow.sh`
|
||||
|
||||
Beware that the script intentionally doesn't clean up after itself and
|
||||
modifies the content of `$GOPATH`, in particular the `kubernetes` and
|
||||
`kind` repositories there. Better run it in an empty, disposable
|
||||
`$GOPATH`.
|
||||
|
||||
When it terminates, the following command can be used to get access to
|
||||
the Kubernetes cluster that was brought up for testing (assuming that
|
||||
this step succeeded):
|
||||
|
||||
export KUBECONFIG="$(kind get kubeconfig-path --name="csi-prow")"
|
||||
|
||||
It is possible to control the execution via environment variables. See
|
||||
`prow.sh` for details. Particularly useful is testing against different
|
||||
Kubernetes releases:
|
||||
|
||||
CSI_PROW_KUBERNETES_VERSION=1.13.3 ./.prow.sh
|
||||
CSI_PROW_KUBERNETES_VERSION=latest ./.prow.sh
|
||||
|
133
filter-junit.go
Normal file
133
filter-junit.go
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This command filters a JUnit file such that only tests with a name
|
||||
* matching a regular expression are passed through. By concatenating
|
||||
* multiple input files it is possible to merge them into a single file.
|
||||
*/
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"flag"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
var (
|
||||
output = flag.String("o", "-", "junit file to write, - for stdout")
|
||||
tests = flag.String("t", "", "regular expression matching the test names that are to be included in the output")
|
||||
)
|
||||
|
||||
/*
|
||||
* TestSuite represents a JUnit file. Due to how encoding/xml works, we have
|
||||
* represent all fields that we want to be passed through. It's therefore
|
||||
* not a complete solution, but good enough for Ginkgo + Spyglass.
|
||||
*/
|
||||
type TestSuite struct {
|
||||
XMLName string `xml:"testsuite"`
|
||||
TestCases []TestCase `xml:"testcase"`
|
||||
}
|
||||
|
||||
type TestCase struct {
|
||||
Name string `xml:"name,attr"`
|
||||
Time string `xml:"time,attr"`
|
||||
SystemOut string `xml:"system-out,omitempty"`
|
||||
Failure string `xml:"failure,omitempty"`
|
||||
Skipped SkipReason `xml:"skipped,omitempty"`
|
||||
}
|
||||
|
||||
// SkipReason deals with the special <skipped></skipped>:
|
||||
// if present, we must re-encode it, even if empty.
|
||||
type SkipReason string
|
||||
|
||||
func (s *SkipReason) UnmarshalText(text []byte) error {
|
||||
*s = SkipReason(text)
|
||||
if *s == "" {
|
||||
*s = " "
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s SkipReason) MarshalText() ([]byte, error) {
|
||||
if s == " " {
|
||||
return []byte{}, nil
|
||||
}
|
||||
return []byte(s), nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
var junit TestSuite
|
||||
var data []byte
|
||||
|
||||
flag.Parse()
|
||||
|
||||
re := regexp.MustCompile(*tests)
|
||||
|
||||
// Read all input files.
|
||||
for _, input := range flag.Args() {
|
||||
if input == "-" {
|
||||
if _, err := os.Stdin.Read(data); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
var err error
|
||||
data, err = ioutil.ReadFile(input)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
if err := xml.Unmarshal(data, &junit); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Keep only matching testcases. Testcases skipped in all test runs are only stored once.
|
||||
filtered := map[string]TestCase{}
|
||||
for _, testcase := range junit.TestCases {
|
||||
if !re.MatchString(testcase.Name) {
|
||||
continue
|
||||
}
|
||||
entry, ok := filtered[testcase.Name]
|
||||
if !ok || // not present yet
|
||||
entry.Skipped != "" && testcase.Skipped == "" { // replaced skipped test with real test run
|
||||
filtered[testcase.Name] = testcase
|
||||
}
|
||||
}
|
||||
junit.TestCases = nil
|
||||
for _, testcase := range filtered {
|
||||
junit.TestCases = append(junit.TestCases, testcase)
|
||||
}
|
||||
|
||||
// Re-encode.
|
||||
data, err := xml.MarshalIndent(junit, "", " ")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Write to output.
|
||||
if *output == "-" {
|
||||
if _, err := os.Stdout.Write(data); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
if err := ioutil.WriteFile(*output, data, 0644); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
945
prow.sh
Executable file
945
prow.sh
Executable file
@@ -0,0 +1,945 @@
|
||||
#! /bin/bash
|
||||
#
|
||||
# Copyright 2019 The Kubernetes Authors.
|
||||
#
|
||||
# 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.
|
||||
|
||||
|
||||
# This script runs inside a Prow job. It can run unit tests ("make test")
|
||||
# and E2E testing. This E2E testing covers different scenarios (see
|
||||
# https://github.com/kubernetes/enhancements/pull/807):
|
||||
# - running the stable hostpath example against a Kubernetes release
|
||||
# - running the canary hostpath example against a Kubernetes release
|
||||
# - building the component in the current repo and running the
|
||||
# stable hostpath example with that one component replaced against
|
||||
# a Kubernetes release
|
||||
#
|
||||
# The intended usage of this script is that individual repos import
|
||||
# csi-release-tools, then link their top-level prow.sh to this or
|
||||
# include it in that file. When including it, several of the variables
|
||||
# can be overridden in the top-level prow.sh to customize the script
|
||||
# for the repo.
|
||||
#
|
||||
# The expected environment is:
|
||||
# - $GOPATH/src/<import path> for the repository that is to be tested,
|
||||
# with PR branch merged (when testing a PR)
|
||||
# - running on linux-amd64
|
||||
# - bazel installed (when testing against Kubernetes master), must be recent
|
||||
# enough for Kubernetes master
|
||||
# - kind (https://github.com/kubernetes-sigs/kind) installed
|
||||
# - optional: Go already installed
|
||||
|
||||
RELEASE_TOOLS_ROOT="$(realpath "$(dirname "${BASH_SOURCE[0]}")")"
|
||||
REPO_DIR="$(pwd)"
|
||||
|
||||
# Sets the default value for a variable if not set already and logs the value.
|
||||
# Any variable set this way is usually something that a repo's .prow.sh
|
||||
# or the job can set.
|
||||
configvar () {
|
||||
# Ignore: Word is of the form "A"B"C" (B indicated). Did you mean "ABC" or "A\"B\"C"?
|
||||
# shellcheck disable=SC2140
|
||||
eval : \$\{"$1":="\$2"\}
|
||||
eval echo "\$3:" "$1=\${$1}"
|
||||
}
|
||||
|
||||
# Prints the value of a variable + version suffix, falling back to variable + "LATEST".
|
||||
get_versioned_variable () {
|
||||
local var="$1"
|
||||
local version="$2"
|
||||
local value
|
||||
|
||||
eval value="\${${var}_${version}}"
|
||||
if ! [ "$value" ]; then
|
||||
eval value="\${${var}_LATEST}"
|
||||
fi
|
||||
echo "$value"
|
||||
}
|
||||
|
||||
# Go versions can be specified seperately for different tasks
|
||||
# If the pre-installed Go is missing or a different
|
||||
# version, the required version here will get installed
|
||||
# from https://golang.org/dl/.
|
||||
go_from_travis_yml () {
|
||||
grep "^ *- go:" "${RELEASE_TOOLS_ROOT}/travis.yml" | sed -e 's/.*go: *//'
|
||||
}
|
||||
configvar CSI_PROW_GO_VERSION_BUILD "$(go_from_travis_yml)" "Go version for building the component" # depends on component's source code
|
||||
configvar CSI_PROW_GO_VERSION_E2E "" "override Go version for building the Kubernetes E2E test suite" # normally doesn't need to be set, see install_e2e
|
||||
configvar CSI_PROW_GO_VERSION_SANITY "${CSI_PROW_GO_VERSION_BUILD}" "Go version for building the csi-sanity test suite" # depends on CSI_PROW_SANITY settings below
|
||||
configvar CSI_PROW_GO_VERSION_KIND "${CSI_PROW_GO_VERSION_BUILD}" "Go version for building 'kind'" # depends on CSI_PROW_KIND_VERSION below
|
||||
configvar CSI_PROW_GO_VERSION_GINKGO "${CSI_PROW_GO_VERSION_BUILD}" "Go version for building ginkgo" # depends on CSI_PROW_GINKGO_VERSION below
|
||||
|
||||
# kind version to use. If the pre-installed version is different,
|
||||
# the desired version is downloaded from https://github.com/kubernetes-sigs/kind/releases/download/
|
||||
# (if available), otherwise it is built from source.
|
||||
configvar CSI_PROW_KIND_VERSION 0.2.1 "kind"
|
||||
|
||||
# ginkgo test runner version to use. If the pre-installed version is
|
||||
# different, the desired version is built from source.
|
||||
configvar CSI_PROW_GINKGO_VERSION v1.7.0 "Ginkgo"
|
||||
|
||||
# Ginkgo runs the E2E test in parallel. The default is based on the number
|
||||
# of CPUs, but typically this can be set to something higher in the job.
|
||||
configvar CSI_PROW_GINKO_PARALLEL "-p" "Ginko parallelism parameter(s)"
|
||||
|
||||
# Enables building the code in the repository. On by default, can be
|
||||
# disabled in jobs which only use pre-built components.
|
||||
configvar CSI_PROW_BUILD_JOB true "building code in repo enabled"
|
||||
|
||||
# Kubernetes version to test against. This must be a version number
|
||||
# (like 1.13.3) for which there is a pre-built kind image (see
|
||||
# https://hub.docker.com/r/kindest/node/tags), "latest" (builds
|
||||
# Kubernetes from the master branch) or "release-x.yy" (builds
|
||||
# Kubernetes from a release branch).
|
||||
#
|
||||
# This can also be a version that was not released yet at the time
|
||||
# that the settings below were chose. The script will then
|
||||
# use the same settings as for "latest" Kubernetes. This works
|
||||
# as long as there are no breaking changes in Kubernetes, like
|
||||
# deprecating or changing the implementation of an alpha feature.
|
||||
configvar CSI_PROW_KUBERNETES_VERSION 1.13.3 "Kubernetes"
|
||||
|
||||
# CSI_PROW_KUBERNETES_VERSION reduced to first two version numbers and
|
||||
# with underscore (1_13 instead of 1.13.3) and in uppercase (LATEST
|
||||
# instead of latest).
|
||||
#
|
||||
# This is used to derive the right defaults for the variables below
|
||||
# when a Prow job just defines the Kubernetes version.
|
||||
csi_prow_kubernetes_version_suffix="$(echo "${CSI_PROW_KUBERNETES_VERSION}" | tr . _ | tr '[:lower:]' '[:upper:]' | sed -e 's/^RELEASE-//' -e 's/\([0-9]*\)_\([0-9]*\).*/\1_\2/')"
|
||||
|
||||
# Work directory. It has to allow running executables, therefore /tmp
|
||||
# is avoided. Cleaning up after the script is intentionally left to
|
||||
# the caller.
|
||||
configvar CSI_PROW_WORK "$(mkdir -p "$GOPATH/pkg" && mktemp -d "$GOPATH/pkg/csiprow.XXXXXXXXXX")" "work directory"
|
||||
|
||||
# The hostpath deployment script is searched for in several places.
|
||||
#
|
||||
# - The "deploy" directory in the current repository: this is useful
|
||||
# for the situation that a component becomes incompatible with the
|
||||
# shared deployment, because then it can (temporarily!) provide its
|
||||
# own example until the shared one can be updated; it's also how
|
||||
# csi-driver-host-path itself provides the example.
|
||||
#
|
||||
# - CSI_PROW_HOSTPATH_VERSION of the CSI_PROW_HOSTPATH_REPO is checked
|
||||
# out: this allows other repos to reference a version of the example
|
||||
# that is known to be compatible.
|
||||
#
|
||||
# - The csi-driver-host-path/deploy directory has multiple sub-directories,
|
||||
# each with different deployments (stable set of images for Kubernetes 1.13,
|
||||
# stable set of images for Kubernetes 1.14, canary for latest Kubernetes, etc.).
|
||||
# This is necessary because there may be incompatible changes in the
|
||||
# "API" of a component (for example, its command line options or RBAC rules)
|
||||
# or in its support for different Kubernetes versions (CSIDriverInfo as
|
||||
# CRD in Kubernetes 1.13 vs builtin API in Kubernetes 1.14).
|
||||
#
|
||||
# When testing an update for a component in a PR job, the
|
||||
# CSI_PROW_DEPLOYMENT variable can be set in the
|
||||
# .prow.sh of each component when there are breaking changes
|
||||
# that require using a non-default deployment. The default
|
||||
# is a deployment named "kubernetes-x.yy" (if available),
|
||||
# otherwise "kubernetes-latest".
|
||||
# "none" disables the deployment of the hostpath driver.
|
||||
#
|
||||
# When no deploy script is found (nothing in `deploy` directory,
|
||||
# CSI_PROW_HOSTPATH_REPO=none), nothing gets deployed.
|
||||
configvar CSI_PROW_HOSTPATH_VERSION 486074dc3beef59955faf7bb5210418d9844e0a7 "hostpath driver" # pre-1.1.0
|
||||
configvar CSI_PROW_HOSTPATH_REPO https://github.com/kubernetes-csi/csi-driver-host-path "hostpath repo"
|
||||
configvar CSI_PROW_DEPLOYMENT "" "deployment"
|
||||
|
||||
# If CSI_PROW_HOSTPATH_CANARY is set (typically to "canary", but also
|
||||
# "1.0-canary"), then all image versions are replaced with that
|
||||
# version tag.
|
||||
configvar CSI_PROW_HOSTPATH_CANARY "" "hostpath image"
|
||||
|
||||
# The E2E testing can come from an arbitrary repo. The expectation is that
|
||||
# the repo supports "go test ./test/e2e -args --storage.testdriver" (https://github.com/kubernetes/kubernetes/pull/72836)
|
||||
# after setting KUBECONFIG. As a special case, if the repository is Kubernetes,
|
||||
# then `make WHAT=test/e2e/e2e.test` is called first to ensure that
|
||||
# all generated files are present.
|
||||
#
|
||||
# CSI_PROW_E2E_REPO=none disables E2E testing.
|
||||
configvar CSI_PROW_E2E_VERSION_1_13 v1.14.0 "E2E version for Kubernetes 1.13.x" # we can't use the one from 1.13.x because it didn't have --storage.testdriver
|
||||
configvar CSI_PROW_E2E_VERSION_1_14 v1.14.0 "E2E version for Kubernetes 1.14.x"
|
||||
# TODO: add new CSI_PROW_E2E_VERSION entry for future Kubernetes releases
|
||||
configvar CSI_PROW_E2E_VERSION_LATEST master "E2E version for Kubernetes master" # testing against Kubernetes master is already tracking a moving target, so we might as well use a moving E2E version
|
||||
configvar CSI_PROW_E2E_REPO_LATEST https://github.com/kubernetes/kubernetes "E2E repo for Kubernetes >= 1.13.x" # currently the same for all versions
|
||||
configvar CSI_PROW_E2E_IMPORT_PATH_LATEST k8s.io/kubernetes "E2E package for Kubernetes >= 1.13.x" # currently the same for all versions
|
||||
configvar CSI_PROW_E2E_VERSION "$(get_versioned_variable CSI_PROW_E2E_VERSION "${csi_prow_kubernetes_version_suffix}")" "E2E version"
|
||||
configvar CSI_PROW_E2E_REPO "$(get_versioned_variable CSI_PROW_E2E_REPO "${csi_prow_kubernetes_version_suffix}")" "E2E repo"
|
||||
configvar CSI_PROW_E2E_IMPORT_PATH "$(get_versioned_variable CSI_PROW_E2E_IMPORT_PATH "${csi_prow_kubernetes_version_suffix}")" "E2E package"
|
||||
|
||||
# csi-sanity testing from the csi-test repo can be run against the installed
|
||||
# CSI driver. For this to work, deploying the driver must expose the Unix domain
|
||||
# csi.sock as a TCP service for use by the csi-sanity command, which runs outside
|
||||
# of the cluster. The alternative would have been to (cross-)compile csi-sanity
|
||||
# and install it inside the cluster, which is not necessarily easier.
|
||||
configvar CSI_PROW_SANITY_REPO https://github.com/kubernetes-csi/csi-test "csi-test repo"
|
||||
configvar CSI_PROW_SANITY_VERSION 5421d9f3c37be3b95b241b44a094a3db11bee789 "csi-test version" # latest master
|
||||
configvar CSI_PROW_SANITY_IMPORT_PATH github.com/kubernetes-csi/csi-test "csi-test package"
|
||||
configvar CSI_PROW_SANITY_SERVICE "hostpath-service" "Kubernetes TCP service name that exposes csi.sock"
|
||||
configvar CSI_PROW_SANITY_POD "csi-hostpathplugin-0" "Kubernetes pod with CSI driver"
|
||||
configvar CSI_PROW_SANITY_CONTAINER "hostpath" "Kubernetes container with CSI driver"
|
||||
|
||||
# Each job can run one or more of the following tests, identified by
|
||||
# a single word:
|
||||
# - unit testing
|
||||
# - parallel excluding alpha features
|
||||
# - serial excluding alpha features
|
||||
# - parallel, only alpha feature
|
||||
# - serial, only alpha features
|
||||
# - sanity
|
||||
#
|
||||
# Sanity testing with csi-sanity only covers the CSI driver itself and thus
|
||||
# is off by default. A CSI driver can change that default in its .prow.sh
|
||||
# by setting CSI_PROW_TESTS_SANITY.
|
||||
configvar CSI_PROW_TESTS "unit parallel serial parallel-alpha serial-alpha ${CSI_PROW_TESTS_SANITY}" "tests to run"
|
||||
test_enabled () {
|
||||
echo "${CSI_PROW_TESTS}" | grep -q -w -e "$1"
|
||||
}
|
||||
|
||||
# Serial vs. parallel is always determined by these regular expressions.
|
||||
# Individual regular expressions are seperated by spaces for readability
|
||||
# and expected to not contain spaces. Use dots instead. The complete
|
||||
# regex for Ginkgo will be created by joining the individual terms.
|
||||
configvar CSI_PROW_E2E_SERIAL '\[Serial\] \[Disruptive\]' "tags for serial E2E tests"
|
||||
regex_join () {
|
||||
echo "$@" | sed -e 's/ */|/g' -e 's/^|*//' -e 's/|*$//' -e 's/^$/this-matches-nothing/g'
|
||||
}
|
||||
|
||||
# Which tests are alpha depends on the Kubernetes version. We could
|
||||
# use the same E2E test for all Kubernetes version. This would have
|
||||
# the advantage that new tests can be applied to older versions
|
||||
# without having to backport tests.
|
||||
#
|
||||
# But the feature tag gets removed from E2E tests when the corresponding
|
||||
# feature becomes beta, so we would have to track which tests were
|
||||
# alpha in previous Kubernetes releases. This was considered too
|
||||
# error prone. Therefore we use E2E tests that match the Kubernetes
|
||||
# version that is getting tested.
|
||||
#
|
||||
# However, for 1.13.x testing we have to use the E2E tests from 1.14
|
||||
# because 1.13 didn't have --storage.testdriver yet, so for that (and only
|
||||
# that version) we have to define alpha tests differently.
|
||||
configvar CSI_PROW_E2E_ALPHA_1_13 '\[Feature: \[Testpattern:.Dynamic.PV..block.volmode.\] should.create.and.delete.block.persistent.volumes' "alpha tests for Kubernetes 1.13" # Raw block was an alpha feature in 1.13.
|
||||
configvar CSI_PROW_E2E_ALPHA_LATEST '\[Feature:' "alpha tests for Kubernetes >= 1.14" # there's no need to update this, adding a new case for CSI_PROW_E2E for a new Kubernetes is enough
|
||||
configvar CSI_PROW_E2E_ALPHA "$(get_versioned_variable CSI_PROW_E2E_ALPHA "${csi_prow_kubernetes_version_suffix}")" "alpha tests"
|
||||
|
||||
# After the parallel E2E test without alpha features, a test cluster
|
||||
# with alpha features is brought up and tests that were previously
|
||||
# disabled are run. The alpha gates in each release have to be listed
|
||||
# explicitly. If none are set (= variable empty), alpha testing
|
||||
# is skipped.
|
||||
#
|
||||
# Testing against "latest" Kubernetes is problematic because some alpha
|
||||
# feature which used to work might stop working or change their behavior
|
||||
# such that the current tests no longer pass. If that happens,
|
||||
# kubernetes-csi components must be updated, either by disabling
|
||||
# the failing test for "latest" or by updating the test and not running
|
||||
# it anymore for older releases.
|
||||
configvar CSI_PROW_E2E_ALPHA_GATES_1_13 'VolumeSnapshotDataSource=true,BlockVolume=true,CSIBlockVolume=true' "alpha feature gates for Kubernetes 1.13"
|
||||
# TODO: add new CSI_PROW_ALPHA_GATES entry for future Kubernetes releases
|
||||
configvar CSI_PROW_E2E_ALPHA_GATES_LATEST 'VolumeSnapshotDataSource=true' "alpha feature gates for latest Kubernetes"
|
||||
configvar CSI_PROW_E2E_ALPHA_GATES "$(get_versioned_variable CSI_PROW_E2E_ALPHA_GATES "${csi_prow_kubernetes_version_suffix}")" "alpha E2E feature gates"
|
||||
|
||||
# Some tests are known to be unusable in a KinD cluster. For example,
|
||||
# stopping kubelet with "ssh <node IP> systemctl stop kubelet" simply
|
||||
# doesn't work. Such tests should be written in a way that they verify
|
||||
# whether they can run with the current cluster provider, but until
|
||||
# they are, we filter them out by name. Like the other test selection
|
||||
# variables, this is again a space separated list of regular expressions.
|
||||
configvar CSI_PROW_E2E_SKIP 'while.kubelet.is.down.*Disruptive' "tests that need to be skipped"
|
||||
|
||||
# This is the directory for additional result files. Usually set by Prow, but
|
||||
# if not (for example, when invoking manually) it defaults to the work directory.
|
||||
configvar ARTIFACTS "${CSI_PROW_WORK}/artifacts" "artifacts"
|
||||
mkdir -p "${ARTIFACTS}"
|
||||
|
||||
run () {
|
||||
echo "$(date) $(go version | sed -e 's/.*version \(go[^ ]*\).*/\1/') $(if [ "$(pwd)" != "${REPO_DIR}" ]; then pwd; fi)\$" "$@" >&2
|
||||
"$@"
|
||||
}
|
||||
|
||||
info () {
|
||||
echo >&2 INFO: "$@"
|
||||
}
|
||||
|
||||
warn () {
|
||||
echo >&2 WARNING: "$@"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo >&2 ERROR: "$@"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# For additional tools.
|
||||
CSI_PROW_BIN="${CSI_PROW_WORK}/bin"
|
||||
mkdir -p "${CSI_PROW_BIN}"
|
||||
PATH="${CSI_PROW_BIN}:$PATH"
|
||||
|
||||
# Ensure that PATH has the desired version of the Go tools, then run command given as argument.
|
||||
# Empty parameter uses the already installed Go. In Prow, that version is kept up-to-date by
|
||||
# bumping the container image regularly.
|
||||
run_with_go () {
|
||||
local version
|
||||
version="$1"
|
||||
shift
|
||||
|
||||
if ! [ "$version" ] || go version 2>/dev/null | grep -q "go$version"; then
|
||||
run "$@"
|
||||
else
|
||||
if ! [ -d "${CSI_PROW_WORK}/go-$version" ]; then
|
||||
run curl --fail --location "https://dl.google.com/go/go$version.linux-amd64.tar.gz" | tar -C "${CSI_PROW_WORK}" -zxf - || die "installation of Go $version failed"
|
||||
mv "${CSI_PROW_WORK}/go" "${CSI_PROW_WORK}/go-$version"
|
||||
fi
|
||||
PATH="${CSI_PROW_WORK}/go-$version/bin:$PATH" run "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
# Ensure that we have the desired version of kind.
|
||||
install_kind () {
|
||||
if kind --version 2>/dev/null | grep -q " ${CSI_PROW_KIND_VERSION}$"; then
|
||||
return
|
||||
fi
|
||||
if run curl --fail --location -o "${CSI_PROW_WORK}/bin/kind" "https://github.com/kubernetes-sigs/kind/releases/download/${CSI_PROW_KIND_VERSION}/kind-linux-amd64"; then
|
||||
chmod u+x "${CSI_PROW_WORK}/bin/kind"
|
||||
else
|
||||
git_checkout https://github.com/kubernetes-sigs/kind "$GOPATH/src/sigs.k8s.io/kind" "${CSI_PROW_KIND_VERSION}" --depth=1 &&
|
||||
run_with_go "${CSI_PROW_GO_VERSION_KIND}" go build -o "${CSI_PROW_WORK}/bin/kind" sigs.k8s.io/kind
|
||||
fi
|
||||
}
|
||||
|
||||
# Ensure that we have the desired version of the ginkgo test runner.
|
||||
install_ginkgo () {
|
||||
# CSI_PROW_GINKGO_VERSION contains the tag with v prefix, the command line output does not.
|
||||
if [ "v$(ginkgo version 2>/dev/null | sed -e 's/.* //')" = "${CSI_PROW_GINKGO_VERSION}" ]; then
|
||||
return
|
||||
fi
|
||||
git_checkout https://github.com/onsi/ginkgo "$GOPATH/src/github.com/onsi/ginkgo" "${CSI_PROW_GINKGO_VERSION}" --depth=1 &&
|
||||
# We have to get dependencies and hence can't call just "go build".
|
||||
run_with_go "${CSI_PROW_GO_VERSION_GINKGO}" go get github.com/onsi/ginkgo/ginkgo || die "building ginkgo failed" &&
|
||||
mv "$GOPATH/bin/ginkgo" "${CSI_PROW_BIN}"
|
||||
}
|
||||
|
||||
# This checks out a repo ("https://github.com/kubernetes/kubernetes")
|
||||
# in a certain location ("$GOPATH/src/k8s.io/kubernetes") at
|
||||
# a certain revision (a hex commit hash, v1.13.1, master). It's okay
|
||||
# for that directory to exist already.
|
||||
git_checkout () {
|
||||
local repo path revision
|
||||
repo="$1"
|
||||
shift
|
||||
path="$1"
|
||||
shift
|
||||
revision="$1"
|
||||
shift
|
||||
|
||||
mkdir -p "$path"
|
||||
if ! [ -d "$path/.git" ]; then
|
||||
run git init "$path"
|
||||
fi
|
||||
if (cd "$path" && run git fetch "$@" "$repo" "$revision"); then
|
||||
(cd "$path" && run git checkout FETCH_HEAD) || die "checking out $repo $revision failed"
|
||||
else
|
||||
# Might have been because fetching by revision is not
|
||||
# supported by GitHub (https://github.com/isaacs/github/issues/436).
|
||||
# Fall back to fetching everything.
|
||||
(cd "$path" && run git fetch "$repo" '+refs/heads/*:refs/remotes/csiprow/heads/*' '+refs/tags/*:refs/tags/*') || die "fetching $repo failed"
|
||||
(cd "$path" && run git checkout "$revision") || die "checking out $repo $revision failed"
|
||||
fi
|
||||
# This is useful for local testing or when switching between different revisions in the same
|
||||
# repo.
|
||||
(cd "$path" && run git clean -fdx) || die "failed to clean $path"
|
||||
}
|
||||
|
||||
list_gates () (
|
||||
set -f; IFS=','
|
||||
# Ignore: Double quote to prevent globbing and word splitting.
|
||||
# shellcheck disable=SC2086
|
||||
set -- $1
|
||||
while [ "$1" ]; do
|
||||
# Ignore: See if you can use ${variable//search/replace} instead.
|
||||
# shellcheck disable=SC2001
|
||||
echo "$1" | sed -e 's/ *\([^ =]*\) *= *\([^ ]*\) */ \1: \2/'
|
||||
shift
|
||||
done
|
||||
)
|
||||
|
||||
go_version_for_kubernetes () (
|
||||
local path="$1"
|
||||
local version="$2"
|
||||
local go_version
|
||||
|
||||
# We use the minimal Go version specified for each K8S release (= minimum_go_version in hack/lib/golang.sh).
|
||||
# More recent versions might also work, but we don't want to count on that.
|
||||
go_version="$(grep minimum_go_version= "$path/hack/lib/golang.sh" | sed -e 's/.*=go//')"
|
||||
if ! [ "$go_version" ]; then
|
||||
die "Unable to determine Go version for Kubernetes $version from hack/lib/golang.sh."
|
||||
fi
|
||||
echo "$go_version"
|
||||
)
|
||||
|
||||
csi_prow_kind_have_kubernetes=false
|
||||
# Brings up a Kubernetes cluster and sets KUBECONFIG.
|
||||
# Accepts additional feature gates in the form gate1=true|false,gate2=...
|
||||
start_cluster () {
|
||||
local image gates
|
||||
gates="$1"
|
||||
|
||||
if kind get clusters | grep -q csi-prow; then
|
||||
run kind delete cluster --name=csi-prow || die "kind delete failed"
|
||||
fi
|
||||
|
||||
# Build from source?
|
||||
if [[ "${CSI_PROW_KUBERNETES_VERSION}" =~ ^release-|^latest$ ]]; then
|
||||
if ! ${csi_prow_kind_have_kubernetes}; then
|
||||
local version="${CSI_PROW_KUBERNETES_VERSION}"
|
||||
if [ "$version" = "latest" ]; then
|
||||
version=master
|
||||
fi
|
||||
git_checkout https://github.com/kubernetes/kubernetes "$GOPATH/src/k8s.io/kubernetes" "$version" --depth=1 || die "checking out Kubernetes $version failed"
|
||||
|
||||
# "kind build" and/or the Kubernetes build rules need at least one tag, which we don't have
|
||||
# when doing a shallow fetch. Therefore we fake one:
|
||||
# release-1.12 -> v1.12.0-release.<rev>.csiprow
|
||||
# latest or <revision> -> v1.14.0-<rev>.csiprow
|
||||
case "${CSI_PROW_KUBERNETES_VERSION}" in
|
||||
release-*)
|
||||
# Ignore: See if you can use ${variable//search/replace} instead.
|
||||
# shellcheck disable=SC2001
|
||||
tag="$(echo "${CSI_PROW_KUBERNETES_VERSION}" | sed -e 's/release-\(.*\)/v\1.0-release./')";;
|
||||
*)
|
||||
# We have to make something up. v1.0.0 did not work for some reasons.
|
||||
tag="v1.14.0-";;
|
||||
esac
|
||||
tag="$tag$(cd "$GOPATH/src/k8s.io/kubernetes" && git rev-list --abbrev-commit HEAD).csiprow"
|
||||
(cd "$GOPATH/src/k8s.io/kubernetes" && run git tag -f "$tag") || die "git tag failed"
|
||||
go_version="$(go_version_for_kubernetes "$GOPATH/src/k8s.io/kubernetes" "$version")" || die "cannot proceed without knowing Go version for Kubernetes"
|
||||
run_with_go "$go_version" kind build node-image --type bazel --image csiprow/node:latest --kube-root "$GOPATH/src/k8s.io/kubernetes" || die "'kind build node-image' failed"
|
||||
csi_prow_kind_have_kubernetes=true
|
||||
fi
|
||||
image="csiprow/node:latest"
|
||||
else
|
||||
image="kindest/node:v${CSI_PROW_KUBERNETES_VERSION}"
|
||||
fi
|
||||
cat >"${CSI_PROW_WORK}/kind-config.yaml" <<EOF
|
||||
kind: Config
|
||||
apiVersion: kind.sigs.k8s.io/v1alpha2
|
||||
nodes:
|
||||
- role: control-plane
|
||||
kubeadmConfigPatches:
|
||||
- |
|
||||
apiVersion: kubeadm.k8s.io/v1beta1
|
||||
kind: ClusterConfiguration
|
||||
metadata:
|
||||
name: config
|
||||
apiServer:
|
||||
extraArgs:
|
||||
"feature-gates": "$gates"
|
||||
controllerManager:
|
||||
extraArgs:
|
||||
"feature-gates": "$gates"
|
||||
scheduler:
|
||||
extraArgs:
|
||||
"feature-gates": "$gates"
|
||||
- |
|
||||
apiVersion: kubelet.config.k8s.io/v1beta1
|
||||
kind: KubeletConfiguration
|
||||
metadata:
|
||||
name: config
|
||||
featureGates:
|
||||
$(list_gates "$gates")
|
||||
- |
|
||||
apiVersion: kubeproxy.config.k8s.io/v1alpha1
|
||||
kind: KubeProxyConfiguration
|
||||
metadata:
|
||||
name: config
|
||||
featureGates:
|
||||
$(list_gates "$gates")
|
||||
EOF
|
||||
run kind create cluster --name csi-prow --config "${CSI_PROW_WORK}/kind-config.yaml" --wait 5m --image "$image" || die "'kind create cluster' failed"
|
||||
KUBECONFIG="$(kind get kubeconfig-path --name=csi-prow)"
|
||||
export KUBECONFIG
|
||||
}
|
||||
|
||||
# Looks for the deployment as specified by CSI_PROW_DEPLOYMENT and CSI_PROW_KUBERNETES_VERSION
|
||||
# in the given directory.
|
||||
find_deployment () {
|
||||
local dir file
|
||||
dir="$1"
|
||||
|
||||
# Fixed deployment name? Use it if it exists, otherwise fail.
|
||||
if [ "${CSI_PROW_DEPLOYMENT}" ]; then
|
||||
file="$dir/${CSI_PROW_DEPLOYMENT}/deploy-hostpath.sh"
|
||||
if ! [ -e "$file" ]; then
|
||||
return 1
|
||||
fi
|
||||
echo "$file"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Ignore: See if you can use ${variable//search/replace} instead.
|
||||
# shellcheck disable=SC2001
|
||||
file="$dir/kubernetes-$(echo "${CSI_PROW_KUBERNETES_VERSION}" | sed -e 's/\([0-9]*\)\.\([0-9]*\).*/\1.\2/')/deploy-hostpath.sh"
|
||||
if ! [ -e "$file" ]; then
|
||||
file="$dir/kubernetes-latest/deploy-hostpath.sh"
|
||||
if ! [ -e "$file" ]; then
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
echo "$file"
|
||||
}
|
||||
|
||||
# This installs the hostpath driver example. CSI_PROW_HOSTPATH_CANARY overrides all
|
||||
# image versions with that canary version. The parameters of install_hostpath can be
|
||||
# used to override registry and/or tag of individual images (CSI_PROVISIONER_REGISTRY=localhost:9000
|
||||
# CSI_PROVISIONER_TAG=latest).
|
||||
install_hostpath () {
|
||||
local images deploy_hostpath
|
||||
images="$*"
|
||||
|
||||
if [ "${CSI_PROW_DEPLOYMENT}" = "none" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if deploy_hostpath="$(find_deployment "$(pwd)/deploy")"; then
|
||||
:
|
||||
elif [ "${CSI_PROW_HOSTPATH_REPO}" = "none" ]; then
|
||||
return 1
|
||||
else
|
||||
git_checkout "${CSI_PROW_HOSTPATH_REPO}" "${CSI_PROW_WORK}/hostpath" "${CSI_PROW_HOSTPATH_VERSION}" --depth=1 || die "checking out hostpath repo failed"
|
||||
if deploy_hostpath="$(find_deployment "${CSI_PROW_WORK}/hostpath/deploy")"; then
|
||||
:
|
||||
else
|
||||
die "deploy-hostpath.sh not found in ${CSI_PROW_HOSTPATH_REPO} ${CSI_PROW_HOSTPATH_VERSION}. To disable E2E testing, set CSI_PROW_HOSTPATH_REPO=none"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "${CSI_PROW_HOSTPATH_CANARY}" != "stable" ]; then
|
||||
images="$images IMAGE_TAG=${CSI_PROW_HOSTPATH_CANARY}"
|
||||
fi
|
||||
# Ignore: Double quote to prevent globbing and word splitting.
|
||||
# It's intentional here for $images.
|
||||
# shellcheck disable=SC2086
|
||||
if ! run env $images "${deploy_hostpath}"; then
|
||||
# Collect information about failed deployment before failing.
|
||||
collect_cluster_info
|
||||
(start_loggers >/dev/null; wait)
|
||||
info "For container output see job artifacts."
|
||||
die "deploying the hostpath driver with ${deploy_hostpath} failed"
|
||||
fi
|
||||
}
|
||||
|
||||
# collect logs and cluster status (like the version of all components, Kubernetes version, test version)
|
||||
collect_cluster_info () {
|
||||
cat <<EOF
|
||||
=========================================================
|
||||
Kubernetes:
|
||||
$(kubectl version)
|
||||
|
||||
Driver installation in default namespace:
|
||||
$(kubectl get all)
|
||||
|
||||
Images in cluster:
|
||||
REPOSITORY TAG REVISION
|
||||
$(
|
||||
# Here we iterate over all images that are in use and print some information about them.
|
||||
# The "revision" label is where our build process puts the version number and revision,
|
||||
# which is always unique, in contrast to the tag (think "canary"...).
|
||||
docker exec csi-prow-control-plane docker image ls --format='{{.Repository}} {{.Tag}} {{.ID}}' | grep -e csi -e hostpath | while read -r repo tag id; do
|
||||
echo "$repo" "$tag" "$(docker exec csi-prow-control-plane docker image inspect --format='{{ index .Config.Labels "revision"}}' "$id")"
|
||||
done
|
||||
)
|
||||
|
||||
=========================================================
|
||||
EOF
|
||||
|
||||
}
|
||||
|
||||
# Gets logs of all containers in the default namespace. When passed -f, kubectl will
|
||||
# keep running and capture new output. Prints the pid of all background processes.
|
||||
# The caller must kill (when using -f) and/or wait for them.
|
||||
#
|
||||
# May be called multiple times and thus appends.
|
||||
start_loggers () {
|
||||
kubectl get pods -o go-template --template='{{range .items}}{{.metadata.name}} {{range .spec.containers}}{{.name}} {{end}}{{"\n"}}{{end}}' | while read -r pod containers; do
|
||||
for container in $containers; do
|
||||
mkdir -p "${ARTIFACTS}/$pod"
|
||||
kubectl logs "$@" "$pod" "$container" >>"${ARTIFACTS}/$pod/$container.log" &
|
||||
echo "$!"
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
# Makes the E2E test suite binary available as "${CSI_PROW_WORK}/e2e.test".
|
||||
install_e2e () {
|
||||
if [ -e "${CSI_PROW_WORK}/e2e.test" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
git_checkout "${CSI_PROW_E2E_REPO}" "${GOPATH}/src/${CSI_PROW_E2E_IMPORT_PATH}" "${CSI_PROW_E2E_VERSION}" --depth=1 &&
|
||||
if [ "${CSI_PROW_E2E_IMPORT_PATH}" = "k8s.io/kubernetes" ]; then
|
||||
go_version="${CSI_PROW_GO_VERSION_E2E:-$(go_version_for_kubernetes "${GOPATH}/src/${CSI_PROW_E2E_IMPORT_PATH}" "${CSI_PROW_E2E_VERSION}")}" &&
|
||||
run_with_go "$go_version" make WHAT=test/e2e/e2e.test "-C${GOPATH}/src/${CSI_PROW_E2E_IMPORT_PATH}" &&
|
||||
ln -s "${GOPATH}/src/${CSI_PROW_E2E_IMPORT_PATH}/_output/bin/e2e.test" "${CSI_PROW_WORK}"
|
||||
else
|
||||
run_with_go "${CSI_PROW_GO_VERSION_E2E}" go test -c -o "${CSI_PROW_WORK}/e2e.test" "${CSI_PROW_E2E_IMPORT_PATH}/test/e2e"
|
||||
fi
|
||||
}
|
||||
|
||||
# Makes the csi-sanity test suite binary available as
|
||||
# "${CSI_PROW_WORK}/csi-sanity".
|
||||
install_sanity () (
|
||||
if [ -e "${CSI_PROW_WORK}/csi-sanity" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
git_checkout "${CSI_PROW_SANITY_REPO}" "${GOPATH}/src/${CSI_PROW_SANITY_IMPORT_PATH}" "${CSI_PROW_SANITY_VERSION}" --depth=1 || die "checking out csi-sanity failed"
|
||||
run_with_go "${CSI_PROW_GO_VERSION_SANITY}" go test -c -o "${CSI_PROW_WORK}/csi-sanity" "${CSI_PROW_SANITY_IMPORT_PATH}/cmd/csi-sanity" || die "building csi-sanity failed"
|
||||
)
|
||||
|
||||
# Whether the hostpath driver supports raw block devices depends on which version
|
||||
# we are testing. It would be much nicer if we could determine that by querying the
|
||||
# installed driver.
|
||||
hostpath_supports_block () {
|
||||
if [ -e "cmd/hostpathplugin" ] && ${CSI_PROW_BUILD_JOB}; then
|
||||
# The assumption is that if we build the hostpath driver, then it is
|
||||
# a current version with support.
|
||||
echo true
|
||||
return
|
||||
fi
|
||||
|
||||
case "${CSI_PROW_DEPLOYMENT}" in kubernetes-1.13) echo false;; # wasn't supported and probably won't be backported
|
||||
*) echo true;; # probably all other deployments have a recent driver
|
||||
esac
|
||||
}
|
||||
|
||||
# Captures pod output while running some other command.
|
||||
run_with_loggers () (
|
||||
loggers=$(start_loggers -f)
|
||||
trap 'kill $loggers' EXIT
|
||||
|
||||
run "$@"
|
||||
)
|
||||
|
||||
# Invokes the filter-junit.go tool.
|
||||
run_filter_junit () {
|
||||
run_with_go "${CSI_PROW_GO_VERSION_BUILD}" go run "${RELEASE_TOOLS_ROOT}/filter-junit.go" "$@"
|
||||
}
|
||||
|
||||
# Runs the E2E test suite in a sub-shell.
|
||||
run_e2e () (
|
||||
name="$1"
|
||||
shift
|
||||
|
||||
install_e2e || die "building e2e.test failed"
|
||||
install_ginkgo || die "installing ginkgo failed"
|
||||
|
||||
# TODO (?): multi-node cluster (depends on https://github.com/kubernetes-csi/csi-driver-host-path/pull/14).
|
||||
# When running on a multi-node cluster, we need to figure out where the
|
||||
# hostpath driver was deployed and set ClientNodeName accordingly.
|
||||
|
||||
# The content of this file depends on both what the E2E suite expects and
|
||||
# what the installed hostpath driver supports. Generating it here seems
|
||||
# prone to breakage, but it is uncertain where a better place might be.
|
||||
cat >"${CSI_PROW_WORK}/hostpath-test-driver.yaml" <<EOF
|
||||
ShortName: csiprow
|
||||
StorageClass:
|
||||
FromName: true
|
||||
SnapshotClass:
|
||||
FromName: true
|
||||
DriverInfo:
|
||||
Name: csi-hostpath
|
||||
Capabilities:
|
||||
block: $(hostpath_supports_block)
|
||||
persistence: true
|
||||
dataSource: true
|
||||
multipods: true
|
||||
EOF
|
||||
|
||||
# Rename, merge and filter JUnit files. Necessary in case that we run the E2E suite again
|
||||
# and to avoid the large number of "skipped" tests that we get from using
|
||||
# the full Kubernetes E2E testsuite while only running a few tests.
|
||||
move_junit () {
|
||||
if ls "${ARTIFACTS}"/junit_[0-9]*.xml 2>/dev/null >/dev/null; then
|
||||
run_filter_junit -t="External Storage" -o "${ARTIFACTS}/junit_${name}.xml" "${ARTIFACTS}"/junit_[0-9]*.xml && rm -f "${ARTIFACTS}"/junit_[0-9]*.xml
|
||||
fi
|
||||
}
|
||||
trap move_junit EXIT
|
||||
|
||||
cd "${GOPATH}/src/${CSI_PROW_E2E_IMPORT_PATH}" &&
|
||||
run_with_loggers ginkgo -v "$@" "${CSI_PROW_WORK}/e2e.test" -- -report-dir "${ARTIFACTS}" -storage.testdriver="${CSI_PROW_WORK}/hostpath-test-driver.yaml"
|
||||
)
|
||||
|
||||
# Run csi-sanity against installed CSI driver.
|
||||
run_sanity () (
|
||||
install_sanity || die "installing csi-sanity failed"
|
||||
|
||||
cat >"${CSI_PROW_WORK}/mkdir_in_pod.sh" <<EOF
|
||||
#!/bin/sh
|
||||
kubectl exec "${CSI_PROW_SANITY_POD}" -c "${CSI_PROW_SANITY_CONTAINER}" -- mkdir "\$@" && echo "\$@"
|
||||
EOF
|
||||
# Using "rm -rf" as fallback for "rmdir" is a workaround for:
|
||||
# Node Service
|
||||
# should work
|
||||
# /nvme/gopath.tmp/src/github.com/kubernetes-csi/csi-test/pkg/sanity/node.go:624
|
||||
# STEP: reusing connection to CSI driver at dns:///172.17.0.2:30896
|
||||
# STEP: creating mount and staging directories
|
||||
# STEP: creating a single node writer volume
|
||||
# STEP: getting a node id
|
||||
# STEP: node staging volume
|
||||
# STEP: publishing the volume on a node
|
||||
# STEP: cleaning up calling nodeunpublish
|
||||
# STEP: cleaning up calling nodeunstage
|
||||
# STEP: cleaning up deleting the volume
|
||||
# cleanup: deleting sanity-node-full-35A55673-604D59E1 = 5211b280-4fad-11e9-8127-0242dfe2bdaf
|
||||
# cleanup: warning: NodeUnpublishVolume: rpc error: code = NotFound desc = volume id 5211b280-4fad-11e9-8127-0242dfe2bdaf does not exit in the volumes list
|
||||
# rmdir: '/tmp/mount': Directory not empty
|
||||
# command terminated with exit code 1
|
||||
#
|
||||
# Somehow the mount directory was not empty. All tests after that
|
||||
# failed in "mkdir". This only occurred once, so its uncertain
|
||||
# why it happened.
|
||||
cat >"${CSI_PROW_WORK}/rmdir_in_pod.sh" <<EOF
|
||||
#!/bin/sh
|
||||
if ! kubectl exec "${CSI_PROW_SANITY_POD}" -c "${CSI_PROW_SANITY_CONTAINER}" -- rmdir "\$@"; then
|
||||
kubectl exec "${CSI_PROW_SANITY_POD}" -c "${CSI_PROW_SANITY_CONTAINER}" -- rm -rf "\$@"
|
||||
exit 1
|
||||
fi
|
||||
EOF
|
||||
chmod u+x "${CSI_PROW_WORK}"/*dir_in_pod.sh
|
||||
|
||||
# This cannot run in parallel, because -csi.junitfile output
|
||||
# from different Ginkgo nodes would go to the same file. Also the
|
||||
# staging and target directories are the same.
|
||||
run_with_loggers "${CSI_PROW_WORK}/csi-sanity" \
|
||||
-ginkgo.v \
|
||||
-csi.junitfile "${ARTIFACTS}/junit_sanity.xml" \
|
||||
-csi.endpoint "dns:///$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' csi-prow-control-plane):$(kubectl get "services/${CSI_PROW_SANITY_SERVICE}" -o "jsonpath={..nodePort}")" \
|
||||
-csi.stagingdir "/tmp/staging" \
|
||||
-csi.mountdir "/tmp/mount" \
|
||||
-csi.createstagingpathcmd "${CSI_PROW_WORK}/mkdir_in_pod.sh" \
|
||||
-csi.createmountpathcmd "${CSI_PROW_WORK}/mkdir_in_pod.sh" \
|
||||
-csi.removestagingpathcmd "${CSI_PROW_WORK}/rmdir_in_pod.sh" \
|
||||
-csi.removemountpathcmd "${CSI_PROW_WORK}/rmdir_in_pod.sh" \
|
||||
)
|
||||
|
||||
ascii_to_xml () {
|
||||
# We must escape special characters and remove escape sequences
|
||||
# (no good representation in the simple XML that we generate
|
||||
# here). filter_junit.go would choke on them during decoding, even
|
||||
# when disabling strict parsing.
|
||||
sed -e 's/&/&/g' -e 's/</\</g' -e 's/>/\>/g' -e 's/\x1B...//g'
|
||||
}
|
||||
|
||||
# The "make test" output starts each test with "### <test-target>:"
|
||||
# and then ends when the next test starts or with "make: ***
|
||||
# [<test-target>] Error 1" when there was a failure. Here we read each
|
||||
# line of that output, split it up into individual tests and generate
|
||||
# a make-test.xml file in JUnit format.
|
||||
make_test_to_junit () {
|
||||
local ret out testname testoutput
|
||||
ret=0
|
||||
# Plain make-test.xml was not delivered as text/xml by the web
|
||||
# server and ignored by spyglass. It seems that the name has to
|
||||
# match junit*.xml.
|
||||
out="${ARTIFACTS}/junit_make_test.xml"
|
||||
testname=
|
||||
echo "<testsuite>" >>"$out"
|
||||
|
||||
while IFS= read -r line; do
|
||||
echo "$line" # pass through
|
||||
if echo "$line" | grep -q "^### [^ ]*:$"; then
|
||||
if [ "$testname" ]; then
|
||||
# previous test succesful
|
||||
echo " </system-out>" >>"$out"
|
||||
echo " </testcase>" >>"$out"
|
||||
fi
|
||||
# Ignore: See if you can use ${variable//search/replace} instead.
|
||||
# shellcheck disable=SC2001
|
||||
#
|
||||
# start new test
|
||||
testname="$(echo "$line" | sed -e 's/^### \([^ ]*\):$/\1/')"
|
||||
testoutput=
|
||||
echo " <testcase name=\"$testname\">" >>"$out"
|
||||
echo " <system-out>" >>"$out"
|
||||
elif echo "$line" | grep -q '^make: .*Error [0-9]*$'; then
|
||||
if [ "$testname" ]; then
|
||||
# Ignore: Consider using { cmd1; cmd2; } >> file instead of individual redirects.
|
||||
# shellcheck disable=SC2129
|
||||
#
|
||||
# end test with failure
|
||||
echo " </system-out>" >>"$out"
|
||||
# Include the same text as in <system-out> also in <failure>,
|
||||
# because then it is easier to view in spyglass (shown directly
|
||||
# instead of having to click through to stdout).
|
||||
echo " <failure>" >>"$out"
|
||||
echo -n "$testoutput" | ascii_to_xml >>"$out"
|
||||
echo " </failure>" >>"$out"
|
||||
echo " </testcase>" >>"$out"
|
||||
fi
|
||||
# remember failure for exit code
|
||||
ret=1
|
||||
# not currently inside a test
|
||||
testname=
|
||||
else
|
||||
if [ "$testname" ]; then
|
||||
# Test output.
|
||||
echo "$line" | ascii_to_xml >>"$out"
|
||||
testoutput="$testoutput$line
|
||||
"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
# if still in a test, close it now
|
||||
if [ "$testname" ]; then
|
||||
echo " </system-out>" >>"$out"
|
||||
echo " </testcase>" >>"$out"
|
||||
fi
|
||||
echo "</testsuite>" >>"$out"
|
||||
|
||||
# this makes the error more visible in spyglass
|
||||
if [ "$ret" -ne 0 ]; then
|
||||
echo "ERROR: 'make test' failed"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
main () {
|
||||
local images ret
|
||||
ret=0
|
||||
|
||||
images=
|
||||
if ${CSI_PROW_BUILD_JOB}; then
|
||||
# A successful build is required for testing.
|
||||
run_with_go "${CSI_PROW_GO_VERSION_BUILD}" make all || die "'make all' failed"
|
||||
# We don't want test failures to prevent E2E testing below, because the failure
|
||||
# might have been minor or unavoidable, for example when experimenting with
|
||||
# changes in "release-tools" in a PR (that fails the "is release-tools unmodified"
|
||||
# test).
|
||||
if test_enabled "unit"; then
|
||||
if ! run_with_go "${CSI_PROW_GO_VERSION_BUILD}" make -k test 2>&1 | make_test_to_junit; then
|
||||
warn "'make test' failed, proceeding anyway"
|
||||
ret=1
|
||||
fi
|
||||
fi
|
||||
# Required for E2E testing.
|
||||
run_with_go "${CSI_PROW_GO_VERSION_BUILD}" make container || die "'make container' failed"
|
||||
fi
|
||||
|
||||
install_kind || die "installing kind failed"
|
||||
start_cluster || die "starting the cluster failed"
|
||||
|
||||
if ${CSI_PROW_BUILD_JOB}; then
|
||||
cmds="$(grep '^\s*CMDS\s*=' Makefile | sed -e 's/\s*CMDS\s*=//')"
|
||||
# Get the image that was just built (if any) from the
|
||||
# top-level Makefile CMDS variable and set the
|
||||
# deploy-hostpath.sh env variables for it. We also need to
|
||||
# side-load those images into the cluster.
|
||||
for i in $cmds; do
|
||||
e=$(echo "$i" | tr '[:lower:]' '[:upper:]' | tr - _)
|
||||
images="$images ${e}_REGISTRY=none ${e}_TAG=csiprow"
|
||||
|
||||
# We must avoid the tag "latest" because that implies
|
||||
# always pulling the image
|
||||
# (https://github.com/kubernetes-sigs/kind/issues/328).
|
||||
docker tag "$i:latest" "$i:csiprow" || die "tagging the locally built container image for $i failed"
|
||||
kind load docker-image --name csi-prow "$i:csiprow" || die "could not load the $i:latest image into the kind cluster"
|
||||
done
|
||||
|
||||
if [ -e deploy/kubernetes/rbac.yaml ]; then
|
||||
# This is one of those components which has its own RBAC rules (like external-provisioner).
|
||||
# We are testing a locally built image and also want to test with the the current,
|
||||
# potentially modified RBAC rules.
|
||||
if [ "$(echo "$cmds" | wc -w)" != 1 ]; then
|
||||
die "ambiguous deploy/kubernetes/rbac.yaml: need exactly one command, got: $cmds"
|
||||
fi
|
||||
e=$(echo "$cmds" | tr '[:lower:]' '[:upper:]' | tr - _)
|
||||
images="$images ${e}_RBAC=$(pwd)/deploy/kubernetes/rbac.yaml"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Installing the driver might be disabled, in which case we bail out early.
|
||||
if ! install_hostpath "$images"; then
|
||||
info "hostpath driver installation disabled, skipping E2E testing"
|
||||
return "$ret"
|
||||
fi
|
||||
|
||||
collect_cluster_info
|
||||
|
||||
if test_enabled "sanity"; then
|
||||
if ! run_sanity; then
|
||||
ret=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if test_enabled "parallel"; then
|
||||
# Ignore: Double quote to prevent globbing and word splitting.
|
||||
# shellcheck disable=SC2086
|
||||
if ! run_e2e parallel ${CSI_PROW_GINKO_PARALLEL} \
|
||||
-focus="External.Storage" \
|
||||
-skip="$(regex_join "${CSI_PROW_E2E_SERIAL}" "${CSI_PROW_E2E_ALPHA}" "${CSI_PROW_E2E_SKIP}")"; then
|
||||
warn "E2E parallel failed"
|
||||
ret=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if test_enabled "serial"; then
|
||||
if ! run_e2e serial \
|
||||
-focus="External.Storage.*($(regex_join "${CSI_PROW_E2E_SERIAL}"))" \
|
||||
-skip="$(regex_join "${CSI_PROW_E2E_ALPHA}" "${CSI_PROW_E2E_SKIP}")"; then
|
||||
warn "E2E serial failed"
|
||||
ret=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if (test_enabled "parallel-alpha" || test_enabled "serial-alpha") && [ "${CSI_PROW_E2E_ALPHA_GATES}" ]; then
|
||||
# Need to (re)create the cluster.
|
||||
start_cluster "${CSI_PROW_E2E_ALPHA_GATES}" || die "starting alpha cluster failed"
|
||||
if ${CSI_PROW_BUILD_JOB}; then
|
||||
# Ignore: Double quote to prevent globbing and word splitting.
|
||||
# Ignore: To read lines rather than words, pipe/redirect to a 'while read' loop.
|
||||
# shellcheck disable=SC2086 disable=SC2013
|
||||
for i in $(grep '^\s*CMDS\s*=' Makefile | sed -e 's/\s*CMDS\s*=//'); do
|
||||
kind load docker-image --name csi-prow $i:csiprow || die "could not load the $i:latest image into the kind cluster"
|
||||
done
|
||||
fi
|
||||
install_hostpath "$images" || die "hostpath driver installation failed unexpectedly on alpha cluster"
|
||||
|
||||
if test_enabled "parallel-alpha"; then
|
||||
# Ignore: Double quote to prevent globbing and word splitting.
|
||||
# shellcheck disable=SC2086
|
||||
if ! run_e2e parallel-alpha ${CSI_PROW_GINKO_PARALLEL} \
|
||||
-focus="External.Storage.*($(regex_join "${CSI_PROW_E2E_ALPHA}"))" \
|
||||
-skip="$(regex_join "${CSI_PROW_E2E_SERIAL}" "${CSI_PROW_E2E_SKIP}")"; then
|
||||
warn "E2E parallel alpha failed"
|
||||
ret=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if test_enabled "serial-alpha"; then
|
||||
if ! run_e2e serial-alpha \
|
||||
-focus="External.Storage.*(($(regex_join "${CSI_PROW_E2E_SERIAL}")).*($(regex_join "${CSI_PROW_E2E_ALPHA}"))|($(regex_join "${CSI_PROW_E2E_ALPHA}")).*($(regex_join "${CSI_PROW_E2E_SERIAL}")))" \
|
||||
-skip="$(regex_join "${CSI_PROW_E2E_SKIP}")"; then
|
||||
warn "E2E serial alpha failed"
|
||||
ret=1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Merge all junit files into one. This gets rid of duplicated "skipped" tests.
|
||||
if ls "${ARTIFACTS}"/junit_*.xml 2>/dev/null >&2; then
|
||||
run_filter_junit -o "${CSI_PROW_WORK}/junit_final.xml" "${ARTIFACTS}"/junit_*.xml && rm "${ARTIFACTS}"/junit_*.xml && mv "${CSI_PROW_WORK}/junit_final.xml" "${ARTIFACTS}"
|
||||
fi
|
||||
|
||||
return "$ret"
|
||||
}
|
Reference in New Issue
Block a user