Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/2093.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
control-plane: set agent localities on Consul servers to the server node's `topology.kubernetes.io/region` label.
```
4 changes: 2 additions & 2 deletions charts/consul/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ Consul server environment variables for consul-k8s commands.
{{- end }}
{{- if and .Values.externalServers.enabled .Values.externalServers.skipServerWatch }}
- name: CONSUL_SKIP_SERVER_WATCH
value: "true"
value: "true"
{{- end }}
{{- end -}}

Expand Down Expand Up @@ -366,7 +366,7 @@ Usage: {{ template "consul.validateCloudSecretKeys" . }}

*/}}
{{- define "consul.validateCloudSecretKeys" -}}
{{- if and .Values.global.cloud.enabled }}
{{- if and .Values.global.cloud.enabled }}
{{- if or (and .Values.global.cloud.resourceId.secretName (not .Values.global.cloud.resourceId.secretKey)) (and .Values.global.cloud.resourceId.secretKey (not .Values.global.cloud.resourceId.secretName)) }}
{{fail "When either global.cloud.resourceId.secretName or global.cloud.resourceId.secretKey is defined, both must be set."}}
{{- end }}
Expand Down
16 changes: 16 additions & 0 deletions charts/consul/templates/server-clusterrole.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ template "consul.fullname" . }}-server
namespace: {{ .Release.Namespace }}
labels:
app: {{ template "consul.name" . }}
chart: {{ template "consul.chart" . }}
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
component: server
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs:
- get
18 changes: 18 additions & 0 deletions charts/consul/templates/server-clusterrolebinding.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ template "consul.fullname" . }}-server
labels:
app: {{ template "consul.name" . }}
chart: {{ template "consul.chart" . }}
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
component: server
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ template "consul.fullname" . }}-server
subjects:
- kind: ServiceAccount
name: {{ template "consul.fullname" . }}-server
namespace: {{ .Release.Namespace }}
27 changes: 22 additions & 5 deletions charts/consul/templates/server-statefulset.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,22 @@ spec:
{{- if .Values.server.priorityClassName }}
priorityClassName: {{ .Values.server.priorityClassName | quote }}
{{- end }}
initContainers:
- name: locality-init
image: {{ .Values.global.imageK8S }}
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
command:
- "/bin/sh"
- "-ec"
- |
consul-k8s-control-plane fetch-server-region -node-name "$NODE_NAME" -output-file /consul/extra-config/locality.json
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️

volumeMounts:
- name: extra-config
mountPath: /consul/extra-config
containers:
- name: consul
image: "{{ default .Values.global.image .Values.server.image }}"
Expand Down Expand Up @@ -291,9 +307,9 @@ spec:
{{- end }}
{{- if .Values.global.cloud.enabled}}
# These are mounted as secrets so that the consul server agent can use them.
# - the hcp-go-sdk in consul agent will already look for HCP_CLIENT_ID, HCP_CLIENT_SECRET, HCP_AUTH_URL,
# - the hcp-go-sdk in consul agent will already look for HCP_CLIENT_ID, HCP_CLIENT_SECRET, HCP_AUTH_URL,
# HCP_SCADA_ADDRESS, and HCP_API_HOST. so nothing more needs to be done.
# - HCP_RESOURCE_ID is created for use in the
# - HCP_RESOURCE_ID is created for use in the
# `-hcl="cloud { resource_id = \"${HCP_RESOURCE_ID}\" }"` logic in the command below.
{{- if .Values.global.cloud.clientId.secretName }}
- name: HCP_CLIENT_ID
Expand Down Expand Up @@ -328,15 +344,15 @@ spec:
valueFrom:
secretKeyRef:
name: {{ .Values.global.cloud.apiHost.secretName }}
key: {{ .Values.global.cloud.apiHost.secretKey }}
key: {{ .Values.global.cloud.apiHost.secretKey }}
{{- end}}
{{- if .Values.global.cloud.scadaAddress.secretName }}
- name: HCP_SCADA_ADDRESS
valueFrom:
secretKeyRef:
name: {{ .Values.global.cloud.scadaAddress.secretName }}
key: {{ .Values.global.cloud.scadaAddress.secretKey }}
{{- end}}
{{- end}}
{{- end }}
{{- include "consul.extraEnvironmentVars" .Values.server | nindent 12 }}
command:
Expand Down Expand Up @@ -375,7 +391,8 @@ spec:
-config-dir=/consul/userconfig/{{ .name }} \
{{- end }}
{{- end }}
-config-file=/consul/extra-config/extra-from-values.json
-config-file=/consul/extra-config/extra-from-values.json \
-config-file=/consul/extra-config/locality.json
{{- if and .Values.global.cloud.enabled .Values.global.cloud.resourceId.secretName }}
-hcl="cloud { resource_id = \"${HCP_RESOURCE_ID}\" }"
{{- end }}
Expand Down
4 changes: 4 additions & 0 deletions control-plane/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
cmdConsulLogout "github.com/hashicorp/consul-k8s/control-plane/subcommand/consul-logout"
cmdCreateFederationSecret "github.com/hashicorp/consul-k8s/control-plane/subcommand/create-federation-secret"
cmdDeleteCompletedJob "github.com/hashicorp/consul-k8s/control-plane/subcommand/delete-completed-job"
cmdFetchServerRegion "github.com/hashicorp/consul-k8s/control-plane/subcommand/fetch-server-region"
cmdGetConsulClientCA "github.com/hashicorp/consul-k8s/control-plane/subcommand/get-consul-client-ca"
cmdGossipEncryptionAutogenerate "github.com/hashicorp/consul-k8s/control-plane/subcommand/gossip-encryption-autogenerate"
cmdInjectConnect "github.com/hashicorp/consul-k8s/control-plane/subcommand/inject-connect"
Expand Down Expand Up @@ -90,6 +91,9 @@ func init() {
"install-cni": func() (cli.Command, error) {
return &cmdInstallCNI.Command{UI: ui}, nil
},
"fetch-server-region": func() (cli.Command, error) {
return &cmdFetchServerRegion.Command{UI: ui}, nil
},
}
}

Expand Down
158 changes: 158 additions & 0 deletions control-plane/subcommand/fetch-server-region/command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package fetchserverregion

import (
"context"
"encoding/json"
"flag"
"fmt"
"os"
"sync"

"github.com/hashicorp/consul-k8s/control-plane/subcommand/common"
"github.com/hashicorp/consul-k8s/control-plane/subcommand/flags"
"github.com/hashicorp/go-hclog"
"github.com/mitchellh/cli"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)

// The consul-logout command issues a Consul logout API request to delete an ACL token.
type Command struct {
UI cli.Ui

flagLogLevel string
flagLogJSON bool
flagNodeName string
flagOutputFile string

flagSet *flag.FlagSet
k8s *flags.K8SFlags

once sync.Once
help string
logger hclog.Logger

// for testing
clientset kubernetes.Interface
}

type Locality struct {
Region string `json:"region"`
}

type Config struct {
Locality Locality `json:"locality"`
}

func (c *Command) init() {
c.flagSet = flag.NewFlagSet("", flag.ContinueOnError)
c.flagSet.StringVar(&c.flagLogLevel, "log-level", "info",
"Log verbosity level. Supported values (in order of detail) are \"trace\", "+
"\"debug\", \"info\", \"warn\", and \"error\".")
c.flagSet.BoolVar(&c.flagLogJSON, "log-json", false,
"Enable or disable JSON output format for logging.")
c.flagSet.StringVar(&c.flagNodeName, "node-name", "",
"Specifies the node name that will be used.")
c.flagSet.StringVar(&c.flagOutputFile, "output-file", "",
"The file path for writing the locality portion of a Consul agent configuration to.")

c.k8s = &flags.K8SFlags{}
flags.Merge(c.flagSet, c.k8s.Flags())

c.help = flags.Usage(help, c.flagSet)

}

func (c *Command) Run(args []string) int {
var err error
c.once.Do(c.init)

if err := c.flagSet.Parse(args); err != nil {
return 1
}

if c.logger == nil {
c.logger, err = common.Logger(c.flagLogLevel, c.flagLogJSON)
if err != nil {
c.UI.Error(err.Error())
return 1
}
}

if c.flagNodeName == "" {
c.UI.Error("-node-name is required")
return 1
}

if c.flagOutputFile == "" {
c.UI.Error("-output-file is required")
return 1
}

if c.clientset == nil {
config, err := rest.InClusterConfig()
if err != nil {
// This just allows us to test it locally.
kubeconfig := clientcmd.RecommendedHomeFile
config, err = clientcmd.BuildConfigFromFlags("", kubeconfig)
if err != nil {
c.UI.Error(err.Error())
return 1
}
}

c.clientset, err = kubernetes.NewForConfig(config)
if err != nil {
c.UI.Error(err.Error())
return 1
}
}

config := c.fetchLocalityConfig()

jsonData, err := json.Marshal(config)
if err != nil {
c.UI.Error(err.Error())
return 1
}

err = os.WriteFile(c.flagOutputFile, jsonData, 0644)
if err != nil {
c.UI.Error(fmt.Sprintf("Error writing locality file: %s", err))
return 1
}

return 0
}

func (c *Command) fetchLocalityConfig() Config {
var cfg Config
node, err := c.clientset.CoreV1().Nodes().Get(context.Background(), c.flagNodeName, metav1.GetOptions{})
if err != nil {
return cfg
}

cfg.Locality.Region = node.Labels[corev1.LabelTopologyRegion]

return cfg
}

func (c *Command) Synopsis() string { return synopsis }
func (c *Command) Help() string {
c.once.Do(c.init)
return c.help
}

const synopsis = "Fetch the cloud region for a Consul server from the Kubernetes node's region label."
const help = `
Usage: consul-k8s-control-plane fetch-server-region [options]

Fetch the region for a Consul server.
Not intended for stand-alone use.
`
Loading