2014-09-09 21:25:35 +00:00
|
|
|
/*
|
|
|
|
Copyright 2014 Google Inc. All rights reserved.
|
|
|
|
|
|
|
|
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_cloud
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"net"
|
|
|
|
"regexp"
|
|
|
|
|
|
|
|
"code.google.com/p/gcfg"
|
|
|
|
"github.com/mitchellh/goamz/aws"
|
|
|
|
"github.com/mitchellh/goamz/ec2"
|
|
|
|
|
2014-09-26 23:28:30 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
2014-09-09 21:25:35 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
|
|
|
|
)
|
|
|
|
|
|
|
|
type EC2 interface {
|
|
|
|
Instances(instIds []string, filter *ec2.Filter) (resp *ec2.InstancesResp, err error)
|
|
|
|
}
|
|
|
|
|
|
|
|
// AWSCloud is an implementation of Interface, TCPLoadBalancer and Instances for Amazon Web Services.
|
|
|
|
type AWSCloud struct {
|
|
|
|
ec2 EC2
|
|
|
|
cfg *AWSCloudConfig
|
|
|
|
}
|
|
|
|
|
|
|
|
type AWSCloudConfig struct {
|
|
|
|
Global struct {
|
|
|
|
Region string
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type AuthFunc func() (auth aws.Auth, err error)
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
cloudprovider.RegisterCloudProvider("aws", func(config io.Reader) (cloudprovider.Interface, error) {
|
|
|
|
return newAWSCloud(config, getAuth)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func getAuth() (auth aws.Auth, err error) {
|
|
|
|
return aws.GetAuth("", "")
|
|
|
|
}
|
|
|
|
|
|
|
|
// readAWSCloudConfig reads an instance of AWSCloudConfig from config reader.
|
|
|
|
func readAWSCloudConfig(config io.Reader) (*AWSCloudConfig, error) {
|
|
|
|
if config == nil {
|
2014-11-20 10:00:36 +00:00
|
|
|
return nil, fmt.Errorf("no AWS cloud provider config file given")
|
2014-09-09 21:25:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var cfg AWSCloudConfig
|
|
|
|
err := gcfg.ReadInto(&cfg, config)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if cfg.Global.Region == "" {
|
2014-11-20 10:00:36 +00:00
|
|
|
return nil, fmt.Errorf("no region specified in configuration file")
|
2014-09-09 21:25:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return &cfg, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// newAWSCloud creates a new instance of AWSCloud.
|
|
|
|
func newAWSCloud(config io.Reader, authFunc AuthFunc) (*AWSCloud, error) {
|
|
|
|
cfg, err := readAWSCloudConfig(config)
|
|
|
|
if err != nil {
|
2014-11-20 10:00:36 +00:00
|
|
|
return nil, fmt.Errorf("unable to read AWS cloud provider config file: %v", err)
|
2014-09-09 21:25:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
auth, err := authFunc()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
region, ok := aws.Regions[cfg.Global.Region]
|
|
|
|
if !ok {
|
2014-11-20 10:00:36 +00:00
|
|
|
return nil, fmt.Errorf("not a valid AWS region: %s", cfg.Global.Region)
|
2014-09-09 21:25:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ec2 := ec2.New(auth, region)
|
|
|
|
return &AWSCloud{
|
|
|
|
ec2: ec2,
|
|
|
|
cfg: cfg,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2014-11-13 20:35:03 +00:00
|
|
|
func (aws *AWSCloud) Clusters() (cloudprovider.Clusters, bool) {
|
|
|
|
return nil, false
|
|
|
|
}
|
|
|
|
|
2014-09-09 21:25:35 +00:00
|
|
|
// TCPLoadBalancer returns an implementation of TCPLoadBalancer for Amazon Web Services.
|
|
|
|
func (aws *AWSCloud) TCPLoadBalancer() (cloudprovider.TCPLoadBalancer, bool) {
|
|
|
|
return nil, false
|
|
|
|
}
|
|
|
|
|
|
|
|
// Instances returns an implementation of Instances for Amazon Web Services.
|
|
|
|
func (aws *AWSCloud) Instances() (cloudprovider.Instances, bool) {
|
|
|
|
return aws, true
|
|
|
|
}
|
|
|
|
|
|
|
|
// Zones returns an implementation of Zones for Amazon Web Services.
|
|
|
|
func (aws *AWSCloud) Zones() (cloudprovider.Zones, bool) {
|
|
|
|
return nil, false
|
|
|
|
}
|
|
|
|
|
|
|
|
// IPAddress is an implementation of Instances.IPAddress.
|
|
|
|
func (aws *AWSCloud) IPAddress(name string) (net.IP, error) {
|
|
|
|
f := ec2.NewFilter()
|
|
|
|
f.Add("private-dns-name", name)
|
|
|
|
|
|
|
|
resp, err := aws.ec2.Instances(nil, f)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if len(resp.Reservations) == 0 {
|
2014-11-20 10:00:36 +00:00
|
|
|
return nil, fmt.Errorf("no reservations found for host: %s", name)
|
2014-09-09 21:25:35 +00:00
|
|
|
}
|
|
|
|
if len(resp.Reservations) > 1 {
|
2014-11-20 10:00:36 +00:00
|
|
|
return nil, fmt.Errorf("multiple reservations found for host: %s", name)
|
2014-09-09 21:25:35 +00:00
|
|
|
}
|
|
|
|
if len(resp.Reservations[0].Instances) == 0 {
|
2014-11-20 10:00:36 +00:00
|
|
|
return nil, fmt.Errorf("no instances found for host: %s", name)
|
2014-09-09 21:25:35 +00:00
|
|
|
}
|
|
|
|
if len(resp.Reservations[0].Instances) > 1 {
|
2014-11-20 10:00:36 +00:00
|
|
|
return nil, fmt.Errorf("multiple instances found for host: %s", name)
|
2014-09-09 21:25:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ipAddress := resp.Reservations[0].Instances[0].PrivateIpAddress
|
|
|
|
ip := net.ParseIP(ipAddress)
|
|
|
|
if ip == nil {
|
2014-11-20 10:00:36 +00:00
|
|
|
return nil, fmt.Errorf("invalid network IP: %s", ipAddress)
|
2014-09-09 21:25:35 +00:00
|
|
|
}
|
|
|
|
return ip, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return a list of instances matching regex string.
|
|
|
|
func (aws *AWSCloud) getInstancesByRegex(regex string) ([]string, error) {
|
|
|
|
resp, err := aws.ec2.Instances(nil, nil)
|
|
|
|
if err != nil {
|
|
|
|
return []string{}, err
|
|
|
|
}
|
|
|
|
if resp == nil {
|
2014-11-20 10:00:36 +00:00
|
|
|
return []string{}, fmt.Errorf("no InstanceResp returned")
|
2014-09-09 21:25:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
re, err := regexp.Compile(regex)
|
|
|
|
if err != nil {
|
|
|
|
return []string{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
instances := []string{}
|
|
|
|
for _, reservation := range resp.Reservations {
|
|
|
|
for _, instance := range reservation.Instances {
|
|
|
|
for _, tag := range instance.Tags {
|
|
|
|
if tag.Key == "Name" && re.MatchString(tag.Value) {
|
|
|
|
instances = append(instances, instance.PrivateDNSName)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return instances, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// List is an implementation of Instances.List.
|
|
|
|
func (aws *AWSCloud) List(filter string) ([]string, error) {
|
|
|
|
// TODO: Should really use tag query. No need to go regexp.
|
|
|
|
return aws.getInstancesByRegex(filter)
|
|
|
|
}
|
2014-09-26 23:28:30 +00:00
|
|
|
|
|
|
|
func (v *AWSCloud) GetNodeResources(name string) (*api.NodeResources, error) {
|
|
|
|
return nil, nil
|
|
|
|
}
|