Initial commit
This commit is contained in:
29
cloud/google.go
Normal file
29
cloud/google.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package gcp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/api/compute/v1"
|
||||
)
|
||||
|
||||
// ComputeClient wraps the original *compute.Service
|
||||
type ComputeClient struct {
|
||||
*compute.Service
|
||||
Project string
|
||||
}
|
||||
|
||||
// NewComputeClient will initialize a GCP compute API client
|
||||
func NewComputeClient(project string) (*ComputeClient, error) {
|
||||
var err error
|
||||
ctx := context.Background()
|
||||
|
||||
s, err := compute.NewService(ctx)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Couldn't initialize GCP client (Compute): %v", err)
|
||||
return nil, err
|
||||
}
|
||||
computeService := &ComputeClient{s, project}
|
||||
|
||||
return computeService, nil
|
||||
}
|
||||
36
cloud/google_firewall.go
Normal file
36
cloud/google_firewall.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package gcp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func getAddress() string {
|
||||
var c = &http.Client{
|
||||
Timeout: time.Second * 5,
|
||||
}
|
||||
resp, err := c.Get("https://atto.run/ip")
|
||||
if err != nil {
|
||||
// handle error
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
return string(body)
|
||||
}
|
||||
|
||||
func (c *ComputeClient) getFirewallRules() error {
|
||||
a, err := c.Firewalls.Get(c.Project, "morning-mgmt-to-backend").Do()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b := getAddress()
|
||||
for _, r := range a.SourceRanges {
|
||||
if strings.HasPrefix(r, b) {
|
||||
fmt.Println(r)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
33
cloud/google_gce.go
Normal file
33
cloud/google_gce.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package gcp
|
||||
|
||||
import (
|
||||
"google.golang.org/api/compute/v1"
|
||||
)
|
||||
|
||||
// GetIPAddresses returns a list of external IP addresses used for the SHH connection
|
||||
func (c *ComputeClient) GetIPAddresses(instances []*compute.Instance) []string {
|
||||
addresses := []string{}
|
||||
for _, instance := range instances {
|
||||
addresses = append(addresses, instance.NetworkInterfaces[0].AccessConfigs[0].NatIP+":22")
|
||||
}
|
||||
return addresses
|
||||
}
|
||||
|
||||
// GetInstances returns a list of external IP addresses used for the SHH connection
|
||||
func (c *ComputeClient) GetInstances(filter string) ([]*compute.Instance, error) {
|
||||
listCall := c.Instances.AggregatedList(c.Project)
|
||||
listCall.Filter(filter)
|
||||
list, err := listCall.Do()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
instances := []*compute.Instance{}
|
||||
for _, item := range list.Items {
|
||||
for _, instance := range item.Instances {
|
||||
instances = append(instances, instance)
|
||||
}
|
||||
}
|
||||
|
||||
return instances, nil
|
||||
}
|
||||
296
cloud/google_metadata.go
Normal file
296
cloud/google_metadata.go
Normal file
@@ -0,0 +1,296 @@
|
||||
package gcp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/user"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/crypto/ssh"
|
||||
"google.golang.org/api/compute/v1"
|
||||
)
|
||||
|
||||
// AddKeyToMetadataP updates SSH key entires in the project metadata
|
||||
func (c *ComputeClient) AddKeyToMetadataP(pubKey ssh.PublicKey) error {
|
||||
getProject := c.Projects.Get(c.Project)
|
||||
projectData, err := getProject.Do()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authorizedKey, err := formatPubKey(pubKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
item, err := createMetadataItem(authorizedKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hasKey, same, i := hasItem(projectData.CommonInstanceMetadata, item)
|
||||
var items []*compute.MetadataItems
|
||||
|
||||
if hasKey && same {
|
||||
return nil
|
||||
} else if hasKey && !same {
|
||||
items = updateMetadata(projectData.CommonInstanceMetadata, item, i)
|
||||
} else if !hasKey {
|
||||
items = appendToMetadata(projectData.CommonInstanceMetadata, item)
|
||||
}
|
||||
|
||||
metadata := compute.Metadata{
|
||||
Fingerprint: projectData.CommonInstanceMetadata.Fingerprint,
|
||||
Items: items,
|
||||
}
|
||||
|
||||
setMetadata := c.Projects.SetCommonInstanceMetadata(c.Project, &metadata)
|
||||
_, err = setMetadata.Do()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddKeyToMetadata adds ssh public key to the intsance metadata
|
||||
func (c *ComputeClient) AddKeyToMetadata(instance *compute.Instance, pubKey ssh.PublicKey) error {
|
||||
authorizedKey, err := formatPubKey(pubKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
item, err := createMetadataItem(authorizedKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hasKey, same, i := hasItem(instance.Metadata, item)
|
||||
var items []*compute.MetadataItems
|
||||
|
||||
if hasKey && same {
|
||||
return nil
|
||||
} else if hasKey && !same {
|
||||
items = updateMetadata(instance.Metadata, item, i)
|
||||
} else if !hasKey {
|
||||
items = appendToMetadata(instance.Metadata, item)
|
||||
}
|
||||
|
||||
metadata := compute.Metadata{
|
||||
Fingerprint: instance.Metadata.Fingerprint,
|
||||
Items: items,
|
||||
}
|
||||
|
||||
instance.Metadata = &metadata
|
||||
s := strings.Split(instance.Zone, "/")
|
||||
zone := s[len(s)-1]
|
||||
call := c.Instances.Update(c.Project, zone, instance.Name, instance)
|
||||
_, err = call.Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s failed to update metadata: ", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveKeyFromMetadataP removes user's ssh public key from the project metadata
|
||||
func (c *ComputeClient) RemoveKeyFromMetadataP(pubKey ssh.PublicKey) error {
|
||||
getProject := c.Projects.Get(c.Project)
|
||||
projectData, err := getProject.Do()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authorizedKey, err := formatPubKey(pubKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
item, err := createMetadataItem(authorizedKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hasKey, same, i := hasItem(projectData.CommonInstanceMetadata, item)
|
||||
var items []*compute.MetadataItems
|
||||
|
||||
if hasKey && same {
|
||||
removeFromMetadata(projectData.CommonInstanceMetadata, item, i)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
||||
metadata := compute.Metadata{
|
||||
Fingerprint: projectData.CommonInstanceMetadata.Fingerprint,
|
||||
Items: items,
|
||||
}
|
||||
|
||||
setMetadata := c.Projects.SetCommonInstanceMetadata(c.Project, &metadata)
|
||||
_, err = setMetadata.Do()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveKeyFromMetadata removes user's ssh public key from the intsance metadata
|
||||
func (c *ComputeClient) RemoveKeyFromMetadata(instance *compute.Instance, pubKey ssh.PublicKey) error {
|
||||
authorizedKey, err := formatPubKey(pubKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
item, err := createMetadataItem(authorizedKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hasKey, same, i := hasItem(instance.Metadata, item)
|
||||
var items []*compute.MetadataItems
|
||||
|
||||
if hasKey && same {
|
||||
removeFromMetadata(instance.Metadata, item, i)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
||||
metadata := compute.Metadata{
|
||||
Fingerprint: instance.Metadata.Fingerprint,
|
||||
Items: items,
|
||||
}
|
||||
|
||||
instance.Metadata = &metadata
|
||||
s := strings.Split(instance.Zone, "/")
|
||||
zone := s[len(s)-1]
|
||||
call := c.Instances.Update(c.Project, zone, instance.Name, instance)
|
||||
_, err = call.Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s failed to update metadata: ", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isBlocking(i *compute.Instance) bool {
|
||||
for _, m := range i.Metadata.Items {
|
||||
if m.Key == "sshKeys" || m.Key == "block-project-ssh-keys" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func formatPubKey(pubKey ssh.PublicKey) (string, error) {
|
||||
authorizedKey := ssh.MarshalAuthorizedKey(pubKey)
|
||||
tk := strings.TrimSuffix(string(authorizedKey), "\n")
|
||||
return tk, nil
|
||||
}
|
||||
|
||||
// Extracts username, algorithm and comment from a metadata SSH key item
|
||||
func parseMetadataitem(key string) (string, string, string) {
|
||||
t := strings.Split(key, " ")
|
||||
head, comment := t[0], t[len(t)-1]
|
||||
username := strings.Split(head, ":")[0]
|
||||
algo := strings.Split(head, ":")[1]
|
||||
return username, algo, comment
|
||||
}
|
||||
|
||||
// Verifies if a metadata item already exists for a given user/cipher/comment combination.
|
||||
// If true it also returns the index number at which the existing item can be found otherwise index is -1.
|
||||
func hasItem(md *compute.Metadata, x string) (bool, bool, int) {
|
||||
flatMD := flattenMetadata(md)
|
||||
if flatMD["ssh-keys"] == nil {
|
||||
return false, false, -1
|
||||
}
|
||||
|
||||
items := strings.Split(flatMD["ssh-keys"].(string), "\n")
|
||||
username, algo, comment := parseMetadataitem(x)
|
||||
|
||||
for i, e := range items {
|
||||
header := fmt.Sprintf("%s:%s", username, algo)
|
||||
if x == e {
|
||||
return true, true, i
|
||||
} else if strings.HasPrefix(e, header) && strings.HasSuffix(e, comment) {
|
||||
return true, false, i
|
||||
}
|
||||
}
|
||||
return false, false, -1
|
||||
}
|
||||
|
||||
// createMetadataItem formats public key item according to GCP guidelines
|
||||
func createMetadataItem(pubKey string) (string, error) {
|
||||
user, err := user.Current()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
hostname, err := os.Hostname()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
v := fmt.Sprintf("%s:%s %s", user.Username, pubKey, hostname)
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func appendToMetadata(md *compute.Metadata, item string) []*compute.MetadataItems {
|
||||
var items []string
|
||||
flatMD := flattenMetadata(md)
|
||||
if flatMD["ssh-keys"] == nil {
|
||||
items = append(items, item)
|
||||
flatMD["ssh-keys"] = strings.Join(items, "\n")
|
||||
return expandComputeMetadata(flatMD)
|
||||
}
|
||||
|
||||
items = strings.Split(flatMD["ssh-keys"].(string), "\n")
|
||||
items = append(items, item)
|
||||
flatMD["ssh-keys"] = strings.Join(items, "\n")
|
||||
return expandComputeMetadata(flatMD)
|
||||
}
|
||||
|
||||
func removeFromMetadata(md *compute.Metadata, item string, i int) []*compute.MetadataItems {
|
||||
var items []string
|
||||
flatMD := flattenMetadata(md)
|
||||
items = strings.Split(flatMD["ssh-keys"].(string), "\n")
|
||||
copy(items[i:], items[i+1:])
|
||||
items[len(items)-1] = ""
|
||||
items = items[:len(items)-1]
|
||||
flatMD["ssh-keys"] = strings.Join(items, "\n")
|
||||
return expandComputeMetadata(flatMD)
|
||||
}
|
||||
|
||||
func updateMetadata(md *compute.Metadata, item string, i int) []*compute.MetadataItems {
|
||||
var items []string
|
||||
flatMD := flattenMetadata(md)
|
||||
items = strings.Split(flatMD["ssh-keys"].(string), "\n")
|
||||
items[i] = item
|
||||
flatMD["ssh-keys"] = strings.Join(items, "\n")
|
||||
return expandComputeMetadata(flatMD)
|
||||
}
|
||||
|
||||
func expandComputeMetadata(m map[string]interface{}) []*compute.MetadataItems {
|
||||
metadata := make([]*compute.MetadataItems, len(m))
|
||||
var keys []string
|
||||
for key := range m {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, key := range keys {
|
||||
v := m[key].(string)
|
||||
metadata = append(metadata, &compute.MetadataItems{
|
||||
Key: key,
|
||||
Value: &v,
|
||||
})
|
||||
}
|
||||
|
||||
return metadata
|
||||
}
|
||||
|
||||
func flattenMetadata(metadata *compute.Metadata) map[string]interface{} {
|
||||
metadataMap := make(map[string]interface{})
|
||||
for _, item := range metadata.Items {
|
||||
metadataMap[item.Key] = *item.Value
|
||||
}
|
||||
return metadataMap
|
||||
}
|
||||
Reference in New Issue
Block a user