github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/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 } 56 57 // TODO(ericsnow) Add specific error types for common failures 58 // (e.g. BadRequest, RequestFailed, RequestError, ConnectionFailed)? 59 60 // Connection provides methods for interacting with the GCE API. The 61 // methods are limited to those needed by the juju GCE provider. 62 // 63 // Before calling any of the methods, the Connect method should be 64 // called to authenticate and open the raw connection to the GCE API. 65 // Otherwise a panic will result. 66 type Connection struct { 67 // TODO(ericsnow) name this something else? 68 raw rawConnectionWrapper 69 region string 70 projectID string 71 } 72 73 // Connect authenticates using the provided credentials and opens a 74 // low-level connection to the GCE API for the Connection. Calling 75 // Connect after a successful connection has already been made will 76 // result in an error. All errors that happen while authenticating and 77 // connecting are returned by Connect. 78 func Connect(connCfg ConnectionConfig, creds *Credentials) (*Connection, error) { 79 raw, err := newRawConnection(creds) 80 if err != nil { 81 return nil, errors.Trace(err) 82 } 83 84 conn := &Connection{ 85 raw: &rawConn{raw}, 86 region: connCfg.Region, 87 projectID: connCfg.ProjectID, 88 } 89 return conn, nil 90 } 91 92 var newRawConnection = func(creds *Credentials) (*compute.Service, error) { 93 return newConnection(creds) 94 } 95 96 // TODO(ericsnow) Verify in each method that Connection.raw is set? 97 98 // VerifyCredentials ensures that the authentication credentials used 99 // to connect are valid for use in the project and region defined for 100 // the Connection. If they are not then an error is returned. 101 func (gc Connection) VerifyCredentials() error { 102 if _, err := gc.raw.GetProject(gc.projectID); err != nil { 103 // TODO(ericsnow) Wrap err with something about bad credentials? 104 return errors.Trace(err) 105 } 106 return nil 107 } 108 109 // AvailabilityZones returns the list of availability zones for a given 110 // GCE region. If none are found the the list is empty. Any failure in 111 // the low-level request is returned as an error. 112 func (gc *Connection) AvailabilityZones(region string) ([]AvailabilityZone, error) { 113 rawZones, err := gc.raw.ListAvailabilityZones(gc.projectID, region) 114 if err != nil { 115 return nil, errors.Trace(err) 116 } 117 118 var zones []AvailabilityZone 119 for _, rawZone := range rawZones { 120 zones = append(zones, AvailabilityZone{rawZone}) 121 } 122 return zones, nil 123 }