Skip to main content
Glama
provisioning_test.go10.2 kB
/* 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. */ package scale_test import ( "context" "strconv" "time" "github.com/samber/lo" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/labels" karpv1 "sigs.k8s.io/karpenter/pkg/apis/v1" "sigs.k8s.io/karpenter/pkg/test" v1 "github.com/aws/karpenter-provider-aws/pkg/apis/v1" "github.com/aws/karpenter-provider-aws/test/pkg/debug" "github.com/aws/karpenter-provider-aws/test/pkg/environment/aws" . "github.com/onsi/ginkgo/v2" ) const testGroup = "provisioning" var _ = Describe("Provisioning", Label(debug.NoWatch), Label(debug.NoEvents), func() { var nodePool *karpv1.NodePool var nodeClass *v1.EC2NodeClass var deployment *appsv1.Deployment var selector labels.Selector var dsCount int BeforeEach(func() { nodeClass = env.DefaultEC2NodeClass() nodePool = env.DefaultNodePool(nodeClass) nodePool.Spec.Limits = nil nodePool.Spec.Disruption.Budgets = []karpv1.Budget{{ Nodes: "70%", }} test.ReplaceRequirements(nodePool, karpv1.NodeSelectorRequirementWithMinValues{ NodeSelectorRequirement: corev1.NodeSelectorRequirement{ Key: v1.LabelInstanceHypervisor, Operator: corev1.NodeSelectorOpIn, Values: []string{"nitro"}, }, }) deployment = test.Deployment(test.DeploymentOptions{ PodOptions: test.PodOptions{ ResourceRequirements: corev1.ResourceRequirements{ Requests: corev1.ResourceList{ corev1.ResourceCPU: resource.MustParse("10m"), corev1.ResourceMemory: resource.MustParse("50Mi"), }, }, TerminationGracePeriodSeconds: lo.ToPtr[int64](0), }, }) selector = labels.SelectorFromSet(deployment.Spec.Selector.MatchLabels) // Get the DS pod count and use it to calculate the DS pod overhead dsCount = env.GetDaemonSetCount(nodePool) }) It("should scale successfully on a node-dense scale-up", Label(debug.NoEvents), func(_ context.Context) { // Disable Prefix Delegation for the node-dense scale-up to not exhaust the IPs // This is required because of the number of Warm ENIs that will be created and the number of IPs // that will be allocated across this large number of nodes, despite the fact that the ENI CIDR space will // be extremely under-utilized env.ExpectPrefixDelegationDisabled() DeferCleanup(func() { env.ExpectPrefixDelegationEnabled() }) replicasPerNode := 1 expectedNodeCount := 500 replicas := replicasPerNode * expectedNodeCount deployment.Spec.Replicas = lo.ToPtr[int32](int32(replicas)) // Hostname anti-affinity to require one pod on each node deployment.Spec.Template.Spec.Affinity = &corev1.Affinity{ PodAntiAffinity: &corev1.PodAntiAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: []corev1.PodAffinityTerm{ { LabelSelector: deployment.Spec.Selector, TopologyKey: corev1.LabelHostname, }, }, }, } By("waiting for the deployment to deploy all of its pods") env.ExpectCreated(deployment) env.EventuallyExpectPendingPodCount(selector, replicas) env.MeasureProvisioningDurationFor(func() { By("kicking off provisioning by applying the nodePool and nodeClass") env.ExpectCreated(nodePool, nodeClass) env.EventuallyExpectCreatedNodeClaimCount("==", expectedNodeCount) env.EventuallyExpectCreatedNodeCount("==", expectedNodeCount) env.EventuallyExpectInitializedNodeCount("==", expectedNodeCount) env.EventuallyExpectHealthyPodCount(selector, replicas) }, map[string]string{ aws.TestCategoryDimension: testGroup, aws.TestNameDimension: "node-dense", aws.ProvisionedNodeCountDimension: strconv.Itoa(expectedNodeCount), aws.DeprovisionedNodeCountDimension: strconv.Itoa(0), aws.PodDensityDimension: strconv.Itoa(replicasPerNode), }) }, SpecTimeout(time.Minute*30)) It("should scale successfully on a node-dense scale-up with minValues in the NodePool requirement", Label(debug.NoEvents), func(_ context.Context) { // Disable Prefix Delegation for the node-dense scale-up to not exhaust the IPs // This is required because of the number of Warm ENIs that will be created and the number of IPs // that will be allocated across this large number of nodes, despite the fact that the ENI CIDR space will // be extremely under-utilized env.ExpectPrefixDelegationDisabled() DeferCleanup(func() { env.ExpectPrefixDelegationEnabled() }) replicasPerNode := 1 expectedNodeCount := 500 replicas := replicasPerNode * expectedNodeCount deployment.Spec.Replicas = lo.ToPtr[int32](int32(replicas)) // Hostname anti-affinity to require one pod on each node deployment.Spec.Template.Spec.Affinity = &corev1.Affinity{ PodAntiAffinity: &corev1.PodAntiAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: []corev1.PodAffinityTerm{ { LabelSelector: deployment.Spec.Selector, TopologyKey: corev1.LabelHostname, }, }, }, } test.ReplaceRequirements(nodePool, karpv1.NodeSelectorRequirementWithMinValues{ // minValues is restricted to 30 to have enough instance types to be sent to launch API and not make this test flaky. NodeSelectorRequirement: corev1.NodeSelectorRequirement{ Key: corev1.LabelInstanceTypeStable, Operator: corev1.NodeSelectorOpExists, }, MinValues: lo.ToPtr(30), }) By("waiting for the deployment to deploy all of its pods") env.ExpectCreated(deployment) env.EventuallyExpectPendingPodCount(selector, replicas) env.MeasureProvisioningDurationFor(func() { By("kicking off provisioning by applying the nodePool and nodeClass") env.ExpectCreated(nodePool, nodeClass) env.EventuallyExpectCreatedNodeClaimCount("==", expectedNodeCount) env.EventuallyExpectCreatedNodeCount("==", expectedNodeCount) env.EventuallyExpectInitializedNodeCount("==", expectedNodeCount) env.EventuallyExpectHealthyPodCount(selector, replicas) }, map[string]string{ aws.TestCategoryDimension: testGroup, aws.TestNameDimension: "node-dense-min-val", aws.ProvisionedNodeCountDimension: strconv.Itoa(expectedNodeCount), aws.DeprovisionedNodeCountDimension: strconv.Itoa(0), aws.PodDensityDimension: strconv.Itoa(replicasPerNode), }) }, SpecTimeout(time.Minute*30)) It("should scale successfully on a pod-dense scale-up", func(_ context.Context) { replicasPerNode := 110 maxPodDensity := replicasPerNode + dsCount expectedNodeCount := 60 replicas := replicasPerNode * expectedNodeCount deployment.Spec.Replicas = lo.ToPtr[int32](int32(replicas)) nodeClass.Spec.Kubelet = &v1.KubeletConfiguration{ MaxPods: lo.ToPtr[int32](int32(maxPodDensity)), } test.ReplaceRequirements(nodePool, karpv1.NodeSelectorRequirementWithMinValues{ // With Prefix Delegation enabled, .large instances can have 434 pods. NodeSelectorRequirement: corev1.NodeSelectorRequirement{ Key: v1.LabelInstanceSize, Operator: corev1.NodeSelectorOpIn, Values: []string{"large"}, }, }, ) env.MeasureProvisioningDurationFor(func() { By("waiting for the deployment to deploy all of its pods") env.ExpectCreated(deployment) env.EventuallyExpectPendingPodCount(selector, replicas) By("kicking off provisioning by applying the nodePool and nodeClass") env.ExpectCreated(nodePool, nodeClass) env.EventuallyExpectHealthyPodCount(selector, replicas) }, map[string]string{ aws.TestCategoryDimension: testGroup, aws.TestNameDimension: "pod-dense", aws.ProvisionedNodeCountDimension: strconv.Itoa(expectedNodeCount), aws.DeprovisionedNodeCountDimension: strconv.Itoa(0), aws.PodDensityDimension: strconv.Itoa(replicasPerNode), }) }, SpecTimeout(time.Minute*30)) It("should scale successfully on a pod-dense scale-up with minValues in the NodePool requirement", func(_ context.Context) { replicasPerNode := 110 maxPodDensity := replicasPerNode + dsCount expectedNodeCount := 60 replicas := replicasPerNode * expectedNodeCount deployment.Spec.Replicas = lo.ToPtr[int32](int32(replicas)) nodeClass.Spec.Kubelet = &v1.KubeletConfiguration{ MaxPods: lo.ToPtr[int32](int32(maxPodDensity)), } test.ReplaceRequirements(nodePool, karpv1.NodeSelectorRequirementWithMinValues{ // With Prefix Delegation enabled, .large instances can have 434 pods. NodeSelectorRequirement: corev1.NodeSelectorRequirement{ Key: v1.LabelInstanceSize, Operator: corev1.NodeSelectorOpIn, Values: []string{"large"}, }, }, karpv1.NodeSelectorRequirementWithMinValues{ // minValues is restricted to 30 to have enough instance types to be sent to launch API and not make this test flaky. NodeSelectorRequirement: corev1.NodeSelectorRequirement{ Key: corev1.LabelInstanceTypeStable, Operator: corev1.NodeSelectorOpExists, }, MinValues: lo.ToPtr(30), }, ) env.MeasureProvisioningDurationFor(func() { By("waiting for the deployment to deploy all of its pods") env.ExpectCreated(deployment) env.EventuallyExpectPendingPodCount(selector, replicas) By("kicking off provisioning by applying the nodePool and nodeClass") env.ExpectCreated(nodePool, nodeClass) env.EventuallyExpectHealthyPodCount(selector, replicas) }, map[string]string{ aws.TestCategoryDimension: testGroup, aws.TestNameDimension: "pod-dense-min-val", aws.ProvisionedNodeCountDimension: strconv.Itoa(expectedNodeCount), aws.DeprovisionedNodeCountDimension: strconv.Itoa(0), aws.PodDensityDimension: strconv.Itoa(replicasPerNode), }) }, SpecTimeout(time.Minute*30)) })

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mengfwan/test-mcp-glama'

If you have feedback or need assistance with the MCP directory API, please join our Discord server