-
Notifications
You must be signed in to change notification settings - Fork 4.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New config parser, HCL support, multiple bind addrs #3480
Conversation
There are still a handful of failing tests which I'll address tomorrow. |
Still need to update all the docs ... |
d8b8905
to
a923011
Compare
👍 big thanks for adding HCL support + enabling multiple bind addresses |
agent/acl_test.go
Outdated
cfg.ACLEnforceVersion8 = Bool(false) | ||
a := NewTestAgent(t.Name(), cfg) | ||
a := NewTestAgent(t.Name(), ` | ||
acl_enforce_version_8 = true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This actually set it to true
when it was supposed to be false
. I'll fix this and make sure this test positively ensures that things are working.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The default is set to a wrong key acl_enforce_version8
(not the lacking final underscore) which may contribute to the test failing.
I am working on a patch which detects invalid field names again and restores the previous functionality. However, since encoding/json
and hashicorp/hcl
decode embedded structs differently (map[string]interface{}
vs []map[string]interface{}
). Therefore, just using mapstructure
as before to detect unused fields won't work. This is a bug in HCL itself for which there is no easy fix AFAICT. Also, using the embedded JSON parser in hcl
will also return []map[string]interface{}
which will trip up mapstructure
. hashicorp/hcl#209
Unless there is an option in mapstructure to do the mapping I think there are several viable approaches:
-
Patching all
[]map
tomap
and then usemapstructure
for the mapping and invalid field detection. However,watches
has[]map[string]interface{}
so there would need to be an exception for that field and others in the future. -
Build a custom invalid field detector which given a
map[string]interface{}
and struct type+tag name can detect which fields will not be mappable. -
Enhance the
hashicorp/hcl
decoder with an invalid field detector and do the same thing withencoding/json
by first forking it and then adding that to the custom code until proposal: encoding/json: reject unknown fields in Decoder golang/go#15314 is added to the stdlib. -
Add that capability to
mapstructure
.
For the 1.0 milestone, the first option seems to be the one with the least amount of work so I'll try that first.
agent/agent_test.go
Outdated
@@ -167,13 +101,20 @@ func TestAgent_TokenStore(t *testing.T) { | |||
} | |||
|
|||
func TestAgent_CheckPerformanceSettings(t *testing.T) { | |||
t.Skip("this test fails because of the change in agent.consulConfig(). We need to decide what to do") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO - I'll take a look at this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've followed your suggestion and dropped the PerformanceRaftMultiplier
parameter and instead compute the right values during the build step.
agent/agent.go
Outdated
defer a.wgServers.Done() | ||
|
||
err := s.ListenAndServe(p.Net, p.Addr, func() { notif <- p }) | ||
// todo(fs): does this also work for unix sockets? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should add unix socket unit tests before we finish the beta.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The underlying DNS lib does not support Unix sockets. We can add this at a later stage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it - yeah if DNS never could have supported it previously it's not important to get that in now (also seems like a fairly rare / low priority use case).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unless you want to test DNS on the socket without exposing it on a network interface. But lets add that later.
return tc.IncomingTLSConfig() | ||
} | ||
|
||
func (c *RuntimeConfig) Sanitized() RuntimeConfig { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should add a test for this - It would be good to fuzz the structure, sanitize, and make sure anything with token in there is redacted. Maybe we should just use reflect
here and a small list of other places to redact and make the logic generic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a test and implemented it reflectively. The expected test result is static so the test should fail once a new field with token, key or secret in the name is added. gofuzz
failed on me with some error but I don't think it is necessary with this approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've used different values for the WAN retry join case in a later commit.
agent/config/builder.go
Outdated
Head: []Source{DefaultSource()}, | ||
} | ||
|
||
if b.stringVal(b.Flags.DeprecatedDatacenter) != "" && b.stringVal(b.Flags.Config.Datacenter) == "" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does this need a special case here? It's also handled in Build()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like a left over from moving code around.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is a bit more complex than that but why do we want to carry on deprecated flags and fields to 1.0 in the first place? This looks like a good time to finally remove them.
agent/config/config.go
Outdated
CleanupDeadServers *bool `json:"cleanup_dead_servers,omitempty" hcl:"cleanup_dead_servers"` | ||
DisableUpgradeMigration *bool `json:"disable_upgrade_migration,omitempty" hcl:"disable_upgrade_migration"` | ||
LastContactThreshold *string `json:"last_contact_threshold,omitempty" hcl:"last_contact_threshold"` | ||
// todo(fs): do we need uint64 here? If yes, then I need to write a special parser b/c of JSON limit of 2^53-1 for ints |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will always be much lower than the max. We could even accept an int here and cast it later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thought so. will fix
agent/config/runtime_test.go
Outdated
rt.DataDir = dataDir | ||
}, | ||
}, | ||
{ // todo(fs): shouldn't this be '-encrypt-key'? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No this looks correct.
agent/config/runtime_test.go
Outdated
rt.DataDir = dataDir | ||
}, | ||
}, | ||
{ // todo(fs): shouldn't this be '-node-name'? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is correct for the CLI flags (it's node_name
in JSON).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, the fact that they are different is one of the issues.
rt.DataDir = dataDir | ||
}, | ||
}, | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a duplicate of the previous test case - did you have something else in mind here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, copy/paste left over when creating additional test cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've removed it.
}, | ||
}, | ||
{ | ||
desc: "client addr, addresses and ports < 0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Paused here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got to this spot - I'll continue from here...
Agree I was thinking the same and some of these are quite old - let's
remove them as long as we are clear in the upgrade guide and list them all.
|
I've pushed a change which removes all deprecated fields and flags and keeps a list in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made it through the whole thing and I think we are super close. If we can get a check in there to catch unknown fields (the simple plan with an exception for watches sounded reasonable) before the beta I think that would a good cross-check for the all the unit tests and to help users.
patch: func(rt *RuntimeConfig) { | ||
rt.Bootstrap = true | ||
rt.ServerMode = true | ||
rt.LeaveOnTerm = false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In client mode the LeaveOnTerm
and SkipLeaveOnInt
values should be the opposite of server mode, so true
and false
, respectively. We should add a case that covers that behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
agent/config/runtime_test.go
Outdated
flags: []string{ | ||
`-data-dir=runtime_test.go`, | ||
}, | ||
patch: func(rt *RuntimeConfig) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need a patch
section when it's checking for an error?
agent/config/runtime_test.go
Outdated
hcl: []string{`dns_config = { udp_answer_limit = 0 }`}, | ||
err: "dns_config.udp_answer_limit cannot be 0. Must be positive", | ||
}, | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicate of previous test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
agent/config/runtime_test.go
Outdated
"dogstatsd_addr": "0wSndumK", | ||
"dogstatsd_tags": [ "3N81zSUB","Xtj8AnXZ" ], | ||
"filter_default": true, | ||
"prefix_fi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like we can eventually divorce the runtime config from the structure with both check and checks.
agent/dns_test.go
Outdated
@@ -2913,7 +2858,7 @@ func TestDNS_ServiceLookup_AnswerLimits(t *testing.T) { | |||
expectedANYQuery int | |||
expectedANYQueryID int | |||
}{ | |||
{"0", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | |||
//{"0", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curious what happened here? Does this fail to validate then we can just delete it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new code did not allow dns_config.udp_answer_limit
to be zero which made this test fail. I guess we commented this out while getting things to work. I've restored the previous behavior.
agent/node-id
Outdated
@@ -0,0 +1 @@ | |||
9e8edccb-1f67-0ef6-a36f-e5121d91d8fb |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file should be deleted (or does a test use this)?
|
||
return nil | ||
} | ||
// done(fs): func ValidateSegments(conf *Config) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did this get moved elsewhere? There's an enterprise version of this file that's in the enterprise fork, so we had this out here so we can swap it with build tags.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had incorporated this into the normal validation. However, to support different types of validation for enterprise I've split up the tests so that we can overload them. I'll send you the ent
fragments you can add.
agent/testagent_test.go
Outdated
|
||
func TestDefaultConfig(t *testing.T) { | ||
for i := 0; i < 500; i++ { | ||
t.Run("bla", func(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bla
might as well be an empty string
|
||
// GetPrivateIPv4 returns the list of private network IPv4 addresses on | ||
// all active interfaces. | ||
func GetPrivateIPv4() ([]*net.IPAddr, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could probably remove these helpers and change the default config to go-sockaddr templates that accomplishes this as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes mocking the address resolution more difficult. Let me think about a solution.
@@ -58,7 +58,8 @@ func NewIPv4Addr(ipv4Str string) (IPv4Addr, error) { | |||
// Strip off any bogus hex-encoded netmasks that will be mis-parsed by Go. In | |||
// particular, clients with the Barracuda VPN client will see something like: | |||
// `192.168.3.51/00ffffff` as their IP address. | |||
trailingHexNetmaskRe := trailingHexNetmaskRE.Copy() | |||
// trailingHexNetmaskRe := trailingHexNetmaskRE.Copy() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a monkey patch? Why was this needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, for some reason this creates a data race which made tests fail randomly at high concurrency. I still need to understand why that is.
I'll try to sort the Raft multiplier stuff. |
@magiconair I'm thinking we can get rid of
|
@magiconair Heads up I pushed my small stuff from the -slackpad branch up onto yours, so please pull that. |
Will do and will go through the comments. I have something working for the invalid fields. Not pretty but it should do for the beta. I'll go through the rest of the comments and fix/respond |
This patch implements a new config parser for the consul agent which makes the following changes to the previous implementation: * add HCL support * all configuration fragments in tests and for default config are expressed as HCL fragments * HCL fragments can be provided on the command line so that they can eventually replace the command line flags. * HCL/JSON fragments are parsed into a temporary Config structure which can be merged using reflection (all values are pointers). The existing merge logic of overwrite for values and append for slices has been preserved. * A single builder process generates a typed runtime configuration for the agent. The new implementation is more strict and fails in the builder process if no valid runtime configuration can be generated. Therefore, additional validations in other parts of the code should be removed. The builder also pre-computes all required network addresses so that no address/port magic should be required where the configuration is used and should therefore be removed.
29f1ee4
to
dddc6af
Compare
I've rebased the branch onto master and added the code for detecting invalid fields. I've immediately found two tests which were broken so this is very useful. The approach is a bit hacky but I've added a long description of why we're doing this. If I can come up with a better approach then I'll try over the next days. The open issues are:
@slackpad you need to incorporate the enterprise test fragments for the segment code I've sent you. |
That's fair and the mock is very nice for testing. We can keep this as is
going in to the beta.
|
We also need to decide where to put the documentation that was part of |
F I N A L L Y ! |
This patch implements a new config parser for the consul agent which
makes the following changes to the previous implementation:
expressed as HCL fragments
can eventually replace the command line flags.
which can be merged using reflection (all values are pointers).
The existing merge logic of overwrite for values and append
for slices has been preserved.
for the agent.
The new implementation is more strict and fails in the builder process if no
valid runtime configuration can be generated. Therefore, additional
validations in other parts of the code should be removed.
The builder also pre-computes all required network addresses so that no
address/port magic should be required where the configuration is used and
should therefore be removed.
As a side effect the code also supports multiple bind addresses for HTTP,
HTTPS and DNS via go-sockaddr and static ip addresses.
Fixes #895
Fixes #2217
Fixes #2825