From 9d40b0e6ca4dcac1bc38be5127d549bd8d1ada04 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Mon, 10 Apr 2017 01:01:34 -0400 Subject: [PATCH] Support internal (gossip) names for AWS also --- hack/.packages | 1 + pkg/model/awsmodel/api_loadbalancer.go | 14 ++++ pkg/model/dns.go | 24 +++--- protokube/pkg/gossip/aws/seeds.go | 73 +++++++++++++++++++ protokube/pkg/protokube/aws_volume.go | 6 +- upup/pkg/fi/cloudup/awstasks/load_balancer.go | 20 +++++ 6 files changed, 128 insertions(+), 10 deletions(-) create mode 100644 protokube/pkg/gossip/aws/seeds.go diff --git a/hack/.packages b/hack/.packages index 15fb11cb13..2aec75856a 100644 --- a/hack/.packages +++ b/hack/.packages @@ -56,6 +56,7 @@ k8s.io/kops/pkg/util/stringorslice k8s.io/kops/pkg/validation k8s.io/kops/protokube/cmd/protokube k8s.io/kops/protokube/pkg/gossip +k8s.io/kops/protokube/pkg/gossip/aws k8s.io/kops/protokube/pkg/gossip/dns k8s.io/kops/protokube/pkg/gossip/dns/provider k8s.io/kops/protokube/pkg/gossip/gce diff --git a/pkg/model/awsmodel/api_loadbalancer.go b/pkg/model/awsmodel/api_loadbalancer.go index 40d0e0a3db..ca2a8a1932 100644 --- a/pkg/model/awsmodel/api_loadbalancer.go +++ b/pkg/model/awsmodel/api_loadbalancer.go @@ -24,8 +24,10 @@ import ( "github.com/golang/glog" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/kops/pkg/apis/kops" + "k8s.io/kops/pkg/dns" "k8s.io/kops/upup/pkg/fi" "k8s.io/kops/upup/pkg/fi/cloudup/awstasks" + "k8s.io/kops/upup/pkg/fi/fitasks" ) const LoadBalancerDefaultIdleTimeout = 5 * time.Minute @@ -185,6 +187,18 @@ func (b *APILoadBalancerBuilder) Build(c *fi.ModelBuilderContext) error { c.AddTask(t) } + if dns.IsGossipHostname(b.Cluster.Name) { + // Ensure the ELB hostname is included in the TLS certificate, + // if we're not going to use an alias for it + // TODO: I don't love this technique for finding the task by name & modifying it + masterKeypairTask, found := c.Tasks["Keypair/master"] + if !found { + return fmt.Errorf("keypair/master task not found") + } + masterKeypair := masterKeypairTask.(*fitasks.Keypair) + masterKeypair.AlternateNameTasks = append(masterKeypair.AlternateNameTasks, elb) + } + for _, ig := range b.MasterInstanceGroups() { t := &awstasks.LoadBalancerAttachment{ Name: s("api-" + ig.ObjectMeta.Name), diff --git a/pkg/model/dns.go b/pkg/model/dns.go index b86a5deadd..9525d9d541 100644 --- a/pkg/model/dns.go +++ b/pkg/model/dns.go @@ -33,6 +33,10 @@ type DNSModelBuilder struct { var _ fi.ModelBuilder = &DNSModelBuilder{} func (b *DNSModelBuilder) ensureDNSZone(c *fi.ModelBuilderContext) error { + if dns.IsGossipHostname(b.Cluster.Name) { + return nil + } + // Configuration for a DNS zone dnsZone := &awstasks.DNSZone{ Name: s(b.NameForDNSZone()), @@ -88,17 +92,19 @@ func (b *DNSModelBuilder) Build(c *fi.ModelBuilderContext) error { // This will point our DNS to the load balancer, and put the pieces // together for kubectl to be work - if err := b.ensureDNSZone(c); err != nil { - return err - } + if !dns.IsGossipHostname(b.Cluster.Name) { + if err := b.ensureDNSZone(c); err != nil { + return err + } - apiDnsName := &awstasks.DNSName{ - Name: s(b.Cluster.Spec.MasterPublicName), - Zone: b.LinkToDNSZone(), - ResourceType: s("A"), - TargetLoadBalancer: b.LinkToELB("api"), + apiDnsName := &awstasks.DNSName{ + Name: s(b.Cluster.Spec.MasterPublicName), + Zone: b.LinkToDNSZone(), + ResourceType: s("A"), + TargetLoadBalancer: b.LinkToELB("api"), + } + c.AddTask(apiDnsName) } - c.AddTask(apiDnsName) } if b.UsesBastionDns() { diff --git a/protokube/pkg/gossip/aws/seeds.go b/protokube/pkg/gossip/aws/seeds.go new file mode 100644 index 0000000000..dee0d73eef --- /dev/null +++ b/protokube/pkg/gossip/aws/seeds.go @@ -0,0 +1,73 @@ +/* +Copyright 2017 The Kubernetes Authors. + +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 aws + +import ( + "fmt" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/service/ec2/ec2iface" + "k8s.io/kops/protokube/pkg/gossip" +) + +type SeedProvider struct { + ec2 ec2iface.EC2API + tags map[string]string +} + +var _ gossip.SeedProvider = &SeedProvider{} + +func (p *SeedProvider) GetSeeds() ([]string, error) { + request := &ec2.DescribeInstancesInput{} + for k, v := range p.tags { + filter := &ec2.Filter{ + Name: aws.String("tag:" + k), + Values: aws.StringSlice([]string{v}), + } + request.Filters = append(request.Filters, filter) + } + request.Filters = append(request.Filters, &ec2.Filter{ + Name: aws.String("instance-state-name"), + Values: aws.StringSlice([]string{"running", "pending"}), + }) + + var seeds []string + err := p.ec2.DescribeInstancesPages(request, func(p *ec2.DescribeInstancesOutput, lastPage bool) (shouldContinue bool) { + for _, r := range p.Reservations { + for _, i := range r.Instances { + ip := aws.StringValue(i.PrivateIpAddress) + if ip != "" { + seeds = append(seeds, ip) + } + } + } + return true + }) + + if err != nil { + return nil, fmt.Errorf("error querying for EC2 instances: %v", err) + } + + return seeds, nil +} + +func NewSeedProvider(ec2 ec2iface.EC2API, tags map[string]string) (*SeedProvider, error) { + return &SeedProvider{ + ec2: ec2, + tags: tags, + }, nil +} diff --git a/protokube/pkg/protokube/aws_volume.go b/protokube/pkg/protokube/aws_volume.go index 110b5aeb49..3d30a76e69 100644 --- a/protokube/pkg/protokube/aws_volume.go +++ b/protokube/pkg/protokube/aws_volume.go @@ -25,6 +25,7 @@ import ( "github.com/aws/aws-sdk-go/service/ec2" "github.com/golang/glog" "k8s.io/kops/protokube/pkg/gossip" + gossipaws "k8s.io/kops/protokube/pkg/gossip/aws" "k8s.io/kops/upup/pkg/fi/cloudup/awsup" "net" "strings" @@ -364,7 +365,10 @@ func (a *AWSVolumes) AttachVolume(volume *Volume) error { } func (a *AWSVolumes) GossipSeeds() (gossip.SeedProvider, error) { - return nil, fmt.Errorf("AWS seed provider not yet implemented") + tags := make(map[string]string) + tags[awsup.TagClusterName] = a.clusterTag + + return gossipaws.NewSeedProvider(a.ec2, tags) } func (a *AWSVolumes) InstanceID() string { diff --git a/upup/pkg/fi/cloudup/awstasks/load_balancer.go b/upup/pkg/fi/cloudup/awstasks/load_balancer.go index 87c159cb29..12dd49e0d4 100644 --- a/upup/pkg/fi/cloudup/awstasks/load_balancer.go +++ b/upup/pkg/fi/cloudup/awstasks/load_balancer.go @@ -388,6 +388,26 @@ func (e *LoadBalancer) Find(c *fi.Context) (*LoadBalancer, error) { return actual, nil } +var _ fi.HasAddress = &LoadBalancer{} + +func (e *LoadBalancer) FindIPAddress(context *fi.Context) (*string, error) { + cloud := context.Cloud.(awsup.AWSCloud) + + lb, err := FindLoadBalancerByNameTag(cloud, fi.StringValue(e.Name)) + if err != nil { + return nil, err + } + if lb == nil { + return nil, nil + } + + lbDnsName := fi.StringValue(lb.DNSName) + if lbDnsName == "" { + return nil, nil + } + return &lbDnsName, nil +} + func (e *LoadBalancer) Run(c *fi.Context) error { // TODO: Make Normalize a standard method e.Normalize()