Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e0157d9bc2 | ||
|
|
1f2da68bbb | ||
|
|
7e2f982af7 | ||
|
|
0502d76c63 | ||
|
|
591b084970 | ||
|
|
f24a8e44ca | ||
|
|
8cb8a5d95d | ||
|
|
a4834dd4f7 | ||
|
|
8b6a8fdd4b | ||
|
|
dbcef2699e | ||
|
|
22aa1df894 | ||
|
|
8f7b481934 | ||
|
|
e843b26759 |
3
.github/ISSUE_TEMPLATE/bug_report.md
vendored
3
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -7,6 +7,9 @@ assignees: ''
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
**My drone-helm3 and drone versions:**
|
||||||
|
<!-- e.g. drone-helm3 0.9.0, drone 1.6.0-->
|
||||||
|
|
||||||
**What I tried to do:**
|
**What I tried to do:**
|
||||||
<!-- e.g. run a helm installation -->
|
<!-- e.g. run a helm installation -->
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM alpine/helm:3.0.2
|
FROM alpine/helm:3.1.1
|
||||||
MAINTAINER Erin Call <erin@liffft.com>
|
MAINTAINER Erin Call <erin@liffft.com>
|
||||||
|
|
||||||
COPY build/drone-helm /bin/drone-helm
|
COPY build/drone-helm /bin/drone-helm
|
||||||
|
|||||||
@@ -95,6 +95,26 @@ values_files: [ "./over_9,000.yml" ]
|
|||||||
values_files: [ "./over_9", "000.yml" ]
|
values_files: [ "./over_9", "000.yml" ]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Interpolating secrets into the `values`, `string_values` and `add_repos` settings
|
||||||
|
|
||||||
|
If you want to send secrets to your charts, you can use syntax similar to shell variable interpolation--either `$VARNAME` or `$${VARNAME}`. The double dollar-sign is necessary when using curly brackets; using curly brackets with a single dollar-sign will trigger Drone's string substitution (which can't use arbitrary environment variables). If an environment variable is not set, it will be treated as if it were set to the empty string.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
environment:
|
||||||
|
DB_PASSWORD:
|
||||||
|
from_secret: db_password
|
||||||
|
SESSION_KEY:
|
||||||
|
from_secret: session_key
|
||||||
|
settings:
|
||||||
|
values:
|
||||||
|
- db_password=$DB_PASSWORD # db_password will be set to the contents of the db_password secret
|
||||||
|
- db_pass=$DB_PASS # db_pass will be set to "" since $DB_PASS is not set
|
||||||
|
- session_key=$${SESSION_KEY} # session_key will be set to the contents of the session_key secret
|
||||||
|
- sess_key=${SESSION_KEY} # sess_key will be set to "" by Drone's variable substitution
|
||||||
|
```
|
||||||
|
|
||||||
|
Variables intended for interpolation must be set in the `environment` section, not `settings`.
|
||||||
|
|
||||||
### Backward-compatibility aliases
|
### Backward-compatibility aliases
|
||||||
|
|
||||||
Some settings have alternate names, for backward-compatibility with drone-helm. We recommend using the canonical name unless you require the backward-compatible form.
|
Some settings have alternate names, for backward-compatibility with drone-helm. We recommend using the canonical name unless you require the backward-compatible form.
|
||||||
|
|||||||
30
internal/env/config.go
vendored
30
internal/env/config.go
vendored
@@ -2,11 +2,12 @@ package env
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/kelseyhightower/envconfig"
|
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/kelseyhightower/envconfig"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -89,6 +90,8 @@ func NewConfig(stdout, stderr io.Writer) (*Config, error) {
|
|||||||
cfg.Timeout = fmt.Sprintf("%ss", cfg.Timeout)
|
cfg.Timeout = fmt.Sprintf("%ss", cfg.Timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cfg.loadValuesSecrets()
|
||||||
|
|
||||||
if cfg.Debug && cfg.Stderr != nil {
|
if cfg.Debug && cfg.Stderr != nil {
|
||||||
cfg.logDebug()
|
cfg.logDebug()
|
||||||
}
|
}
|
||||||
@@ -98,6 +101,31 @@ func NewConfig(stdout, stderr io.Writer) (*Config, error) {
|
|||||||
return &cfg, nil
|
return &cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cfg *Config) loadValuesSecrets() {
|
||||||
|
findVar := regexp.MustCompile(`\$\{?(\w+)\}?`)
|
||||||
|
|
||||||
|
replacer := func(varName string) string {
|
||||||
|
sigils := regexp.MustCompile(`[${}]`)
|
||||||
|
varName = sigils.ReplaceAllString(varName, "")
|
||||||
|
|
||||||
|
if value, ok := os.LookupEnv(varName); ok {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.Debug {
|
||||||
|
fmt.Fprintf(cfg.Stderr, "$%s not present in environment, replaced with \"\"\n", varName)
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.Values = findVar.ReplaceAllStringFunc(cfg.Values, replacer)
|
||||||
|
cfg.StringValues = findVar.ReplaceAllStringFunc(cfg.StringValues, replacer)
|
||||||
|
|
||||||
|
for i := 0; i < len(cfg.AddRepos); i++ {
|
||||||
|
cfg.AddRepos[i] = findVar.ReplaceAllStringFunc(cfg.AddRepos[i], replacer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (cfg Config) logDebug() {
|
func (cfg Config) logDebug() {
|
||||||
if cfg.KubeToken != "" {
|
if cfg.KubeToken != "" {
|
||||||
cfg.KubeToken = "(redacted)"
|
cfg.KubeToken = "(redacted)"
|
||||||
|
|||||||
36
internal/env/config_test.go
vendored
36
internal/env/config_test.go
vendored
@@ -2,10 +2,11 @@ package env
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/stretchr/testify/suite"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ConfigTestSuite struct {
|
type ConfigTestSuite struct {
|
||||||
@@ -183,6 +184,39 @@ func (suite *ConfigTestSuite) TestLogDebugCensorsKubeToken() {
|
|||||||
suite.Equal(kubeToken, cfg.KubeToken) // The actual config value should be left unchanged
|
suite.Equal(kubeToken, cfg.KubeToken) // The actual config value should be left unchanged
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *ConfigTestSuite) TestNewConfigWithValuesSecrets() {
|
||||||
|
suite.unsetenv("VALUES")
|
||||||
|
suite.unsetenv("STRING_VALUES")
|
||||||
|
suite.unsetenv("SECRET_WATER")
|
||||||
|
suite.setenv("SECRET_FIRE", "Eru_Ilúvatar")
|
||||||
|
suite.setenv("SECRET_RINGS", "1")
|
||||||
|
suite.setenv("PLUGIN_VALUES", "fire=$SECRET_FIRE,water=${SECRET_WATER}")
|
||||||
|
suite.setenv("PLUGIN_STRING_VALUES", "rings=${SECRET_RINGS}")
|
||||||
|
suite.setenv("PLUGIN_ADD_REPOS", "testrepo=https://user:${SECRET_FIRE}@testrepo.test")
|
||||||
|
|
||||||
|
cfg, err := NewConfig(&strings.Builder{}, &strings.Builder{})
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
suite.Equal("fire=Eru_Ilúvatar,water=", cfg.Values)
|
||||||
|
suite.Equal("rings=1", cfg.StringValues)
|
||||||
|
suite.Equal(fmt.Sprintf("testrepo=https://user:%s@testrepo.test", os.Getenv("SECRET_FIRE")), cfg.AddRepos[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *ConfigTestSuite) TestValuesSecretsWithDebugLogging() {
|
||||||
|
suite.unsetenv("VALUES")
|
||||||
|
suite.unsetenv("SECRET_WATER")
|
||||||
|
suite.setenv("SECRET_FIRE", "Eru_Ilúvatar")
|
||||||
|
suite.setenv("PLUGIN_DEBUG", "true")
|
||||||
|
suite.setenv("PLUGIN_STRING_VALUES", "fire=$SECRET_FIRE")
|
||||||
|
suite.setenv("PLUGIN_VALUES", "fire=$SECRET_FIRE,water=$SECRET_WATER")
|
||||||
|
stderr := strings.Builder{}
|
||||||
|
_, err := NewConfig(&strings.Builder{}, &stderr)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
suite.Contains(stderr.String(), "Values:fire=Eru_Ilúvatar,water=")
|
||||||
|
suite.Contains(stderr.String(), `$SECRET_WATER not present in environment, replaced with ""`)
|
||||||
|
}
|
||||||
|
|
||||||
func (suite *ConfigTestSuite) setenv(key, val string) {
|
func (suite *ConfigTestSuite) setenv(key, val string) {
|
||||||
orig, ok := os.LookupEnv(key)
|
orig, ok := os.LookupEnv(key)
|
||||||
if ok {
|
if ok {
|
||||||
|
|||||||
Reference in New Issue
Block a user