Skip to content

Commit

Permalink
Add vSphere e2e standalone test
Browse files Browse the repository at this point in the history
  • Loading branch information
a13x5 committed Sep 14, 2024
1 parent 5d20c0f commit 4b4e536
Show file tree
Hide file tree
Showing 12 changed files with 408 additions and 51 deletions.
18 changes: 8 additions & 10 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -293,21 +293,25 @@ dev-aws-creds: yq
dev-azure-creds: envsubst
@NAMESPACE=$(NAMESPACE) $(ENVSUBST) -no-unset -i config/dev/azure-credentials.yaml | $(KUBECTL) apply -f -

.PHONY: dev-vsphere-creds
dev-vsphere-creds: envsubst
@NAMESPACE=$(NAMESPACE) $(ENVSUBST) -no-unset -i config/dev/vsphere-credentials.yaml | $(KUBECTL) apply -f -

.PHONY: dev-apply
dev-apply: kind-deploy registry-deploy dev-push dev-deploy dev-templates

.PHONY: dev-destroy
dev-destroy: kind-undeploy registry-undeploy ## Destroy the development environment by deleting the kind cluster and local registry.

.PHONY: dev-provider-apply
dev-provider-apply: envsubst
.PHONY: dev-mcluster-apply
dev-mcluster-apply: envsubst
@if [ $(DEV_PROVIDER) = "aws" ]; then \
$(MAKE) dev-aws-creds; \
fi
@NAMESPACE=$(NAMESPACE) $(ENVSUBST) -no-unset -i config/dev/$(DEV_PROVIDER)-managedcluster.yaml | $(KUBECTL) apply -f -

.PHONY: dev-provider-delete
dev-provider-delete: envsubst
.PHONY: dev-mcluster-delete
dev-mcluster-delete: envsubst
@NAMESPACE=$(NAMESPACE) $(ENVSUBST) -no-unset -i config/dev/$(DEV_PROVIDER)-managedcluster.yaml | $(KUBECTL) delete -f -

.PHONY: dev-creds-apply
Expand All @@ -320,12 +324,6 @@ dev-aws-nuke: ## Warning: Destructive! Nuke all AWS resources deployed by 'DEV_P
@rm config/dev/cloud_nuke.yaml
@CLUSTER_NAME=$(CLUSTER_NAME) YQ=$(YQ) AWSCLI=$(AWSCLI) bash -c ./scripts/aws-nuke-ccm.sh

.PHONY: test-apply
test-apply: kind-deploy registry-deploy dev-push dev-deploy dev-templates

.PHONY: test-destroy
test-destroy: kind-undeploy registry-undeploy

.PHONY: cli-install
cli-install: clusterawsadm clusterctl cloud-nuke yq awscli ## Install the necessary CLI tools for deployment, development and testing.

Expand Down
20 changes: 20 additions & 0 deletions config/dev/vsphere-credentials.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: VSphereClusterIdentity
metadata:
name: vsphere-cluster-identity
namespace: ${NAMESPACE}
spec:
secretName: vsphere-cluster-identity-secret
allowedNamespaces:
selector:
matchLabels: {}
---
apiVersion: v1
kind: Secret
metadata:
name: vsphere-cluster-identity-secret
namespace: ${NAMESPACE}
stringData:
username: ${VSPHERE_USER}
password: ${VSPHERE_PASSWORD}
42 changes: 42 additions & 0 deletions config/dev/vsphere-managedcluster.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
apiVersion: hmc.mirantis.com/v1alpha1
kind: ManagedCluster
metadata:
name: vsphere-dev
namespace: ${NAMESPACE}
spec:
template: vsphere-standalone-cp
config:
controlPlaneNumber: 1
workersNumber: 1
clusterIdentity:
name: vsphere-cluster-identity
vsphere:
server: ${VSPHERE_SERVER}
thumbprint: ${VSPHERE_THUMBPRINT}
datacenter: ${VSPHERE_DATACENTER}
datastore: ${VSPHERE_DATASTORE}
resourcePool: ${VSPHERE_RESOURCEPOOL}
folder: ${VSPHERE_FOLDER}
username: ${VSPHERE_USER}
password: ${VSPHERE_PASSWORD}
controlPlaneEndpointIP: ${VSPHERE_CONTROL_PLANE_ENDPOINT}

controlPlane:
ssh:
user: ubuntu
publicKey: ${VSPHERE_SSH_KEY}
rootVolumeSize: 50
cpus: 4
memory: 4096
vmTemplate: ${VSPHERE_VM_TEMPLATE}
network: ${VSPHERE_NETWORK}

worker:
ssh:
user: ubuntu
publicKey: ${VSPHERE_SSH_KEY}
rootVolumeSize: 50
cpus: 4
memory: 4096
vmTemplate: ${VSPHERE_VM_TEMPLATE}
network: ${VSPHERE_NETWORK}
26 changes: 25 additions & 1 deletion docs/dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,30 @@ be set before running deployment:
More detailed description of these parameters can be found
[here](azure/cluster-parameters.md).

### vSphere Provider Setup

Follow the instruction on how to configure [vSphere Provider](vsphere/main.md).

To properly deploy dev cluster you need to have the following variables set:

- `VSPHERE_USER`
- `VSPHERE_PASSWORD`
- `VSPHERE_SERVER`
- `VSPHERE_THUMBPRINT`
- `VSPHERE_DATACENTER`
- `VSPHERE_DATASTORE`
- `VSPHERE_RESOURCEPOOL`
- `VSPHERE_FOLDER`
- `VSPHERE_CONTROL_PLANE_ENDPOINT`
- `VSPHERE_VM_TEMPLATE`
- `VSPHERE_NETWORK`
- `VSPHERE_SSH_KEY`

Naming of the variables duplicates parameters in `ManagementCluster`. To get
full explanation for each parameter visit
[vSphere cluster parameters](cluster-parameters.md) and
[vSphere machine parameters](machine-parameters.md).

## Deploy HMC

Default provider which will be used to deploy cluster is AWS, if you want to use
Expand All @@ -57,7 +81,7 @@ running make (e.g. `export DEV_PROVIDER=azure`).

4. Apply credentials for your provider by executing `make dev-creds-apply`.

5. Run `make dev-provider-apply` to deploy managed cluster on provider of your
5. Run `make dev-mcluster-apply` to deploy managed cluster on provider of your
choice with default configuration.

6. Wait for infrastructure to be provisioned and the cluster to be deployed. You
Expand Down
78 changes: 74 additions & 4 deletions test/e2e/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/Mirantis/hmc/test/kubeclient"
"github.com/Mirantis/hmc/test/managedcluster"
"github.com/Mirantis/hmc/test/utils"
vsphereutils "github.com/Mirantis/hmc/test/utils/vsphere"
)

const (
Expand All @@ -43,14 +44,14 @@ const (
var _ = Describe("controller", Ordered, func() {
BeforeAll(func() {
By("building and deploying the controller-manager")
cmd := exec.Command("make", "test-apply")
cmd := exec.Command("make", "dev-apply")
_, err := utils.Run(cmd)
Expect(err).NotTo(HaveOccurred())
})

AfterAll(func() {
By("removing the controller-manager")
cmd := exec.Command("make", "test-destroy")
cmd := exec.Command("make", "dev-destroy")
_, err := utils.Run(cmd)
Expect(err).NotTo(HaveOccurred())
})
Expand All @@ -71,6 +72,7 @@ var _ = Describe("controller", Ordered, func() {
managedcluster.ProviderCAPI,
managedcluster.ProviderAWS,
managedcluster.ProviderAzure,
managedcluster.ProviderVSphere,
} {
// Ensure only one controller pod is running.
if err := verifyControllerUp(kc, managedcluster.GetProviderLabel(provider), string(provider)); err != nil {
Expand Down Expand Up @@ -143,15 +145,15 @@ var _ = Describe("controller", Ordered, func() {
}

By("creating a Deployment")
d := managedcluster.GetUnstructured(managedcluster.ProviderAWS, template)
d := managedcluster.GetUnstructured(template)
clusterName = d.GetName()

deleteFunc, err = kc.CreateManagedCluster(context.Background(), d)
Expect(err).NotTo(HaveOccurred())

By("waiting for infrastructure providers to deploy successfully")
Eventually(func() error {
return managedcluster.VerifyProviderDeployed(context.Background(), kc, clusterName)
return managedcluster.VerifyProviderDeployed(context.Background(), kc, clusterName, managedcluster.ProviderAWS)
}).WithTimeout(30 * time.Minute).WithPolling(10 * time.Second).Should(Succeed())

By("verify the deployment deletes successfully")
Expand All @@ -163,6 +165,74 @@ var _ = Describe("controller", Ordered, func() {
})
}
})

Context("vSphere templates", func() {
var (
kc *kubeclient.KubeClient
deleteFunc func() error
clusterName string
err error
)

BeforeAll(func() {
// Set here to skip CI runs for now
_, testVsphere := os.LookupEnv("TEST_VSPHERE")
if !testVsphere {
Skip("Skipping vSphere tests")
}

By("ensuring that env vars are set correctly")
Expect(vsphereutils.CheckEnv()).Should(Succeed())
By("creating kube client")
kc, err = kubeclient.NewFromLocal(namespace)
Expect(err).NotTo(HaveOccurred())
By("providing cluster identity")
credSecretName := "vsphere-cluster-identity-secret-e2e"
clusterIdentityName := "vsphere-cluster-identity-e2e"
Expect(kc.CreateVSphereSecret(credSecretName)).Should(Succeed())
Expect(kc.CreateVSphereClusterIdentity(credSecretName, clusterIdentityName)).Should(Succeed())
By("setting VSPHERE_CLUSTER_IDENTITY env variable")
Expect(os.Setenv("VSPHERE_CLUSTER_IDENTITY", clusterIdentityName)).Should(Succeed())
})

AfterEach(func() {
// If we failed collect logs from each of the affiliated controllers
// as well as the output of clusterctl to store as artifacts.
if CurrentSpecReport().Failed() {
By("collecting failure logs from controllers")
collectLogArtifacts(kc, clusterName, managedcluster.ProviderVSphere, managedcluster.ProviderCAPI)
}

if deleteFunc != nil {
By("deleting the deployment")
err = deleteFunc()
Expect(err).NotTo(HaveOccurred())
}

})

It("should deploy standalone managed cluster", func() {
By("creating a managed cluster")
d := managedcluster.GetUnstructured(managedcluster.TemplateVSphereStandaloneCP)
clusterName = d.GetName()

deleteFunc, err = kc.CreateManagedCluster(context.Background(), d)
Expect(err).NotTo(HaveOccurred())

By("waiting for infrastructure providers to deploy successfully")
Eventually(func() error {
return managedcluster.VerifyProviderDeployed(context.Background(), kc, clusterName, managedcluster.ProviderVSphere)
}).WithTimeout(30 * time.Minute).WithPolling(10 * time.Second).Should(Succeed())

By("verify the deployment deletes successfully")
err = deleteFunc()
Expect(err).NotTo(HaveOccurred())
Eventually(func() error {
return managedcluster.VerifyProviderDeleted(context.Background(), kc, clusterName)
}).WithTimeout(10 * time.Minute).WithPolling(10 * time.Second).Should(Succeed())
})
})

})

func verifyControllerUp(kc *kubeclient.KubeClient, labelSelector string, name string) error {
Expand Down
69 changes: 69 additions & 0 deletions test/kubeclient/kubeclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,75 @@ func (kc *KubeClient) CreateAWSCredentialsKubeSecret(ctx context.Context) error
return nil
}

func (kc *KubeClient) CreateVSphereSecret(secretName string) error {
ctx := context.Background()
_, err := kc.Client.CoreV1().Secrets(kc.Namespace).Get(ctx, secretName, metav1.GetOptions{})

if !apierrors.IsNotFound(err) {
return nil
}
username := os.Getenv("VSPHERE_USER")
password := os.Getenv("VSPHERE_PASSWORD")

_, err = kc.Client.CoreV1().Secrets(kc.Namespace).Create(ctx, &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
},
StringData: map[string]string{
"username": username,
"password": password,
},
Type: corev1.SecretTypeOpaque,
}, metav1.CreateOptions{})

if err != nil {
return fmt.Errorf("failed to create AWS credentials secret: %w", err)
}

return nil
}

func (kc *KubeClient) CreateVSphereClusterIdentity(secretName string, identityName string) error {
ctx := context.Background()
client, err := dynamic.NewForConfig(kc.Config)

if err != nil {
return fmt.Errorf("failed to create dynamic client: %w", err)
}

gvr := schema.GroupVersionResource{
Group: "infrastructure.cluster.x-k8s.io",
Version: "v1beta1",
Resource: "vsphereclusteridentities",
}

clusterIdentity := &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "infrastructure.cluster.x-k8s.io/v1beta1",
"kind": "VSphereClusterIdentity",
"metadata": map[string]interface{}{
"name": identityName,
},
"spec": map[string]interface{}{
"secretName": secretName,
"allowedNamespaces": map[string]interface{}{
"selector": map[string]interface{}{
"matchLabels": map[string]interface{}{},
},
},
},
},
}

result, err := client.Resource(gvr).Create(ctx, clusterIdentity, metav1.CreateOptions{})
if err != nil {
fmt.Printf("%+v", result)
return fmt.Errorf("Failed to create vsphereclusteridentity: %w", err)
}

return nil
}

// GetDynamicClient returns a dynamic client for the given GroupVersionResource.
func (kc *KubeClient) GetDynamicClient(gvr schema.GroupVersionResource) (dynamic.ResourceInterface, error) {
client, err := dynamic.NewForConfig(kc.Config)
Expand Down
Loading

0 comments on commit 4b4e536

Please sign in to comment.