github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/provider/gce/google/conn.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package google 5 6 import ( 7 "github.com/juju/errors" 8 "google.golang.org/api/compute/v1" 9 ) 10 11 // rawConnectionWrapper facilitates mocking out the GCE API during tests. 12 type rawConnectionWrapper interface { 13 // GetProject sends a request to the GCE API for info about the 14 // specified project. If the project does not exist then an error 15 // will be returned. 16 GetProject(projectID string) (*compute.Project, error) 17 // GetInstance sends a request to the GCE API for info about the 18 // specified instance. If the instance does not exist then an error 19 // will be returned. 20 GetInstance(projectID, id, zone string) (*compute.Instance, error) 21 // ListInstances sends a request to the GCE API for a list of all 22 // instances in project for which the name starts with the provided 23 // prefix. The result is also limited to those instances with one of 24 // the specified statuses (if any). 25 ListInstances(projectID, prefix string, status ...string) ([]*compute.Instance, error) 26 // AddInstance sends a request to GCE to add a new instance to the 27 // given project, with the provided instance data. The call blocks 28 // until the instance is created or the request fails. 29 AddInstance(projectID, zone string, spec *compute.Instance) error 30 // RemoveInstance sends a request to the GCE API to remove the instance 31 // with the provided ID (in the specified zone). The call blocks until 32 // the instance is removed (or the request fails). 33 RemoveInstance(projectID, id, zone string) error 34 // GetFirewall sends an API request to GCE for the information about 35 // the named firewall and returns it. If the firewall is not found, 36 // errors.NotFound is returned. 37 GetFirewall(projectID, name string) (*compute.Firewall, error) 38 // AddFirewall requests GCE to add a firewall with the provided info. 39 // If the firewall already exists then an error will be returned. 40 // The call blocks until the firewall is added or the request fails. 41 AddFirewall(projectID string, firewall *compute.Firewall) error 42 // UpdateFirewall requests GCE to update the named firewall with the 43 // provided info, overwriting the existing data. If the firewall does 44 // not exist then an error will be returned. The call blocks until the 45 // firewall is updated or the request fails. 46 UpdateFirewall(projectID, name string, firewall *compute.Firewall) error 47 // RemoveFirewall removed the named firewall from the project. If it 48 // does not exist then this is a noop. The call blocks until the 49 // firewall is added or the request fails. 50 RemoveFirewall(projectID, name string) error 51 // ListAvailabilityZones returns the list of availability zones for a given 52 // GCE region. If none are found the the list is empty. Any failure in 53 // the low-level request is returned as an error. 54 ListAvailabilityZones(projectID, region string) ([]*compute.Zone, error) 55 // CreateDisk will create a gce Persistent Block device that matches 56 // the specified in spec. 57 CreateDisk(project, zone string, spec *compute.Disk) error 58 // ListDisks returns a list of disks available for a given project. 59 ListDisks(project, zone string) ([]*compute.Disk, error) 60 // RemoveDisk will delete the disk identified by id. 61 RemoveDisk(project, zone, id string) error 62 // GetDisk will return the disk correspondent to the passed id. 63 GetDisk(project, zone, id string) (*compute.Disk, error) 64 // AttachDisk will attach the disk described in attachedDisks (if it exists) into 65 // the instance with id instanceId. 66 AttachDisk(project, zone, instanceId string, attachedDisk *compute.AttachedDisk) error 67 // Detach disk detaches device diskDeviceName (if it exists and its attached) 68 // form the machine with id instanceId. 69 DetachDisk(project, zone, instanceId, diskDeviceName string) error 70 // InstanceDisks returns the disks attached to the instance identified 71 // by instanceId 72 InstanceDisks(project, zone, instanceId string) ([]*compute.AttachedDisk, error) 73 } 74 75 // TODO(ericsnow) Add specific error types for common failures 76 // (e.g. BadRequest, RequestFailed, RequestError, ConnectionFailed)? 77 78 // Connection provides methods for interacting with the GCE API. The 79 // methods are limited to those needed by the juju GCE provider. 80 // 81 // Before calling any of the methods, the Connect method should be 82 // called to authenticate and open the raw connection to the GCE API. 83 // Otherwise a panic will result. 84 type Connection struct { 85 // TODO(ericsnow) name this something else? 86 raw rawConnectionWrapper 87 region string 88 projectID string 89 } 90 91 // Connect authenticates using the provided credentials and opens a 92 // low-level connection to the GCE API for the Connection. Calling 93 // Connect after a successful connection has already been made will 94 // result in an error. All errors that happen while authenticating and 95 // connecting are returned by Connect. 96 func Connect(connCfg ConnectionConfig, creds *Credentials) (*Connection, error) { 97 raw, err := newRawConnection(creds) 98 if err != nil { 99 return nil, errors.Trace(err) 100 } 101 102 conn := &Connection{ 103 raw: &rawConn{raw}, 104 region: connCfg.Region, 105 projectID: connCfg.ProjectID, 106 } 107 return conn, nil 108 } 109 110 var newRawConnection = func(creds *Credentials) (*compute.Service, error) { 111 return newConnection(creds) 112 } 113 114 // TODO(ericsnow) Verify in each method that Connection.raw is set? 115 116 // VerifyCredentials ensures that the authentication credentials used 117 // to connect are valid for use in the project and region defined for 118 // the Connection. If they are not then an error is returned. 119 func (gc Connection) VerifyCredentials() error { 120 if _, err := gc.raw.GetProject(gc.projectID); err != nil { 121 // TODO(ericsnow) Wrap err with something about bad credentials? 122 return errors.Trace(err) 123 } 124 return nil 125 } 126 127 // AvailabilityZones returns the list of availability zones for a given 128 // GCE region. If none are found the the list is empty. Any failure in 129 // the low-level request is returned as an error. 130 func (gc *Connection) AvailabilityZones(region string) ([]AvailabilityZone, error) { 131 rawZones, err := gc.raw.ListAvailabilityZones(gc.projectID, region) 132 if err != nil { 133 return nil, errors.Trace(err) 134 } 135 136 var zones []AvailabilityZone 137 for _, rawZone := range rawZones { 138 zones = append(zones, AvailabilityZone{rawZone}) 139 } 140 return zones, nil 141 }