Skip to content

Commit

Permalink
Support resource requirements by annotations
Browse files Browse the repository at this point in the history
  • Loading branch information
ksauzz committed May 12, 2022
1 parent 37fbda3 commit 0ab34d1
Show file tree
Hide file tree
Showing 2 changed files with 175 additions and 14 deletions.
106 changes: 92 additions & 14 deletions controller/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,29 +20,35 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"strings"

"k8s.io/api/admission/v1beta1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/kubernetes"
corev1Types "k8s.io/client-go/kubernetes/typed/core/v1"
"log"
"net/http"
"os"
"strings"
)

const (
signingProxyWebhookAnnotationHostKey = "sidecar.aws.signing-proxy/host"
signingProxyWebhookAnnotationInjectKey = "sidecar.aws.signing-proxy/inject"
signingProxyWebhookAnnotationNameKey = "sidecar.aws.signing-proxy/name"
signingProxyWebhookAnnotationRegionKey = "sidecar.aws.signing-proxy/region"
signingProxyWebhookAnnotationRoleArnKey = "sidecar.aws.signing-proxy/role-arn"
signingProxyWebhookAnnotationStatusKey = "sidecar.aws.signing-proxy/status"
signingProxyWebhookLabelHostKey = "sidecar-host"
signingProxyWebhookLabelNameKey = "sidecar-name"
signingProxyWebhookLabelRegionKey = "sidecar-region"
signingProxyWebhookLabelRoleArnKey = "sidecar-role-arn"
signingProxyWebhookAnnotationHostKey = "sidecar.aws.signing-proxy/host"
signingProxyWebhookAnnotationInjectKey = "sidecar.aws.signing-proxy/inject"
signingProxyWebhookAnnotationNameKey = "sidecar.aws.signing-proxy/name"
signingProxyWebhookAnnotationRegionKey = "sidecar.aws.signing-proxy/region"
signingProxyWebhookAnnotationRoleArnKey = "sidecar.aws.signing-proxy/role-arn"
signingProxyWebhookAnnotationStatusKey = "sidecar.aws.signing-proxy/status"
signingProxyWebhookAnnotationCPURequestKey = "sidecar.aws.signing-proxy/cpu"
signingProxyWebhookAnnotationCPULimitKey = "sidecar.aws.signing-proxy/cpu-limit"
signingProxyWebhookAnnotationMemRequestKey = "sidecar.aws.signing-proxy/memory"
signingProxyWebhookAnnotationMemLimitKey = "sidecar.aws.signing-proxy/memory-limit"
signingProxyWebhookLabelHostKey = "sidecar-host"
signingProxyWebhookLabelNameKey = "sidecar-name"
signingProxyWebhookLabelRegionKey = "sidecar-region"
signingProxyWebhookLabelRoleArnKey = "sidecar-role-arn"
)

var (
Expand Down Expand Up @@ -176,6 +182,16 @@ func (whsvr *WebhookServer) mutate(ctx context.Context, admissionReview *v1beta1
Args: sidecarArgs,
}}

resources, err := whsvr.getResourceRequirements(&pod.ObjectMeta)

if err != nil {
return &v1beta1.AdmissionResponse{Result: &metav1.Status{Message: err.Error()}}, fmt.Errorf("Error getting resources: %v", err)
}

if resources != nil {
sidecarContainer[0].Resources = *resources
}

patchOperations = append(patchOperations, addContainers(pod.Spec.Containers, sidecarContainer, "/spec/containers")...)

annotations := map[string]string{signingProxyWebhookAnnotationStatusKey: "injected"}
Expand Down Expand Up @@ -297,6 +313,68 @@ func extractParameters(host string, name string, region string) (string, string,
return host, name, region
}

func (whsvr *WebhookServer) getResourceRequirements(podMetadata *metav1.ObjectMeta) (*corev1.ResourceRequirements, error) {
annotations := podMetadata.GetAnnotations()

if annotations == nil {
annotations = map[string]string{}
}

cpuReq := annotations[signingProxyWebhookAnnotationCPURequestKey]
cpuLimit := annotations[signingProxyWebhookAnnotationCPULimitKey]
memReq := annotations[signingProxyWebhookAnnotationMemRequestKey]
memLimit := annotations[signingProxyWebhookAnnotationMemLimitKey]

if cpuReq == "" && cpuLimit == "" && memReq == "" && memLimit == "" {
return nil, nil
}

requests := map[corev1.ResourceName]resource.Quantity{}
limits := map[corev1.ResourceName]resource.Quantity{}

if cpuReq != "" {
quantity, err := resource.ParseQuantity(cpuReq)
if err != nil {
return nil, fmt.Errorf("Error parsing cpu requests: %v", err)
} else {
requests[corev1.ResourceCPU] = quantity
}
}
if memReq != "" {
quantity, err := resource.ParseQuantity(memReq)
if err != nil {
return nil, fmt.Errorf("Error parsing memory requests: %v", err)
} else {
requests[corev1.ResourceMemory] = quantity
}
}
if cpuLimit != "" {
quantity, err := resource.ParseQuantity(cpuLimit)
if err != nil {
return nil, fmt.Errorf("Error parsing cpu limit: %v", err)
} else {
limits[corev1.ResourceCPU] = quantity
}
}
if memLimit != "" {
quantity, err := resource.ParseQuantity(memLimit)
if err != nil {
return nil, fmt.Errorf("Error parsing memory limit: %v", err)
} else {
limits[corev1.ResourceMemory] = quantity
}
}
resource := &corev1.ResourceRequirements{}
if len(requests) > 0 {
resource.Requests = requests
}
if len(limits) > 0 {
resource.Limits = limits
}

return resource, nil
}

func (whsvr *WebhookServer) getRoleArn(nsLabels map[string]string, podMetadata *metav1.ObjectMeta) string {
annotations := podMetadata.GetAnnotations()

Expand Down
83 changes: 83 additions & 0 deletions controller/webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"testing"
)
Expand Down Expand Up @@ -347,3 +348,85 @@ func TestWebhookServer_getRoleArn(t *testing.T) {
})
}
}

func TestWebhookServer_getResourceRequirements(t *testing.T) {
var testCases = []struct {
name string
podObjectMeta *metav1.ObjectMeta
labels map[string]string
expected *corev1.ResourceRequirements
errorMessage string
}{
{
name: "TestSidecarResourceAnnotationPresent",
podObjectMeta: &metav1.ObjectMeta{
Annotations: map[string]string{
signingProxyWebhookAnnotationCPURequestKey: "200m",
signingProxyWebhookAnnotationMemRequestKey: "200Mi",
signingProxyWebhookAnnotationCPULimitKey: "400m",
signingProxyWebhookAnnotationMemLimitKey: "400Mi",
},
},
expected: &corev1.ResourceRequirements{
Requests: map[corev1.ResourceName]resource.Quantity{
corev1.ResourceCPU: resource.MustParse("200m"),
corev1.ResourceMemory: resource.MustParse("200Mi"),
},
Limits: map[corev1.ResourceName]resource.Quantity{
corev1.ResourceCPU: resource.MustParse("400m"),
corev1.ResourceMemory: resource.MustParse("400Mi"),
},
},
errorMessage: "Should return ResourceRequiremts value",
},
{
name: "TestSidecarResourceAnnotationRequestsCPUPresent",
podObjectMeta: &metav1.ObjectMeta{
Annotations: map[string]string{
signingProxyWebhookAnnotationCPURequestKey: "200m",
},
},
expected: &corev1.ResourceRequirements{
Requests: map[corev1.ResourceName]resource.Quantity{
corev1.ResourceCPU: resource.MustParse("200m"),
},
},
errorMessage: "Should return ResourceRequestsCPU only",
},
{
name: "TestSidecarResourceAnnotationLimitCPUPreset",
podObjectMeta: &metav1.ObjectMeta{
Annotations: map[string]string{
signingProxyWebhookAnnotationCPULimitKey: "400m",
},
},
expected: &corev1.ResourceRequirements{
Limits: map[corev1.ResourceName]resource.Quantity{
corev1.ResourceCPU: resource.MustParse("400m"),
},
},
errorMessage: "Should return ResourceLimitCPU only",
},
{
name: "TestSidecarNoResourceAnnotationPresent",
podObjectMeta: &metav1.ObjectMeta{
Annotations: map[string]string{},
},
expected: nil,
errorMessage: "Should return nil",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
whsvr := &WebhookServer{
server: nil,
namespaceClient: nil,
}

r, err := whsvr.getResourceRequirements(tc.podObjectMeta)
assert.Equal(t, tc.expected, r, tc.errorMessage)
assert.Nil(t, err, "Should succeed")
})
}
}

0 comments on commit 0ab34d1

Please sign in to comment.