Skip to content

Commit

Permalink
Add support for cfg via env vars and define external volumes
Browse files Browse the repository at this point in the history
  • Loading branch information
mszostok committed Jun 3, 2022
1 parent 7735b83 commit 10b8f46
Show file tree
Hide file tree
Showing 7 changed files with 249 additions and 13 deletions.
6 changes: 5 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ require (
github.com/bwmarrin/discordgo v0.25.0
github.com/fsnotify/fsnotify v1.5.4
github.com/google/go-github/v44 v44.1.0
github.com/hashicorp/go-multierror v1.1.1
github.com/infracloudio/msbotbuilder-go v0.2.5
github.com/knadh/koanf v1.4.1
github.com/larksuite/oapi-sdk-go v1.1.44
github.com/mattermost/mattermost-server/v5 v5.39.3
github.com/olivere/elastic v6.2.37+incompatible
Expand Down Expand Up @@ -61,7 +63,6 @@ require (
github.com/gorilla/websocket v1.5.0 // indirect
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
Expand All @@ -83,8 +84,11 @@ require (
github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/minio-go/v7 v7.0.11 // indirect
github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-wordwrap v1.0.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/moby/spdystream v0.2.0 // indirect
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
Expand Down
44 changes: 44 additions & 0 deletions go.sum

Large diffs are not rendered by default.

13 changes: 8 additions & 5 deletions helm/botkube/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ spec:
volumeMounts:
- name: config-volume
mountPath: "/config"
{{- if ne (len .Values.extraVolumeMounts) 0 }}
{{ toYaml .Values.extraVolumeMounts | nindent 12 }}
{{- end }}
{{- if .Values.config.ssl.enabled }}
- name: certs
mountPath: "/etc/ssl/certs"
Expand All @@ -73,12 +76,9 @@ spec:
- name: KUBECONFIG
value: "/.kube/config"
{{- end }}
{{- if .Values.extraEnv }}
{{- range $name, $value := .Values.extraEnv }}
- name: {{ $name }}
value: {{ quote $value }}
{{- if .Values.extraEnv }}
{{ tpl (toYaml .Values.extraEnv) . | nindent 12 }}
{{- end }}
{{- end }}
{{- if .Values.resources }}
resources:
{{ toYaml .Values.resources | indent 12 }}
Expand All @@ -91,6 +91,9 @@ spec:
name: {{ include "botkube.fullname" . }}-configmap
- secret:
name: {{ include "botkube.CommunicationsSecretName" . }}
{{- if ne (len .Values.extraVolumes) 0 }}
{{ toYaml .Values.extraVolumes | nindent 8 }}
{{- end }}
{{- if .Values.config.ssl.enabled }}
- name: certs
secret:
Expand Down
43 changes: 40 additions & 3 deletions helm/botkube/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -417,10 +417,47 @@ resources: {}
# cpu: 100m
# memory: 128Mi

# Extra environment variables to pass to the BotKube container.
extraEnv: []
## Extra environment variables to pass to the BotKube container, example HTTP_PROXY
## extraEnv:
## HTTP_PROXY: <proxyURL>:<port>
# - name: <key>
# valueFrom:
# configMapKeyRef:
# name: configmap-name
# key: value_key
# - name: <key>
# value: value


# Extra volumes to pass to the BotKube container. Mount it later with extraVolumeMounts.
extraVolumes: []
# - name: extra-volume-0
# secret:
# secretName: <secret-name>
#
# for CSI e.g. Vault:
# - name: secrets-store-inline
# csi:
# driver: secrets-store.csi.k8s.io
# readOnly: true
# volumeAttributes:
# secretProviderClass: "vault-database"

# Extra volume mounts to pass to the BotKube container.
extraVolumeMounts: []
# - name: extra-volume-0
# mountPath: /mnt/volume0
# readOnly: true
# - name: extra-volume-1
# mountPath: /mnt/volume1
# readOnly: true
# - name: secret-files
# mountPath: /etc/secrets
# subPath: ""
#
# for CSI e.g. Vault:
# - name: secrets-store-inline
# mountPath: "/mnt/secrets-store"
# readOnly: true

nodeSelector: {}

Expand Down
37 changes: 33 additions & 4 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@ package config
import (
"os"
"path/filepath"
"strings"

"github.com/knadh/koanf"
koanfyaml "github.com/knadh/koanf/parsers/yaml"
"github.com/knadh/koanf/providers/env"
"github.com/knadh/koanf/providers/file"
"gopkg.in/yaml.v3"
)

Expand Down Expand Up @@ -69,6 +74,9 @@ const (
DiscordBot BotPlatform = "discord"
// LarkBot bot platform
LarkBot BotPlatform = "lark"

communicationEnvVariablePrefix = "COMMUNICATION_"
communicationConfigDelimiter = "."
)

// EventType to watch
Expand Down Expand Up @@ -256,16 +264,37 @@ func (eventType EventType) String() string {
func NewCommunicationsConfig() (*Communications, error) {
configPath := os.Getenv("CONFIG_PATH")
commCfgFilePath := filepath.Join(configPath, CommunicationConfigFileName)
rawCfg, err := os.ReadFile(filepath.Clean(commCfgFilePath))

k := koanf.New(communicationConfigDelimiter)

// Load base YAML config.
if err := k.Load(file.Provider(filepath.Clean(commCfgFilePath)), koanfyaml.Parser()); err != nil {
return nil, err
}

// Load environment variables and merge into the loaded config.
err := k.Load(env.Provider(
communicationEnvVariablePrefix,
communicationConfigDelimiter,
normalizeCommunicationConfigEnvName,
), nil)
if err != nil {
return nil, err
}

commCfg := &Communications{}
if err := yaml.Unmarshal(rawCfg, commCfg); err != nil {
var cfg Communications
err = k.UnmarshalWithConf("", &cfg, koanf.UnmarshalConf{Tag: "yaml"})
if err != nil {
return nil, err
}
return commCfg, nil

return &cfg, nil
}

func normalizeCommunicationConfigEnvName(name string) string {
name = strings.ReplaceAll(name, communicationEnvVariablePrefix, "COMMUNICATIONS_") // append 's' to fulfil the Communications field name.
name = strings.ToLower(name)
return strings.ReplaceAll(name, "_", ".")
}

// New returns new Config
Expand Down
62 changes: 62 additions & 0 deletions pkg/config/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package config

import (
"fmt"
"os"
"path/filepath"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gopkg.in/yaml.v3"
)

const sampleCommunicationConfig = "testdata/comm_config.yaml"

func TestCommunicationConfigSuccess(t *testing.T) {
t.Run("Load from file", func(t *testing.T) {
// given
t.Setenv("CONFIG_PATH", "testdata")

var expConfig Communications
loadYAMLFile(t, sampleCommunicationConfig, &expConfig)

// when
gotCfg, err := NewCommunicationsConfig()

//then
require.NoError(t, err)
require.NotNil(t, gotCfg)
assert.Equal(t, expConfig, *gotCfg)
})

t.Run("Load from file and override with environment variables", func(t *testing.T) {
// given
t.Setenv("CONFIG_PATH", "testdata")

fixToken := fmt.Sprintf("TOKEN_FROM_ENV_%d", time.Now().Unix())
t.Setenv("COMMUNICATION_SLACK_TOKEN", fixToken)
var expConfig Communications
loadYAMLFile(t, sampleCommunicationConfig, &expConfig)
expConfig.Communications.Slack.Token = fixToken

// when
gotCfg, err := NewCommunicationsConfig()

//then
require.NoError(t, err)
require.NotNil(t, gotCfg)
assert.Equal(t, expConfig, *gotCfg)
})
}

func loadYAMLFile(t *testing.T, path string, out interface{}) {
t.Helper()

raw, err := os.ReadFile(filepath.Clean(path))
require.NoError(t, err)

err = yaml.Unmarshal(raw, out)
require.NoError(t, err)
}
57 changes: 57 additions & 0 deletions pkg/config/testdata/comm_config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Channels configuration
communications:
# Settings for Slack
slack:
enabled: false
channel: 'SLACK_CHANNEL'
token: 'SLACK_API_TOKEN'
notiftype: short # Change notification type short/long you want to receive. notiftype is optional and Default notification type is short (if not specified)

# Settings for Mattermost
mattermost:
enabled: false
url: 'MATTERMOST_SERVER_URL' # URL where Mattermost is running. e.g https://example.com:9243
token: 'MATTERMOST_TOKEN' # Personal Access token generated by BotKube user
team: 'MATTERMOST_TEAM' # Mattermost Team to configure with BotKube
channel: 'MATTERMOST_CHANNEL' # Mattermost Channel for receiving BotKube alerts
notiftype: short # Change notification type short/long you want to receive. notiftype is optional and Default notification type is short (if not specified)

# Settings for MS Teams
teams:
enabled: false
appID: 'APPLICATION_ID'
appPassword: 'APPLICATION_PASSWORD'
notiftype: short
port: 3978

# Settings for Discord
discord:
enabled: false
token: 'DISCORD_TOKEN' # BotKube Bot Token
botid: 'DISCORD_BOT_ID' # BotKube Application Client ID
channel: 'DISCORD_CHANNEL_ID' # Discord Channel id for receiving BotKube alerts
notiftype: short # Change notification type short/long you want to receive. notiftype is optional and Default notification type is short (if not specified)


# Settings for ELS
elasticsearch:
enabled: false
awsSigning:
enabled: false # enable awsSigning using IAM for Elastisearch hosted on AWS, if true make sure AWS environment variables are set. Refer https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html
awsRegion: 'us-east-1' # AWS region where Elasticsearch is deployed
roleArn: '' # AWS IAM Role arn to assume for credentials, use this only if you dont want to use the EC2 instance role or not running on AWS instance
server: 'ELASTICSEARCH_ADDRESS' # e.g https://example.com:9243
username: 'ELASTICSEARCH_USERNAME' # Basic Auth
password: 'ELASTICSEARCH_PASSWORD'
skipTLSVerify: false # toggle verification of TLS certificate of the Elastic nodes. Verification is skipped when option is true. Enable to connect to clusters with self-signed certs
# ELS index settings
index:
name: botkube
type: botkube-event
shards: 1
replicas: 0

# Settings for Webhook
webhook:
enabled: false
url: 'WEBHOOK_URL' # e.g https://example.com:80

0 comments on commit 10b8f46

Please sign in to comment.