gcloud 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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