Add helpers to the API client to help with getting information from `AgentMember` tags (#8575)

Lots of constants were added for various tags that would concern users and are not already parsed out.

Additionally two methods on the AgentMember type were added to ask a member what its ACL Mode is and whether its a server or not.
This commit is contained in:
Matt Keeler 2020-08-27 11:00:48 -04:00 committed by GitHub
parent d7017aa4db
commit 7c3914d89e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 187 additions and 0 deletions

11
.changelog/8575.txt Normal file
View File

@ -0,0 +1,11 @@
```release-note:improvement
api: Added constants for common tag keys and values in the `Tags` field of the `AgentMember` struct.
```
```release-note:improvement
api: Added `IsConsulServer` method to the `AgentMember` type to easily determine whether the agent is a server.
```
```release-note:improvement
api: Added `ACLMode` method to the `AgentMember` type to determine what ACL mode the agent is operating in.
```

View File

@ -121,6 +121,70 @@ type AgentServiceConnectProxyConfig struct {
Expose ExposeConfig `json:",omitempty"` Expose ExposeConfig `json:",omitempty"`
} }
const (
// MemberTagKeyACLMode is the key used to indicate what ACL mode the agent is
// operating in. The values of this key will be one of the MemberACLMode constants
// with the key not being present indicating ACLModeUnknown.
MemberTagKeyACLMode = "acls"
// MemberTagRole is the key used to indicate that the member is a server or not.
MemberTagKeyRole = "role"
// MemberTagValueRoleServer is the value of the MemberTagKeyRole used to indicate
// that the member represents a Consul server.
MemberTagValueRoleServer = "consul"
// MemberTagKeySegment is the key name of the tag used to indicate which network
// segment this member is in.
// Network Segments are a Consul Enterprise feature.
MemberTagKeySegment = "segment"
// MemberTagKeyBootstrap is the key name of the tag used to indicate whether this
// agent was started with the "bootstrap" configuration enabled
MemberTagKeyBootstrap = "bootstrap"
// MemberTagValueBootstrap is the value of the MemberTagKeyBootstrap key when the
// agent was started with the "bootstrap" configuration enabled.
MemberTagValueBootstrap = "1"
// MemberTagKeyBootstrapExpect is the key name of the tag used to indicate whether
// this agent was started with the "bootstrap_expect" configuration set to a non-zero
// value. The value of this key will be the string for of that configuration value.
MemberTagKeyBootstrapExpect = "expect"
// MemberTagKeyUseTLS is the key name of the tag used to indicate whther this agent
// was configured to use TLS.
MemberTagKeyUseTLS = "use_tls"
// MemberTagValueUseTLS is the value of the MemberTagKeyUseTLS when the agent was
// configured to use TLS. Any other value indicates that it was not setup in
// that manner.
MemberTagValueUseTLS = "1"
// MemberTagKeyReadReplica is the key used to indicate that the member is a read
// replica server (will remain a Raft non-voter).
// Read Replicas are a Consul Enterprise feature.
MemberTagKeyReadReplica = "nonvoter"
// MemberTagValueReadReplica is the value of the MemberTagKeyReadReplica key when
// the member is in fact a read-replica. Any other value indicates that it is not.
// Read Replicas are a Consul Enterprise feature.
MemberTagValueReadReplica = "1"
)
type MemberACLMode string
const (
// ACLModeDisables indicates that ACLs are disabled for this agent
ACLModeDisabled MemberACLMode = "0"
// ACLModeEnabled indicates that ACLs are enabled and operating in new ACL
// mode (v1.4.0+ ACLs)
ACLModeEnabled MemberACLMode = "1"
// ACLModeLegacy indicates that ACLs are enabled and operating in legacy mode.
ACLModeLegacy MemberACLMode = "2"
// ACLModeUnkown is used to indicate that the AgentMember.Tags didn't advertise
// an ACL mode at all. This is the case for Consul versions before v1.4.0 and
// should be treated similarly to ACLModeLegacy.
ACLModeUnknown MemberACLMode = "3"
)
// AgentMember represents a cluster member known to the agent // AgentMember represents a cluster member known to the agent
type AgentMember struct { type AgentMember struct {
Name string Name string
@ -144,6 +208,30 @@ type AgentMember struct {
DelegateCur uint8 DelegateCur uint8
} }
// ACLMode returns the ACL mode this agent is operating in.
func (m *AgentMember) ACLMode() MemberACLMode {
mode := m.Tags[MemberTagKeyACLMode]
// the key may not have existed but then an
// empty string will be returned and we will
// handle that in the default case of the switch
switch MemberACLMode(mode) {
case ACLModeDisabled:
return ACLModeDisabled
case ACLModeEnabled:
return ACLModeEnabled
case ACLModeLegacy:
return ACLModeLegacy
default:
return ACLModeUnknown
}
}
// IsConsulServer returns true when this member is a Consul server.
func (m *AgentMember) IsConsulServer() bool {
return m.Tags[MemberTagKeyRole] == MemberTagValueRoleServer
}
// AllSegments is used to select for all segments in MembersOpts. // AllSegments is used to select for all segments in MembersOpts.
const AllSegments = "_all" const AllSegments = "_all"

View File

@ -1798,3 +1798,91 @@ func TestAgentService_ExposeChecks(t *testing.T) {
require.True(t, svc.Proxy.Expose.Checks) require.True(t, svc.Proxy.Expose.Checks)
require.Equal(t, path, svc.Proxy.Expose.Paths[0]) require.Equal(t, path, svc.Proxy.Expose.Paths[0])
} }
func TestMemberACLMode(t *testing.T) {
type testCase struct {
tagValue string
expectedMode MemberACLMode
}
cases := map[string]testCase{
"disabled": {
tagValue: "0",
expectedMode: ACLModeDisabled,
},
"enabled": {
tagValue: "1",
expectedMode: ACLModeEnabled,
},
"legacy": {
tagValue: "2",
expectedMode: ACLModeLegacy,
},
"unknown-3": {
tagValue: "3",
expectedMode: ACLModeUnknown,
},
"unknown-other": {
tagValue: "77",
expectedMode: ACLModeUnknown,
},
"unknown-not-present": {
tagValue: "",
expectedMode: ACLModeUnknown,
},
}
for name, tcase := range cases {
t.Run(name, func(t *testing.T) {
tags := map[string]string{}
if tcase.tagValue != "" {
tags[MemberTagKeyACLMode] = tcase.tagValue
}
m := AgentMember{
Tags: tags,
}
require.Equal(t, tcase.expectedMode, m.ACLMode())
})
}
}
func TestMemberIsConsulServer(t *testing.T) {
type testCase struct {
tagValue string
isServer bool
}
cases := map[string]testCase{
"not-present": {
tagValue: "",
isServer: false,
},
"server": {
tagValue: MemberTagValueRoleServer,
isServer: true,
},
"client": {
tagValue: "client",
isServer: false,
},
}
for name, tcase := range cases {
t.Run(name, func(t *testing.T) {
tags := map[string]string{}
if tcase.tagValue != "" {
tags[MemberTagKeyRole] = tcase.tagValue
}
m := AgentMember{
Tags: tags,
}
require.Equal(t, tcase.isServer, m.IsConsulServer())
})
}
}