Merge pull request #45932 from lpabon/elbtag_pr

Automatic merge from submit-queue (batch tested with PRs 45518, 46127, 46146, 45932, 45003)

aws: Support for ELB tagging by users

This PR provides support for tagging AWS ELBs using information in an
annotation and provided as a list of comma separated key-value pairs.

Closes https://github.com/kubernetes/community/pull/404
This commit is contained in:
Kubernetes Submit Queue 2017-05-25 11:46:06 -07:00 committed by GitHub
commit 29b3bb44ba
3 changed files with 109 additions and 4 deletions

View File

@ -131,6 +131,12 @@ const ServiceAnnotationLoadBalancerSSLPorts = "service.beta.kubernetes.io/aws-lo
// a HTTP listener is used.
const ServiceAnnotationLoadBalancerBEProtocol = "service.beta.kubernetes.io/aws-load-balancer-backend-protocol"
// ServiceAnnotationLoadBalancerAdditionalTags is the annotation used on the service
// to specify a comma-separated list of key-value pairs which will be recorded as
// additional tags in the ELB.
// For example: "Key1=Val1,Key2=Val2,KeyNoVal1=,KeyNoVal2"
const ServiceAnnotationLoadBalancerAdditionalTags = "service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags"
const (
// volumeAttachmentConsecutiveErrorLimit is the number of consecutive errors we will ignore when waiting for a volume to attach/detach
volumeAttachmentStatusConsecutiveErrorLimit = 10
@ -2792,6 +2798,7 @@ func (c *Cloud) EnsureLoadBalancer(clusterName string, apiService *v1.Service, n
internalELB,
proxyProtocol,
loadBalancerAttributes,
annotations,
)
if err != nil {
return nil, err

View File

@ -20,6 +20,7 @@ import (
"fmt"
"reflect"
"strconv"
"strings"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
@ -31,7 +32,36 @@ import (
const ProxyProtocolPolicyName = "k8s-proxyprotocol-enabled"
func (c *Cloud) ensureLoadBalancer(namespacedName types.NamespacedName, loadBalancerName string, listeners []*elb.Listener, subnetIDs []string, securityGroupIDs []string, internalELB, proxyProtocol bool, loadBalancerAttributes *elb.LoadBalancerAttributes) (*elb.LoadBalancerDescription, error) {
// getLoadBalancerAdditionalTags converts the comma separated list of key-value
// pairs in the ServiceAnnotationLoadBalancerAdditionalTags annotation and returns
// it as a map.
func getLoadBalancerAdditionalTags(annotations map[string]string) map[string]string {
additionalTags := make(map[string]string)
if additionalTagsList, ok := annotations[ServiceAnnotationLoadBalancerAdditionalTags]; ok {
additionalTagsList = strings.TrimSpace(additionalTagsList)
// Break up list of "Key1=Val,Key2=Val2"
tagList := strings.Split(additionalTagsList, ",")
// Break up "Key=Val"
for _, tagSet := range tagList {
tag := strings.Split(strings.TrimSpace(tagSet), "=")
// Accept "Key=val" or "Key=" or just "Key"
if len(tag) >= 2 && len(tag[0]) != 0 {
// There is a key and a value, so save it
additionalTags[tag[0]] = tag[1]
} else if len(tag) == 1 && len(tag[0]) != 0 {
// Just "Key"
additionalTags[tag[0]] = ""
}
}
}
return additionalTags
}
func (c *Cloud) ensureLoadBalancer(namespacedName types.NamespacedName, loadBalancerName string, listeners []*elb.Listener, subnetIDs []string, securityGroupIDs []string, internalELB, proxyProtocol bool, loadBalancerAttributes *elb.LoadBalancerAttributes, annotations map[string]string) (*elb.LoadBalancerDescription, error) {
loadBalancer, err := c.describeLoadBalancer(loadBalancerName)
if err != nil {
return nil, err
@ -55,9 +85,12 @@ func (c *Cloud) ensureLoadBalancer(namespacedName types.NamespacedName, loadBala
createRequest.SecurityGroups = stringPointerArray(securityGroupIDs)
tags := c.tagging.buildTags(ResourceLifecycleOwned, map[string]string{
TagNameKubernetesService: namespacedName.String(),
})
// Get additional tags set by the user
tags := getLoadBalancerAdditionalTags(annotations)
// Add default tags
tags[TagNameKubernetesService] = namespacedName.String()
tags = c.tagging.buildTags(ResourceLifecycleOwned, tags)
for k, v := range tags {
createRequest.Tags = append(createRequest.Tags, &elb.Tag{

View File

@ -1284,3 +1284,68 @@ func TestProxyProtocolEnabled(t *testing.T) {
result = proxyProtocolEnabled(fakeBackend)
assert.False(t, result, "did not expect to find %s in %s", ProxyProtocolPolicyName, policies)
}
func TestGetLoadBalancerAdditionalTags(t *testing.T) {
tagTests := []struct {
Annotations map[string]string
Tags map[string]string
}{
{
Annotations: map[string]string{
ServiceAnnotationLoadBalancerAdditionalTags: "Key=Val",
},
Tags: map[string]string{
"Key": "Val",
},
},
{
Annotations: map[string]string{
ServiceAnnotationLoadBalancerAdditionalTags: "Key1=Val1, Key2=Val2",
},
Tags: map[string]string{
"Key1": "Val1",
"Key2": "Val2",
},
},
{
Annotations: map[string]string{
ServiceAnnotationLoadBalancerAdditionalTags: "Key1=, Key2=Val2",
"anotherKey": "anotherValue",
},
Tags: map[string]string{
"Key1": "",
"Key2": "Val2",
},
},
{
Annotations: map[string]string{
"Nothing": "Key1=, Key2=Val2, Key3",
},
Tags: map[string]string{},
},
{
Annotations: map[string]string{
ServiceAnnotationLoadBalancerAdditionalTags: "K=V K1=V2,Key1========, =====, ======Val, =Val, , 234,",
},
Tags: map[string]string{
"K": "V K1",
"Key1": "",
"234": "",
},
},
}
for _, tagTest := range tagTests {
result := getLoadBalancerAdditionalTags(tagTest.Annotations)
for k, v := range result {
if len(result) != len(tagTest.Tags) {
t.Errorf("incorrect expected length: %v != %v", result, tagTest.Tags)
continue
}
if tagTest.Tags[k] != v {
t.Errorf("%s != %s", tagTest.Tags[k], v)
continue
}
}
}
}