Skip to content

Commit dd50ea0

Browse files
authored
Validate: add support for kubernetes deployment validation with src validate kube subcommand (#926)
* Refactor out shared vars * Add basic kube validation * Add pod validation * Add skeleton for service and connection validation * Add connection validations * Add go modules files * Fix --kubeconfig flag * Fix line output * Add usage output to cli * Fix path in example * Add quiet flag to suppress output and return exit status only * Fix exit status to be consistent if there are failures * Remove TODOs * Update CHANGELOG.md
1 parent 1c70d53 commit dd50ea0

File tree

11 files changed

+1014
-39
lines changed

11 files changed

+1014
-39
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ All notable changes to `src-cli` are documented in this file.
1515

1616
- `src codeintel upload` will now upload SCIP indexes (over LSIF indexes) when the target instance supports it. [#897](https://github.com/sourcegraph/src-cli/pull/897)
1717

18+
- `src validate kube` adds support for validating Sourcegraph deployments on Kubernetes. Validations include Pods, Services, PVCs, and network connectivity. [#926](https://github.com/sourcegraph/src-cli/pull/926)
19+
1820
### Changed
1921

2022
### Fixed

cmd/src/validate.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Usage:
2121
The commands are:
2222
2323
install validates a Sourcegraph installation
24+
kube validates a Sourcegraph deployment on a Kubernetes cluster
2425
2526
Use "src validate [command] -h" for more information about a command.
2627
`

cmd/src/validate_install.go

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,12 @@ import (
99
"strings"
1010

1111
"github.com/mattn/go-isatty"
12+
1213
"github.com/sourcegraph/src-cli/internal/api"
1314
"github.com/sourcegraph/src-cli/internal/validate"
15+
"github.com/sourcegraph/src-cli/internal/validate/install"
1416

1517
"github.com/sourcegraph/sourcegraph/lib/errors"
16-
"github.com/sourcegraph/sourcegraph/lib/output"
17-
)
18-
19-
var (
20-
validateWarningEmoji = output.EmojiWarning
2118
)
2219

2320
func init() {
@@ -60,7 +57,7 @@ Environmental variables
6057

6158
client := cfg.apiClient(apiFlags, flagSet.Output())
6259

63-
var validationSpec *validate.ValidationSpec
60+
var validationSpec *install.ValidationSpec
6461

6562
if len(flagSet.Args()) == 1 {
6663
fileName := flagSet.Arg(0)
@@ -70,14 +67,14 @@ Environmental variables
7067
}
7168

7269
if strings.HasSuffix(fileName, ".yaml") || strings.HasSuffix(fileName, ".yml") {
73-
validationSpec, err = validate.LoadYamlConfig(f)
70+
validationSpec, err = install.LoadYamlConfig(f)
7471
if err != nil {
7572
return err
7673
}
7774
}
7875

7976
if strings.HasSuffix(fileName, ".json") {
80-
validationSpec, err = validate.LoadJsonConfig(f)
77+
validationSpec, err = install.LoadJsonConfig(f)
8178
if err != nil {
8279
return err
8380
}
@@ -90,26 +87,26 @@ Environmental variables
9087
if err != nil {
9188
return errors.Wrap(err, "failed to read installation validation config from pipe")
9289
}
93-
validationSpec, err = validate.LoadYamlConfig(input)
90+
validationSpec, err = install.LoadYamlConfig(input)
9491
if err != nil {
9592
return err
9693
}
9794
}
9895

9996
if validationSpec == nil {
100-
validationSpec = validate.DefaultConfig()
97+
validationSpec = install.DefaultConfig()
10198
}
10299

103100
envGithubToken := os.Getenv("SRC_GITHUB_TOKEN")
104101

105102
// will work for now with only GitHub supported but will need to be revisited when other code hosts are supported
106103
if envGithubToken == "" {
107-
return errors.Newf("%s failed to read `SRC_GITHUB_TOKEN` environment variable", validateWarningEmoji)
104+
return errors.Newf("%s failed to read `SRC_GITHUB_TOKEN` environment variable", validate.WarningSign)
108105
}
109106

110107
validationSpec.ExternalService.Config.GitHub.Token = envGithubToken
111108

112-
return validate.Installation(context.Background(), client, validationSpec)
109+
return install.Validate(context.Background(), client, validationSpec)
113110
}
114111

115112
validateCommands = append(validateCommands, &command{

cmd/src/validate_kube.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"flag"
6+
"fmt"
7+
"path/filepath"
8+
9+
"k8s.io/client-go/kubernetes"
10+
"k8s.io/client-go/tools/clientcmd"
11+
"k8s.io/client-go/util/homedir"
12+
13+
"github.com/sourcegraph/src-cli/internal/validate/kube"
14+
15+
"github.com/sourcegraph/sourcegraph/lib/errors"
16+
)
17+
18+
func init() {
19+
usage := `'src validate kube' is a tool that validates a Kubernetes based Sourcegraph deployment
20+
21+
Examples:
22+
23+
Run default deployment validation:
24+
$ src validate kube
25+
26+
Specify Kubernetes namespace:
27+
$ src validate kube --namespace sourcegraph
28+
29+
Specify the kubeconfig file location:
30+
$ src validate kube --kubeconfig ~/.kube/config
31+
32+
Suppress output (useful for CI/CD pipelines)
33+
$ src validate kube --quiet
34+
`
35+
36+
flagSet := flag.NewFlagSet("kube", flag.ExitOnError)
37+
usageFunc := func() {
38+
fmt.Fprintf(flag.CommandLine.Output(), "Usage of 'src validate %s':\n", flagSet.Name())
39+
flagSet.PrintDefaults()
40+
fmt.Println(usage)
41+
}
42+
43+
var (
44+
kubeConfig *string
45+
namespace = flagSet.String("namespace", "", "(optional) specify the kubernetes namespace to use")
46+
quiet = flagSet.Bool("quiet", false, "(optional) suppress output and return exit status only")
47+
)
48+
49+
if home := homedir.HomeDir(); home != "" {
50+
kubeConfig = flagSet.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
51+
} else {
52+
kubeConfig = flagSet.String("kubeconfig", "", "absolute path to the kubeconfig file")
53+
}
54+
55+
handler := func(args []string) error {
56+
if err := flagSet.Parse(args); err != nil {
57+
return err
58+
}
59+
60+
// use the current context in kubeConfig
61+
config, err := clientcmd.BuildConfigFromFlags("", *kubeConfig)
62+
if err != nil {
63+
return errors.Wrap(err, "failed to load kubernetes config")
64+
}
65+
66+
clientSet, err := kubernetes.NewForConfig(config)
67+
if err != nil {
68+
return errors.Wrap(err, "failed to create kubernetes client")
69+
}
70+
71+
// parse through flag options
72+
var options []kube.Option
73+
74+
if *namespace != "" {
75+
options = append(options, kube.WithNamespace(*namespace))
76+
}
77+
78+
if *quiet {
79+
options = append(options, kube.Quiet())
80+
}
81+
82+
return kube.Validate(context.Background(), clientSet, config, options...)
83+
}
84+
85+
validateCommands = append(validateCommands, &command{
86+
flagSet: flagSet,
87+
handler: handler,
88+
usageFunc: usageFunc,
89+
})
90+
}

go.mod

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ require (
2929
google.golang.org/protobuf v1.28.1
3030
gopkg.in/yaml.v3 v3.0.1
3131
jaytaylor.com/html2text v0.0.0-20200412013138-3577fbdbcff7
32+
k8s.io/api v0.26.1
33+
k8s.io/apimachinery v0.26.1
34+
k8s.io/client-go v0.26.1
3235
)
3336

3437
require (
@@ -50,41 +53,52 @@ require (
5053
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
5154
github.com/davecgh/go-spew v1.1.1 // indirect
5255
github.com/dlclark/regexp2 v1.4.0 // indirect
56+
github.com/emicklei/go-restful/v3 v3.9.0 // indirect
5357
github.com/envoyproxy/protoc-gen-validate v0.3.0-java // indirect
5458
github.com/fatih/color v1.13.0 // indirect
5559
github.com/getsentry/sentry-go v0.13.0 // indirect
5660
github.com/ghodss/yaml v1.0.0 // indirect
61+
github.com/go-logr/logr v1.2.3 // indirect
62+
github.com/go-openapi/jsonpointer v0.19.5 // indirect
63+
github.com/go-openapi/jsonreference v0.20.0 // indirect
64+
github.com/go-openapi/swag v0.19.14 // indirect
5765
github.com/gofrs/flock v0.8.1 // indirect
5866
github.com/gofrs/uuid v4.2.0+incompatible // indirect
5967
github.com/gogo/protobuf v1.3.2 // indirect
6068
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
6169
github.com/golang/protobuf v1.5.2 // indirect
70+
github.com/google/gnostic v0.5.7-v3refs // indirect
71+
github.com/google/gofuzz v1.1.0 // indirect
6272
github.com/google/uuid v1.3.0 // indirect
6373
github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect
6474
github.com/googleapis/gax-go/v2 v2.6.0 // indirect
6575
github.com/gorilla/css v1.0.0 // indirect
6676
github.com/hexops/gotextdiff v1.0.3 // indirect
6777
github.com/hexops/valast v1.4.1 // indirect
6878
github.com/huandu/xstrings v1.0.0 // indirect
69-
github.com/imdario/mergo v0.3.4 // indirect
79+
github.com/imdario/mergo v0.3.6 // indirect
7080
github.com/inconshreveable/mousetrap v1.0.0 // indirect
7181
github.com/jdxcode/netrc v0.0.0-20210204082910-926c7f70242a // indirect
7282
github.com/jhump/protocompile v0.0.0-20220216033700-d705409f108f // indirect
7383
github.com/jhump/protoreflect v1.12.1-0.20220417024638-438db461d753 // indirect
84+
github.com/josharian/intern v1.0.0 // indirect
7485
github.com/json-iterator/go v1.1.12 // indirect
7586
github.com/klauspost/compress v1.15.1 // indirect
7687
github.com/klauspost/pgzip v1.2.5 // indirect
7788
github.com/kr/pretty v0.3.0 // indirect
7889
github.com/kr/text v0.2.0 // indirect
7990
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
91+
github.com/mailru/easyjson v0.7.6 // indirect
8092
github.com/mattn/go-colorable v0.1.13 // indirect
8193
github.com/mattn/go-runewidth v0.0.13 // indirect
8294
github.com/microcosm-cc/bluemonday v1.0.17 // indirect
95+
github.com/moby/spdystream v0.2.0 // indirect
8396
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
8497
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
8598
github.com/modern-go/reflect2 v1.0.2 // indirect
8699
github.com/muesli/reflow v0.3.0 // indirect
87100
github.com/muesli/termenv v0.12.0 // indirect
101+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
88102
github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007 // indirect
89103
github.com/nightlyone/lockfile v1.0.0 // indirect
90104
github.com/olekukonko/tablewriter v0.0.5 // indirect
@@ -117,13 +131,21 @@ require (
117131
golang.org/x/sys v0.4.0 // indirect
118132
golang.org/x/term v0.4.0 // indirect
119133
golang.org/x/text v0.6.0 // indirect
134+
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
120135
golang.org/x/tools v0.5.0 // indirect
121136
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
122137
google.golang.org/appengine v1.6.7 // indirect
123138
google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e // indirect
124139
google.golang.org/grpc v1.50.1 // indirect
140+
gopkg.in/inf.v0 v0.9.1 // indirect
125141
gopkg.in/yaml.v2 v2.4.0 // indirect
142+
k8s.io/klog/v2 v2.80.1 // indirect
143+
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect
144+
k8s.io/utils v0.0.0-20221107191617-1a15be271d1d // indirect
126145
mvdan.cc/gofumpt v0.2.1 // indirect
146+
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
147+
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
148+
sigs.k8s.io/yaml v1.3.0 // indirect
127149
)
128150

129151
// See: https://github.com/ghodss/yaml/pull/65

0 commit comments

Comments
 (0)