Skip to content

Commit a10b83f

Browse files
committed
Add e2es for configuring ACME solver pod resources via flags
1 parent 71bfc87 commit a10b83f

2 files changed

Lines changed: 106 additions & 11 deletions

File tree

test/e2e/certificates_test.go

Lines changed: 65 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
corev1 "k8s.io/api/core/v1"
1414
networkingv1 "k8s.io/api/networking/v1"
1515
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
16+
k8sresource "k8s.io/apimachinery/pkg/api/resource"
1617
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1718
"k8s.io/apimachinery/pkg/util/wait"
1819

@@ -30,6 +31,12 @@ const (
3031
// letsEncryptStagingServerURL is the address for the Let's Encrypt staging environment server.
3132
letsEncryptStagingServerURL = "https://acme-staging-v02.api.letsencrypt.org/directory"
3233

34+
// acmeSolverPodLabel is the label that cert-manager uses to identify ACME solver pods.
35+
acmeSolverPodLabel = "acme.cert-manager.io/http01-solver"
36+
37+
// acmeSolverContainerName is the name of the container in the ACME solver pod.
38+
acmeSolverContainerName = "acmesolver"
39+
3340
// TARGET_PLATFORM is the environment variable for IBM Cloud CIS test.
3441
targetPlatformEnvironmentVar = "TARGET_PLATFORM"
3542

@@ -693,11 +700,15 @@ var _ = Describe("ACME Certificate", Ordered, func() {
693700
})
694701

695702
Context("http-01 challenge using ingress", func() {
696-
It("should obtain a valid LetsEncrypt certificate", func() {
703+
var ingressHost string
704+
var secretName string
697705

698-
By("creating a cluster issuer")
706+
BeforeEach(func() {
699707
clusterIssuerName := "letsencrypt-http01"
700708
ingressClassName := "openshift-default"
709+
secretName = "ingress-http01-secret"
710+
711+
By("creating a cluster issuer")
701712
clusterIssuer := &certmanagerv1.ClusterIssuer{
702713
ObjectMeta: metav1.ObjectMeta{
703714
Name: clusterIssuerName,
@@ -726,20 +737,16 @@ var _ = Describe("ACME Certificate", Ordered, func() {
726737
}
727738
_, err := certmanagerClient.CertmanagerV1().ClusterIssuers().Create(ctx, clusterIssuer, metav1.CreateOptions{})
728739
Expect(err).NotTo(HaveOccurred())
729-
defer certmanagerClient.CertmanagerV1().ClusterIssuers().Delete(ctx, clusterIssuerName, metav1.DeleteOptions{})
730740

731741
By("creating an hello-openshift deployment")
732742
loader.CreateFromFile(testassets.ReadFile, filepath.Join("testdata", "acme", "deployment.yaml"), ns.Name)
733-
defer loader.DeleteFromFile(testassets.ReadFile, filepath.Join("testdata", "acme", "deployment.yaml"), ns.Name)
734743

735744
By("creating a service for the deployment hello-openshift")
736745
loader.CreateFromFile(testassets.ReadFile, filepath.Join("testdata", "acme", "service.yaml"), ns.Name)
737-
defer loader.DeleteFromFile(testassets.ReadFile, filepath.Join("testdata", "acme", "service.yaml"), ns.Name)
738746

739747
By("creating an Ingress object")
740-
ingressHost := fmt.Sprintf("ahi-%s.%s", randomStr(3), appsDomain) // acronym for "ACME http-01 Ingress"
748+
ingressHost = fmt.Sprintf("ahi-%s.%s", randomStr(3), appsDomain) // acronym for "ACME http-01 Ingress"
741749
pathType := networkingv1.PathTypePrefix
742-
secretName := "ingress-http01-secret"
743750
ingress := &networkingv1.Ingress{
744751
TypeMeta: metav1.TypeMeta{
745752
APIVersion: "networking.k8s.io/v1",
@@ -776,13 +783,18 @@ var _ = Describe("ACME Certificate", Ordered, func() {
776783
}},
777784
},
778785
}
779-
ingress, err = loader.KubeClient.NetworkingV1().Ingresses(ingress.Namespace).Create(ctx, ingress, metav1.CreateOptions{})
786+
ingress, err = loader.KubeClient.NetworkingV1().Ingresses(ns.Name).Create(ctx, ingress, metav1.CreateOptions{})
780787
Expect(err).NotTo(HaveOccurred())
781-
defer loader.KubeClient.NetworkingV1().Ingresses(ingress.Namespace).Delete(ctx, ingress.Name, metav1.DeleteOptions{})
782788

789+
DeferCleanup(func() {
790+
certmanagerClient.CertmanagerV1().ClusterIssuers().Delete(ctx, clusterIssuerName, metav1.DeleteOptions{})
791+
})
792+
})
793+
794+
It("should obtain a valid LetsEncrypt certificate", func() {
783795
By("checking TLS certificate contents")
784-
err = wait.PollUntilContextTimeout(context.TODO(), slowPollInterval, highTimeout, true, func(context.Context) (bool, error) {
785-
secret, err := loader.KubeClient.CoreV1().Secrets(ingress.Namespace).Get(ctx, secretName, metav1.GetOptions{})
796+
err := wait.PollUntilContextTimeout(context.TODO(), slowPollInterval, highTimeout, true, func(context.Context) (bool, error) {
797+
secret, err := loader.KubeClient.CoreV1().Secrets(ns.Name).Get(ctx, secretName, metav1.GetOptions{})
786798
tlsConfig, isvalid := library.GetTLSConfig(secret)
787799
if !isvalid {
788800
return false, nil
@@ -800,6 +812,48 @@ var _ = Describe("ACME Certificate", Ordered, func() {
800812
})
801813
Expect(err).NotTo(HaveOccurred())
802814
})
815+
816+
It("should create HTTP01 solver pods with custom resource limits and requests", func() {
817+
By("monitoring for ACME HTTP01 solver pods with expected resource configuration")
818+
// These values match what's configured in BeforeAll
819+
expectedResources := corev1.ResourceRequirements{
820+
Limits: corev1.ResourceList{
821+
corev1.ResourceCPU: k8sresource.MustParse("150m"),
822+
corev1.ResourceMemory: k8sresource.MustParse("200Mi"),
823+
},
824+
Requests: corev1.ResourceList{
825+
corev1.ResourceCPU: k8sresource.MustParse("100m"),
826+
corev1.ResourceMemory: k8sresource.MustParse("100Mi"),
827+
},
828+
}
829+
830+
err := wait.PollUntilContextTimeout(ctx, fastPollInterval, lowTimeout, true, func(ctx context.Context) (bool, error) {
831+
pods, err := k8sClientSet.CoreV1().Pods("").List(ctx, metav1.ListOptions{
832+
LabelSelector: acmeSolverPodLabel,
833+
})
834+
if err != nil {
835+
return false, nil // Retry on transient errors
836+
}
837+
838+
if len(pods.Items) == 0 {
839+
return false, nil // Keep waiting for pods to appear
840+
}
841+
842+
// Check if any pod matches the expected resource configuration
843+
for _, pod := range pods.Items {
844+
if err := VerifyContainerResources(pod, acmeSolverContainerName, expectedResources); err == nil {
845+
return true, nil
846+
}
847+
}
848+
849+
return false, nil // No matching pods yet, keep waiting
850+
})
851+
Expect(err).NotTo(HaveOccurred(), "should find ACME HTTP01 solver pods with expected resource configuration")
852+
853+
By("waiting for certificate to get ready")
854+
err = waitForCertificateReadiness(ctx, secretName, ns.Name)
855+
Expect(err).NotTo(HaveOccurred())
856+
})
803857
})
804858
})
805859

test/e2e/utils_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,3 +764,44 @@ func pollTillDeploymentAvailable(ctx context.Context, clientSet *kubernetes.Clie
764764

765765
return err
766766
}
767+
768+
// VerifyContainerResources verifies that a container in a pod has resources matching the expected configuration.
769+
// If containerName is empty, it verifies the first container.
770+
func VerifyContainerResources(pod corev1.Pod, containerName string, expectedResources corev1.ResourceRequirements) error {
771+
var targetContainer *corev1.Container
772+
773+
if containerName == "" {
774+
// Default to first container when no specific container name is provided
775+
targetContainer = &pod.Spec.Containers[0]
776+
} else {
777+
// Find the specific container by name
778+
for i := range pod.Spec.Containers {
779+
if pod.Spec.Containers[i].Name == containerName {
780+
targetContainer = &pod.Spec.Containers[i]
781+
break
782+
}
783+
}
784+
if targetContainer == nil {
785+
return fmt.Errorf("container '%s' not found in pod '%s'", containerName, pod.Name)
786+
}
787+
}
788+
789+
// Verify limits
790+
if expectedResources.Limits != nil {
791+
for resourceType, expectedValue := range expectedResources.Limits {
792+
if actualValue := targetContainer.Resources.Limits[resourceType]; !actualValue.Equal(expectedValue) {
793+
return fmt.Errorf("%s limit for container '%s' in pod '%s' is '%v' but expected '%v'", resourceType, targetContainer.Name, pod.Name, actualValue, expectedValue)
794+
}
795+
}
796+
}
797+
798+
// Verify requests
799+
if expectedResources.Requests != nil {
800+
for resourceType, expectedValue := range expectedResources.Requests {
801+
if actualValue := targetContainer.Resources.Requests[resourceType]; !actualValue.Equal(expectedValue) {
802+
return fmt.Errorf("%s request for container '%s' in pod '%s' is '%v' but expected '%v'", resourceType, targetContainer.Name, pod.Name, actualValue, expectedValue)
803+
}
804+
}
805+
}
806+
return nil
807+
}

0 commit comments

Comments
 (0)