google-cloud-core 0.20.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/google/cloud.rb +75 -0
- data/lib/google/cloud/core/backoff.rb +89 -0
- data/lib/google/cloud/core/gce.rb +60 -0
- data/lib/google/cloud/core/grpc_backoff.rb +89 -0
- data/lib/google/cloud/core/grpc_utils.rb +91 -0
- data/lib/google/cloud/core/version.rb +22 -0
- data/lib/google/cloud/credentials.rb +132 -0
- data/lib/google/cloud/errors.rb +208 -0
- metadata +166 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 29d08e42cbb895f42a47e1eedcd28c7b15dd77fa
|
4
|
+
data.tar.gz: f5808aba10c3cf10fd76786e774b878f7ee9925f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9e6c3fcc7b93a69cf29254ccef9c5c7b404743cdbc6e05ea1d08ace3a2c79c884c97e9d536e9e99d5259ca441d5e2d72c1df2af1af7df8557ea6cda3ca96b2c2
|
7
|
+
data.tar.gz: ef9af1e66e014e1f92922e6c869798a27294cb11f0b7d2402780603a80a3a1a327ad883c4ec9f4ab63ced13af05740cf105f466c75eb6b5e7ca395e1c4ebc6cf
|
data/lib/google/cloud.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
# Copyright 2015 Google Inc. All rights reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
|
16
|
+
require "google/cloud/core/version"
|
17
|
+
|
18
|
+
##
|
19
|
+
# # Google Cloud
|
20
|
+
#
|
21
|
+
# The google-cloud library is the official library for interacting with Google
|
22
|
+
# Cloud Platform. Google Cloud Platform is a set of modular cloud-based services
|
23
|
+
# that allow you to create anything from simple websites to complex
|
24
|
+
# applications.
|
25
|
+
#
|
26
|
+
# The goal of google-cloud is to provide a API that is familiar and comfortable
|
27
|
+
# to Rubyists. Authentication is handled by providing project and credential
|
28
|
+
# information, or if you are running on Google Compute Engine this configuration
|
29
|
+
# is taken care of for you.
|
30
|
+
#
|
31
|
+
# You can learn more about various options for connection on the [Authentication
|
32
|
+
# Guide](https://googlecloudplatform.github.io/google-cloud-ruby/#/docs/guides/authentication).
|
33
|
+
#
|
34
|
+
module Google
|
35
|
+
module Cloud
|
36
|
+
##
|
37
|
+
# Creates a new object for connecting to Google Cloud.
|
38
|
+
#
|
39
|
+
# For more information on connecting to Google Cloud see the [Authentication
|
40
|
+
# Guide](https://googlecloudplatform.github.io/google-cloud-ruby/#/docs/guides/authentication).
|
41
|
+
#
|
42
|
+
# @param [String] project Project identifier for the Pub/Sub service you are
|
43
|
+
# connecting to.
|
44
|
+
# @param [String, Hash] keyfile Keyfile downloaded from Google Cloud. If
|
45
|
+
# file path the file must be readable.
|
46
|
+
# @param [Integer] retries Number of times to retry requests on server
|
47
|
+
# error. The default value is `3`. Optional.
|
48
|
+
# @param [Integer] timeout Default timeout to use in requests. Optional.
|
49
|
+
#
|
50
|
+
# @return [Google::Cloud]
|
51
|
+
#
|
52
|
+
# @example
|
53
|
+
# require "google/cloud"
|
54
|
+
#
|
55
|
+
# gcloud = Google::Cloud.new
|
56
|
+
# datastore = gcloud.datastore
|
57
|
+
# pubsub = gcloud.pubsub
|
58
|
+
# storage = gcloud.storage
|
59
|
+
#
|
60
|
+
def self.new project = nil, keyfile = nil, retries: nil, timeout: nil
|
61
|
+
gcloud = Object.new
|
62
|
+
gcloud.instance_variable_set "@project", project
|
63
|
+
gcloud.instance_variable_set "@keyfile", keyfile
|
64
|
+
gcloud.instance_variable_set "@retries", retries
|
65
|
+
gcloud.instance_variable_set "@timeout", timeout
|
66
|
+
gcloud.extend Google::Cloud
|
67
|
+
gcloud
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Auto-load all Google Cloud service gems.
|
73
|
+
Gem.find_files("google-cloud-*.rb").each do |google_cloud_service|
|
74
|
+
require google_cloud_service
|
75
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# Copyright 2014 Google Inc. All rights reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
|
16
|
+
module Google
|
17
|
+
module Cloud
|
18
|
+
module Core
|
19
|
+
##
|
20
|
+
# @private
|
21
|
+
# Backoff allows users to control how Google API calls are retried.
|
22
|
+
# If an API call fails the response will be checked to see if the
|
23
|
+
# call can be retried. If the response matches the criteria, then it
|
24
|
+
# will be retried with an incremental backoff. This means that an
|
25
|
+
# increasing delay will be added between each retried call. The first
|
26
|
+
# retry will be delayed one second, the second retry will be delayed
|
27
|
+
# two seconds, and so on.
|
28
|
+
class GrpcBackoff
|
29
|
+
class << self
|
30
|
+
##
|
31
|
+
# The number of times a retriable API call should be retried.
|
32
|
+
#
|
33
|
+
# The default value is `3`.
|
34
|
+
attr_reader :retries
|
35
|
+
def retries= new_retries
|
36
|
+
@retries = new_retries
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# The GRPC Status Codes that should be retried.
|
41
|
+
#
|
42
|
+
# The default values are `14`.
|
43
|
+
attr_accessor :grpc_codes
|
44
|
+
|
45
|
+
##
|
46
|
+
# The code to run when a backoff is handled.
|
47
|
+
# This must be a Proc and must take the number of
|
48
|
+
# retries as an argument.
|
49
|
+
#
|
50
|
+
# Note: This method is undocumented and may change.
|
51
|
+
attr_accessor :backoff # :nodoc:
|
52
|
+
end
|
53
|
+
# Set the default values
|
54
|
+
self.retries = 3
|
55
|
+
self.grpc_codes = [14]
|
56
|
+
self.backoff = ->(retries) { sleep retries.to_i }
|
57
|
+
|
58
|
+
##
|
59
|
+
# @private
|
60
|
+
# Creates a new GrpcBackoff object to catch common errors when calling
|
61
|
+
# the Google API and handle the error by retrying the call.
|
62
|
+
#
|
63
|
+
# Google::Cloud::Core::GrpcBackoff.new(options).execute do
|
64
|
+
# datastore.lookup lookup_req
|
65
|
+
# end
|
66
|
+
def initialize options = {}
|
67
|
+
@retries = (options[:retries] || GrpcBackoff.retries).to_i
|
68
|
+
@grpc_codes = (options[:grpc_codes] || GrpcBackoff.grpc_codes).to_a
|
69
|
+
@backoff = options[:backoff] || GrpcBackoff.backoff
|
70
|
+
end
|
71
|
+
|
72
|
+
# @private
|
73
|
+
def execute
|
74
|
+
current_retries = 0
|
75
|
+
loop do
|
76
|
+
begin
|
77
|
+
return yield
|
78
|
+
rescue GRPC::BadStatus => e
|
79
|
+
raise e unless @grpc_codes.include?(e.code) &&
|
80
|
+
(current_retries < @retries)
|
81
|
+
current_retries += 1
|
82
|
+
@backoff.call current_retries
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# Copyright 2015 Google Inc. All rights reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
|
16
|
+
require "faraday"
|
17
|
+
|
18
|
+
module Google
|
19
|
+
module Cloud
|
20
|
+
module Core
|
21
|
+
##
|
22
|
+
# @private
|
23
|
+
# Represents the Google Compute Engine environment.
|
24
|
+
module GCE
|
25
|
+
CHECK_URI = "http://169.254.169.254"
|
26
|
+
PROJECT_URI = "#{CHECK_URI}/computeMetadata/v1/project/project-id"
|
27
|
+
|
28
|
+
def self.gce? options = {}
|
29
|
+
conn = options[:connection] || Faraday.default_connection
|
30
|
+
resp = conn.get CHECK_URI do |req|
|
31
|
+
req.options.timeout = 0.1
|
32
|
+
end
|
33
|
+
return false unless resp.status == 200
|
34
|
+
return false unless resp.headers.key? "Metadata-Flavor"
|
35
|
+
return resp.headers["Metadata-Flavor"] == "Google"
|
36
|
+
rescue Faraday::TimeoutError, Faraday::ConnectionFailed
|
37
|
+
return false
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.project_id options = {}
|
41
|
+
@gce ||= {}
|
42
|
+
return @gce[:project_id] if @gce.key? :project_id
|
43
|
+
conn = options[:connection] || Faraday.default_connection
|
44
|
+
conn.headers = { "Metadata-Flavor" => "Google" }
|
45
|
+
resp = conn.get PROJECT_URI do |req|
|
46
|
+
req.options.timeout = 0.1
|
47
|
+
end
|
48
|
+
if resp.status == 200
|
49
|
+
@gce[:project_id] = resp.body
|
50
|
+
else
|
51
|
+
@gce[:project_id] = nil
|
52
|
+
end
|
53
|
+
rescue Faraday::TimeoutError, Faraday::ConnectionFailed
|
54
|
+
@gce ||= {}
|
55
|
+
@gce[:project_id] = nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# Copyright 2014 Google Inc. All rights reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
|
16
|
+
module Google
|
17
|
+
module Cloud
|
18
|
+
module Core
|
19
|
+
##
|
20
|
+
# @private
|
21
|
+
# Backoff allows users to control how Google API calls are retried.
|
22
|
+
# If an API call fails the response will be checked to see if the
|
23
|
+
# call can be retried. If the response matches the criteria, then it
|
24
|
+
# will be retried with an incremental backoff. This means that an
|
25
|
+
# increasing delay will be added between each retried call. The first
|
26
|
+
# retry will be delayed one second, the second retry will be delayed
|
27
|
+
# two seconds, and so on.
|
28
|
+
class GrpcBackoff
|
29
|
+
class << self
|
30
|
+
##
|
31
|
+
# The number of times a retriable API call should be retried.
|
32
|
+
#
|
33
|
+
# The default value is `3`.
|
34
|
+
attr_reader :retries
|
35
|
+
def retries= new_retries
|
36
|
+
@retries = new_retries
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# The GRPC Status Codes that should be retried.
|
41
|
+
#
|
42
|
+
# The default values are `14`.
|
43
|
+
attr_accessor :grpc_codes
|
44
|
+
|
45
|
+
##
|
46
|
+
# The code to run when a backoff is handled.
|
47
|
+
# This must be a Proc and must take the number of
|
48
|
+
# retries as an argument.
|
49
|
+
#
|
50
|
+
# Note: This method is undocumented and may change.
|
51
|
+
attr_accessor :backoff # :nodoc:
|
52
|
+
end
|
53
|
+
# Set the default values
|
54
|
+
self.retries = 3
|
55
|
+
self.grpc_codes = [14]
|
56
|
+
self.backoff = ->(retries) { sleep retries.to_i }
|
57
|
+
|
58
|
+
##
|
59
|
+
# @private
|
60
|
+
# Creates a new Backoff object to catch common errors when calling
|
61
|
+
# the Google API and handle the error by retrying the call.
|
62
|
+
#
|
63
|
+
# Google::Cloud::Core::GrpcBackoff.new(options).execute do
|
64
|
+
# datastore.lookup lookup_ref
|
65
|
+
# end
|
66
|
+
def initialize options = {}
|
67
|
+
@retries = (options[:retries] || GrpcBackoff.retries).to_i
|
68
|
+
@grpc_codes = (options[:grpc_codes] || GrpcBackoff.grpc_codes).to_a
|
69
|
+
@backoff = options[:backoff] || GrpcBackoff.backoff
|
70
|
+
end
|
71
|
+
|
72
|
+
# @private
|
73
|
+
def execute
|
74
|
+
current_retries = 0
|
75
|
+
loop do
|
76
|
+
begin
|
77
|
+
return yield
|
78
|
+
rescue GRPC::BadStatus => e
|
79
|
+
raise e unless @grpc_codes.include?(e.code) &&
|
80
|
+
(current_retries < @retries)
|
81
|
+
current_retries += 1
|
82
|
+
@backoff.call current_retries
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# Copyright 2016 Google Inc. All rights reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
|
16
|
+
require "google/cloud"
|
17
|
+
require "google/protobuf/struct_pb"
|
18
|
+
|
19
|
+
module Google
|
20
|
+
module Cloud
|
21
|
+
module Core
|
22
|
+
##
|
23
|
+
# @private Conversion to/from GRPC objects.
|
24
|
+
module GRPCUtils
|
25
|
+
##
|
26
|
+
# @private Convert a Hash to a Google::Protobuf::Struct.
|
27
|
+
def self.hash_to_struct hash
|
28
|
+
# TODO: ArgumentError if hash is not a Hash
|
29
|
+
Google::Protobuf::Struct.new fields:
|
30
|
+
Hash[hash.map { |k, v| [String(k), object_to_value(v)] }]
|
31
|
+
end
|
32
|
+
|
33
|
+
##
|
34
|
+
# @private Convert a Google::Protobuf::Struct to a Hash.
|
35
|
+
def self.struct_to_hash struct
|
36
|
+
# TODO: ArgumentError if struct is not a Google::Protobuf::Struct
|
37
|
+
Hash[struct.fields.map { |k, v| [k, value_to_object(v)] }]
|
38
|
+
end
|
39
|
+
|
40
|
+
##
|
41
|
+
# @private Convert a Google::Protobuf::Value to an Object.
|
42
|
+
def self.value_to_object value
|
43
|
+
# TODO: ArgumentError if struct is not a Google::Protobuf::Value
|
44
|
+
if value.null_value
|
45
|
+
nil
|
46
|
+
elsif value.number_value
|
47
|
+
value.number_value
|
48
|
+
elsif value.struct_value
|
49
|
+
struct_to_hash value.struct_value
|
50
|
+
elsif value.list_value
|
51
|
+
value.list_value.values.map { |v| value_to_object(v) }
|
52
|
+
elsif !value.bool_value.nil? # Make sure its a bool, not nil
|
53
|
+
value.bool_value
|
54
|
+
else
|
55
|
+
nil # just in case
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
##
|
60
|
+
# @private Convert an Object to a Google::Protobuf::Value.
|
61
|
+
def self.object_to_value obj
|
62
|
+
case obj
|
63
|
+
when String then Google::Protobuf::Value.new string_value: obj
|
64
|
+
when Array then Google::Protobuf::ListValue.new(values:
|
65
|
+
obj.map { |o| object_to_value(o) })
|
66
|
+
when Hash then Google::Protobuf::Value.new struct_value:
|
67
|
+
hash_to_struct(obj)
|
68
|
+
when Numeric then Google::Protobuf::Value.new number_value: obj
|
69
|
+
when TrueClass then Google::Protobuf::Value.new bool_value: true
|
70
|
+
when FalseClass then Google::Protobuf::Value.new bool_value: false
|
71
|
+
when NilClass then Google::Protobuf::Value.new null_value: :NULL_VALUE
|
72
|
+
else
|
73
|
+
# We could raise ArgumentError here, or we could convert to a string
|
74
|
+
Google::Protobuf::Value.new string_value: obj.to_s
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
##
|
79
|
+
# @private Convert a Google::Protobuf::Map to a Hash
|
80
|
+
def self.map_to_hash map
|
81
|
+
if map.respond_to? :to_h
|
82
|
+
map.to_h
|
83
|
+
else
|
84
|
+
# Enumerable doesn't have to_h on ruby 2.0...
|
85
|
+
Hash[map.to_a]
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Copyright 2016 Google Inc. All rights reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
|
16
|
+
module Google
|
17
|
+
module Cloud
|
18
|
+
module Core
|
19
|
+
VERSION = "0.20.1"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
# Copyright 2014 Google Inc. All rights reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
|
16
|
+
require "json"
|
17
|
+
require "signet/oauth_2/client"
|
18
|
+
require "forwardable"
|
19
|
+
require "googleauth"
|
20
|
+
|
21
|
+
module Google
|
22
|
+
module Cloud
|
23
|
+
##
|
24
|
+
# @private
|
25
|
+
# Represents the OAuth 2.0 signing logic.
|
26
|
+
# This class is intended to be inherited by API-specific classes
|
27
|
+
# which overrides the SCOPE constant.
|
28
|
+
class Credentials
|
29
|
+
TOKEN_CREDENTIAL_URI = "https://accounts.google.com/o/oauth2/token"
|
30
|
+
AUDIENCE = "https://accounts.google.com/o/oauth2/token"
|
31
|
+
SCOPE = []
|
32
|
+
PATH_ENV_VARS = %w(GOOGLE_CLOUD_KEYFILE GCLOUD_KEYFILE)
|
33
|
+
JSON_ENV_VARS = %w(GOOGLE_CLOUD_KEYFILE_JSON GCLOUD_KEYFILE_JSON)
|
34
|
+
DEFAULT_PATHS = ["~/.config/gcloud/application_default_credentials.json"]
|
35
|
+
|
36
|
+
attr_accessor :client
|
37
|
+
|
38
|
+
##
|
39
|
+
# Delegate client methods to the client object.
|
40
|
+
extend Forwardable
|
41
|
+
def_delegators :@client,
|
42
|
+
:token_credential_uri, :audience,
|
43
|
+
:scope, :issuer, :signing_key
|
44
|
+
|
45
|
+
def initialize keyfile, scope: nil
|
46
|
+
verify_keyfile_provided! keyfile
|
47
|
+
if keyfile.is_a? Signet::OAuth2::Client
|
48
|
+
@client = keyfile
|
49
|
+
elsif keyfile.is_a? Hash
|
50
|
+
hash = stringify_hash_keys keyfile
|
51
|
+
hash["scope"] ||= scope
|
52
|
+
@client = init_client hash
|
53
|
+
else
|
54
|
+
verify_keyfile_exists! keyfile
|
55
|
+
json = JSON.parse ::File.read(keyfile)
|
56
|
+
json["scope"] ||= scope
|
57
|
+
@client = init_client json
|
58
|
+
end
|
59
|
+
@client.fetch_access_token!
|
60
|
+
end
|
61
|
+
|
62
|
+
##
|
63
|
+
# Returns the default credentials.
|
64
|
+
#
|
65
|
+
def self.default scope: nil
|
66
|
+
env = ->(v) { ENV[v] }
|
67
|
+
json = ->(v) { JSON.parse ENV[v] rescue nil unless ENV[v].nil? }
|
68
|
+
path = ->(p) { ::File.file? p }
|
69
|
+
|
70
|
+
# First try to find keyfile file from environment variables.
|
71
|
+
self::PATH_ENV_VARS.map(&env).reject(&:nil?).select(&path)
|
72
|
+
.each do |file|
|
73
|
+
return new file, scope: scope
|
74
|
+
end
|
75
|
+
# Second try to find keyfile json from environment variables.
|
76
|
+
self::JSON_ENV_VARS.map(&json).reject(&:nil?).each do |hash|
|
77
|
+
return new hash, scope: scope
|
78
|
+
end
|
79
|
+
# Third try to find keyfile file from known file paths.
|
80
|
+
self::DEFAULT_PATHS.select(&path).each do |file|
|
81
|
+
return new file, scope: scope
|
82
|
+
end
|
83
|
+
# Finally get instantiated client from Google::Auth.
|
84
|
+
scope ||= self::SCOPE
|
85
|
+
client = Google::Auth.get_application_default scope
|
86
|
+
new client
|
87
|
+
end
|
88
|
+
|
89
|
+
protected
|
90
|
+
|
91
|
+
##
|
92
|
+
# Verify that the keyfile argument is provided.
|
93
|
+
def verify_keyfile_provided! keyfile
|
94
|
+
fail "You must provide a keyfile to connect with." if keyfile.nil?
|
95
|
+
end
|
96
|
+
|
97
|
+
##
|
98
|
+
# Verify that the keyfile argument is a file.
|
99
|
+
def verify_keyfile_exists! keyfile
|
100
|
+
exists = ::File.file? keyfile
|
101
|
+
fail "The keyfile '#{keyfile}' is not a valid file." unless exists
|
102
|
+
end
|
103
|
+
|
104
|
+
##
|
105
|
+
# Initializes the Signet client.
|
106
|
+
def init_client keyfile
|
107
|
+
client_opts = client_options keyfile
|
108
|
+
Signet::OAuth2::Client.new client_opts
|
109
|
+
end
|
110
|
+
|
111
|
+
##
|
112
|
+
# returns a new Hash with string keys instead of symbol keys.
|
113
|
+
def stringify_hash_keys hash
|
114
|
+
Hash[hash.map { |(k, v)| [k.to_s, v] }]
|
115
|
+
end
|
116
|
+
|
117
|
+
def client_options options
|
118
|
+
# Keyfile options have higher priority over constructor defaults
|
119
|
+
options["token_credential_uri"] ||= self.class::TOKEN_CREDENTIAL_URI
|
120
|
+
options["audience"] ||= self.class::AUDIENCE
|
121
|
+
options["scope"] ||= self.class::SCOPE
|
122
|
+
|
123
|
+
# client options for initializing signet client
|
124
|
+
{ token_credential_uri: options["token_credential_uri"],
|
125
|
+
audience: options["audience"],
|
126
|
+
scope: Array(options["scope"]),
|
127
|
+
issuer: options["client_email"],
|
128
|
+
signing_key: OpenSSL::PKey::RSA.new(options["private_key"]) }
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,208 @@
|
|
1
|
+
# Copyright 2015 Google Inc. All rights reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
|
16
|
+
module Google
|
17
|
+
module Cloud
|
18
|
+
##
|
19
|
+
# Base google-cloud exception class.
|
20
|
+
class Error < StandardError
|
21
|
+
# @private Create a new error object from a client error
|
22
|
+
def self.from_error error
|
23
|
+
klass = if error.respond_to? :code
|
24
|
+
grpc_error_class_for error.code
|
25
|
+
elsif error.respond_to? :status_code
|
26
|
+
gapi_error_class_for error.status_code
|
27
|
+
else
|
28
|
+
self
|
29
|
+
end
|
30
|
+
klass.new error.message
|
31
|
+
end
|
32
|
+
|
33
|
+
# @private Identify the subclass for a gRPC error
|
34
|
+
def self.grpc_error_class_for grpc_error_code
|
35
|
+
# The gRPC status code 0 is for a successful response.
|
36
|
+
# So there is no error subclass for a 0 status code, use current class.
|
37
|
+
[self, CanceledError, UnknownError, InvalidArgumentError,
|
38
|
+
DeadlineExceededError, NotFoundError, AlreadyExistsError,
|
39
|
+
PermissionDeniedError, ResourceExhaustedError, FailedPreconditionError,
|
40
|
+
AbortedError, OutOfRangeError, UnimplementedError, InternalError,
|
41
|
+
UnavailableError, DataLossError, UnauthenticatedError
|
42
|
+
][grpc_error_code] || self
|
43
|
+
end
|
44
|
+
|
45
|
+
# @private Identify the subclass for a Google API Client error
|
46
|
+
def self.gapi_error_class_for http_status_code
|
47
|
+
# The http status codes mapped to their error classes.
|
48
|
+
{ 400 => InvalidArgumentError, # FailedPreconditionError/OutOfRangeError
|
49
|
+
401 => UnauthenticatedError,
|
50
|
+
403 => PermissionDeniedError,
|
51
|
+
404 => NotFoundError,
|
52
|
+
409 => AlreadyExistsError, # AbortedError
|
53
|
+
429 => ResourceExhaustedError,
|
54
|
+
499 => CanceledError,
|
55
|
+
500 => InternalError, # UnknownError/DataLossError
|
56
|
+
501 => UnimplementedError,
|
57
|
+
503 => UnavailableError,
|
58
|
+
504 => DeadlineExceededError
|
59
|
+
}[http_status_code] || self
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# Canceled indicates the operation was cancelled (typically by the caller).
|
65
|
+
class CanceledError < Error
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# Unknown error. An example of where this error may be returned is
|
70
|
+
# if a Status value received from another address space belongs to
|
71
|
+
# an error-space that is not known in this address space. Also
|
72
|
+
# errors raised by APIs that do not return enough error information
|
73
|
+
# may be converted to this error.
|
74
|
+
class UnknownError < Error
|
75
|
+
end
|
76
|
+
|
77
|
+
##
|
78
|
+
# InvalidArgument indicates client specified an invalid argument.
|
79
|
+
# Note that this differs from FailedPrecondition. It indicates arguments
|
80
|
+
# that are problematic regardless of the state of the system
|
81
|
+
# (e.g., a malformed file name).
|
82
|
+
class InvalidArgumentError < Error
|
83
|
+
end
|
84
|
+
|
85
|
+
##
|
86
|
+
# DeadlineExceeded means operation expired before completion.
|
87
|
+
# For operations that change the state of the system, this error may be
|
88
|
+
# returned even if the operation has completed successfully. For
|
89
|
+
# example, a successful response from a server could have been delayed
|
90
|
+
# long enough for the deadline to expire.
|
91
|
+
class DeadlineExceededError < Error
|
92
|
+
end
|
93
|
+
|
94
|
+
##
|
95
|
+
# NotFound means some requested entity (e.g., file or directory) was
|
96
|
+
# not found.
|
97
|
+
class NotFoundError < Error
|
98
|
+
end
|
99
|
+
|
100
|
+
##
|
101
|
+
# AlreadyExists means an attempt to create an entity failed because one
|
102
|
+
# already exists.
|
103
|
+
class AlreadyExistsError < Error
|
104
|
+
end
|
105
|
+
|
106
|
+
##
|
107
|
+
# PermissionDenied indicates the caller does not have permission to
|
108
|
+
# execute the specified operation. It must not be used for rejections
|
109
|
+
# caused by exhausting some resource (use ResourceExhausted
|
110
|
+
# instead for those errors). It must not be
|
111
|
+
# used if the caller cannot be identified (use Unauthenticated
|
112
|
+
# instead for those errors).
|
113
|
+
class PermissionDeniedError < Error
|
114
|
+
end
|
115
|
+
|
116
|
+
##
|
117
|
+
# Unauthenticated indicates the request does not have valid
|
118
|
+
# authentication credentials for the operation.
|
119
|
+
class UnauthenticatedError < Error
|
120
|
+
end
|
121
|
+
|
122
|
+
##
|
123
|
+
# ResourceExhausted indicates some resource has been exhausted, perhaps
|
124
|
+
# a per-user quota, or perhaps the entire file system is out of space.
|
125
|
+
class ResourceExhaustedError < Error
|
126
|
+
end
|
127
|
+
|
128
|
+
##
|
129
|
+
# FailedPrecondition indicates operation was rejected because the
|
130
|
+
# system is not in a state required for the operation's execution.
|
131
|
+
# For example, directory to be deleted may be non-empty, an rmdir
|
132
|
+
# operation is applied to a non-directory, etc.
|
133
|
+
#
|
134
|
+
# A litmus test that may help a service implementor in deciding
|
135
|
+
# between FailedPrecondition, Aborted, and Unavailable:
|
136
|
+
# (a) Use Unavailable if the client can retry just the failing call.
|
137
|
+
# (b) Use Aborted if the client should retry at a higher-level
|
138
|
+
# (e.g., restarting a read-modify-write sequence).
|
139
|
+
# (c) Use FailedPrecondition if the client should not retry until
|
140
|
+
# the system state has been explicitly fixed. E.g., if an "rmdir"
|
141
|
+
# fails because the directory is non-empty, FailedPrecondition
|
142
|
+
# should be returned since the client should not retry unless
|
143
|
+
# they have first fixed up the directory by deleting files from it.
|
144
|
+
# (d) Use FailedPrecondition if the client performs conditional
|
145
|
+
# REST Get/Update/Delete on a resource and the resource on the
|
146
|
+
# server does not match the condition. E.g., conflicting
|
147
|
+
# read-modify-write on the same resource.
|
148
|
+
class FailedPreconditionError < Error
|
149
|
+
end
|
150
|
+
|
151
|
+
##
|
152
|
+
# Aborted indicates the operation was aborted, typically due to a
|
153
|
+
# concurrency issue like sequencer check failures, transaction aborts,
|
154
|
+
# etc.
|
155
|
+
#
|
156
|
+
# See litmus test above for deciding between FailedPrecondition,
|
157
|
+
# Aborted, and Unavailable.
|
158
|
+
class AbortedError < Error
|
159
|
+
end
|
160
|
+
|
161
|
+
##
|
162
|
+
# OutOfRange means operation was attempted past the valid range.
|
163
|
+
# E.g., seeking or reading past end of file.
|
164
|
+
#
|
165
|
+
# Unlike InvalidArgument, this error indicates a problem that may
|
166
|
+
# be fixed if the system state changes. For example, a 32-bit file
|
167
|
+
# system will generate InvalidArgument if asked to read at an
|
168
|
+
# offset that is not in the range [0,2^32-1], but it will generate
|
169
|
+
# OutOfRange if asked to read from an offset past the current
|
170
|
+
# file size.
|
171
|
+
#
|
172
|
+
# There is a fair bit of overlap between FailedPrecondition and
|
173
|
+
# OutOfRange. We recommend using OutOfRange (the more specific
|
174
|
+
# error) when it applies so that callers who are iterating through
|
175
|
+
# a space can easily look for an OutOfRange error to detect when
|
176
|
+
# they are done.
|
177
|
+
class OutOfRangeError < Error
|
178
|
+
end
|
179
|
+
|
180
|
+
##
|
181
|
+
# Unimplemented indicates operation is not implemented or not
|
182
|
+
# supported/enabled in this service.
|
183
|
+
class UnimplementedError < Error
|
184
|
+
end
|
185
|
+
|
186
|
+
##
|
187
|
+
# Internal errors. Means some invariants expected by underlying
|
188
|
+
# system has been broken. If you see one of these errors,
|
189
|
+
# something is very broken.
|
190
|
+
class InternalError < Error
|
191
|
+
end
|
192
|
+
|
193
|
+
##
|
194
|
+
# Unavailable indicates the service is currently unavailable.
|
195
|
+
# This is a most likely a transient condition and may be corrected
|
196
|
+
# by retrying with a backoff.
|
197
|
+
#
|
198
|
+
# See litmus test above for deciding between FailedPrecondition,
|
199
|
+
# Aborted, and Unavailable.
|
200
|
+
class UnavailableError < Error
|
201
|
+
end
|
202
|
+
|
203
|
+
##
|
204
|
+
# DataLoss indicates unrecoverable data loss or corruption.
|
205
|
+
class DataLossError < Error
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
metadata
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: google-cloud-core
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.20.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mike Moore
|
8
|
+
- Chris Smith
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2016-08-27 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: minitest
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '5.9'
|
21
|
+
type: :development
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '5.9'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: minitest-autotest
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '1.0'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '1.0'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: minitest-focus
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - "~>"
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '1.1'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - "~>"
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '1.1'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: minitest-rg
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - "~>"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '5.2'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '5.2'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: autotest-suffix
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - "~>"
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '1.1'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - "~>"
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '1.1'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: rubocop
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - "<="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: 0.35.1
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - "<="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: 0.35.1
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: simplecov
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - "~>"
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0.9'
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - "~>"
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0.9'
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: yard
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - "~>"
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0.9'
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - "~>"
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0.9'
|
126
|
+
description: google-cloud-core is the internal shared library for google-cloud-ruby.
|
127
|
+
email:
|
128
|
+
- mike@blowmage.com
|
129
|
+
- quartzmo@gmail.com
|
130
|
+
executables: []
|
131
|
+
extensions: []
|
132
|
+
extra_rdoc_files: []
|
133
|
+
files:
|
134
|
+
- lib/google/cloud.rb
|
135
|
+
- lib/google/cloud/core/backoff.rb
|
136
|
+
- lib/google/cloud/core/gce.rb
|
137
|
+
- lib/google/cloud/core/grpc_backoff.rb
|
138
|
+
- lib/google/cloud/core/grpc_utils.rb
|
139
|
+
- lib/google/cloud/core/version.rb
|
140
|
+
- lib/google/cloud/credentials.rb
|
141
|
+
- lib/google/cloud/errors.rb
|
142
|
+
homepage: http://googlecloudplatform.github.io/google-cloud-ruby/
|
143
|
+
licenses:
|
144
|
+
- Apache-2.0
|
145
|
+
metadata: {}
|
146
|
+
post_install_message:
|
147
|
+
rdoc_options: []
|
148
|
+
require_paths:
|
149
|
+
- lib
|
150
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
151
|
+
requirements:
|
152
|
+
- - ">="
|
153
|
+
- !ruby/object:Gem::Version
|
154
|
+
version: 2.0.0
|
155
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
requirements: []
|
161
|
+
rubyforge_project:
|
162
|
+
rubygems_version: 2.6.4
|
163
|
+
signing_key:
|
164
|
+
specification_version: 4
|
165
|
+
summary: Internal shared library for google-cloud-ruby
|
166
|
+
test_files: []
|