diff --git a/cmd/cloudinitsave/cloudinitsave.go b/cmd/cloudinitsave/cloudinitsave.go index c43bda14..bc57a30b 100755 --- a/cmd/cloudinitsave/cloudinitsave.go +++ b/cmd/cloudinitsave/cloudinitsave.go @@ -26,7 +26,6 @@ import ( yaml "github.com/cloudfoundry-incubator/candiedyaml" "github.com/docker/docker/pkg/mount" - "github.com/rancher/os/cmd/cloudinitsave/gce" "github.com/rancher/os/cmd/control" "github.com/rancher/os/cmd/network" rancherConfig "github.com/rancher/os/config" @@ -36,6 +35,7 @@ import ( "github.com/rancher/os/config/cloudinit/datasource/file" "github.com/rancher/os/config/cloudinit/datasource/metadata/digitalocean" "github.com/rancher/os/config/cloudinit/datasource/metadata/ec2" + "github.com/rancher/os/config/cloudinit/datasource/metadata/gce" "github.com/rancher/os/config/cloudinit/datasource/metadata/packet" "github.com/rancher/os/config/cloudinit/datasource/proccmdline" "github.com/rancher/os/config/cloudinit/datasource/url" diff --git a/cmd/cloudinitsave/gce/metadata.go b/cmd/cloudinitsave/gce/metadata.go deleted file mode 100755 index 80a43fea..00000000 --- a/cmd/cloudinitsave/gce/metadata.go +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2016 CoreOS, Inc. -// -// 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 gce - -import ( - "fmt" - "net" - "net/http" - "strconv" - "strings" - - "github.com/rancher/os/config/cloudinit/datasource" - "github.com/rancher/os/config/cloudinit/datasource/metadata" -) - -const ( - apiVersion = "computeMetadata/v1/" - metadataPath = apiVersion - userdataPath = apiVersion + "instance/attributes/user-data" -) - -type MetadataService struct { - metadata.Service -} - -func NewDatasource(root string) *MetadataService { - return &MetadataService{metadata.NewDatasource(root, apiVersion, userdataPath, metadataPath, http.Header{"Metadata-Flavor": {"Google"}})} -} - -func (ms MetadataService) FetchMetadata() (datasource.Metadata, error) { - public, err := ms.fetchIP("instance/network-interfaces/0/access-configs/0/external-ip") - if err != nil { - return datasource.Metadata{}, err - } - local, err := ms.fetchIP("instance/network-interfaces/0/ip") - if err != nil { - return datasource.Metadata{}, err - } - hostname, err := ms.fetchString("instance/hostname") - if err != nil { - return datasource.Metadata{}, err - } - - projectSSHKeys, err := ms.fetchString("project/attributes/sshKeys") - if err != nil { - return datasource.Metadata{}, err - } - instanceSSHKeys, err := ms.fetchString("instance/attributes/sshKeys") - if err != nil { - return datasource.Metadata{}, err - } - - keyStrings := strings.Split(projectSSHKeys+"\n"+instanceSSHKeys, "\n") - - sshPublicKeys := map[string]string{} - i := 0 - for _, keyString := range keyStrings { - keySlice := strings.SplitN(keyString, ":", 2) - if len(keySlice) == 2 { - key := strings.TrimSpace(keySlice[1]) - if key != "" { - sshPublicKeys[strconv.Itoa(i)] = strings.TrimSpace(keySlice[1]) - i++ - } - } - } - - return datasource.Metadata{ - PublicIPv4: public, - PrivateIPv4: local, - Hostname: hostname, - SSHPublicKeys: sshPublicKeys, - }, nil -} - -func (ms MetadataService) Type() string { - return "gce-metadata-service" -} - -func (ms MetadataService) fetchString(key string) (string, error) { - data, err := ms.FetchData(ms.MetadataURL() + key) - if err != nil { - return "", err - } - - return string(data), nil -} - -func (ms MetadataService) fetchIP(key string) (net.IP, error) { - str, err := ms.fetchString(key) - if err != nil { - return nil, err - } - - if str == "" { - return nil, nil - } - - if ip := net.ParseIP(str); ip != nil { - return ip, nil - } - return nil, fmt.Errorf("couldn't parse %q as IP address", str) -} - -func (ms MetadataService) FetchUserdata() ([]byte, error) { - data, err := ms.FetchData(ms.MetadataURL()) - if err != nil { - return nil, err - } - if len(data) == 0 { - data, err = ms.FetchData(ms.MetadataURL() + "instance/attributes/startup-script") - if err != nil { - return nil, err - } - } - return data, nil -} diff --git a/config/cloudinit/datasource/metadata/gce/metadata.go b/config/cloudinit/datasource/metadata/gce/metadata.go old mode 100644 new mode 100755 index 39b2b835..35e3ce9f --- a/config/cloudinit/datasource/metadata/gce/metadata.go +++ b/config/cloudinit/datasource/metadata/gce/metadata.go @@ -18,6 +18,8 @@ import ( "fmt" "net" "net/http" + "strconv" + "strings" "github.com/rancher/os/config/cloudinit/datasource" "github.com/rancher/os/config/cloudinit/datasource/metadata" @@ -25,7 +27,7 @@ import ( const ( apiVersion = "computeMetadata/v1/" - metadataPath = apiVersion + "instance/" + metadataPath = apiVersion userdataPath = apiVersion + "instance/attributes/user-data" ) @@ -38,24 +40,52 @@ func NewDatasource(root string) *MetadataService { } func (ms MetadataService) FetchMetadata() (datasource.Metadata, error) { - public, err := ms.fetchIP("network-interfaces/0/access-configs/0/external-ip") + public, err := ms.fetchIP("instance/network-interfaces/0/access-configs/0/external-ip") if err != nil { return datasource.Metadata{}, err } - local, err := ms.fetchIP("network-interfaces/0/ip") + local, err := ms.fetchIP("instance/network-interfaces/0/ip") if err != nil { return datasource.Metadata{}, err } - hostname, err := ms.fetchString("hostname") + hostname, err := ms.fetchString("instance/hostname") if err != nil { return datasource.Metadata{}, err } - return datasource.Metadata{ - PublicIPv4: public, - PrivateIPv4: local, - Hostname: hostname, - }, nil + projectSSHKeys, err := ms.fetchString("project/attributes/sshKeys") + if err != nil { + return datasource.Metadata{}, err + } + instanceSSHKeys, err := ms.fetchString("instance/attributes/sshKeys") + if err != nil { + return datasource.Metadata{}, err + } + md := datasource.Metadata{ + PublicIPv4: public, + PrivateIPv4: local, + Hostname: hostname, + SSHPublicKeys: nil, + } + + keyStrings := strings.Split(projectSSHKeys+"\n"+instanceSSHKeys, "\n") + + i := 0 + for _, keyString := range keyStrings { + keySlice := strings.SplitN(keyString, ":", 2) + if len(keySlice) == 2 { + key := strings.TrimSpace(keySlice[1]) + if key != "" { + if md.SSHPublicKeys == nil { + md.SSHPublicKeys = map[string]string{} + } + md.SSHPublicKeys[strconv.Itoa(i)] = strings.TrimSpace(keySlice[1]) + i++ + } + } + } + + return md, nil } func (ms MetadataService) Type() string { @@ -86,3 +116,17 @@ func (ms MetadataService) fetchIP(key string) (net.IP, error) { } return nil, fmt.Errorf("couldn't parse %q as IP address", str) } + +func (ms MetadataService) FetchUserdata() ([]byte, error) { + data, err := ms.FetchData(ms.MetadataURL()) + if err != nil { + return nil, err + } + if len(data) == 0 { + data, err = ms.FetchData(ms.MetadataURL() + "instance/attributes/startup-script") + if err != nil { + return nil, err + } + } + return data, nil +} diff --git a/config/cloudinit/datasource/metadata/gce/metadata_test.go b/config/cloudinit/datasource/metadata/gce/metadata_test.go old mode 100644 new mode 100755 index fcd00f2f..4e88ec40 --- a/config/cloudinit/datasource/metadata/gce/metadata_test.go +++ b/config/cloudinit/datasource/metadata/gce/metadata_test.go @@ -35,6 +35,7 @@ func TestType(t *testing.T) { func TestFetchMetadata(t *testing.T) { for _, tt := range []struct { + testName string root string metadataPath string resources map[string]string @@ -43,13 +44,15 @@ func TestFetchMetadata(t *testing.T) { expectErr error }{ { + testName: "one", root: "/", - metadataPath: "computeMetadata/v1/instance/", + metadataPath: "computeMetadata/v1/", resources: map[string]string{}, }, { + testName: "two", root: "/", - metadataPath: "computeMetadata/v1/instance/", + metadataPath: "computeMetadata/v1/", resources: map[string]string{ "/computeMetadata/v1/instance/hostname": "host", }, @@ -58,8 +61,9 @@ func TestFetchMetadata(t *testing.T) { }, }, { + testName: "three", root: "/", - metadataPath: "computeMetadata/v1/instance/", + metadataPath: "computeMetadata/v1/", resources: map[string]string{ "/computeMetadata/v1/instance/hostname": "host", "/computeMetadata/v1/instance/network-interfaces/0/ip": "1.2.3.4", @@ -72,6 +76,7 @@ func TestFetchMetadata(t *testing.T) { }, }, { + testName: "four", clientErr: pkg.ErrTimeout{Err: fmt.Errorf("test error")}, expectErr: pkg.ErrTimeout{Err: fmt.Errorf("test error")}, }, @@ -83,10 +88,10 @@ func TestFetchMetadata(t *testing.T) { }} metadata, err := service.FetchMetadata() if Error(err) != Error(tt.expectErr) { - t.Fatalf("bad error (%q): want %q, got %q", tt.resources, tt.expectErr, err) + t.Fatalf("bad error (%q): want \n%q\n, got \n%q\n", tt.resources, tt.expectErr, err) } if !reflect.DeepEqual(tt.expect, metadata) { - t.Fatalf("bad fetch (%q): want %#v, got %#v", tt.resources, tt.expect, metadata) + t.Fatalf("bad fetch %s(%q): want \n%#v\n, got \n%#v\n", tt.testName, tt.resources, tt.expect, metadata) } } }