2021-12-21 14:23:26 +00:00
|
|
|
/*
|
|
|
|
Copyright 2021 The Ceph-CSI Authors.
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2020-01-29 11:44:45 +00:00
|
|
|
package e2e
|
|
|
|
|
|
|
|
import (
|
2020-04-14 06:59:04 +00:00
|
|
|
"context"
|
2021-07-08 08:33:17 +00:00
|
|
|
"fmt"
|
2020-02-26 08:11:05 +00:00
|
|
|
"strings"
|
2020-02-25 11:45:54 +00:00
|
|
|
|
2024-04-04 08:49:32 +00:00
|
|
|
. "github.com/onsi/gomega"
|
2020-01-29 11:44:45 +00:00
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
"k8s.io/client-go/kubernetes"
|
2023-02-01 17:06:36 +00:00
|
|
|
"k8s.io/kubernetes/test/e2e/framework"
|
2020-01-29 11:44:45 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2021-07-08 08:33:17 +00:00
|
|
|
vaultExamplePath = "../examples/kms/vault/"
|
|
|
|
vaultServicePath = "vault.yaml"
|
|
|
|
vaultRBACPath = "csi-vaulttokenreview-rbac.yaml"
|
|
|
|
vaultConfigPath = "kms-config.yaml"
|
|
|
|
vaultTenantPath = "tenant-sa.yaml"
|
|
|
|
vaultTenantAdminPath = "tenant-sa-admin.yaml"
|
2021-08-05 11:58:48 +00:00
|
|
|
vaultUserSecret = "user-secret.yaml"
|
2020-01-29 11:44:45 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func deployVault(c kubernetes.Interface, deployTimeout int) {
|
2020-04-01 07:20:43 +00:00
|
|
|
// hack to make helm E2E pass as helm charts creates this configmap as part
|
|
|
|
// of cephcsi deployment
|
2021-07-28 03:51:18 +00:00
|
|
|
err := retryKubectlArgs(
|
2021-06-25 12:47:11 +00:00
|
|
|
cephCSINamespace,
|
2021-07-28 03:51:18 +00:00
|
|
|
kubectlDelete,
|
|
|
|
deployTimeout,
|
2021-06-25 12:47:11 +00:00
|
|
|
"cm",
|
|
|
|
"ceph-csi-encryption-kms-config",
|
|
|
|
"--ignore-not-found=true")
|
2023-06-02 09:54:25 +00:00
|
|
|
Expect(err).ShouldNot(HaveOccurred())
|
2020-04-01 07:20:43 +00:00
|
|
|
|
2021-07-16 13:40:48 +00:00
|
|
|
createORDeleteVault(kubectlCreate)
|
2020-01-29 11:44:45 +00:00
|
|
|
opt := metav1.ListOptions{
|
|
|
|
LabelSelector: "app=vault",
|
|
|
|
}
|
|
|
|
|
2020-04-14 06:59:04 +00:00
|
|
|
pods, err := c.CoreV1().Pods(cephCSINamespace).List(context.TODO(), opt)
|
2023-06-02 09:54:25 +00:00
|
|
|
Expect(err).ShouldNot(HaveOccurred())
|
|
|
|
Expect(pods.Items).Should(HaveLen(1))
|
2020-01-29 11:44:45 +00:00
|
|
|
name := pods.Items[0].Name
|
2021-06-15 10:08:51 +00:00
|
|
|
err = waitForPodInRunningState(name, cephCSINamespace, c, deployTimeout, noError)
|
2023-06-02 09:54:25 +00:00
|
|
|
Expect(err).ShouldNot(HaveOccurred())
|
2020-01-29 11:44:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func deleteVault() {
|
2021-07-16 13:40:48 +00:00
|
|
|
createORDeleteVault(kubectlDelete)
|
2020-02-26 08:11:05 +00:00
|
|
|
}
|
|
|
|
|
2021-07-16 13:40:48 +00:00
|
|
|
func createORDeleteVault(action kubectlAction) {
|
2020-02-26 08:11:05 +00:00
|
|
|
data, err := replaceNamespaceInTemplate(vaultExamplePath + vaultServicePath)
|
|
|
|
if err != nil {
|
2023-02-01 17:06:36 +00:00
|
|
|
framework.Failf("failed to read content from %s %v", vaultExamplePath+vaultServicePath, err)
|
2020-02-26 08:11:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
data = strings.ReplaceAll(data, "vault.default", "vault."+cephCSINamespace)
|
|
|
|
|
|
|
|
data = strings.ReplaceAll(data, "value: default", "value: "+cephCSINamespace)
|
2021-07-16 13:40:48 +00:00
|
|
|
err = retryKubectlInput(cephCSINamespace, action, data, deployTimeout)
|
2020-02-26 08:11:05 +00:00
|
|
|
if err != nil {
|
2023-02-01 17:06:36 +00:00
|
|
|
framework.Failf("failed to %s vault statefulset %v", action, err)
|
2020-02-26 08:11:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
data, err = replaceNamespaceInTemplate(vaultExamplePath + vaultRBACPath)
|
|
|
|
if err != nil {
|
2023-02-01 17:06:36 +00:00
|
|
|
framework.Failf("failed to read content from %s %v", vaultExamplePath+vaultRBACPath, err)
|
2020-02-26 08:11:05 +00:00
|
|
|
}
|
2021-07-16 13:40:48 +00:00
|
|
|
err = retryKubectlInput(cephCSINamespace, action, data, deployTimeout)
|
2020-01-29 11:44:45 +00:00
|
|
|
if err != nil {
|
2023-02-01 17:06:36 +00:00
|
|
|
framework.Failf("failed to %s vault statefulset %v", action, err)
|
2020-01-29 11:44:45 +00:00
|
|
|
}
|
2020-02-26 08:11:05 +00:00
|
|
|
|
|
|
|
data, err = replaceNamespaceInTemplate(vaultExamplePath + vaultConfigPath)
|
|
|
|
if err != nil {
|
2023-02-01 17:06:36 +00:00
|
|
|
framework.Failf("failed to read content from %s %v", vaultExamplePath+vaultConfigPath, err)
|
2020-02-26 08:11:05 +00:00
|
|
|
}
|
|
|
|
data = strings.ReplaceAll(data, "default", cephCSINamespace)
|
2021-07-16 13:40:48 +00:00
|
|
|
err = retryKubectlInput(cephCSINamespace, action, data, deployTimeout)
|
2020-01-29 11:44:45 +00:00
|
|
|
if err != nil {
|
2023-02-01 17:06:36 +00:00
|
|
|
framework.Failf("failed to %s vault configmap %v", action, err)
|
2020-01-29 11:44:45 +00:00
|
|
|
}
|
|
|
|
}
|
2021-07-08 08:33:17 +00:00
|
|
|
|
|
|
|
// createTenantServiceAccount uses the tenant-sa.yaml example file to create
|
|
|
|
// the ServiceAccount for the tenant and configured Hashicorp Vault with a
|
|
|
|
// kv-store that the ServiceAccount has access to.
|
|
|
|
func createTenantServiceAccount(c kubernetes.Interface, ns string) error {
|
2021-07-16 13:40:48 +00:00
|
|
|
err := createORDeleteTenantServiceAccount(kubectlCreate, ns)
|
2021-07-08 08:33:17 +00:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to create ServiceAccount: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// wait for the Job to finish
|
|
|
|
const jobName = "vault-tenant-sa"
|
|
|
|
err = waitForJobCompletion(c, cephCSINamespace, jobName, deployTimeout)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("job %s/%s did not succeed: %w", cephCSINamespace, jobName, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// deleteTenantServiceAccount removed the ServiceAccount and other objects that
|
|
|
|
// were created with createTenantServiceAccount.
|
|
|
|
func deleteTenantServiceAccount(ns string) {
|
2021-07-16 13:40:48 +00:00
|
|
|
err := createORDeleteTenantServiceAccount(kubectlDelete, ns)
|
2023-06-02 09:54:25 +00:00
|
|
|
Expect(err).ShouldNot(HaveOccurred())
|
2021-07-08 08:33:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// createORDeleteTenantServiceAccount is a helper that reads the tenant-sa.yaml
|
|
|
|
// example file and replaces the default namespaces with the current deployment
|
|
|
|
// configuration.
|
2021-07-16 13:40:48 +00:00
|
|
|
func createORDeleteTenantServiceAccount(action kubectlAction, ns string) error {
|
|
|
|
err := retryKubectlFile(ns, action, vaultExamplePath+vaultTenantPath, deployTimeout)
|
2021-07-08 08:33:17 +00:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to %s tenant ServiceAccount: %w", action, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// the ServiceAccount needs permissions in Vault, the admin job sets that up
|
|
|
|
data, err := replaceNamespaceInTemplate(vaultExamplePath + vaultTenantAdminPath)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to read content from %q: %w", vaultExamplePath+vaultTenantAdminPath, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// replace the value for TENANT_NAMESPACE
|
|
|
|
data = strings.ReplaceAll(data, "value: tenant", "value: "+ns)
|
|
|
|
|
|
|
|
// replace "default" in the URL to the Vault service
|
|
|
|
data = strings.ReplaceAll(data, "vault.default", "vault."+cephCSINamespace)
|
|
|
|
|
2021-07-16 13:40:48 +00:00
|
|
|
err = retryKubectlInput(cephCSINamespace, action, data, deployTimeout)
|
2021-07-08 08:33:17 +00:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to %s ServiceAccount: %w", action, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|