Skip to content

Commit

Permalink
API Version preflight check for sonobuoy run (#339)
Browse files Browse the repository at this point in the history
* API Version preflight check for sonobuoy run
* Add version deps

Signed-off-by: liz <liz@heptio.com>
  • Loading branch information
liztio authored Mar 8, 2018
1 parent 026485c commit ca818df
Show file tree
Hide file tree
Showing 14 changed files with 1,090 additions and 42 deletions.
8 changes: 7 additions & 1 deletion Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions cmd/sonobuoy/app/e2e.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,16 @@ func e2es(cmd *cobra.Command, args []string) {
os.Exit(1)
}

if !e2eflags.skipPreflight {
if errs := sonobuoy.PreflightChecks(); len(errs) > 0 {
errlog.LogError(errors.New("Preflight checks failed"))
for _, err := range errs {
errlog.LogError(err)
}
os.Exit(1)
}
}

fmt.Printf("Rerunning %d tests:\n", len(testCases))
if err := sonobuoy.Run(cfg); err != nil {
errlog.LogError(errors.Wrap(err, "error attempting to rerun failed tests"))
Expand Down
15 changes: 13 additions & 2 deletions cmd/sonobuoy/app/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@ func (r *runFlags) Config() (*ops.RunConfig, error) {
return nil, err
}
return &ops.RunConfig{
GenConfig: *gencfg,
SkipPreflight: r.skipPreflight,
GenConfig: *gencfg,
}, nil
}

Expand Down Expand Up @@ -85,6 +84,7 @@ func submitSonobuoyRun(cmd *cobra.Command, args []string) {
errlog.LogError(errors.Wrap(err, "could not create sonobuoy client"))
os.Exit(1)
}

m := genflags.mode.Get()
plugins := []string{}
for _, plugin := range m.Selectors {
Expand All @@ -93,6 +93,17 @@ func submitSonobuoyRun(cmd *cobra.Command, args []string) {
if len(plugins) > 0 {
fmt.Printf("Running plugins: %v\n", strings.Join(plugins, ", "))
}

if !runflags.skipPreflight {
if errs := sbc.PreflightChecks(); len(errs) > 0 {
errlog.LogError(errors.New("Preflight checks failed"))
for _, err := range errs {
errlog.LogError(err)
}
os.Exit(1)
}
}

if err := sbc.Run(cfg); err != nil {
errlog.LogError(errors.Wrap(err, "error attempting to run sonobuoy"))
os.Exit(1)
Expand Down
6 changes: 6 additions & 0 deletions pkg/buildinfo/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,9 @@ var Version = "v0.11.0-alpha"

// DockerImage is the full path to the docker image for this build, example gcr.io/heptio-images/sonobuoy
var DockerImage string

// MinimumKubeVersion is the lowest API version of Kubernetes this release of Sonobuoy supports.
var MinimumKubeVersion = "1.8.0"

// MaximumKubeVersion is the highest API version of Kubernetes this release of Sonobuoy supports.
var MaximumKubeVersion = "1.11.0"
3 changes: 1 addition & 2 deletions pkg/client/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ func NewGenConfig() *GenConfig {
// NewRunConfig is a RunConfig with DefaultGenConfig and and preflight checks enabled.
func NewRunConfig() *RunConfig {
return &RunConfig{
GenConfig: *NewGenConfig(),
SkipPreflight: false,
GenConfig: *NewGenConfig(),
}
}

Expand Down
4 changes: 2 additions & 2 deletions pkg/client/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,6 @@ type E2EConfig struct {
// RunConfig are the input options for running Sonobuoy.
type RunConfig struct {
GenConfig
// SkipPreflight means don't run any checks before kicking off the Sonobuoy run.
SkipPreflight bool
}

// DeleteConfig are the input options for cleaning up a Sonobuoy run.
Expand Down Expand Up @@ -130,4 +128,6 @@ type Interface interface {
LogReader(cfg *LogConfig) (*Reader, error)
// Delete removes a sonobuoy run, namespace, and all associated resources.
Delete(cfg *DeleteConfig) error
// PreflightChecks runs a number of preflight checks to confirm the environment is good for Sonobuoy
PreflightChecks() []error
}
99 changes: 99 additions & 0 deletions pkg/client/preflight.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
Copyright 2018 Heptio Inc.
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 client

import (
"fmt"

version "github.com/hashicorp/go-version"
"github.com/heptio/sonobuoy/pkg/buildinfo"
"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)

var preflightChecks = []func(kubernetes.Interface) error{
preflightDNSCheck,
preflightVersionCheck,
}

// PreflightChecks runs all preflight checks in order, returning the first error encountered.
func (c *SonobuoyClient) PreflightChecks() []error {
client, err := c.Client()
if err != nil {
return []error{err}
}

errors := []error{}

for _, check := range preflightChecks {
if err := check(client); err != nil {
errors = append(errors, err)
}
}
return errors
}

const (
kubeSystemNamespace = "kube-system"
kubeDNSLabelKey = "k8s-app"
kubeDNSLabelValue = "kube-dns"
)

func preflightDNSCheck(client kubernetes.Interface) error {
selector := metav1.AddLabelToSelector(&metav1.LabelSelector{}, kubeDNSLabelKey, kubeDNSLabelValue)

obj, err := client.CoreV1().Pods(kubeSystemNamespace).List(
metav1.ListOptions{LabelSelector: metav1.FormatLabelSelector(selector)},
)
if err != nil {
return errors.Wrap(err, "could not retrieve list of pods")
}

if len(obj.Items) == 0 {
return errors.New("no kube-dns tests found")
}

return nil
}

var (
minimumKubeVersion = version.Must(version.NewVersion(buildinfo.MinimumKubeVersion))
maximumKubeVersion = version.Must(version.NewVersion(buildinfo.MaximumKubeVersion))
)

func preflightVersionCheck(client kubernetes.Interface) error {
versionInfo, err := client.Discovery().ServerVersion()
if err != nil {
return errors.Wrap(err, "failed to retrieve server version")
}

serverVersion, err := version.NewVersion(versionInfo.String())
if err != nil {
return errors.Wrap(err, "couldn't parse version string")
}

if serverVersion.LessThan(minimumKubeVersion) {
return fmt.Errorf("Minimum kubernetes version is %s, got %s", minimumKubeVersion.String(), versionInfo.String())
}

if serverVersion.GreaterThan(maximumKubeVersion) {
return fmt.Errorf("Maximum kubernetes version is %s, got %s", maximumKubeVersion.String(), versionInfo.String())
}

return nil
}
35 changes: 0 additions & 35 deletions pkg/client/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,25 +31,13 @@ import (
"k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/client-go/discovery"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
)

const bufferSize = 4096

func (c *SonobuoyClient) Run(cfg *RunConfig) error {
client, err := c.Client()
if err != nil {
return err
}

if !cfg.SkipPreflight {
if err := preflightCheck(client); err != nil {
return errors.Wrap(err, "preflight check failed")
}
}

manifest, err := c.GenerateManifest(&cfg.GenConfig)
if err != nil {
return errors.Wrap(err, "couldn't run invalid manifest")
Expand Down Expand Up @@ -176,26 +164,3 @@ func unstructuredVersionInterface(version schema.GroupVersion) (*meta.VersionInt
MetadataAccessor: meta.NewAccessor(),
}, nil
}

const (
kubeSystemNamespace = "kube-system"
kubeDNSLabelKey = "k8s-app"
kubeDNSLabelValue = "kube-dns"
)

func preflightCheck(client kubernetes.Interface) error {
selector := metav1.AddLabelToSelector(&metav1.LabelSelector{}, kubeDNSLabelKey, kubeDNSLabelValue)

obj, err := client.CoreV1().Pods(kubeSystemNamespace).List(
metav1.ListOptions{LabelSelector: metav1.FormatLabelSelector(selector)},
)
if err != nil {
return errors.Wrap(err, "could not retrieve list of pods")
}

if len(obj.Items) == 0 {
return errors.New("no kube-dns tests found")
}

return nil
}
12 changes: 12 additions & 0 deletions vendor/github.com/hashicorp/go-version/.travis.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit ca818df

Please sign in to comment.