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  }