From 33a19f7ac16ed8963d7245d40062508c631202a1 Mon Sep 17 00:00:00 2001 From: Bill Maxwell Date: Fri, 3 Apr 2015 15:01:19 -0700 Subject: [PATCH] added google cloud config --- cmd/cloudinit/cloudinit.go | 9 +++ cmd/cloudinit/gcecloudinit.go | 140 ++++++++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+) create mode 100644 cmd/cloudinit/gcecloudinit.go diff --git a/cmd/cloudinit/cloudinit.go b/cmd/cloudinit/cloudinit.go index aa4378c8..2100a376 100644 --- a/cmd/cloudinit/cloudinit.go +++ b/cmd/cloudinit/cloudinit.go @@ -277,6 +277,15 @@ func getDatasources(cfg *rancherConfig.Config) []datasource.Datasource { } else { enableDoLinkLocal() } + case "gce": + if network { + gceCloudConfigFile, err := GetAndCreateGceDataSourceFilename() + if err != nil { + log.Errorf("Could not retrieve GCE CloudConfig %s", err) + continue + } + dss = append(dss, file.NewDatasource(gceCloudConfigFile)) + } } } diff --git a/cmd/cloudinit/gcecloudinit.go b/cmd/cloudinit/gcecloudinit.go new file mode 100644 index 00000000..e08bdd5a --- /dev/null +++ b/cmd/cloudinit/gcecloudinit.go @@ -0,0 +1,140 @@ +package cloudinit + +import ( + "io/ioutil" + "strings" + + log "github.com/Sirupsen/logrus" + "google.golang.org/cloud/compute/metadata" + "gopkg.in/yaml.v2" +) + +type GceCloudConfig struct { + FileName string + UserData string + NonUserDataSSHKeys []string +} + +const ( + gceCloudConfigFile = "/var/lib/rancher/conf/gce_cloudinit_config.yml" +) + +func NewGceCloudConfig() *GceCloudConfig { + + userData, err := metadata.InstanceAttributeValue("user-data") + if err != nil { + log.Errorf("Could not retrieve user-data: %s", err) + } + + projectSSHKeys, err := metadata.ProjectAttributeValue("sshKeys") + if err != nil { + log.Errorf("Could not retrieve project SSH Keys: %s", err) + } + + instanceSSHKeys, err := metadata.InstanceAttributeValue("sshKeys") + if err != nil { + log.Errorf("Could not retrieve instance SSH Keys: %s", err) + } + + nonUserDataSSHKeysRaw := projectSSHKeys + instanceSSHKeys + nonUserDataSSHKeys := gceSshKeyFormatter(nonUserDataSSHKeysRaw) + + gceCC := &GceCloudConfig{ + FileName: gceCloudConfigFile, + UserData: userData, + NonUserDataSSHKeys: nonUserDataSSHKeys, + } + + return gceCC +} + +func GetAndCreateGceDataSourceFilename() (string, error) { + gceCC := NewGceCloudConfig() + err := gceCC.saveToFile(gceCC.FileName) + if err != nil { + log.Errorf("Error: %s", err) + return "", err + } + return gceCC.FileName, nil +} + +func (cc *GceCloudConfig) saveToFile(filename string) error { + //Get Merged UserData sshkeys + data, err := cc.getMergedUserData() + if err != nil { + log.Errorf("Could not process userdata: %s", err) + return err + } + //write file + writeFile(filename, data) + return nil +} + +func (cc *GceCloudConfig) getMergedUserData() ([]byte, error) { + var returnUserData []byte + userdata := make(map[string]interface{}) + + if cc.UserData != "" { + log.Infof("Found UserData Config") + err := yaml.Unmarshal([]byte(cc.UserData), &userdata) + if err != nil { + log.Errorf("Could not unmarshal data: %s", err) + return nil, err + } + } + + var auth_keys []string + if _, exists := userdata["ssh_authorized_keys"]; exists { + udSshKeys := userdata["ssh_authorized_keys"].([]interface{}) + log.Infof("userdata %s", udSshKeys) + + for _, value := range udSshKeys { + auth_keys = append(auth_keys, value.(string)) + } + } + if cc.NonUserDataSSHKeys != nil { + for _, value := range cc.NonUserDataSSHKeys { + auth_keys = append(auth_keys, value) + } + } + userdata["ssh_authorized_keys"] = auth_keys + + yamlUserData, err := yaml.Marshal(&userdata) + if err != nil { + log.Errorf("Could not Marshal userdata: %s", err) + return nil, err + } else { + returnUserData = append([]byte("#cloud-config\n"), yamlUserData...) + } + + return returnUserData, nil +} + +func writeFile(filename string, data []byte) error { + if err := ioutil.WriteFile(filename, data, 400); err != nil { + log.Errorf("Could not write file %v", err) + return err + } + return nil +} + +func gceSshKeyFormatter(rawKeys string) []string { + keySlice := strings.Split(rawKeys, "\n") + var cloudFormatedKeys []string + + if len(keySlice) > 0 { + for i := range keySlice { + keyString := keySlice[i] + sIdx := strings.Index(keyString, ":") + if sIdx != -1 { + key := strings.TrimSpace(keyString[sIdx+1:]) + keyA := strings.Split(key, " ") + key = strings.Join(keyA, " ") + if key != "" { + cloudFormatedKeys = append(cloudFormatedKeys, key) + } + } + } + } + return cloudFormatedKeys +}