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 }