Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions cmd/src/validate_kube.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ Examples:

Suppress output (useful for CI/CD pipelines)
$ src validate kube --quiet

Validate EKS cluster:
$ src validate kube --eks

Validate GKE cluster:
$ src validate kube --gke

Validate AKS cluster:
$ src validate kube --aks
`

flagSet := flag.NewFlagSet("kube", flag.ExitOnError)
Expand All @@ -48,6 +57,7 @@ Examples:
quiet = flagSet.Bool("quiet", false, "(optional) suppress output and return exit status only")
eks = flagSet.Bool("eks", false, "(optional) validate EKS cluster")
gke = flagSet.Bool("gke", false, "(optional) validate GKE cluster")
aks = flagSet.Bool("aks", false, "(optional) validate AKS cluster")
)

if home := homedir.HomeDir(); home != "" {
Expand Down Expand Up @@ -96,6 +106,10 @@ Examples:
options = append(options, kube.Gke())
}

if *aks {
options = append(options, kube.Aks())
}

return kube.Validate(context.Background(), clientSet, config, options...)
}

Expand Down
91 changes: 91 additions & 0 deletions internal/validate/kube/aks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package kube

import (
"context"

"github.com/sourcegraph/src-cli/internal/validate"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func Aks() Option {
return func(config *Config) {
config.aks = true
}
}

func AksCsiDrivers(ctx context.Context, config *Config) ([]validate.Result, error) {
var results []validate.Result

storageClassResults, err := validateStorageClass(ctx, config)
if err != nil {
results = append(results, validate.Result{
Status: validate.Failure,
Message: "AKS: could not validate if persistent volumes are enabled",
})

return results, err
}

results = append(results, storageClassResults...)

return results, nil
}

func validateStorageClass(ctx context.Context, config *Config) ([]validate.Result, error) {
var results []validate.Result

storageClient := config.clientSet.StorageV1()
storageClasses, err := storageClient.StorageClasses().List(ctx, metav1.ListOptions{})
if err != nil {
return nil, err
}

for _, item := range storageClasses.Items {
if item.Name == "sourcegraph" {
if item.Provisioner != "disk.csi.azure.com" {
results = append(results, validate.Result{
Status: validate.Failure,
Message: "provisioner does not enable persistent volumes",
})
} else {
results = append(results, validate.Result{
Status: validate.Success,
Message: "persistent volumes enabled",
})
}

if string(*item.ReclaimPolicy) != "Retain" {
results = append(results, validate.Result{
Status: validate.Failure,
Message: "storageclass has a reclaim policy other than 'Retain'",
})
} else {
results = append(results, validate.Result{
Status: validate.Success,
Message: "storageclass has correct reclaim policy (Retain)",
})
}

if string(*item.VolumeBindingMode) != "WaitForFirstConsumer" {
results = append(results, validate.Result{
Status: validate.Failure,
Message: "storageclass has a binding mode other than 'WaitForFirstConsumer'",
})
} else {
results = append(results, validate.Result{
Status: validate.Success,
Message: "storageclass has correct volumeBindingMode (WaitForFirstConsumer)",
})
}
}
}

if len(results) == 0 {
results = append(results, validate.Result{
Status: validate.Warning,
Message: "you have not yet deployed a sourcegraph instance to this cluster, or you've named your storageclass something other than 'sourcegraph'",
})
}

return results, nil
}
29 changes: 29 additions & 0 deletions internal/validate/kube/kube.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ type Config struct {
restConfig *rest.Config
eks bool
gke bool
aks bool
eksClient *eks.Client
ec2Client *ec2.Client
iamClient *iam.Client
Expand Down Expand Up @@ -81,6 +82,7 @@ func Validate(ctx context.Context, clientSet *kubernetes.Clientset, restConfig *
restConfig: restConfig,
eks: false,
gke: false,
aks: false,
}

for _, opt := range opts {
Expand Down Expand Up @@ -133,6 +135,21 @@ func Validate(ctx context.Context, clientSet *kubernetes.Clientset, restConfig *
})
}

if cfg.aks {
if err := CurrentContextSetTo("aks"); err != nil {
return errors.Newf("%s %s", validate.FailureEmoji, err)
}

Aks()

validations = append(validations, validation{
Validate: AksCsiDrivers,
WaitMsg: "AKS: validating persistent volumes",
SuccessMsg: "AKS: persistent volumes validated",
ErrMsg: "AKS: validating persistent volumes failed",
})
}

var totalFailCount int

for _, v := range validations {
Expand Down Expand Up @@ -457,12 +474,24 @@ func CurrentContextSetTo(clusterService string) error {
got := strings.Split(currentContext, ":")
want := []string{"arn", "aws", clusterService}

if got[0] != "arn" {
return errors.New("no eks cluster configured")
}

if len(got) >= 3 {
got = got[:3]
if !reflect.DeepEqual(got, want) {
return errors.New("no eks cluster configured")
}
}
} else if clusterService == "aks" {
colons := strings.Split(currentContext, ":") // aws string
underscores := strings.Split(currentContext, "_") // gke string

// if current context has 'arn' or 'gke' in string, return error
if colons[0] == "arn" || underscores[0] == "gke" {
return errors.New("no aks cluster configured")
}
}

return nil
Expand Down