github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/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  
    18  	// GetInstance sends a request to the GCE API for info about the
    19  	// specified instance. If the instance does not exist then an error
    20  	// will be returned.
    21  	GetInstance(projectID, id, zone string) (*compute.Instance, error)
    22  
    23  	// ListInstances sends a request to the GCE API for a list of all
    24  	// instances in project for which the name starts with the provided
    25  	// prefix. The result is also limited to those instances with one of
    26  	// the specified statuses (if any).
    27  	ListInstances(projectID, prefix string, status ...string) ([]*compute.Instance, error)
    28  
    29  	// AddInstance sends a request to GCE to add a new instance to the
    30  	// given project, with the provided instance data. The call blocks
    31  	// until the instance is created or the request fails.
    32  	AddInstance(projectID, zone string, spec *compute.Instance) error
    33  
    34  	// RemoveInstance sends a request to the GCE API to remove the instance
    35  	// with the provided ID (in the specified zone). The call blocks until
    36  	// the instance is removed (or the request fails).
    37  	RemoveInstance(projectID, id, zone string) error
    38  
    39  	// SetMetadata sends a request to the GCE API to update one
    40  	// instance's metadata. The call blocks until the request is
    41  	// completed or fails.
    42  	SetMetadata(projectID, zone, instanceID string, metadata *compute.Metadata) error
    43  
    44  	// GetFirewalls sends an API request to GCE for the information about
    45  	// the firewalls with the namePrefix and returns them.
    46  	// If no firewalls are not found, errors.NotFound is returned.
    47  	GetFirewalls(projectID, namePrefix string) ([]*compute.Firewall, error)
    48  
    49  	// AddFirewall requests GCE to add a firewall with the provided info.
    50  	// If the firewall already exists then an error will be returned.
    51  	// The call blocks until the firewall is added or the request fails.
    52  	AddFirewall(projectID string, firewall *compute.Firewall) error
    53  
    54  	// UpdateFirewall requests GCE to update the named firewall with the
    55  	// provided info, overwriting the existing data. If the firewall does
    56  	// not exist then an error will be returned. The call blocks until the
    57  	// firewall is updated or the request fails.
    58  	UpdateFirewall(projectID, name string, firewall *compute.Firewall) error
    59  
    60  	// RemoveFirewall removed the named firewall from the project. If it
    61  	// does not exist then this is a noop. The call blocks until the
    62  	// firewall is added or the request fails.
    63  	RemoveFirewall(projectID, name string) error
    64  
    65  	// ListAvailabilityZones returns the list of availability zones for a given
    66  	// GCE region. If none are found the the list is empty. Any failure in
    67  	// the low-level request is returned as an error.
    68  	ListAvailabilityZones(projectID, region string) ([]*compute.Zone, error)
    69  
    70  	// CreateDisk will create a gce Persistent Block device that matches
    71  	// the specified in spec.
    72  	CreateDisk(project, zone string, spec *compute.Disk) error
    73  
    74  	// ListDisks returns a list of disks available for a given project.
    75  	ListDisks(project string) ([]*compute.Disk, error)
    76  
    77  	// RemoveDisk will delete the disk identified by id.
    78  	RemoveDisk(project, zone, id string) error
    79  
    80  	// GetDisk will return the disk correspondent to the passed id.
    81  	GetDisk(project, zone, id string) (*compute.Disk, error)
    82  
    83  	// SetDiskLabels sets the labels on a disk, ensuring that the disk's
    84  	// label fingerprint matches the one supplied.
    85  	SetDiskLabels(project, zone, id, labelFingerprint string, labels map[string]string) error
    86  
    87  	// AttachDisk will attach the disk described in attachedDisks (if it exists) into
    88  	// the instance with id instanceId.
    89  	AttachDisk(project, zone, instanceId string, attachedDisk *compute.AttachedDisk) error
    90  
    91  	// Detach disk detaches device diskDeviceName (if it exists and its attached)
    92  	// form the machine with id instanceId.
    93  	DetachDisk(project, zone, instanceId, diskDeviceName string) error
    94  
    95  	// InstanceDisks returns the disks attached to the instance identified
    96  	// by instanceId
    97  	InstanceDisks(project, zone, instanceId string) ([]*compute.AttachedDisk, error)
    98  
    99  	// ListMachineTypes returns a list of machines available in the project and zone provided.
   100  	ListMachineTypes(projectID, zone string) (*compute.MachineTypeList, error)
   101  
   102  	// ListSubnetworks returns a list of subnets available in the given project and region.
   103  	ListSubnetworks(projectID, region string) ([]*compute.Subnetwork, error)
   104  
   105  	// ListNetworks returns a list of Networks available in the given project.
   106  	ListNetworks(projectID string) ([]*compute.Network, error)
   107  }
   108  
   109  // TODO(ericsnow) Add specific error types for common failures
   110  // (e.g. BadRequest, RequestFailed, RequestError, ConnectionFailed)?
   111  
   112  // Connection provides methods for interacting with the GCE API. The
   113  // methods are limited to those needed by the juju GCE provider.
   114  //
   115  // Before calling any of the methods, the Connect method should be
   116  // called to authenticate and open the raw connection to the GCE API.
   117  // Otherwise a panic will result.
   118  type Connection struct {
   119  	// TODO(ericsnow) name this something else?
   120  	raw       rawConnectionWrapper
   121  	region    string
   122  	projectID string
   123  }
   124  
   125  // Connect authenticates using the provided credentials and opens a
   126  // low-level connection to the GCE API for the Connection. Calling
   127  // Connect after a successful connection has already been made will
   128  // result in an error. All errors that happen while authenticating and
   129  // connecting are returned by Connect.
   130  func Connect(connCfg ConnectionConfig, creds *Credentials) (*Connection, error) {
   131  	raw, err := newRawConnection(creds)
   132  	if err != nil {
   133  		return nil, errors.Trace(err)
   134  	}
   135  
   136  	conn := &Connection{
   137  		raw:       &rawConn{raw},
   138  		region:    connCfg.Region,
   139  		projectID: connCfg.ProjectID,
   140  	}
   141  	return conn, nil
   142  }
   143  
   144  var newRawConnection = func(creds *Credentials) (*compute.Service, error) {
   145  	return newConnection(creds)
   146  }
   147  
   148  // TODO(ericsnow) Verify in each method that Connection.raw is set?
   149  
   150  // VerifyCredentials ensures that the authentication credentials used
   151  // to connect are valid for use in the project and region defined for
   152  // the Connection. If they are not then an error is returned.
   153  func (gc Connection) VerifyCredentials() error {
   154  	if _, err := gc.raw.GetProject(gc.projectID); err != nil {
   155  		// TODO(ericsnow) Wrap err with something about bad credentials?
   156  		return errors.Trace(err)
   157  	}
   158  	return nil
   159  }
   160  
   161  // AvailabilityZones returns the list of availability zones for a given
   162  // GCE region. If none are found the the list is empty. Any failure in
   163  // the low-level request is returned as an error.
   164  func (gc *Connection) AvailabilityZones(region string) ([]AvailabilityZone, error) {
   165  	rawZones, err := gc.raw.ListAvailabilityZones(gc.projectID, region)
   166  	if err != nil {
   167  		return nil, errors.Trace(err)
   168  	}
   169  
   170  	var zones []AvailabilityZone
   171  	for _, rawZone := range rawZones {
   172  		zones = append(zones, AvailabilityZone{rawZone})
   173  	}
   174  	return zones, nil
   175  }