Skip to content

Commit

Permalink
Update dockerfile, add kubeconfig, minor fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
mszostok committed Jul 2, 2023
1 parent 406fc7b commit 4829a1b
Show file tree
Hide file tree
Showing 12 changed files with 138 additions and 55 deletions.
7 changes: 6 additions & 1 deletion build/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM alpine:3.15
FROM alpine:3.18
ARG botkube_version="dev"
LABEL org.opencontainers.image.source="[email protected]:kubeshop/botkube.git" \
org.opencontainers.image.title="Botkube" \
Expand All @@ -9,6 +9,11 @@ LABEL org.opencontainers.image.source="[email protected]:kubeshop/botkube.git" \

COPY botkube /usr/local/bin/botkube

RUN apk add --no-cache 'git=>2.38' 'openssh=~9.3' && \
mkdir /root/.ssh && \
chmod 700 /root/.ssh && \
ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts

# Create Non Privileged user
RUN addgroup --gid 1001 botkube && \
adduser -S --uid 1001 --ingroup botkube botkube
Expand Down
74 changes: 51 additions & 23 deletions cmd/executor/x/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,14 @@ func (i *XExecutor) Execute(ctx context.Context, in executor.ExecuteInput) (exec
log.WithField("tool", tool).Info("Running command...")

state := state.ExtractSlackState(in.Context.SlackState)
return x.NewRunner(log, renderer).Run(ctx, cfg, state, tool)

kubeConfigPath, deleteFn, err := i.getKubeconfig(ctx, log, in)
defer deleteFn()
if err != nil {
return executor.ExecuteOutput{}, err
}

return x.NewRunner(log, renderer).Run(ctx, cfg, state, tool, kubeConfigPath)
case cmd.Install != nil:
var (
tool = Normalize(strings.Join(cmd.Install.Tool, " "))
Expand Down Expand Up @@ -148,6 +155,23 @@ func (i *XExecutor) Execute(ctx context.Context, in executor.ExecuteInput) (exec
}, nil
}

func (i *XExecutor) getKubeconfig(ctx context.Context, log logrus.FieldLogger, in executor.ExecuteInput) (string, func(), error) {
if len(in.Context.KubeConfig) == 0 {
return "", func() {}, nil
}
kubeConfigPath, deleteFn, err := pluginx.PersistKubeConfig(ctx, in.Context.KubeConfig)
if err != nil {
return "", func() {}, fmt.Errorf("while writing kubeconfig file: %w", err)
}

return kubeConfigPath, func() {
err := deleteFn(ctx)
if err != nil {
log.WithError(err).WithField("kubeconfigPath", kubeConfigPath).Error("Failed to delete kubeconfig file")
}
}, nil
}

func main() {
executor.Serve(map[string]plugin.Plugin{
pluginName: &executor.Plugin{
Expand All @@ -160,28 +184,32 @@ func main() {
func jsonSchema() api.JSONSchema {
return api.JSONSchema{
Value: heredoc.Docf(`{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "x",
"description": "Install and run CLIs directly from chat window without hassle. All magic included.",
"type": "object",
"properties": {
"templates": {
"type": "array",
"items": {
"type": "object",
"properties": {
"ref": {
"type": "string",
"default": "github.com/mszostok/botkube-plugins//x-templates?ref=hackathon"
}
},
"required": ["ref"],
"additionalProperties": false
}
}
},
"required": ["templates"]
}`),
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "x",
"description": "Install and run CLIs directly from chat window without hassle. All magic included.",
"type": "object",
"properties": {
"templates": {
"type": "array",
"items": {
"type": "object",
"properties": {
"ref": {
"type": "string",
"default": "github.com/mszostok/botkube-plugins//x-templates?ref=hackathon"
}
},
"required": [
"ref"
],
"additionalProperties": false
}
}
},
"required": [
"templates"
]
}`),
}
}

Expand Down
12 changes: 12 additions & 0 deletions cmd/executor/x/templates/argo.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
templates:
- command:
prefix: "argo list"
parser: "table"
message:
select:
name: "Workflows"
itemKey: "{{ .Namespace }}/{{ .Name }}"
actions:
logs: "argo logs {{ .Name }} -n {{ .Namespace }}"
describe: "argo get {{ .Name }} -n {{ .Namespace }}"
delete: "argo delete {{ .Name }} -n {{ .Namespace }}"
16 changes: 16 additions & 0 deletions cmd/executor/x/templates/flux.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
templates:
- trigger:
command: "flux get sources"
type: "parser:table:space"
message:
selects:
- name: "Source"
keyTpl: "{{ .Name }}"
actions:
export: "flux export source git {{ .Name }}"
preview: |
Name: {{ .Name }}
Revision: {{ .Revision }}
Suspended: {{ .Suspended }}
Ready: {{ .Ready }}
Message: {{ .Message}}
17 changes: 17 additions & 0 deletions cmd/executor/x/templates/helm.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
templates:
- trigger:
command: "helm list"
type: "parser:table:space"
message:
selects:
- name: "Release"
keyTpl: "{{ .Namespace }}/{{ .Name }}"
actions:
notes: "helm get notes {{ .Name }} -n {{ .Namespace }}"
values: "helm get values {{ .Name }} -n {{ .Namespace }}"
delete: "helm delete {{ .Name }} -n {{ .Namespace }}"
preview: |
Name: {{ .Name }}
Namespace: {{ .Namespace }}
Status: {{ .Status }}
Chart: {{ .Chart }}
2 changes: 1 addition & 1 deletion internal/executor/x/getter/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func Load[T any](ctx context.Context, tmpDir string, templateSources []Source) (
return nil
}

file, err := os.ReadFile(path)
file, err := os.ReadFile(filepath.Clean(path))
if err != nil {
return err
}
Expand Down
10 changes: 3 additions & 7 deletions internal/executor/x/output/message_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,7 @@ func (p *CommandParser) RenderMessage(cmd, output string, state *state.Container
var sections []api.Section

// dropdowns
dropdowns, selectedIdx, err := p.renderDropdowns(msg.Selects, out.Table, cmd, state)
if err != nil {
return api.Message{}, err
}
dropdowns, selectedIdx := p.renderDropdowns(msg.Selects, out.Table, cmd, state)
sections = append(sections, dropdowns)
// preview
preview, err := p.renderPreview(msg, out, selectedIdx)
Expand Down Expand Up @@ -160,8 +157,7 @@ func (*CommandParser) getPreviewLine(lines []string, idx int) string {
return lines[1] // otherwise default first line
}

func (p *CommandParser) renderDropdowns(selects []template.Select, commandData parser.Table, cmd string, state *state.Container) (api.Section, int, error) {

func (p *CommandParser) renderDropdowns(selects []template.Select, commandData parser.Table, cmd string, state *state.Container) (api.Section, int) {
var (
dropdowns []api.Select
lastSelectedIdx int
Expand All @@ -184,7 +180,7 @@ func (p *CommandParser) renderDropdowns(selects []template.Select, commandData p
ID: state.GetSelectsBlockID(),
Items: dropdowns,
},
}, lastSelectedIdx, nil
}, lastSelectedIdx
}

func (p *CommandParser) selectDropdown(name, cmd, keyTpl string, table parser.Table, state *state.Container) (*api.Select, int) {
Expand Down
1 change: 1 addition & 0 deletions internal/executor/x/parser/space_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type TableSpace struct{}
func (*TableSpace) TableSeparated(in string) TableOutput {
var out TableOutput
in = replaceTabsWithSpaces(in)
in = strings.TrimSpace(in)
scanner := bufio.NewScanner(strings.NewReader(in))

// Parse the headers
Expand Down
1 change: 0 additions & 1 deletion internal/executor/x/renderer.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ func (r *Renderer) Get(output string) (Render, error) {
printer, found := r.renderer[output]
if found {
return printer, nil

}
keys := maps.Keys(r.renderer)
for _, key := range keys {
Expand Down
31 changes: 14 additions & 17 deletions internal/executor/x/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package x

import (
"context"
"os"

"github.com/gookit/color"
"github.com/sirupsen/logrus"
Expand All @@ -28,7 +27,7 @@ func NewRunner(log logrus.FieldLogger, renderer *Renderer) *Runner {
}
}

func (i *Runner) Run(ctx context.Context, cfg Config, state *state.Container, tool string) (executor.ExecuteOutput, error) {
func (i *Runner) Run(ctx context.Context, cfg Config, state *state.Container, tool string, kubeconfigPath string) (executor.ExecuteOutput, error) {
cmd := Parse(tool)

templates, err := getter.Load[template.Template](ctx, cfg.TmpDir.GetDirectory(), cfg.Templates)
Expand All @@ -43,15 +42,12 @@ func (i *Runner) Run(ctx context.Context, cfg Config, state *state.Container, to
}).Info("Command template")
}

cmdTemplate, found := template.FindWithPrefix(templates, cmd.ToExecute)

var out string
if !found || cmdTemplate.Type != "tutorial" {
out, err = runCmd(ctx, cfg.TmpDir, cmd.ToExecute)
if err != nil {
i.log.WithError(err).WithField("command", cmd.ToExecute).Error("failed to run command")
return executor.ExecuteOutput{}, err
}
out, err := runCmd(ctx, cfg.TmpDir, cmd.ToExecute, map[string]string{
"KUBECONFIG": kubeconfigPath,
})
if err != nil {
i.log.WithError(err).WithField("command", cmd.ToExecute).Error("failed to run command")
return executor.ExecuteOutput{}, err
}

if cmd.IsRawRequired {
Expand All @@ -61,14 +57,15 @@ func (i *Runner) Run(ctx context.Context, cfg Config, state *state.Container, to
}, nil
}

cmdTemplate, found := template.FindWithPrefix(templates, cmd.ToExecute)
if !found {
i.log.Info("Templates config not found for command")
return executor.ExecuteOutput{
Message: api.NewCodeBlockMessage(color.ClearCode(out), true),
}, nil
}

render, err := i.renderer.Get(cmdTemplate.Type) // Message.Type
render, err := i.renderer.Get(cmdTemplate.Type)
if err != nil {
return executor.ExecuteOutput{}, err
}
Expand All @@ -82,15 +79,15 @@ func (i *Runner) Run(ctx context.Context, cfg Config, state *state.Container, to
}, nil
}

func runCmd(ctx context.Context, tmp plugin.TmpDir, in string) (string, error) {
func runCmd(ctx context.Context, tmp plugin.TmpDir, in string, envs map[string]string) (string, error) {
path, custom := tmp.Get()
if custom {
// FIXME: get rid of it
defer os.Setenv("PLUGIN_DEPENDENCY_DIR", os.Getenv("PLUGIN_DEPENDENCY_DIR"))
os.Setenv("PLUGIN_DEPENDENCY_DIR", path)
// we installed all assets in different directory, e.g. because we run it locally,
// so we override the default deps path
envs[plugin.DependencyDirEnvName] = path
}

out, err := pluginx.ExecuteCommand(ctx, in)
out, err := pluginx.ExecuteCommandWithEnvs(ctx, in, envs)
if err != nil {
return "", err
}
Expand Down
13 changes: 10 additions & 3 deletions internal/executor/x/state/slack.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,16 @@ func ExtractSlackState(state *slack.BlockActionStates) *Container {
for blockID, blocks := range state.Values {
cnt.SelectsBlockID = blockID
for id, act := range blocks {
//id = strings.TrimPrefix(id, kubectlCommandName)
//id = strings.TrimSpace(id)
cnt.Fields[id] = act.SelectedOption.Value
var val string
switch {
case act.SelectedOption.Value != "":
val = act.SelectedOption.Value
case act.Value != "":
val = act.Value
default:
continue
}
cnt.Fields[id] = val
}
}
return &cnt
Expand Down
9 changes: 7 additions & 2 deletions pkg/pluginx/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,13 @@ func ExecuteCommandWithEnvs(ctx context.Context, rawCmd string, envs map[string]
}

bin, binArgs := args[0], args[1:]
depDir, found := os.LookupEnv(plugin.DependencyDirEnvName)
if found {
if depDir, found := os.LookupEnv(plugin.DependencyDirEnvName); found {
// Use exactly the binary from the $PLUGIN_DEPENDENCY_DIR directory
bin = fmt.Sprintf("%s/%s", depDir, bin)
}

// allow to override it if needed
if depDir, found := envs[plugin.DependencyDirEnvName]; found {
// Use exactly the binary from the $PLUGIN_DEPENDENCY_DIR directory
bin = fmt.Sprintf("%s/%s", depDir, bin)
}
Expand Down

0 comments on commit 4829a1b

Please sign in to comment.