Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove built-in kubectl from the code-base, adjust e2e tests to use plugin version #986

Closed
Closed
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
77 changes: 12 additions & 65 deletions cmd/botkube/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package main

import (
"context"
"encoding/json"
"fmt"
"log"
"net/http"
Expand Down Expand Up @@ -41,7 +40,6 @@ import (
"github.com/kubeshop/botkube/pkg/config"
"github.com/kubeshop/botkube/pkg/controller"
"github.com/kubeshop/botkube/pkg/execute"
"github.com/kubeshop/botkube/pkg/execute/kubectl"
"github.com/kubeshop/botkube/pkg/filterengine"
"github.com/kubeshop/botkube/pkg/httpsrv"
"github.com/kubeshop/botkube/pkg/notifier"
Expand Down Expand Up @@ -127,7 +125,7 @@ func run(ctx context.Context) error {
if err != nil {
return reportFatalError("while loading k8s config", err)
}
dynamicCli, discoveryCli, mapper, err := getK8sClients(kubeConfig)
dynamicCli, mapper, err := getK8sClients(kubeConfig)
if err != nil {
return reportFatalError("while getting K8s clients", err)
}
Expand Down Expand Up @@ -159,46 +157,20 @@ func run(ctx context.Context) error {
// Set up the filter engine
filterEngine := filterengine.WithAllFilters(logger, dynamicCli, mapper, conf.Filters)

// Kubectl config merger
kcMerger := kubectl.NewMerger(conf.Executors)

// Load resource variants name if needed
var resourceNameNormalizerFunc kubectl.ResourceVariantsFunc
if kcMerger.IsAtLeastOneEnabled() {
resourceNameNormalizer, err := kubectl.NewResourceNormalizer(
logger.WithField(componentLogFieldKey, "Resource Name Normalizer"),
discoveryCli,
)
if err != nil {
return reportFatalError("while creating resource name normalizer", err)
}
resourceNameNormalizerFunc = resourceNameNormalizer.Normalize
}

cmdGuard := kubectl.NewCommandGuard(logger.WithField(componentLogFieldKey, "Command Guard"), discoveryCli)
commander := kubectl.NewCommander(logger.WithField(componentLogFieldKey, "Commander"), kcMerger, cmdGuard)

runner := &execute.OSCommand{}
k8sVersion, err := findK8sVersion(runner)
botkubeVersion, err := findVersions(k8sCli)
if err != nil {
return reportFatalError("while fetching kubernetes version", err)
return reportFatalError("while fetching versions", err)
}
botkubeVersion := findBotkubeVersion(k8sVersion)

// Create executor factory
cfgManager := config.NewManager(logger.WithField(componentLogFieldKey, "Config manager"), conf.Settings.PersistentConfig, k8sCli)
executorFactory, err := execute.NewExecutorFactory(
execute.DefaultExecutorFactoryParams{
Log: logger.WithField(componentLogFieldKey, "Executor"),
CmdRunner: runner,
Cfg: *conf,
FilterEngine: filterEngine,
KcChecker: kubectl.NewChecker(resourceNameNormalizerFunc),
Merger: kcMerger,
CfgManager: cfgManager,
AnalyticsReporter: reporter,
NamespaceLister: k8sCli.CoreV1().Namespaces(),
CommandGuard: cmdGuard,
PluginManager: pluginManager,
BotKubeVersion: botkubeVersion,
},
Expand Down Expand Up @@ -243,7 +215,7 @@ func run(ctx context.Context) error {
}

if commGroupCfg.SocketSlack.Enabled {
sb, err := bot.NewSocketSlack(commGroupLogger.WithField(botLogFieldKey, "SocketSlack"), commGroupName, commGroupCfg.SocketSlack, executorFactory, commander, reporter)
sb, err := bot.NewSocketSlack(commGroupLogger.WithField(botLogFieldKey, "SocketSlack"), commGroupName, commGroupCfg.SocketSlack, executorFactory, reporter)
if err != nil {
return reportFatalError("while creating SocketSlack bot", err)
}
Expand Down Expand Up @@ -443,20 +415,20 @@ func newAnalyticsReporter(disableAnalytics bool, logger logrus.FieldLogger) (ana
return analyticsReporter, nil
}

func getK8sClients(cfg *rest.Config) (dynamic.Interface, discovery.DiscoveryInterface, meta.RESTMapper, error) {
func getK8sClients(cfg *rest.Config) (dynamic.Interface, meta.RESTMapper, error) {
discoveryClient, err := discovery.NewDiscoveryClientForConfig(cfg)
if err != nil {
return nil, nil, nil, fmt.Errorf("while creating discovery client: %w", err)
return nil, nil, fmt.Errorf("while creating discovery client: %w", err)
}

dynamicK8sCli, err := dynamic.NewForConfig(cfg)
if err != nil {
return nil, nil, nil, fmt.Errorf("while creating dynamic K8s client: %w", err)
return nil, nil, fmt.Errorf("while creating dynamic K8s client: %w", err)
}

discoCacheClient := memory.NewMemCacheClient(discoveryClient)
mapper := restmapper.NewDeferredDiscoveryRESTMapper(discoCacheClient)
return dynamicK8sCli, discoCacheClient, mapper, nil
return dynamicK8sCli, mapper, nil
}

func reportFatalErrFn(logger logrus.FieldLogger, reporter analytics.Reporter, status status.StatusReporter) func(ctx string, err error) error {
Expand Down Expand Up @@ -503,41 +475,16 @@ func sendHelp(ctx context.Context, s *storage.Help, clusterName string, executor
return s.MarkHelpAsSent(ctx, sent)
}

func findK8sVersion(runner *execute.OSCommand) (string, error) {
type kubectlVersionOutput struct {
Server struct {
GitVersion string `json:"gitVersion"`
} `json:"serverVersion"`
}

args := []string{"-c", fmt.Sprintf("%s version --output=json", execute.KubectlBinary)}
stdout, stderr, err := runner.RunSeparateOutput("sh", args)
func findVersions(cli *kubernetes.Clientset) (string, error) {
k8sVer, err := cli.ServerVersion()
if err != nil {
return "", fmt.Errorf("unable to execute kubectl version: %w [%q]", err, stderr)
return "", fmt.Errorf("while getting server version: %w", err)
}

var out kubectlVersionOutput
err = json.Unmarshal([]byte(stdout), &out)
if err != nil {
return "", err
}
if out.Server.GitVersion == "" {
return "", fmt.Errorf("unable to unmarshal server git version from %q", stdout)
}

ver := out.Server.GitVersion
if stderr != "" {
ver += "\n" + stderr
}

return ver, nil
}

func findBotkubeVersion(k8sVersion string) (versions string) {
botkubeVersion := version.Short()
if len(botkubeVersion) == 0 {
botkubeVersion = "Unknown"
}

return fmt.Sprintf("K8s Server Version: %s\nBotkube version: %s", k8sVersion, botkubeVersion)
return fmt.Sprintf("K8s Server Version: %s\nBotkube version: %s", k8sVer.String(), botkubeVersion), nil
}
77 changes: 40 additions & 37 deletions helm/botkube/e2e-test-values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -138,51 +138,54 @@ sources:

executors:
'k8s-default-tools':
kubectl:
botkube/kubectl:
enabled: true
namespaces:
include:
- botkube
- default
context:
rbac:
group:
type: Static
static:
# read-only access to 'botkube' and 'default' namespaces
values: ["kc-default"]
'kubectl-wait-cmd':
kubectl:
botkube/kubectl:
enabled: true
namespaces:
include:
- botkube
- default
commands:
verbs: [ "wait" ]
restrictAccess: false
context:
rbac:
group:
type: Static
static:
# 'wait' verb perms on 'botkube' and 'default' namespaces
values: [ "kc-wait" ]
'kubectl-exec-cmd':
kubectl:
enabled: false
namespaces:
include:
- botkube
- default
commands:
verbs: [ "exec" ]
restrictAccess: false
botkube/kubectl:
context:
rbac:
group:
type: Static
static:
# 'exec' verb perms on 'botkube' and 'default' namespaces
values: [ "kc-exec" ]
'kubectl-allow-all':
kubectl:
botkube/kubectl:
enabled: true
namespaces:
include:
- ".*"
commands:
verbs: [ "get" ]
resources: [ "deployments" ]
context:
rbac:
group:
type: Static
static:
# get deployments across all namespaces
values: [ "kc-get-deploy-all" ]
'kubectl-not-bound-to-any-channel':
kubectl:
botkube/kubectl:
enabled: true
namespaces:
include:
- ".*"
commands:
verbs: [ "port-forward" ]
resources: [ "deployments" ]

context:
rbac:
group:
type: Static
static:
# deployments port-forward across all namespaces
values: [ "kc-port-deploy-all" ]
'plugin-based':
botkube/[email protected]:
enabled: true
Expand Down
26 changes: 0 additions & 26 deletions helm/botkube/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -427,32 +427,6 @@ filters:
## Format: executors.{alias}
executors:
k8s-default-tools:
## Built-in Kubectl executor configuration.
## DEPRECATED: The botkube/kubectl plugin version should be used instead. If both are enabled the plugin version takes the precedences.
kubectl:
namespaces:
# -- List of allowed Kubernetes Namespaces for command execution.
# It can also contain a regex expressions:
# `- ".*"` - to specify all Namespaces.
include:
- ".*"
# -- List of ignored Kubernetes Namespace.
# It can also contain a regex expressions:
# `- "test-.*"` - to specify all Namespaces.
exclude: []
# -- If true, enables `kubectl` commands execution.
enabled: false
## List of allowed `kubectl` commands.
commands:
# -- Configures which `kubectl` methods are allowed.
verbs: ["api-resources", "api-versions", "cluster-info", "describe", "explain", "get", "logs", "top"]
# -- Configures which K8s resource are allowed.
resources: ["deployments", "pods", "namespaces", "daemonsets", "statefulsets", "storageclasses", "nodes", "configmaps", "services", "ingresses"]
# -- Configures the default Namespace for executing Botkube `kubectl` commands. If not set, uses the 'default'.
defaultNamespace: default
# -- If true, enables commands execution from configured channel only.
restrictAccess: false

## Helm executor configuration
## Plugin name syntax: <repo>/<plugin>[@<version>]. If version is not provided, the latest version from repository is used.
botkube/helm:
Expand Down
Loading