fog-google 0.2.0 → 0.3.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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/README.md +7 -3
  4. data/examples/pubsub/subscriptions.rb +54 -0
  5. data/examples/pubsub/topics.rb +33 -0
  6. data/fog-google.gemspec +2 -2
  7. data/lib/fog/compute/google.rb +4 -884
  8. data/lib/fog/compute/google/mock.rb +871 -0
  9. data/lib/fog/compute/google/real.rb +22 -0
  10. data/lib/fog/dns/google.rb +3 -42
  11. data/lib/fog/dns/google/mock.rb +33 -0
  12. data/lib/fog/dns/google/real.rb +19 -0
  13. data/lib/fog/google.rb +14 -208
  14. data/lib/fog/google/mock.rb +14 -0
  15. data/lib/fog/google/models/pubsub/received_message.rb +40 -0
  16. data/lib/fog/google/models/pubsub/subscription.rb +86 -0
  17. data/lib/fog/google/models/pubsub/subscriptions.rb +32 -0
  18. data/lib/fog/google/models/pubsub/topic.rb +72 -0
  19. data/lib/fog/google/models/pubsub/topics.rb +31 -0
  20. data/lib/fog/google/monitoring.rb +3 -45
  21. data/lib/fog/google/monitoring/mock.rb +35 -0
  22. data/lib/fog/google/monitoring/real.rb +20 -0
  23. data/lib/fog/google/pubsub.rb +59 -0
  24. data/lib/fog/google/pubsub/mock.rb +34 -0
  25. data/lib/fog/google/pubsub/real.rb +20 -0
  26. data/lib/fog/google/requests/pubsub/acknowledge_subscription.rb +46 -0
  27. data/lib/fog/google/requests/pubsub/create_subscription.rb +57 -0
  28. data/lib/fog/google/requests/pubsub/create_topic.rb +36 -0
  29. data/lib/fog/google/requests/pubsub/delete_subscription.rb +28 -0
  30. data/lib/fog/google/requests/pubsub/delete_topic.rb +29 -0
  31. data/lib/fog/google/requests/pubsub/get_subscription.rb +44 -0
  32. data/lib/fog/google/requests/pubsub/get_topic.rb +41 -0
  33. data/lib/fog/google/requests/pubsub/list_subscriptions.rb +39 -0
  34. data/lib/fog/google/requests/pubsub/list_topics.rb +33 -0
  35. data/lib/fog/google/requests/pubsub/publish_topic.rb +61 -0
  36. data/lib/fog/google/requests/pubsub/pull_subscription.rb +77 -0
  37. data/lib/fog/google/shared.rb +191 -0
  38. data/lib/fog/google/sql.rb +3 -50
  39. data/lib/fog/google/sql/mock.rb +40 -0
  40. data/lib/fog/google/sql/real.rb +20 -0
  41. data/lib/fog/google/version.rb +1 -1
  42. data/lib/fog/storage/google_json.rb +4 -99
  43. data/lib/fog/storage/google_json/mock.rb +18 -0
  44. data/lib/fog/storage/google_json/real.rb +64 -0
  45. data/lib/fog/storage/google_json/utils.rb +32 -0
  46. data/lib/fog/storage/google_xml.rb +4 -260
  47. data/lib/fog/storage/google_xml/mock.rb +102 -0
  48. data/lib/fog/storage/google_xml/models/file.rb +14 -4
  49. data/lib/fog/storage/google_xml/real.rb +106 -0
  50. data/lib/fog/storage/google_xml/utils.rb +66 -0
  51. data/tests/models/pubsub/received_message_tests.rb +18 -0
  52. data/tests/models/pubsub/subscription_tests.rb +26 -0
  53. data/tests/models/pubsub/subscriptions_tests.rb +33 -0
  54. data/tests/models/pubsub/topic_tests.rb +18 -0
  55. data/tests/models/pubsub/topics_tests.rb +27 -0
  56. metadata +50 -14
@@ -0,0 +1,22 @@
1
+ module Fog
2
+ module Compute
3
+ class Google
4
+ class Real
5
+ include Fog::Google::Shared
6
+
7
+ attr_accessor :client
8
+ attr_reader :compute, :extra_global_projects
9
+
10
+ def initialize(options)
11
+ shared_initialize(options[:google_project], GOOGLE_COMPUTE_API_VERSION, GOOGLE_COMPUTE_BASE_URL)
12
+ options[:google_api_scope_url] = GOOGLE_COMPUTE_API_SCOPE_URLS.join(" ")
13
+
14
+ @client = initialize_google_client(options)
15
+ @compute = @client.discovered_api("compute", api_version)
16
+ @resourceviews = @client.discovered_api("resourceviews", "v1beta1")
17
+ @extra_global_projects = options[:google_extra_global_projects] || []
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,6 +1,9 @@
1
1
  module Fog
2
2
  module DNS
3
3
  class Google < Fog::Service
4
+ autoload :Mock, File.expand_path("../google/mock", __FILE__)
5
+ autoload :Real, File.expand_path("../google/real", __FILE__)
6
+
4
7
  requires :google_project
5
8
  recognizes :app_name, :app_version, :google_client_email, :google_key_location, :google_key_string,
6
9
  :google_client, :google_json_key_location, :google_json_key_string
@@ -49,48 +52,6 @@ module Fog
49
52
 
50
53
  # Project
51
54
  request :get_project
52
-
53
- class Mock
54
- include Fog::Google::Shared
55
-
56
- def initialize(options)
57
- shared_initialize(options[:google_project], GOOGLE_DNS_API_VERSION, GOOGLE_DNS_BASE_URL)
58
- end
59
-
60
- def self.data(_api_version)
61
- @data ||= {}
62
- end
63
-
64
- def self.reset
65
- @data = nil
66
- end
67
-
68
- def data(project = @project)
69
- self.class.data(api_version)[project] ||= {
70
- :managed_zones => {},
71
- :resource_record_sets => {},
72
- :changes => {}
73
- }
74
- end
75
-
76
- def reset_data
77
- self.class.data(api_version).delete(@project)
78
- end
79
- end
80
-
81
- class Real
82
- include Fog::Google::Shared
83
-
84
- attr_accessor :client
85
- attr_reader :dns
86
-
87
- def initialize(options)
88
- shared_initialize(options[:google_project], GOOGLE_DNS_API_VERSION, GOOGLE_DNS_BASE_URL)
89
- options.merge!(:google_api_scope_url => GOOGLE_DNS_API_SCOPE_URLS.join(" "))
90
- @client = initialize_google_client(options)
91
- @dns = @client.discovered_api("dns", api_version)
92
- end
93
- end
94
55
  end
95
56
  end
96
57
  end
@@ -0,0 +1,33 @@
1
+ module Fog
2
+ module DNS
3
+ class Google
4
+ class Mock
5
+ include Fog::Google::Shared
6
+
7
+ def initialize(options)
8
+ shared_initialize(options[:google_project], GOOGLE_DNS_API_VERSION, GOOGLE_DNS_BASE_URL)
9
+ end
10
+
11
+ def self.data(_api_version)
12
+ @data ||= {}
13
+ end
14
+
15
+ def self.reset
16
+ @data = nil
17
+ end
18
+
19
+ def data(project = @project)
20
+ self.class.data(api_version)[project] ||= {
21
+ :managed_zones => {},
22
+ :resource_record_sets => {},
23
+ :changes => {}
24
+ }
25
+ end
26
+
27
+ def reset_data
28
+ self.class.data(api_version).delete(@project)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,19 @@
1
+ module Fog
2
+ module DNS
3
+ class Google
4
+ class Real
5
+ include Fog::Google::Shared
6
+
7
+ attr_accessor :client
8
+ attr_reader :dns
9
+
10
+ def initialize(options)
11
+ shared_initialize(options[:google_project], GOOGLE_DNS_API_VERSION, GOOGLE_DNS_BASE_URL)
12
+ options[:google_api_scope_url] = GOOGLE_DNS_API_SCOPE_URLS.join(" ")
13
+ @client = initialize_google_client(options)
14
+ @dns = @client.discovered_api("dns", api_version)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
data/lib/fog/google.rb CHANGED
@@ -4,15 +4,27 @@ require "fog/xml"
4
4
  require "fog/google/version"
5
5
 
6
6
  module Fog
7
+ module Compute
8
+ autoload :Google, File.expand_path("../compute/google", __FILE__)
9
+ end
10
+
11
+ module DNS
12
+ autoload :Google, File.expand_path("../dns/google", __FILE__)
13
+ end
14
+
7
15
  module Google
8
- autoload :Monitoring, "fog/google/monitoring"
9
- autoload :SQL, "fog/google/sql"
16
+ autoload :Mock, File.expand_path("../google/mock", __FILE__)
17
+ autoload :Monitoring, File.expand_path("../google/monitoring", __FILE__)
18
+ autoload :Pubsub, File.expand_path("../google/pubsub", __FILE__)
19
+ autoload :Shared, File.expand_path("../google/shared", __FILE__)
20
+ autoload :SQL, File.expand_path("../google/sql", __FILE__)
10
21
 
11
22
  extend Fog::Provider
12
23
 
13
24
  service(:compute, "Compute")
14
25
  service(:dns, "DNS")
15
26
  service(:monitoring, "Monitoring")
27
+ service(:pubsub, "Pubsub")
16
28
  service(:storage, "Storage")
17
29
  service(:sql, "SQL")
18
30
 
@@ -25,212 +37,6 @@ module Fog
25
37
  "%" + Regexp.last_match(1).unpack("H2" * Regexp.last_match(1).bytesize).join("%").upcase
26
38
  end
27
39
  end
28
-
29
- class Mock
30
- def self.etag
31
- hex(32)
32
- end
33
-
34
- def self.hex(length)
35
- max = ("f" * length).to_i(16)
36
- rand(max).to_s(16)
37
- end
38
- end
39
-
40
- module Shared
41
- attr_reader :project, :api_version, :api_url
42
-
43
- ##
44
- # Initializes shared attributes
45
- #
46
- # @param [String] project Google Cloud Project
47
- # @param [String] api_version Google API version
48
- # @param [String] base_url Google API base url
49
- # @return [void]
50
- def shared_initialize(project, api_version, base_url)
51
- @project = project
52
- @api_version = api_version
53
- @api_url = base_url + api_version + "/projects/"
54
- end
55
-
56
- ##
57
- # Initializes the Google API Client
58
- #
59
- # @param [Hash] options Google API options
60
- # @option options [String] :google_client_email A @developer.gserviceaccount.com email address to use
61
- # @option options [String] :google_key_location The location of a pkcs12 key file
62
- # @option options [String] :google_key_string The content of the pkcs12 key file
63
- # @option options [String] :google_json_key_location The location of a JSON key file
64
- # @option options [String] :google_json_key_string The content of the JSON key file
65
- # @option options [String] :google_api_scope_url The access scope URLs
66
- # @option options [String] :app_name The app name to set in the user agent
67
- # @option options [String] :app_version The app version to set in the user agent
68
- # @option options [Google::APIClient] :google_client Existing Google API Client
69
- # @return [Google::APIClient] Google API Client
70
- # @raises [ArgumentError] If there is any missing argument
71
- def initialize_google_client(options)
72
- # NOTE: loaded here to avoid requiring this as a core Fog dependency
73
- begin
74
- require "google/api_client"
75
- rescue LoadError => error
76
- Fog::Logger.warning("Please install the google-api-client gem before using this provider")
77
- raise error
78
- end
79
-
80
- # User can provide an existing Google API Client
81
- client = options[:google_client]
82
- return client unless client.nil?
83
-
84
- # Create a signing key
85
- signing_key = create_signing_key(options)
86
-
87
- # Validate required arguments
88
- unless options[:google_client_email]
89
- raise ArgumentError.new("Missing required arguments: google_client_email")
90
- end
91
-
92
- unless options[:google_api_scope_url]
93
- raise ArgumentError.new("Missing required arguments: google_api_scope_url")
94
- end
95
-
96
- # Create a new Google API Client
97
- new_pk12_google_client(
98
- options[:google_client_email],
99
- signing_key,
100
- options[:google_api_scope_url],
101
- options[:app_name],
102
- options[:app_version]
103
- )
104
- end
105
-
106
- ##
107
- # Creates a Google signing key
108
- #
109
- def create_signing_key(options)
110
- if options[:google_json_key_location] || options[:google_json_key_string]
111
- if options[:google_json_key_location]
112
- json_key_location = File.expand_path(options[:google_json_key_location])
113
- json_key = File.open(json_key_location, "r", &:read)
114
- else
115
- json_key = options[:google_json_key_string]
116
- end
117
-
118
- json_key_hash = Fog::JSON.decode(json_key)
119
- unless json_key_hash.key?("client_email") || json_key_hash.key?("private_key")
120
- raise ArgumentError.new("Invalid Google JSON key")
121
- end
122
-
123
- options[:google_client_email] = json_key_hash["client_email"]
124
- ::Google::APIClient::KeyUtils.load_from_pem(json_key_hash["private_key"], "notasecret")
125
- elsif options[:google_key_location] || options[:google_key_string]
126
- if options[:google_key_location]
127
- google_key = File.expand_path(options[:google_key_location])
128
- else
129
- google_key = options[:google_key_string]
130
- end
131
-
132
- ::Google::APIClient::KeyUtils.load_from_pkcs12(google_key, "notasecret")
133
- else
134
- raise ArgumentError.new("Missing required arguments: google_key_location, google_key_string, " \
135
- "google_json_key_location or google_json_key_string")
136
- end
137
- end
138
-
139
- ##
140
- # Create a Google API Client with a user email and a pkcs12 key
141
- #
142
- # @param [String] google_client_email A @developer.gserviceaccount.com email address to use
143
- # @param [OpenSSL::PKey] signing_key The private key for signing
144
- # @param [String] google_api_scope_url Access scope URLs
145
- # @param [String] app_name The app name to set in the user agent
146
- # @param [String] app_version The app version to set in the user agent
147
- # @return [Google::APIClient] Google API Client
148
- def new_pk12_google_client(google_client_email, signing_key, google_api_scope_url, app_name = nil, app_version = nil)
149
- application_name = app_name.nil? ? "fog" : "#{app_name}/#{app_version || '0.0.0'} fog"
150
- api_client_options = {
151
- :application_name => application_name,
152
- :application_version => Fog::Google::VERSION
153
- }
154
- client = ::Google::APIClient.new(api_client_options)
155
-
156
- client.authorization = Signet::OAuth2::Client.new(
157
- :audience => "https://accounts.google.com/o/oauth2/token",
158
- :auth_provider_x509_cert_url => "https://www.googleapis.com/oauth2/v1/certs",
159
- :client_x509_cert_url => "https://www.googleapis.com/robot/v1/metadata/x509/#{google_client_email}",
160
- :issuer => google_client_email,
161
- :scope => google_api_scope_url,
162
- :signing_key => signing_key,
163
- :token_credential_uri => "https://accounts.google.com/o/oauth2/token"
164
- )
165
- client.authorization.fetch_access_token!
166
-
167
- client
168
- end
169
-
170
- ##
171
- # Executes a request and wraps it in a result object
172
- #
173
- # @param [Google::APIClient::Method] api_method The method object or the RPC name of the method being executed
174
- # @param [Hash] parameters The parameters to send to the method
175
- # @param [Hash] body_object The body object of the request
176
- # @return [Excon::Response] The result from the API
177
- def request(api_method, parameters, body_object = nil, media = nil)
178
- client_parms = {
179
- :api_method => api_method,
180
- :parameters => parameters
181
- }
182
- # The Google API complains when given null values for enums, so just don't pass it any null fields
183
- # XXX It may still balk if we have a nested object, e.g.:
184
- # {:a_field => "string", :a_nested_field => { :an_empty_nested_field => nil } }
185
- client_parms[:body_object] = body_object.reject { |_k, v| v.nil? } if body_object
186
- client_parms[:media] = media if media
187
-
188
- result = @client.execute(client_parms)
189
-
190
- build_excon_response(result.body.nil? || result.body.empty? ? nil : Fog::JSON.decode(result.body), result.status)
191
- end
192
-
193
- ##
194
- # Builds an Excon response
195
- #
196
- # @param [Hash] Response body
197
- # @param [Integer] Response status
198
- # @return [Excon::Response] Excon response
199
- def build_excon_response(body, status = 200)
200
- response = Excon::Response.new(:body => body, :status => status)
201
- if body && body.key?("error")
202
- msg = "Google Cloud did not return an error message"
203
-
204
- if body["error"].is_a?(Hash)
205
- response.status = body["error"]["code"]
206
- if body["error"].key?("errors")
207
- msg = body["error"]["errors"].map { |error| error["message"] }.join(", ")
208
- elsif body["error"].key?("message")
209
- msg = body["error"]["message"]
210
- end
211
- elsif body["error"].is_a?(Array)
212
- msg = body["error"].map { |error| error["code"] }.join(", ")
213
- end
214
-
215
- case response.status
216
- when 404
217
- raise Fog::Errors::NotFound.new(msg)
218
- else
219
- raise Fog::Errors::Error.new(msg)
220
- end
221
- end
222
-
223
- response
224
- end
225
- end
226
- end
227
-
228
- module Compute
229
- autoload :Google, File.expand_path("../compute/google", __FILE__)
230
- end
231
-
232
- module DNS
233
- autoload :Google, File.expand_path("../dns/google", __FILE__)
234
40
  end
235
41
 
236
42
  module Parsers
@@ -0,0 +1,14 @@
1
+ module Fog
2
+ module Google
3
+ class Mock
4
+ def self.etag
5
+ hex(32)
6
+ end
7
+
8
+ def self.hex(length)
9
+ max = ("f" * length).to_i(16)
10
+ rand(max).to_s(16)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,40 @@
1
+ require "fog/core/model"
2
+
3
+ module Fog
4
+ module Google
5
+ class Pubsub
6
+ # Represents a ReceivedMessage retrieved from a Google Pubsub
7
+ # subscription. Note that ReceivedMessages are immutable.
8
+ #
9
+ # @see https://cloud.google.com/pubsub/reference/rest/v1/projects.subscriptions/pull#ReceivedMessage
10
+ class ReceivedMessage < Fog::Model
11
+ identity :ack_id, :aliases => "ackId"
12
+
13
+ attribute :message
14
+
15
+ def initialize(new_attributes = {})
16
+ # Here we secretly store the subscription name we were received on
17
+ # in order to support #acknowledge
18
+ attributes = new_attributes.clone
19
+ @subscription_name = attributes.delete(:subscription_name)
20
+ super(attributes)
21
+ end
22
+
23
+ # Acknowledges a message.
24
+ #
25
+ # @see https://cloud.google.com/pubsub/reference/rest/v1/projects.subscriptions/acknowledge
26
+ def acknowledge
27
+ requires :ack_id
28
+
29
+ service.acknowledge_subscription(@subscription_name, [ack_id])
30
+ nil
31
+ end
32
+
33
+ def reload
34
+ # Message is immutable - do nothing
35
+ Fog::Logger.warning("#reload called on immutable ReceivedMessage")
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,86 @@
1
+ module Fog
2
+ module Google
3
+ class Pubsub
4
+ # Represents a Pubsub subscription resource
5
+ #
6
+ # @see https://cloud.google.com/pubsub/reference/rest/v1/projects.subscriptions
7
+ class Subscription < Fog::Model
8
+ identity :name
9
+ attribute :topic
10
+ attribute :push_config, :aliases => "pushConfig"
11
+ attribute :ack_deadline_seconds, :aliases => "ackDeadlineSeconds"
12
+
13
+ # Pulls from this subscription, returning any available messages. By
14
+ # default, this method returns immediately with up to 10 messages. The
15
+ # option 'return_immediately' allows the method to block until a
16
+ # message is received, or the remote service closes the connection.
17
+ #
18
+ # Note that this method automatically performs a base64 decode on the
19
+ # 'data' field.
20
+ #
21
+ # @param options [Hash] options to modify the pull request
22
+ # @option options [Boolean] :return_immediately If true, method returns
23
+ # after checking for messages. Otherwise the method blocks until one
24
+ # or more messages are available, or the connection is closed.
25
+ # @option options [Number] :max_messages maximum number of messages to
26
+ # receive
27
+ # @return [Array<Fog::Google::Pubsub::ReceivedMessage>] list of
28
+ # received messages, or an empty list if no messages are available.
29
+ # @see https://cloud.google.com/pubsub/reference/rest/v1/projects.subscriptions/pull
30
+ def pull(options = { :return_immediately => true, :max_messages => 10 })
31
+ requires :name
32
+
33
+ data = service.pull_subscription(name, options).body
34
+
35
+ return [] unless data.key?("receivedMessages")
36
+ # Turn into a list of ReceivedMessage, but ensure we perform a base64 decode first
37
+ data["receivedMessages"].map do |recv_message|
38
+ attrs = {
39
+ :service => service,
40
+ :subscription_name => name
41
+ }.merge(recv_message)
42
+
43
+ attrs["message"]["data"] = Base64.decode64(recv_message["message"]["data"]) if recv_message["message"].key?("data")
44
+ ReceivedMessage.new(attrs)
45
+ end
46
+ end
47
+
48
+ # Acknowledges a list of received messages for this subscription.
49
+ #
50
+ # @param messages [Array<Fog::Google::Pubsub::ReceivedMessage, #to_s>]
51
+ # A list containing either ReceivedMessage instances to acknowledge,
52
+ # or a list of ackIds (@see
53
+ # https://cloud.google.com/pubsub/reference/rest/v1/projects.subscriptions/pull#ReceivedMessage).
54
+ # @see https://cloud.google.com/pubsub/reference/rest/v1/projects.subscriptions/acknowledge
55
+ def acknowledge(messages)
56
+ return if messages.empty?
57
+
58
+ ack_ids = messages.map { |m| m.is_a?(ReceivedMessage) ? m.ack_id : m.to_s }
59
+
60
+ service.acknowledge_subscription(name, ack_ids)
61
+ nil
62
+ end
63
+
64
+ # Save this instance on the remove service.
65
+ #
66
+ # @return [Fog::Google::Pubsub::Subscription] this instance
67
+ # @see https://cloud.google.com/pubsub/reference/rest/v1/projects.subscriptions/create
68
+ def save
69
+ requires :name, :topic
70
+
71
+ data = service.create_subscription(name, topic, push_config, ack_deadline_seconds).body
72
+ merge_attributes(data)
73
+ end
74
+
75
+ # Deletes this subscription on the remote service.
76
+ #
77
+ # @see https://cloud.google.com/pubsub/reference/rest/v1/projects.subscriptions/delete
78
+ def destroy
79
+ requires :name
80
+
81
+ service.delete_subscription(name)
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end