config: Unexport Builder and NewBuilder

This type and constructor are implementation details of config loading.
All callers should use config.Load.
This commit is contained in:
Daniel Nephin 2020-12-21 13:55:53 -05:00
parent 08b2039f5a
commit aa42ff5d81
5 changed files with 55 additions and 67 deletions

View File

@ -89,7 +89,7 @@ type LoadOpts struct {
// The caller is responsible for handling any warnings in LoadResult.Warnings.
func Load(opts LoadOpts) (LoadResult, error) {
r := LoadResult{}
b, err := NewBuilder(opts)
b, err := newBuilder(opts)
if err != nil {
return r, err
}
@ -107,32 +107,20 @@ type LoadResult struct {
Warnings []string
}
// Builder constructs a valid runtime configuration from multiple
// builder constructs and validates a runtime configuration from multiple
// configuration sources.
//
// To build the runtime configuration first call Build() which merges
// the sources in a pre-defined order, converts the data types and
// structures into their final form and performs the syntactic
// validation.
//
// The sources are merged in the following order:
//
// * default configuration
// * config files in alphabetical order
// * command line arguments
// * overrides
//
// The config sources are merged sequentially and later values
// overwrite previously set values. Slice values are merged by
// concatenating the two slices. Map values are merged by over-
// laying the later maps on top of earlier ones.
//
// Then call Validate() to perform the semantic validation to ensure
// that the configuration is ready to be used.
//
// Splitting the construction into two phases greatly simplifies testing
// since not all pre-conditions have to be satisfied when performing
// syntactical tests.
type Builder struct {
// The config sources are merged sequentially and later values overwrite
// previously set values. Slice values are merged by concatenating the two slices.
// Map values are merged by over-laying the later maps on top of earlier ones.
type builder struct {
opts LoadOpts
// Head, Sources, and Tail are used to manage the order of the
@ -150,14 +138,14 @@ type Builder struct {
err error
}
// NewBuilder returns a new configuration Builder from the LoadOpts.
func NewBuilder(opts LoadOpts) (*Builder, error) {
// newBuilder returns a new configuration Builder from the LoadOpts.
func newBuilder(opts LoadOpts) (*builder, error) {
configFormat := opts.ConfigFormat
if configFormat != "" && configFormat != "json" && configFormat != "hcl" {
return nil, fmt.Errorf("config: -config-format must be either 'hcl' or 'json'")
}
b := &Builder{
b := &builder{
opts: opts,
Head: []Source{DefaultSource(), DefaultEnterpriseSource()},
}
@ -205,7 +193,7 @@ func NewBuilder(opts LoadOpts) (*Builder, error) {
// sourcesFromPath reads a single config file or all files in a directory (but
// not its sub-directories) and returns Sources created from the
// files.
func (b *Builder) sourcesFromPath(path string, format string) ([]Source, error) {
func (b *builder) sourcesFromPath(path string, format string) ([]Source, error) {
f, err := os.Open(path)
if err != nil {
return nil, fmt.Errorf("config: Open failed on %s. %s", path, err)
@ -306,7 +294,7 @@ func (a byName) Len() int { return len(a) }
func (a byName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byName) Less(i, j int) bool { return a[i].Name() < a[j].Name() }
func (b *Builder) BuildAndValidate() (RuntimeConfig, error) {
func (b *builder) BuildAndValidate() (RuntimeConfig, error) {
rt, err := b.Build()
if err != nil {
return RuntimeConfig{}, err
@ -323,7 +311,7 @@ func (b *Builder) BuildAndValidate() (RuntimeConfig, error) {
// precedence over the other sources. If the error is nil then
// warnings can still contain deprecation or format warnings that should
// be presented to the user.
func (b *Builder) Build() (rt RuntimeConfig, err error) {
func (b *builder) Build() (rt RuntimeConfig, err error) {
srcs := make([]Source, 0, len(b.Head)+len(b.Sources)+len(b.Tail))
srcs = append(srcs, b.Head...)
srcs = append(srcs, b.Sources...)
@ -1181,7 +1169,7 @@ func validateBasicName(field, value string, allowEmpty bool) error {
}
// Validate performs semantic validation of the runtime configuration.
func (b *Builder) Validate(rt RuntimeConfig) error {
func (b *builder) Validate(rt RuntimeConfig) error {
// validContentPath defines a regexp for a valid content path name.
var validContentPath = regexp.MustCompile(`^[A-Za-z0-9/_-]+$`)
@ -1549,11 +1537,11 @@ func splitSlicesAndValues(c Config) (slices, values Config) {
return rs.Elem().Interface().(Config), rv.Elem().Interface().(Config)
}
func (b *Builder) warn(msg string, args ...interface{}) {
func (b *builder) warn(msg string, args ...interface{}) {
b.Warnings = append(b.Warnings, fmt.Sprintf(msg, args...))
}
func (b *Builder) checkVal(v *CheckDefinition) *structs.CheckDefinition {
func (b *builder) checkVal(v *CheckDefinition) *structs.CheckDefinition {
if v == nil {
return nil
}
@ -1591,7 +1579,7 @@ func (b *Builder) checkVal(v *CheckDefinition) *structs.CheckDefinition {
}
}
func (b *Builder) svcTaggedAddresses(v map[string]ServiceAddress) map[string]structs.ServiceAddress {
func (b *builder) svcTaggedAddresses(v map[string]ServiceAddress) map[string]structs.ServiceAddress {
if len(v) <= 0 {
return nil
}
@ -1611,7 +1599,7 @@ func (b *Builder) svcTaggedAddresses(v map[string]ServiceAddress) map[string]str
return svcAddrs
}
func (b *Builder) serviceVal(v *ServiceDefinition) *structs.ServiceDefinition {
func (b *builder) serviceVal(v *ServiceDefinition) *structs.ServiceDefinition {
if v == nil {
return nil
}
@ -1664,7 +1652,7 @@ func (b *Builder) serviceVal(v *ServiceDefinition) *structs.ServiceDefinition {
}
}
func (b *Builder) serviceKindVal(v *string) structs.ServiceKind {
func (b *builder) serviceKindVal(v *string) structs.ServiceKind {
if v == nil {
return structs.ServiceKindTypical
}
@ -1682,7 +1670,7 @@ func (b *Builder) serviceKindVal(v *string) structs.ServiceKind {
}
}
func (b *Builder) serviceProxyVal(v *ServiceProxy) *structs.ConnectProxyConfig {
func (b *builder) serviceProxyVal(v *ServiceProxy) *structs.ConnectProxyConfig {
if v == nil {
return nil
}
@ -1699,7 +1687,7 @@ func (b *Builder) serviceProxyVal(v *ServiceProxy) *structs.ConnectProxyConfig {
}
}
func (b *Builder) upstreamsVal(v []Upstream) structs.Upstreams {
func (b *builder) upstreamsVal(v []Upstream) structs.Upstreams {
ups := make(structs.Upstreams, len(v))
for i, u := range v {
ups[i] = structs.Upstream{
@ -1719,7 +1707,7 @@ func (b *Builder) upstreamsVal(v []Upstream) structs.Upstreams {
return ups
}
func (b *Builder) meshGatewayConfVal(mgConf *MeshGatewayConfig) structs.MeshGatewayConfig {
func (b *builder) meshGatewayConfVal(mgConf *MeshGatewayConfig) structs.MeshGatewayConfig {
cfg := structs.MeshGatewayConfig{Mode: structs.MeshGatewayModeDefault}
if mgConf == nil || mgConf.Mode == nil {
// return defaults
@ -1736,7 +1724,7 @@ func (b *Builder) meshGatewayConfVal(mgConf *MeshGatewayConfig) structs.MeshGate
return cfg
}
func (b *Builder) exposeConfVal(v *ExposeConfig) structs.ExposeConfig {
func (b *builder) exposeConfVal(v *ExposeConfig) structs.ExposeConfig {
var out structs.ExposeConfig
if v == nil {
return out
@ -1747,7 +1735,7 @@ func (b *Builder) exposeConfVal(v *ExposeConfig) structs.ExposeConfig {
return out
}
func (b *Builder) pathsVal(v []ExposePath) []structs.ExposePath {
func (b *builder) pathsVal(v []ExposePath) []structs.ExposePath {
paths := make([]structs.ExposePath, len(v))
for i, p := range v {
paths[i] = structs.ExposePath{
@ -1760,7 +1748,7 @@ func (b *Builder) pathsVal(v []ExposePath) []structs.ExposePath {
return paths
}
func (b *Builder) serviceConnectVal(v *ServiceConnect) *structs.ServiceConnect {
func (b *builder) serviceConnectVal(v *ServiceConnect) *structs.ServiceConnect {
if v == nil {
return nil
}
@ -1786,7 +1774,7 @@ func (b *Builder) serviceConnectVal(v *ServiceConnect) *structs.ServiceConnect {
}
}
func (b *Builder) uiConfigVal(v RawUIConfig) UIConfig {
func (b *builder) uiConfigVal(v RawUIConfig) UIConfig {
return UIConfig{
Enabled: boolVal(v.Enabled),
Dir: stringVal(v.Dir),
@ -1799,7 +1787,7 @@ func (b *Builder) uiConfigVal(v RawUIConfig) UIConfig {
}
}
func (b *Builder) uiMetricsProxyVal(v RawUIMetricsProxy) UIMetricsProxy {
func (b *builder) uiMetricsProxyVal(v RawUIMetricsProxy) UIMetricsProxy {
var hdrs []UIMetricsProxyAddHeader
for _, hdr := range v.AddHeaders {
@ -1830,7 +1818,7 @@ func boolVal(v *bool) bool {
return *v
}
func (b *Builder) durationValWithDefault(name string, v *string, defaultVal time.Duration) (d time.Duration) {
func (b *builder) durationValWithDefault(name string, v *string, defaultVal time.Duration) (d time.Duration) {
if v == nil {
return defaultVal
}
@ -1841,7 +1829,7 @@ func (b *Builder) durationValWithDefault(name string, v *string, defaultVal time
return d
}
func (b *Builder) durationVal(name string, v *string) (d time.Duration) {
func (b *builder) durationVal(name string, v *string) (d time.Duration) {
return b.durationValWithDefault(name, v, 0)
}
@ -1873,7 +1861,7 @@ func uint64Val(v *uint64) uint64 {
return *v
}
func (b *Builder) portVal(name string, v *int) int {
func (b *builder) portVal(name string, v *int) int {
if v == nil || *v <= 0 {
return -1
}
@ -1908,7 +1896,7 @@ func float64Val(v *float64) float64 {
return float64ValWithDefault(v, 0)
}
func (b *Builder) cidrsVal(name string, v []string) (nets []*net.IPNet) {
func (b *builder) cidrsVal(name string, v []string) (nets []*net.IPNet) {
if v == nil {
return
}
@ -1924,7 +1912,7 @@ func (b *Builder) cidrsVal(name string, v []string) (nets []*net.IPNet) {
return
}
func (b *Builder) tlsCipherSuites(name string, v *string) []uint16 {
func (b *builder) tlsCipherSuites(name string, v *string) []uint16 {
if v == nil {
return nil
}
@ -1937,7 +1925,7 @@ func (b *Builder) tlsCipherSuites(name string, v *string) []uint16 {
return a
}
func (b *Builder) nodeName(v *string) string {
func (b *builder) nodeName(v *string) string {
nodeName := stringVal(v)
if nodeName == "" {
fn := b.opts.hostname
@ -1956,7 +1944,7 @@ func (b *Builder) nodeName(v *string) string {
// expandAddrs expands the go-sockaddr template in s and returns the
// result as a list of *net.IPAddr and *net.UnixAddr.
func (b *Builder) expandAddrs(name string, s *string) []net.Addr {
func (b *builder) expandAddrs(name string, s *string) []net.Addr {
if s == nil || *s == "" {
return nil
}
@ -1995,7 +1983,7 @@ func (b *Builder) expandAddrs(name string, s *string) []net.Addr {
// error set. In contrast to expandAddrs, expandOptionalAddrs does not validate
// if the result contains valid addresses and returns a list of strings.
// However, if the expansion of the go-sockaddr template fails an error is set.
func (b *Builder) expandOptionalAddrs(name string, s *string) []string {
func (b *builder) expandOptionalAddrs(name string, s *string) []string {
if s == nil || *s == "" {
return nil
}
@ -2015,7 +2003,7 @@ func (b *Builder) expandOptionalAddrs(name string, s *string) []string {
}
}
func (b *Builder) expandAllOptionalAddrs(name string, addrs []string) []string {
func (b *builder) expandAllOptionalAddrs(name string, addrs []string) []string {
out := make([]string, 0, len(addrs))
for _, a := range addrs {
expanded := b.expandOptionalAddrs(name, &a)
@ -2029,7 +2017,7 @@ func (b *Builder) expandAllOptionalAddrs(name string, addrs []string) []string {
// expandIPs expands the go-sockaddr template in s and returns a list of
// *net.IPAddr. If one of the expanded addresses is a unix socket
// address an error is set and nil is returned.
func (b *Builder) expandIPs(name string, s *string) []*net.IPAddr {
func (b *builder) expandIPs(name string, s *string) []*net.IPAddr {
if s == nil || *s == "" {
return nil
}
@ -2055,7 +2043,7 @@ func (b *Builder) expandIPs(name string, s *string) []*net.IPAddr {
// first address which is either a *net.IPAddr or a *net.UnixAddr. If
// the template expands to multiple addresses an error is set and nil
// is returned.
func (b *Builder) expandFirstAddr(name string, s *string) net.Addr {
func (b *builder) expandFirstAddr(name string, s *string) net.Addr {
if s == nil || *s == "" {
return nil
}
@ -2078,7 +2066,7 @@ func (b *Builder) expandFirstAddr(name string, s *string) net.Addr {
// expandFirstIP expands the go-sockaddr template in s and returns the
// first address if it is not a unix socket address. If the template
// expands to multiple addresses an error is set and nil is returned.
func (b *Builder) expandFirstIP(name string, s *string) *net.IPAddr {
func (b *builder) expandFirstIP(name string, s *string) *net.IPAddr {
if s == nil || *s == "" {
return nil
}
@ -2106,7 +2094,7 @@ func makeIPAddr(pri *net.IPAddr, sec *net.IPAddr) *net.IPAddr {
return sec
}
func (b *Builder) makeTCPAddr(pri *net.IPAddr, sec net.Addr, port int) *net.TCPAddr {
func (b *builder) makeTCPAddr(pri *net.IPAddr, sec net.Addr, port int) *net.TCPAddr {
if pri == nil && reflect.ValueOf(sec).IsNil() || port <= 0 {
return nil
}
@ -2127,7 +2115,7 @@ func (b *Builder) makeTCPAddr(pri *net.IPAddr, sec net.Addr, port int) *net.TCPA
// makeAddr creates an *net.TCPAddr or a *net.UnixAddr from either the
// primary or secondary address and the given port. If the port is <= 0
// then the address is considered to be disabled and nil is returned.
func (b *Builder) makeAddr(pri, sec net.Addr, port int) net.Addr {
func (b *builder) makeAddr(pri, sec net.Addr, port int) net.Addr {
if reflect.ValueOf(pri).IsNil() && reflect.ValueOf(sec).IsNil() || port <= 0 {
return nil
}
@ -2149,7 +2137,7 @@ func (b *Builder) makeAddr(pri, sec net.Addr, port int) net.Addr {
// from either the primary or secondary addresses and the given port.
// If the port is <= 0 then the address is considered to be disabled
// and nil is returned.
func (b *Builder) makeAddrs(pri []net.Addr, sec []*net.IPAddr, port int) []net.Addr {
func (b *builder) makeAddrs(pri []net.Addr, sec []*net.IPAddr, port int) []net.Addr {
if len(pri) == 0 && len(sec) == 0 || port <= 0 {
return nil
}
@ -2167,7 +2155,7 @@ func (b *Builder) makeAddrs(pri []net.Addr, sec []*net.IPAddr, port int) []net.A
return x
}
func (b *Builder) autoConfigVal(raw AutoConfigRaw) AutoConfig {
func (b *builder) autoConfigVal(raw AutoConfigRaw) AutoConfig {
var val AutoConfig
val.Enabled = boolValWithDefault(raw.Enabled, false)
@ -2200,7 +2188,7 @@ func (b *Builder) autoConfigVal(raw AutoConfigRaw) AutoConfig {
return val
}
func (b *Builder) autoConfigAuthorizerVal(raw AutoConfigAuthorizationRaw) AutoConfigAuthorizer {
func (b *builder) autoConfigAuthorizerVal(raw AutoConfigAuthorizationRaw) AutoConfigAuthorizer {
// Our config file syntax wraps the static authorizer configuration in a "static" stanza. However
// internally we do not support multiple configured authorization types so the RuntimeConfig just
// inlines the static one. While we can and probably should extend the authorization types in the
@ -2235,7 +2223,7 @@ func (b *Builder) autoConfigAuthorizerVal(raw AutoConfigAuthorizationRaw) AutoCo
return val
}
func (b *Builder) validateAutoConfig(rt RuntimeConfig) error {
func (b *builder) validateAutoConfig(rt RuntimeConfig) error {
autoconf := rt.AutoConfig
if err := validateAutoConfigAuthorizer(rt); err != nil {

View File

@ -62,10 +62,10 @@ func (e enterpriseConfigKeyError) Error() string {
return fmt.Sprintf("%q is a Consul Enterprise configuration and will have no effect", e.key)
}
func (*Builder) BuildEnterpriseRuntimeConfig(_ *RuntimeConfig, _ *Config) error {
func (*builder) BuildEnterpriseRuntimeConfig(_ *RuntimeConfig, _ *Config) error {
return nil
}
func (*Builder) validateEnterpriseConfig(_ RuntimeConfig) error {
func (*builder) validateEnterpriseConfig(_ RuntimeConfig) error {
return nil
}

View File

@ -69,7 +69,7 @@ func TestShouldParseFile(t *testing.T) {
func TestNewBuilder_PopulatesSourcesFromConfigFiles(t *testing.T) {
paths := setupConfigFiles(t)
b, err := NewBuilder(LoadOpts{ConfigFiles: paths})
b, err := newBuilder(LoadOpts{ConfigFiles: paths})
require.NoError(t, err)
expected := []Source{
@ -85,7 +85,7 @@ func TestNewBuilder_PopulatesSourcesFromConfigFiles(t *testing.T) {
func TestNewBuilder_PopulatesSourcesFromConfigFiles_WithConfigFormat(t *testing.T) {
paths := setupConfigFiles(t)
b, err := NewBuilder(LoadOpts{ConfigFiles: paths, ConfigFormat: "hcl"})
b, err := newBuilder(LoadOpts{ConfigFiles: paths, ConfigFormat: "hcl"})
require.NoError(t, err)
expected := []Source{
@ -136,7 +136,7 @@ func TestBuilder_BuildAndValidate_NodeName(t *testing.T) {
}
fn := func(t *testing.T, tc testCase) {
b, err := NewBuilder(LoadOpts{
b, err := newBuilder(LoadOpts{
FlagValues: Config{
NodeName: pString(tc.nodeName),
DataDir: pString("dir"),
@ -175,7 +175,7 @@ func TestBuilder_BuildAndValidate_NodeName(t *testing.T) {
}
}
func patchBuilderShims(b *Builder) {
func patchBuilderShims(b *builder) {
b.opts.hostname = func() (string, error) {
return "thehostname", nil
}

View File

@ -4912,7 +4912,7 @@ func testConfig(t *testing.T, tests []configTest, dataDir string) {
}
// Then create a builder with the flags.
b, err := NewBuilder(flags)
b, err := newBuilder(flags)
require.NoError(t, err)
patchBuilderShims(b)
@ -4963,7 +4963,7 @@ func testConfig(t *testing.T, tests []configTest, dataDir string) {
// build a default configuration, then patch the fields we expect to change
// and compare it with the generated configuration. Since the expected
// runtime config has been validated we do not need to validate it again.
x, err := NewBuilder(LoadOpts{})
x, err := newBuilder(LoadOpts{})
if err != nil {
t.Fatal(err)
}
@ -7235,7 +7235,7 @@ func TestFullConfig(t *testing.T) {
}
require.Len(t, fs.Args(), 0)
b, err := NewBuilder(flags)
b, err := newBuilder(flags)
if err != nil {
t.Fatalf("NewBuilder: %s", err)
}

View File

@ -6,7 +6,7 @@ import (
"github.com/hashicorp/consul/agent/structs"
)
func (b *Builder) validateSegments(rt RuntimeConfig) error {
func (b *builder) validateSegments(rt RuntimeConfig) error {
if rt.SegmentName != "" {
return structs.ErrSegmentsNotSupported
}