gcloud 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,163 @@
1
+ #--
2
+ # Copyright 2015 Google Inc. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require "gcloud/dns/change/list"
17
+ require "time"
18
+
19
+ module Gcloud
20
+ module Dns
21
+ ##
22
+ # = DNS Change
23
+ #
24
+ # Represents a request containing additions or deletions or records.
25
+ # Additions and deletions can be done in bulk, in a single atomic
26
+ # transaction, and take effect at the same time in each authoritative DNS
27
+ # server.
28
+ #
29
+ # require "gcloud"
30
+ #
31
+ # gcloud = Gcloud.new
32
+ # dns = gcloud.dns
33
+ # zone = dns.zone "example-com"
34
+ # zone.changes.each do |change|
35
+ # puts "Change includes #{change.additions.count} additions " \
36
+ # "and #{change.additions.count} deletions."
37
+ # end
38
+ #
39
+ class Change
40
+ ##
41
+ # The Zone object this Change belongs to.
42
+ attr_accessor :zone #:nodoc:
43
+
44
+ ##
45
+ # The Google API Client object.
46
+ attr_accessor :gapi #:nodoc:
47
+
48
+ ##
49
+ # Create an empty Change object.
50
+ def initialize #:nodoc:
51
+ @zone = nil
52
+ @gapi = {}
53
+ end
54
+
55
+ ##
56
+ # Unique identifier for the resource; defined by the server.
57
+ #
58
+ def id
59
+ @gapi["id"]
60
+ end
61
+
62
+ ##
63
+ # The records added in this change request.
64
+ #
65
+ def additions
66
+ Array(@gapi["additions"]).map { |gapi| Record.from_gapi gapi }
67
+ end
68
+
69
+ ##
70
+ # The records removed in this change request.
71
+ #
72
+ def deletions
73
+ Array(@gapi["deletions"]).map { |gapi| Record.from_gapi gapi }
74
+ end
75
+
76
+ ##
77
+ # Status of the operation. Values are +"done"+ and +"pending"+.
78
+ #
79
+ def status
80
+ @gapi["status"]
81
+ end
82
+
83
+ ##
84
+ # Checks if the status is +"done"+.
85
+ def done?
86
+ return false if status.nil?
87
+ "done".casecmp(status).zero?
88
+ end
89
+
90
+ ##
91
+ # Checks if the status is +"pending"+.
92
+ def pending?
93
+ return false if status.nil?
94
+ "pending".casecmp(status).zero?
95
+ end
96
+
97
+ ##
98
+ # The time that this operation was started by the server.
99
+ #
100
+ def started_at
101
+ Time.parse @gapi["startTime"]
102
+ rescue
103
+ nil
104
+ end
105
+
106
+ ##
107
+ # Reloads the change with updated status from the DNS service.
108
+ def reload!
109
+ ensure_connection!
110
+ resp = zone.connection.get_change @zone.id, id
111
+ if resp.success?
112
+ @gapi = resp.data
113
+ else
114
+ fail ApiError.from_response(resp)
115
+ end
116
+ end
117
+ alias_method :refresh!, :reload!
118
+
119
+ ##
120
+ # Refreshes the change until the status is +done+.
121
+ # The delay between refreshes will incrementally increase.
122
+ #
123
+ # === Example
124
+ #
125
+ # require "gcloud"
126
+ #
127
+ # gcloud = Gcloud.new
128
+ # dns = gcloud.dns
129
+ # zone = dns.zone "example-com"
130
+ # change = zone.change 1234567890
131
+ # change.done? #=> false
132
+ # change.wait_until_done!
133
+ # change.done? #=> true
134
+ #
135
+ def wait_until_done!
136
+ backoff = ->(retries) { sleep 2 * retries + 5 }
137
+ retries = 0
138
+ until done?
139
+ backoff.call retries
140
+ retries += 1
141
+ reload!
142
+ end
143
+ end
144
+
145
+ ##
146
+ # New Change from a Google API Client object.
147
+ def self.from_gapi gapi, zone #:nodoc:
148
+ new.tap do |f|
149
+ f.gapi = gapi
150
+ f.zone = zone
151
+ end
152
+ end
153
+
154
+ protected
155
+
156
+ ##
157
+ # Raise an error unless an active connection is available.
158
+ def ensure_connection!
159
+ fail "Must have active connection" unless zone && zone.connection
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,70 @@
1
+ #--
2
+ # Copyright 2015 Google Inc. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ module Gcloud
17
+ module Dns
18
+ class Change
19
+ ##
20
+ # Change::List is a special case Array with additional values.
21
+ class List < DelegateClass(::Array)
22
+ ##
23
+ # If not empty, indicates that there are more records that match
24
+ # the request and this value should be passed to continue.
25
+ attr_accessor :token
26
+
27
+ ##
28
+ # Create a new Change::List with an array of Change instances.
29
+ def initialize arr = []
30
+ super arr
31
+ end
32
+
33
+ ##
34
+ # Whether there a next page of zones.
35
+ def next?
36
+ !token.nil?
37
+ end
38
+
39
+ ##
40
+ # Retrieve the next page of zones.
41
+ def next
42
+ return nil unless next?
43
+ ensure_zone!
44
+ @zone.changes token: token
45
+ end
46
+
47
+ ##
48
+ # New Changes::List from a response object.
49
+ def self.from_response resp, zone #:nodoc:
50
+ changes = new(Array(resp.data["changes"]).map do |gapi_object|
51
+ Change.from_gapi gapi_object, zone
52
+ end)
53
+ changes.instance_eval do
54
+ @token = resp.data["nextPageToken"]
55
+ @zone = zone
56
+ end
57
+ changes
58
+ end
59
+
60
+ protected
61
+
62
+ ##
63
+ # Raise an error unless an active connection is available.
64
+ def ensure_zone!
65
+ fail "Must have active connection" unless @zone
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,164 @@
1
+ #--
2
+ # Copyright 2015 Google Inc. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require "gcloud/version"
17
+ require "google/api_client"
18
+
19
+ module Gcloud
20
+ module Dns
21
+ ##
22
+ # Represents the connection to DNS,
23
+ # as well as expose the API calls.
24
+ class Connection #:nodoc:
25
+ API_VERSION = "v1"
26
+
27
+ attr_accessor :project
28
+ attr_accessor :credentials #:nodoc:
29
+
30
+ ##
31
+ # Creates a new Connection instance.
32
+ def initialize project, credentials #:nodoc:
33
+ @project = project
34
+ @credentials = credentials
35
+ @client = Google::APIClient.new application_name: "gcloud-ruby",
36
+ application_version: Gcloud::VERSION
37
+ @client.authorization = @credentials.client
38
+ @dns = @client.discovered_api "dns", API_VERSION
39
+ end
40
+
41
+ def get_project project_id = @project
42
+ @client.execute(
43
+ api_method: @dns.projects.get,
44
+ parameters: { project: project_id }
45
+ )
46
+ end
47
+
48
+ def get_zone zone_id
49
+ @client.execute(
50
+ api_method: @dns.managed_zones.get,
51
+ parameters: { project: @project, managedZone: zone_id }
52
+ )
53
+ end
54
+
55
+ def list_zones options = {}
56
+ params = { project: @project,
57
+ pageToken: options.delete(:token),
58
+ maxResults: options.delete(:max)
59
+ }.delete_if { |_, v| v.nil? }
60
+
61
+ @client.execute(
62
+ api_method: @dns.managed_zones.list,
63
+ parameters: params
64
+ )
65
+ end
66
+
67
+ def create_zone zone_name, zone_dns, options = {}
68
+ body = { kind: "dns#managedZone",
69
+ name: zone_name, dnsName: zone_dns,
70
+ description: (options[:description] || ""),
71
+ nameServerSet: options[:name_server_set]
72
+ }.delete_if { |_, v| v.nil? }
73
+
74
+ @client.execute(
75
+ api_method: @dns.managed_zones.create,
76
+ parameters: { project: @project },
77
+ body_object: body
78
+ )
79
+ end
80
+
81
+ def delete_zone zone_id
82
+ @client.execute(
83
+ api_method: @dns.managed_zones.delete,
84
+ parameters: { project: @project, managedZone: zone_id }
85
+ )
86
+ end
87
+
88
+ def get_change zone_id, change_id
89
+ @client.execute(
90
+ api_method: @dns.changes.get,
91
+ parameters: { project: @project, managedZone: zone_id,
92
+ changeId: change_id }
93
+ )
94
+ end
95
+
96
+ def list_changes zone_id, options = {}
97
+ params = { project: @project, managedZone: zone_id,
98
+ pageToken: options.delete(:token),
99
+ maxResults: options.delete(:max),
100
+ sortBy: options.delete(:sort),
101
+ sortOrder: options.delete(:order)
102
+ }.delete_if { |_, v| v.nil? }
103
+
104
+ @client.execute(
105
+ api_method: @dns.changes.list,
106
+ parameters: params
107
+ )
108
+ end
109
+
110
+ def create_change zone_id, additions, deletions
111
+ change = { "kind" => "dns#change",
112
+ "additions" => Array(additions),
113
+ "deletions" => Array(deletions) }
114
+
115
+ @client.execute(
116
+ api_method: @dns.changes.create,
117
+ parameters: { project: @project, managedZone: zone_id },
118
+ body_object: change
119
+ )
120
+ end
121
+
122
+ def list_records zone_id, options = {}
123
+ params = { project: @project, managedZone: zone_id,
124
+ pageToken: options.delete(:token),
125
+ maxResults: options.delete(:max),
126
+ name: options.delete(:name),
127
+ type: options.delete(:type)
128
+ }.delete_if { |_, v| v.nil? }
129
+
130
+ @client.execute(
131
+ api_method: @dns.resource_record_sets.list,
132
+ parameters: params
133
+ )
134
+ end
135
+
136
+ ##
137
+ # Fully Qualified Domain Name
138
+ def self.fqdn name, origin_dns #:nodoc:
139
+ name = name.to_s.strip
140
+ return name if self.ip_addr? name
141
+ name = origin_dns if name.empty?
142
+ name = origin_dns if name == "@"
143
+ name = "#{name}.#{origin_dns}" unless name.include? "."
144
+ name = "#{name}." unless name.end_with? "."
145
+ name
146
+ end
147
+
148
+ require "ipaddr"
149
+ # Fix to make ip_addr? work on ruby 1.9
150
+ IPAddr::Error = ArgumentError unless defined? IPAddr::Error #:nodoc:
151
+
152
+ def self.ip_addr? name #:nodoc:
153
+ IPAddr.new name
154
+ true
155
+ rescue IPAddr::Error
156
+ false
157
+ end
158
+
159
+ def inspect #:nodoc:
160
+ "#{self.class}(#{@project})"
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,29 @@
1
+ #--
2
+ # Copyright 2015 Google Inc. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require "gcloud/credentials"
17
+
18
+ module Gcloud
19
+ module Dns
20
+ ##
21
+ # Represents the Oauth2 signing logic for DNS.
22
+ class Credentials < Gcloud::Credentials #:nodoc:
23
+ SCOPE = ["https://www.googleapis.com/auth/ndev.clouddns.readwrite"]
24
+ PATH_ENV_VARS = %w(DNS_KEYFILE GCLOUD_KEYFILE GOOGLE_CLOUD_KEYFILE)
25
+ JSON_ENV_VARS = %w(DNS_KEYFILE_JSON GCLOUD_KEYFILE_JSON
26
+ GOOGLE_CLOUD_KEYFILE_JSON)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,64 @@
1
+ #--
2
+ # Copyright 2015 Google Inc. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require "gcloud/errors"
17
+
18
+ module Gcloud
19
+ module Dns
20
+ ##
21
+ # Base DNS exception class.
22
+ class Error < Gcloud::Error
23
+ end
24
+
25
+ ##
26
+ # Raised when an API call is not successful.
27
+ class ApiError < Error
28
+ ##
29
+ # The code of the error.
30
+ attr_reader :code
31
+
32
+ ##
33
+ # The errors encountered.
34
+ attr_reader :errors
35
+
36
+ def initialize message, code, errors = [] #:nodoc:
37
+ super message
38
+ @code = code
39
+ @errors = errors
40
+ end
41
+
42
+ def self.from_response resp #:nodoc:
43
+ if resp.data? && resp.data["error"]
44
+ from_response_data resp.data["error"]
45
+ else
46
+ from_response_status resp
47
+ end
48
+ end
49
+
50
+ def self.from_response_data error #:nodoc:
51
+ new error["message"], error["code"], error["errors"]
52
+ end
53
+
54
+ def self.from_response_status resp #:nodoc:
55
+ if resp.status == 404
56
+ new "#{resp.error_message}: #{resp.request.uri.request_uri}",
57
+ resp.status
58
+ else
59
+ new resp.error_message, resp.status
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end