mirror of
https://github.com/ceph/ceph-csi.git
synced 2024-12-18 02:50:30 +00:00
util: split vaultTenantConnection from VaultTokensKMS
This makes the Tenant configuration for Hashicorp Vault KMS connections more modular. Additional KMS implementations that use Hashicorp Vault with per-Tenant options can re-use the new vaultTenantConnection. Signed-off-by: Niels de Vos <ndevos@redhat.com>
This commit is contained in:
parent
ed298341a6
commit
6dc5bf2b29
@ -27,6 +27,7 @@ import (
|
|||||||
"github.com/hashicorp/vault/api"
|
"github.com/hashicorp/vault/api"
|
||||||
apierrs "k8s.io/apimachinery/pkg/api/errors"
|
apierrs "k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/client-go/kubernetes"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -165,14 +166,21 @@ Example JSON structure in the KMS config is,
|
|||||||
...
|
...
|
||||||
}.
|
}.
|
||||||
*/
|
*/
|
||||||
type VaultTokensKMS struct {
|
type vaultTenantConnection struct {
|
||||||
vaultConnection
|
vaultConnection
|
||||||
integratedDEK
|
integratedDEK
|
||||||
|
|
||||||
|
client *kubernetes.Clientset
|
||||||
|
|
||||||
// Tenant is the name of the owner of the volume
|
// Tenant is the name of the owner of the volume
|
||||||
Tenant string
|
Tenant string
|
||||||
// ConfigName is the name of the ConfigMap in the Tenants Kubernetes Namespace
|
// ConfigName is the name of the ConfigMap in the Tenants Kubernetes Namespace
|
||||||
ConfigName string
|
ConfigName string
|
||||||
|
}
|
||||||
|
|
||||||
|
type VaultTokensKMS struct {
|
||||||
|
vaultTenantConnection
|
||||||
|
|
||||||
// TokenName is the name of the Secret in the Tenants Kubernetes Namespace
|
// TokenName is the name of the Secret in the Tenants Kubernetes Namespace
|
||||||
TokenName string
|
TokenName string
|
||||||
}
|
}
|
||||||
@ -182,7 +190,6 @@ var _ = RegisterKMSProvider(KMSProvider{
|
|||||||
Initializer: initVaultTokensKMS,
|
Initializer: initVaultTokensKMS,
|
||||||
})
|
})
|
||||||
|
|
||||||
// InitVaultTokensKMS returns an interface to HashiCorp Vault KMS.
|
|
||||||
// InitVaultTokensKMS returns an interface to HashiCorp Vault KMS.
|
// InitVaultTokensKMS returns an interface to HashiCorp Vault KMS.
|
||||||
func initVaultTokensKMS(args KMSInitializerArgs) (EncryptionKMS, error) {
|
func initVaultTokensKMS(args KMSInitializerArgs) (EncryptionKMS, error) {
|
||||||
var err error
|
var err error
|
||||||
@ -212,6 +219,12 @@ func initVaultTokensKMS(args KMSInitializerArgs) (EncryptionKMS, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = kms.setTokenName(config)
|
||||||
|
if err != nil && !errors.Is(err, errConfigOptionMissing) {
|
||||||
|
return nil, fmt.Errorf("failed to set the TokenName from global config %q: %w",
|
||||||
|
kms.ConfigName, err)
|
||||||
|
}
|
||||||
|
|
||||||
// fetch the configuration for the tenant
|
// fetch the configuration for the tenant
|
||||||
if args.Tenant != "" {
|
if args.Tenant != "" {
|
||||||
kms.Tenant = args.Tenant
|
kms.Tenant = args.Tenant
|
||||||
@ -228,11 +241,17 @@ func initVaultTokensKMS(args KMSInitializerArgs) (EncryptionKMS, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse config for tenant: %w", err)
|
return nil, fmt.Errorf("failed to parse config for tenant: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = kms.setTokenName(tenantConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to set the TokenName from %s for tenant (%s): %w",
|
||||||
|
kms.ConfigName, kms.Tenant, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetch the Vault Token from the Secret (TokenName) in the Kubernetes
|
// fetch the Vault Token from the Secret (TokenName) in the Kubernetes
|
||||||
// Namespace (tenant)
|
// Namespace (tenant)
|
||||||
kms.vaultConfig[api.EnvVaultToken], err = getToken(args.Tenant, kms.TokenName)
|
kms.vaultConfig[api.EnvVaultToken], err = kms.getToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed fetching token from %s/%s: %w", args.Tenant, kms.TokenName, err)
|
return nil, fmt.Errorf("failed fetching token from %s/%s: %w", args.Tenant, kms.TokenName, err)
|
||||||
}
|
}
|
||||||
@ -253,18 +272,25 @@ func initVaultTokensKMS(args KMSInitializerArgs) (EncryptionKMS, error) {
|
|||||||
// parseConfig updates the kms.vaultConfig with the options from config and
|
// parseConfig updates the kms.vaultConfig with the options from config and
|
||||||
// secrets. This method can be called multiple times, i.e. to override
|
// secrets. This method can be called multiple times, i.e. to override
|
||||||
// configuration options from tenants.
|
// configuration options from tenants.
|
||||||
func (kms *VaultTokensKMS) parseConfig(config map[string]interface{}) error {
|
func (vtc *vaultTenantConnection) parseConfig(config map[string]interface{}) error {
|
||||||
err := kms.initConnection(config)
|
err := vtc.initConnection(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = setConfigString(&kms.ConfigName, config, "tenantConfigName")
|
err = setConfigString(&vtc.ConfigName, config, "tenantConfigName")
|
||||||
if errors.Is(err, errConfigOptionInvalid) {
|
if errors.Is(err, errConfigOptionInvalid) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = setConfigString(&kms.TokenName, config, "tenantTokenName")
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// setTokenName updates the kms.TokenName with the options from config. This
|
||||||
|
// method can be called multiple times, i.e. to override configuration options
|
||||||
|
// from tenants.
|
||||||
|
func (kms *VaultTokensKMS) setTokenName(config map[string]interface{}) error {
|
||||||
|
err := setConfigString(&kms.TokenName, config, "tenantTokenName")
|
||||||
if errors.Is(err, errConfigOptionInvalid) {
|
if errors.Is(err, errConfigOptionInvalid) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -276,7 +302,7 @@ func (kms *VaultTokensKMS) parseConfig(config map[string]interface{}) error {
|
|||||||
// it calls the kubernetes secrets and get the required data.
|
// it calls the kubernetes secrets and get the required data.
|
||||||
|
|
||||||
// nolint:gocyclo // iterating through many config options, not complex at all.
|
// nolint:gocyclo // iterating through many config options, not complex at all.
|
||||||
func (kms *VaultTokensKMS) initCertificates(config map[string]interface{}) error {
|
func (vtc *vaultTenantConnection) initCertificates(config map[string]interface{}) error {
|
||||||
vaultConfig := make(map[string]interface{})
|
vaultConfig := make(map[string]interface{})
|
||||||
|
|
||||||
csiNamespace := os.Getenv("POD_NAMESPACE")
|
csiNamespace := os.Getenv("POD_NAMESPACE")
|
||||||
@ -287,14 +313,14 @@ func (kms *VaultTokensKMS) initCertificates(config map[string]interface{}) error
|
|||||||
}
|
}
|
||||||
// ignore errConfigOptionMissing, no default was set
|
// ignore errConfigOptionMissing, no default was set
|
||||||
if vaultCAFromSecret != "" {
|
if vaultCAFromSecret != "" {
|
||||||
cert, cErr := getCertificate(kms.Tenant, vaultCAFromSecret, "cert")
|
cert, cErr := vtc.getCertificate(vtc.Tenant, vaultCAFromSecret, "cert")
|
||||||
if cErr != nil && !apierrs.IsNotFound(cErr) {
|
if cErr != nil && !apierrs.IsNotFound(cErr) {
|
||||||
return fmt.Errorf("failed to get CA certificate from secret %s: %w", vaultCAFromSecret, cErr)
|
return fmt.Errorf("failed to get CA certificate from secret %s: %w", vaultCAFromSecret, cErr)
|
||||||
}
|
}
|
||||||
// if the certificate is not present in tenant namespace get it from
|
// if the certificate is not present in tenant namespace get it from
|
||||||
// cephcsi pod namespace
|
// cephcsi pod namespace
|
||||||
if apierrs.IsNotFound(cErr) {
|
if apierrs.IsNotFound(cErr) {
|
||||||
cert, cErr = getCertificate(csiNamespace, vaultCAFromSecret, "cert")
|
cert, cErr = vtc.getCertificate(csiNamespace, vaultCAFromSecret, "cert")
|
||||||
if cErr != nil {
|
if cErr != nil {
|
||||||
return fmt.Errorf("failed to get CA certificate from secret %s: %w", vaultCAFromSecret, cErr)
|
return fmt.Errorf("failed to get CA certificate from secret %s: %w", vaultCAFromSecret, cErr)
|
||||||
}
|
}
|
||||||
@ -312,14 +338,14 @@ func (kms *VaultTokensKMS) initCertificates(config map[string]interface{}) error
|
|||||||
}
|
}
|
||||||
// ignore errConfigOptionMissing, no default was set
|
// ignore errConfigOptionMissing, no default was set
|
||||||
if vaultClientCertFromSecret != "" {
|
if vaultClientCertFromSecret != "" {
|
||||||
cert, cErr := getCertificate(kms.Tenant, vaultClientCertFromSecret, "cert")
|
cert, cErr := vtc.getCertificate(vtc.Tenant, vaultClientCertFromSecret, "cert")
|
||||||
if cErr != nil && !apierrs.IsNotFound(cErr) {
|
if cErr != nil && !apierrs.IsNotFound(cErr) {
|
||||||
return fmt.Errorf("failed to get client certificate from secret %s: %w", vaultClientCertFromSecret, cErr)
|
return fmt.Errorf("failed to get client certificate from secret %s: %w", vaultClientCertFromSecret, cErr)
|
||||||
}
|
}
|
||||||
// if the certificate is not present in tenant namespace get it from
|
// if the certificate is not present in tenant namespace get it from
|
||||||
// cephcsi pod namespace
|
// cephcsi pod namespace
|
||||||
if apierrs.IsNotFound(cErr) {
|
if apierrs.IsNotFound(cErr) {
|
||||||
cert, cErr = getCertificate(csiNamespace, vaultClientCertFromSecret, "cert")
|
cert, cErr = vtc.getCertificate(csiNamespace, vaultClientCertFromSecret, "cert")
|
||||||
if cErr != nil {
|
if cErr != nil {
|
||||||
return fmt.Errorf("failed to get client certificate from secret %s: %w", vaultCAFromSecret, cErr)
|
return fmt.Errorf("failed to get client certificate from secret %s: %w", vaultCAFromSecret, cErr)
|
||||||
}
|
}
|
||||||
@ -338,7 +364,7 @@ func (kms *VaultTokensKMS) initCertificates(config map[string]interface{}) error
|
|||||||
|
|
||||||
// ignore errConfigOptionMissing, no default was set
|
// ignore errConfigOptionMissing, no default was set
|
||||||
if vaultClientCertKeyFromSecret != "" {
|
if vaultClientCertKeyFromSecret != "" {
|
||||||
certKey, err := getCertificate(kms.Tenant, vaultClientCertKeyFromSecret, "key")
|
certKey, err := vtc.getCertificate(vtc.Tenant, vaultClientCertKeyFromSecret, "key")
|
||||||
if err != nil && !apierrs.IsNotFound(err) {
|
if err != nil && !apierrs.IsNotFound(err) {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"failed to get client certificate key from secret %s: %w",
|
"failed to get client certificate key from secret %s: %w",
|
||||||
@ -348,7 +374,7 @@ func (kms *VaultTokensKMS) initCertificates(config map[string]interface{}) error
|
|||||||
// if the certificate is not present in tenant namespace get it from
|
// if the certificate is not present in tenant namespace get it from
|
||||||
// cephcsi pod namespace
|
// cephcsi pod namespace
|
||||||
if apierrs.IsNotFound(err) {
|
if apierrs.IsNotFound(err) {
|
||||||
certKey, err = getCertificate(csiNamespace, vaultClientCertKeyFromSecret, "key")
|
certKey, err = vtc.getCertificate(csiNamespace, vaultClientCertKeyFromSecret, "key")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get client certificate key from secret %s: %w", vaultCAFromSecret, err)
|
return fmt.Errorf("failed to get client certificate key from secret %s: %w", vaultCAFromSecret, err)
|
||||||
}
|
}
|
||||||
@ -360,16 +386,24 @@ func (kms *VaultTokensKMS) initCertificates(config map[string]interface{}) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
for key, value := range vaultConfig {
|
for key, value := range vaultConfig {
|
||||||
kms.vaultConfig[key] = value
|
vtc.vaultConfig[key] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (vtc *vaultTenantConnection) getK8sClient() *kubernetes.Clientset {
|
||||||
|
if vtc.client == nil {
|
||||||
|
vtc.client = NewK8sClient()
|
||||||
|
}
|
||||||
|
|
||||||
|
return vtc.client
|
||||||
|
}
|
||||||
|
|
||||||
// FetchDEK returns passphrase from Vault. The passphrase is stored in a
|
// FetchDEK returns passphrase from Vault. The passphrase is stored in a
|
||||||
// data.data.passphrase structure.
|
// data.data.passphrase structure.
|
||||||
func (kms *VaultTokensKMS) FetchDEK(key string) (string, error) {
|
func (vtc *vaultTenantConnection) FetchDEK(key string) (string, error) {
|
||||||
s, err := kms.secrets.GetSecret(key, kms.keyContext)
|
s, err := vtc.secrets.GetSecret(key, vtc.keyContext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -387,14 +421,14 @@ func (kms *VaultTokensKMS) FetchDEK(key string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// StoreDEK saves new passphrase in Vault.
|
// StoreDEK saves new passphrase in Vault.
|
||||||
func (kms *VaultTokensKMS) StoreDEK(key, value string) error {
|
func (vtc *vaultTenantConnection) StoreDEK(key, value string) error {
|
||||||
data := map[string]interface{}{
|
data := map[string]interface{}{
|
||||||
"data": map[string]string{
|
"data": map[string]string{
|
||||||
"passphrase": value,
|
"passphrase": value,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
err := kms.secrets.PutSecret(key, data, kms.keyContext)
|
err := vtc.secrets.PutSecret(key, data, vtc.keyContext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("saving passphrase at %s request to vault failed: %w", key, err)
|
return fmt.Errorf("saving passphrase at %s request to vault failed: %w", key, err)
|
||||||
}
|
}
|
||||||
@ -403,8 +437,8 @@ func (kms *VaultTokensKMS) StoreDEK(key, value string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RemoveDEK deletes passphrase from Vault.
|
// RemoveDEK deletes passphrase from Vault.
|
||||||
func (kms *VaultTokensKMS) RemoveDEK(key string) error {
|
func (vtc *vaultTenantConnection) RemoveDEK(key string) error {
|
||||||
err := kms.secrets.DeleteSecret(key, kms.keyContext)
|
err := vtc.secrets.DeleteSecret(key, vtc.keyContext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("delete passphrase at %s request to vault failed: %w", key, err)
|
return fmt.Errorf("delete passphrase at %s request to vault failed: %w", key, err)
|
||||||
}
|
}
|
||||||
@ -412,9 +446,9 @@ func (kms *VaultTokensKMS) RemoveDEK(key string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getToken(tenant, tokenName string) (string, error) {
|
func (kms *VaultTokensKMS) getToken() (string, error) {
|
||||||
c := NewK8sClient()
|
c := kms.getK8sClient()
|
||||||
secret, err := c.CoreV1().Secrets(tenant).Get(context.TODO(), tokenName, metav1.GetOptions{})
|
secret, err := c.CoreV1().Secrets(kms.Tenant).Get(context.TODO(), kms.TokenName, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -427,8 +461,8 @@ func getToken(tenant, tokenName string) (string, error) {
|
|||||||
return string(token), nil
|
return string(token), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCertificate(tenant, secretName, key string) (string, error) {
|
func (vtc *vaultTenantConnection) getCertificate(tenant, secretName, key string) (string, error) {
|
||||||
c := NewK8sClient()
|
c := vtc.getK8sClient()
|
||||||
secret, err := c.CoreV1().Secrets(tenant).Get(context.TODO(), secretName, metav1.GetOptions{})
|
secret, err := c.CoreV1().Secrets(tenant).Get(context.TODO(), secretName, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@ -461,21 +495,21 @@ func isTenantConfigOption(opt string) bool {
|
|||||||
// parseTenantConfig gets the optional ConfigMap from the Tenants namespace,
|
// parseTenantConfig gets the optional ConfigMap from the Tenants namespace,
|
||||||
// and applies the allowable options (see isTenantConfigOption) to the KMS
|
// and applies the allowable options (see isTenantConfigOption) to the KMS
|
||||||
// configuration.
|
// configuration.
|
||||||
func (kms *VaultTokensKMS) parseTenantConfig() error {
|
func (vtc *vaultTenantConnection) parseTenantConfig() error {
|
||||||
if kms.Tenant == "" || kms.ConfigName == "" {
|
if vtc.Tenant == "" || vtc.ConfigName == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetch the ConfigMap from the tenants namespace
|
// fetch the ConfigMap from the tenants namespace
|
||||||
c := NewK8sClient()
|
c := vtc.getK8sClient()
|
||||||
cm, err := c.CoreV1().ConfigMaps(kms.Tenant).Get(context.TODO(),
|
cm, err := c.CoreV1().ConfigMaps(vtc.Tenant).Get(context.TODO(),
|
||||||
kms.ConfigName, metav1.GetOptions{})
|
vtc.ConfigName, metav1.GetOptions{})
|
||||||
if apierrs.IsNotFound(err) {
|
if apierrs.IsNotFound(err) {
|
||||||
// the tenant did not (re)configure any options
|
// the tenant did not (re)configure any options
|
||||||
return nil
|
return nil
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return fmt.Errorf("failed to get config (%s) for tenant (%s): %w",
|
return fmt.Errorf("failed to get config (%s) for tenant (%s): %w",
|
||||||
kms.ConfigName, kms.Tenant, err)
|
vtc.ConfigName, vtc.Tenant, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a new map with config options, but only include the options
|
// create a new map with config options, but only include the options
|
||||||
@ -492,10 +526,10 @@ func (kms *VaultTokensKMS) parseTenantConfig() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// apply the configuration options from the tenant
|
// apply the configuration options from the tenant
|
||||||
err = kms.parseConfig(config)
|
err = vtc.parseConfig(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to parse config (%s) for tenant (%s): %w",
|
return fmt.Errorf("failed to parse config (%s) for tenant (%s): %w",
|
||||||
kms.ConfigName, kms.Tenant, err)
|
vtc.ConfigName, vtc.Tenant, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -28,12 +28,12 @@ import (
|
|||||||
|
|
||||||
func TestParseConfig(t *testing.T) {
|
func TestParseConfig(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
kms := VaultTokensKMS{}
|
vtc := vaultTenantConnection{}
|
||||||
|
|
||||||
config := make(map[string]interface{})
|
config := make(map[string]interface{})
|
||||||
|
|
||||||
// empty config map
|
// empty config map
|
||||||
err := kms.parseConfig(config)
|
err := vtc.parseConfig(config)
|
||||||
if !errors.Is(err, errConfigOptionMissing) {
|
if !errors.Is(err, errConfigOptionMissing) {
|
||||||
t.Errorf("unexpected error (%T): %s", err, err)
|
t.Errorf("unexpected error (%T): %s", err, err)
|
||||||
}
|
}
|
||||||
@ -41,28 +41,25 @@ func TestParseConfig(t *testing.T) {
|
|||||||
// fill default options (normally done in initVaultTokensKMS)
|
// fill default options (normally done in initVaultTokensKMS)
|
||||||
config["vaultAddress"] = "https://vault.default.cluster.svc"
|
config["vaultAddress"] = "https://vault.default.cluster.svc"
|
||||||
config["tenantConfigName"] = vaultTokensDefaultConfigName
|
config["tenantConfigName"] = vaultTokensDefaultConfigName
|
||||||
config["tenantTokenName"] = vaultTokensDefaultTokenName
|
|
||||||
|
|
||||||
// parsing with all required options
|
// parsing with all required options
|
||||||
err = kms.parseConfig(config)
|
err = vtc.parseConfig(config)
|
||||||
switch {
|
switch {
|
||||||
case err != nil:
|
case err != nil:
|
||||||
t.Errorf("unexpected error: %s", err)
|
t.Errorf("unexpected error: %s", err)
|
||||||
case kms.ConfigName != vaultTokensDefaultConfigName:
|
case vtc.ConfigName != vaultTokensDefaultConfigName:
|
||||||
t.Errorf("ConfigName contains unexpected value: %s", kms.ConfigName)
|
t.Errorf("ConfigName contains unexpected value: %s", vtc.ConfigName)
|
||||||
case kms.TokenName != vaultTokensDefaultTokenName:
|
|
||||||
t.Errorf("TokenName contains unexpected value: %s", kms.TokenName)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// tenant "bob" uses a different kms.ConfigName
|
// tenant "bob" uses a different kms.ConfigName
|
||||||
bob := make(map[string]interface{})
|
bob := make(map[string]interface{})
|
||||||
bob["tenantConfigName"] = "the-config-from-bob"
|
bob["tenantConfigName"] = "the-config-from-bob"
|
||||||
err = kms.parseConfig(bob)
|
err = vtc.parseConfig(bob)
|
||||||
switch {
|
switch {
|
||||||
case err != nil:
|
case err != nil:
|
||||||
t.Errorf("unexpected error: %s", err)
|
t.Errorf("unexpected error: %s", err)
|
||||||
case kms.ConfigName != "the-config-from-bob":
|
case vtc.ConfigName != "the-config-from-bob":
|
||||||
t.Errorf("ConfigName contains unexpected value: %s", kms.ConfigName)
|
t.Errorf("ConfigName contains unexpected value: %s", vtc.ConfigName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user