Don't fail on configuration keys like a:config:b:c

Configuration keys are simple namespace/name pairs, delimited by
":". For compatability, we also allow
"<namespace>:config:<name>", but we always record the "nice" name in
`Pulumi.<stack-name>.yaml`.

While `pulumi config` and friends would block setting a key like
`a🅱️c` (where the "name" has a colon in it), it would allow
`a:config:b:c`. However, this would be recorded as `a🅱️c` in
`Pulumi.<stack-name>.yaml`, which meant we'd error when parsing the
configuration file later.

To work around this, disallow ":" in the "name" part of a
configuration key.  With this change the following all work:

```
keyName
my-project:keyName
my-project:config:keyName
```

However, both

`my-project:keyName:subKey`
`my-project:config:keyName:subKey`

are now disallowed.

I considered allowing colons in subkeys, but I think it adds more
confusion (due to the interaction with how we allow you elide the
project name in the default case) than is worthwhile at this point.

Fixes #2171
This commit is contained in:
Matt Ellis 2018-11-19 14:14:42 -08:00
parent c878916901
commit 72d52c6e1f
3 changed files with 24 additions and 28 deletions

View file

@ -7,6 +7,8 @@
- Fix an issue where if the directory containing the `pulumi` executable was not on the `$PATH` we would fail to load language plugins. We now will also search next to the current running copy of Pulumi (fixes [pulumi/pulumi#1956](https://github.com/pulumi/pulumi/issues/1956))
- Fix an issue where passing a key of the form `foo:config:bar:baz` to `pulumi config set` would succeed but cause errors later when trying to interact with the stack. Setting this value is now blocked eagerly (fixes [pulumi/pulumi#2171](https://github.com/pulumi/pulumi/issues/2171))
## 0.16.5 (Released Novemeber 16th, 2018)
### Improvements

View file

@ -36,26 +36,30 @@ func MustMakeKey(namespace string, name string) Key {
}
func ParseKey(s string) (Key, error) {
mm, err := tokens.ParseModuleMember(s)
if err == nil {
return fromModuleMember(mm)
}
if idx := strings.Index(s, ":"); idx > -1 {
// Keys can take on of two forms:
//
// - <namespace>:<name> (the preferred form)
// - <namespace>:config:<name> (compat with an old requirement that every config value be in the "config" module)
//
// Where <namespace> and <name> may be any string of characters, excluding ':'.
switch strings.Count(s, ":") {
case 1:
idx := strings.Index(s, ":")
return Key{namespace: s[:idx], name: s[idx+1:]}, nil
case 2:
if mm, err := tokens.ParseModuleMember(s); err == nil {
if mm.Module().Name() == tokens.ModuleName("config") {
return Key{
namespace: mm.Module().Package().String(),
name: mm.Name().String(),
}, nil
}
}
}
return Key{}, errors.Errorf("could not parse %s as a configuration key", s)
}
func fromModuleMember(m tokens.ModuleMember) (Key, error) {
if m.Module().Name() != tokens.ModuleName("config") {
return Key{}, errors.Errorf("%s is not in config module", m)
}
return Key{
namespace: m.Module().Package().String(),
name: m.Name().String(),
}, nil
return Key{}, errors.Errorf("could not parse %s as a configuration key "+
"(configuration keys should be of the form `<namespace>:<name>`)", s)
}
func (k Key) Namespace() string {

View file

@ -18,7 +18,6 @@ import (
"encoding/json"
"testing"
"github.com/pulumi/pulumi/pkg/tokens"
"github.com/stretchr/testify/assert"
yaml "gopkg.in/yaml.v2"
)
@ -36,17 +35,8 @@ func TestParseKey(t *testing.T) {
_, err = ParseKey("foo")
assert.Error(t, err)
}
func TestFromModuleMember(t *testing.T) {
mm := tokens.ModuleMember("test:config:key")
k, err := fromModuleMember(mm)
assert.NoError(t, err)
assert.Equal(t, "test", k.namespace)
assert.Equal(t, "key", k.name)
mm = tokens.ModuleMember("test:data:key")
_, err = fromModuleMember(mm)
_, err = ParseKey("test:data:key")
assert.Error(t, err)
}