2020-02-13 17:56:29 +00:00
|
|
|
package kubernetes
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"strconv"
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
"github.com/hashicorp/go-hclog"
|
|
|
|
sr "github.com/hashicorp/vault/serviceregistration"
|
|
|
|
"github.com/hashicorp/vault/serviceregistration/kubernetes/client"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
// Labels are placed in a pod's metadata.
|
|
|
|
labelVaultVersion = "vault-version"
|
|
|
|
labelActive = "vault-active"
|
|
|
|
labelSealed = "vault-sealed"
|
|
|
|
labelPerfStandby = "vault-perf-standby"
|
|
|
|
labelInitialized = "vault-initialized"
|
|
|
|
|
|
|
|
// This is the path to where these labels are applied.
|
|
|
|
pathToLabels = "/metadata/labels/"
|
|
|
|
)
|
|
|
|
|
2020-05-15 18:06:58 +00:00
|
|
|
func NewServiceRegistration(config map[string]string, logger hclog.Logger, state sr.State) (sr.ServiceRegistration, error) {
|
2020-02-13 17:56:29 +00:00
|
|
|
namespace, err := getRequiredField(logger, config, client.EnvVarKubernetesNamespace, "namespace")
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
podName, err := getRequiredField(logger, config, client.EnvVarKubernetesPodName, "pod_name")
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-05-15 18:06:58 +00:00
|
|
|
|
|
|
|
c, err := client.New(logger)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-02-24 22:19:58 +00:00
|
|
|
// The Vault version must be sanitized because it can contain special
|
|
|
|
// characters like "+" which aren't acceptable by the Kube API.
|
|
|
|
state.VaultVersion = client.Sanitize(state.VaultVersion)
|
2020-02-13 17:56:29 +00:00
|
|
|
return &serviceRegistration{
|
2020-05-15 18:06:58 +00:00
|
|
|
logger: logger,
|
|
|
|
namespace: namespace,
|
|
|
|
podName: podName,
|
2020-02-13 17:56:29 +00:00
|
|
|
retryHandler: &retryHandler{
|
|
|
|
logger: logger,
|
|
|
|
namespace: namespace,
|
|
|
|
podName: podName,
|
2020-05-15 18:06:58 +00:00
|
|
|
initialState: state,
|
2020-02-13 17:56:29 +00:00
|
|
|
patchesToRetry: make(map[string]*client.Patch),
|
2020-05-15 18:06:58 +00:00
|
|
|
client: c,
|
2020-02-13 17:56:29 +00:00
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type serviceRegistration struct {
|
|
|
|
logger hclog.Logger
|
|
|
|
namespace, podName string
|
|
|
|
retryHandler *retryHandler
|
|
|
|
}
|
|
|
|
|
2020-05-15 18:06:58 +00:00
|
|
|
func (r *serviceRegistration) Run(shutdownCh <-chan struct{}, wait *sync.WaitGroup, _ string) error {
|
|
|
|
r.retryHandler.Run(shutdownCh, wait)
|
2020-02-13 17:56:29 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *serviceRegistration) NotifyActiveStateChange(isActive bool) error {
|
2020-05-15 18:06:58 +00:00
|
|
|
r.retryHandler.Notify(&client.Patch{
|
2020-02-13 17:56:29 +00:00
|
|
|
Operation: client.Replace,
|
|
|
|
Path: pathToLabels + labelActive,
|
|
|
|
Value: strconv.FormatBool(isActive),
|
|
|
|
})
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *serviceRegistration) NotifySealedStateChange(isSealed bool) error {
|
2020-05-15 18:06:58 +00:00
|
|
|
r.retryHandler.Notify(&client.Patch{
|
2020-02-13 17:56:29 +00:00
|
|
|
Operation: client.Replace,
|
|
|
|
Path: pathToLabels + labelSealed,
|
|
|
|
Value: strconv.FormatBool(isSealed),
|
|
|
|
})
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *serviceRegistration) NotifyPerformanceStandbyStateChange(isStandby bool) error {
|
2020-05-15 18:06:58 +00:00
|
|
|
r.retryHandler.Notify(&client.Patch{
|
2020-02-13 17:56:29 +00:00
|
|
|
Operation: client.Replace,
|
|
|
|
Path: pathToLabels + labelPerfStandby,
|
|
|
|
Value: strconv.FormatBool(isStandby),
|
|
|
|
})
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *serviceRegistration) NotifyInitializedStateChange(isInitialized bool) error {
|
2020-05-15 18:06:58 +00:00
|
|
|
r.retryHandler.Notify(&client.Patch{
|
2020-02-13 17:56:29 +00:00
|
|
|
Operation: client.Replace,
|
|
|
|
Path: pathToLabels + labelInitialized,
|
|
|
|
Value: strconv.FormatBool(isInitialized),
|
|
|
|
})
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func getRequiredField(logger hclog.Logger, config map[string]string, envVar, configParam string) (string, error) {
|
|
|
|
value := ""
|
|
|
|
switch {
|
|
|
|
case os.Getenv(envVar) != "":
|
|
|
|
value = os.Getenv(envVar)
|
|
|
|
case config[configParam] != "":
|
|
|
|
value = config[configParam]
|
|
|
|
default:
|
|
|
|
return "", fmt.Errorf(`%s must be provided via %q or the %q config parameter`, configParam, envVar, configParam)
|
|
|
|
}
|
|
|
|
if logger.IsDebug() {
|
|
|
|
logger.Debug(fmt.Sprintf("%q: %q", configParam, value))
|
|
|
|
}
|
|
|
|
return value, nil
|
|
|
|
}
|