Skip to content

Commit 4ef4256

Browse files
authored
(MAINT) Allow config values to be mandatory (#55)
1 parent c12085b commit 4ef4256

File tree

4 files changed

+43
-11
lines changed

4 files changed

+43
-11
lines changed

pkg/certificate/certificate.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ import (
1414
"math/big"
1515
"net"
1616
"time"
17-
18-
"github.com/sirupsen/logrus"
1917
)
2018

2119
const (
@@ -230,8 +228,6 @@ func populateDNSNamesAndIPs(hostnames HostNames, dnsNames []string, ips []net.IP
230228
for _, ip := range ipList {
231229
ips = append(ips, net.ParseIP(ip))
232230
}
233-
} else {
234-
logrus.Errorf("Could not resolve hostname %s\n", hostname)
235231
}
236232
dnsNames = append(dnsNames, hostname)
237233
}

pkg/config/README.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@
55
The objective of the config package is to allow a client to tag a struct with (optional)default values and environment variables and then the config package will use viper to populate a struct.
66

77
## Tag descriptions
8-
| Tag|Mandatory |Description|
9-
|--|--|--|
10-
| env |Y |The environment variable the field value will be retrieved from if the environment variable is present. N.B. It takes priority over any other tag.|
11-
| file |N |The path to the file to take the default value from. This can be useful for things like passwords where they can be taken from docker / k8s secrets. N.B. If this tag is present and the file can be successfully processed then the default is redundant - if the value can not be read from the file and the default is present then the default is used.|
12-
| default |N |The default value which will be used if no environment variable is present. N.B. If this is not populated then the default for the type will be used i.e. 0 for int, "" for string, false for bool etc etc.|
13-
8+
| Tag |Mandatory | Description |
9+
|-----------|--|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
10+
| env |Y | The environment variable the field value will be retrieved from if the environment variable is present. N.B. It takes priority over any other tag. |
11+
| file |N | The path to the file to take the default value from. This can be useful for things like passwords where they can be taken from docker / k8s secrets. N.B. If this tag is present and the file can be successfully processed then the default is redundant - if the value can not be read from the file and the default is present then the default is used. |
12+
| default |N | The default value which will be used if no environment variable is present. N.B. If this is not populated then the default for the type will be used i.e. 0 for int, "" for string, false for bool etc etc. |
13+
| mandatory |N | Whether the field is mandatory or not. N.B. If this is not populated then it will default to false so the field will be optional. |
14+
15+
1416
N.B. A nested struct does not need tags associated with it. Tags are only required for non struct entries.
1517
N.N.B. Nested structs will use the "squash" property by default. That means no mapstructure tag is required.
1618

pkg/config/config.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ var (
2020
errInvalidConfigType = errors.New("config type must be either a pointer to a struct or a struct")
2121
errMissingFileExtension = errors.New("missing file extension")
2222
errViperConfigNonPointerArgument = errors.New("reading Viper config requires a pointer argument")
23+
errMandatoryFieldMissing = errors.New("mandatory field required but not set in environment variable")
2324
)
2425

2526
func setUpViperConfig(cfg interface{}, v *viper.Viper) error {
@@ -54,15 +55,24 @@ func setUpViperConfig(cfg interface{}, v *viper.Viper) error {
5455
continue
5556
}
5657

58+
envTag, ok := f.Tag.Lookup("env")
5759
// The env tag is mandatory. It not present or we fail to set it up then error.
58-
if envTag, ok := f.Tag.Lookup("env"); ok {
60+
if ok {
5961
if err := v.BindEnv(f.Name, envTag); err != nil {
6062
return fmt.Errorf("unable to bind %s to environment variable %s: %w", f.Name, envTag, err)
6163
}
6264
} else {
6365
return fmt.Errorf("%w: %s", errEmptyEnvTagForField, f.Name)
6466
}
6567

68+
if mandatoryTag, ok := f.Tag.Lookup("mandatory"); ok {
69+
if mandatoryTag == "true" {
70+
if os.Getenv(envTag) == "" {
71+
return fmt.Errorf("%w: %s", errMandatoryFieldMissing, envTag)
72+
}
73+
}
74+
}
75+
6676
var fileDefaultSet bool
6777
if fileTag, ok := f.Tag.Lookup("file"); ok {
6878
// It is not mandatory to have a default set, so we will log this and move on.

pkg/config/config_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"reflect"
88
"testing"
99
"time"
10+
11+
"github.com/stretchr/testify/assert"
1012
)
1113

1214
var yamlExample = []byte(`db:
@@ -98,6 +100,11 @@ type AppConfig struct {
98100
WebServer
99101
}
100102

103+
// MandatorySet has config with a value that is mandatory
104+
type MandatorySet struct {
105+
TestVal string `env:"MANDATORY_TEST_VAL" mandatory:"true"`
106+
}
107+
101108
func TestNoTagsErrors(t *testing.T) {
102109
var noTags StructNoTags
103110
err := LoadViperConfig(noTags)
@@ -242,3 +249,20 @@ func TestLoadViperConfigFromFileNoFileExtension(t *testing.T) {
242249
t.Error("File with no extension should error")
243250
}
244251
}
252+
253+
func TestMandatorySet(t *testing.T) {
254+
os.Clearenv()
255+
256+
err := os.Setenv("MANDATORY_TEST_VAL", "blah")
257+
if err != nil {
258+
t.Errorf("Unexpected error occurred %s.", err)
259+
}
260+
261+
var actual MandatorySet
262+
err = LoadViperConfig(&actual)
263+
assert.NoError(t, err)
264+
265+
os.Clearenv()
266+
err = LoadViperConfig(&actual)
267+
assert.Error(t, err)
268+
}

0 commit comments

Comments
 (0)