From 60d099176c1842f1a54cda2e49bcd2ee65676e20 Mon Sep 17 00:00:00 2001 From: Ken Cochrane Date: Thu, 1 Jun 2017 16:37:48 -0400 Subject: [PATCH] Added AWS provider to metadata package Signed-off-by: Ken Cochrane --- pkg/metadata/main.go | 2 +- pkg/metadata/provider_aws.go | 105 +++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 pkg/metadata/provider_aws.go diff --git a/pkg/metadata/main.go b/pkg/metadata/main.go index 97aba9967..61b7ee603 100644 --- a/pkg/metadata/main.go +++ b/pkg/metadata/main.go @@ -47,7 +47,7 @@ var netProviders []Provider var cdromProviders []Provider func init() { - netProviders = []Provider{NewGCP()} + netProviders = []Provider{NewGCP(), NewAWS()} cdromProviders = []Provider{NewCDROM()} } diff --git a/pkg/metadata/provider_aws.go b/pkg/metadata/provider_aws.go new file mode 100644 index 000000000..b3c8ff49f --- /dev/null +++ b/pkg/metadata/provider_aws.go @@ -0,0 +1,105 @@ +package main + +import ( + "fmt" + "io/ioutil" + "log" + "net/http" + "os" + "path" + "time" +) + +const ( + userDataURL = "http://169.254.169.254/latest/user-data" + metaDataURL = "http://169.254.169.254/latest/meta-data/" +) + +// ProviderAWS is the type implementing the Provider interface for AWS +type ProviderAWS struct { +} + +// NewAWS returns a new ProviderAWS +func NewAWS() *ProviderAWS { + return &ProviderAWS{} +} + +func (p *ProviderAWS) String() string { + return "AWS" +} + +// Probe checks if we are running on AWS +func (p *ProviderAWS) Probe() bool { + // Getting the hostname should always work... + _, err := awsGet(metaDataURL + "hostname") + return (err == nil) +} + +// Extract gets both the AWS specific and generic userdata +func (p *ProviderAWS) Extract() ([]byte, error) { + // Get host name. This must not fail + hostname, err := awsGet(metaDataURL + "hostname") + if err != nil { + return nil, err + } + err = ioutil.WriteFile(path.Join(ConfigPath, Hostname), hostname, 0644) + if err != nil { + return nil, fmt.Errorf("AWS: Failed to write hostname: %s", err) + } + + if err := p.handleSSH(); err != nil { + log.Printf("AWS: Failed to get ssh data: %s", err) + } + + // Generic userdata + userData, err := awsGet(userDataURL) + if err != nil { + log.Printf("AWS: Failed to get user-data: %s", err) + // This is not an error + return nil, nil + } + return userData, nil +} + +// awsGet requests and extracts the requested URL +func awsGet(url string) ([]byte, error) { + var client = &http.Client{ + Timeout: time.Second * 2, + } + + req, err := http.NewRequest("", url, nil) + if err != nil { + return nil, fmt.Errorf("AWS: http.NewRequest failed: %s", err) + } + + resp, err := client.Do(req) + if err != nil { + return nil, fmt.Errorf("AWS: Could not contact metadata service: %s", err) + } + if resp.StatusCode != 200 { + return nil, fmt.Errorf("AWS: Status not ok: %d", resp.StatusCode) + } + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("AWS: Failed to read http response: %s", err) + } + return body, nil +} + +// SSH keys: +func (p *ProviderAWS) handleSSH() error { + sshKeys, err := awsGet(metaDataURL + "public-keys/0/openssh-key") + if err != nil { + return fmt.Errorf("Failed to get sshKeys: %s", err) + } + + if err := os.Mkdir(path.Join(ConfigPath, SSH), 0755); err != nil { + return fmt.Errorf("Failed to create %s: %s", SSH, err) + } + + err = ioutil.WriteFile(path.Join(ConfigPath, SSH, "authorized_keys"), sshKeys, 0600) + if err != nil { + return fmt.Errorf("Failed to write ssh keys: %s", err) + } + return nil +}