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