fog-google 1.10.0 → 1.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (164) hide show
  1. checksums.yaml +5 -5
  2. data/.github/dependabot.yml +10 -0
  3. data/.github/workflows/ruby.yml +34 -0
  4. data/.github/workflows/stale.yml +23 -0
  5. data/.rubocop.yml +3 -3
  6. data/CHANGELOG.md +100 -1
  7. data/README.md +56 -10
  8. data/ci/docker-image/Dockerfile +3 -3
  9. data/fog-google.gemspec +4 -4
  10. data/lib/fog/compute/google.rb +0 -4
  11. data/lib/fog/compute/google/models/address.rb +1 -1
  12. data/lib/fog/compute/google/models/addresses.rb +6 -6
  13. data/lib/fog/compute/google/models/backend_service.rb +1 -1
  14. data/lib/fog/compute/google/models/disk.rb +3 -3
  15. data/lib/fog/compute/google/models/disk_types.rb +2 -2
  16. data/lib/fog/compute/google/models/disks.rb +2 -2
  17. data/lib/fog/compute/google/models/firewall.rb +2 -2
  18. data/lib/fog/compute/google/models/firewalls.rb +1 -1
  19. data/lib/fog/compute/google/models/forwarding_rules.rb +2 -2
  20. data/lib/fog/compute/google/models/global_addresses.rb +1 -1
  21. data/lib/fog/compute/google/models/global_forwarding_rules.rb +1 -1
  22. data/lib/fog/compute/google/models/http_health_check.rb +2 -2
  23. data/lib/fog/compute/google/models/instance_group_managers.rb +2 -2
  24. data/lib/fog/compute/google/models/machine_types.rb +2 -2
  25. data/lib/fog/compute/google/models/operations.rb +3 -3
  26. data/lib/fog/compute/google/models/server.rb +3 -3
  27. data/lib/fog/compute/google/models/servers.rb +3 -3
  28. data/lib/fog/compute/google/models/subnetworks.rb +2 -2
  29. data/lib/fog/compute/google/models/target_instances.rb +2 -2
  30. data/lib/fog/compute/google/models/target_pools.rb +2 -2
  31. data/lib/fog/compute/google/models/url_maps.rb +1 -1
  32. data/lib/fog/compute/google/requests/abandon_instances.rb +1 -1
  33. data/lib/fog/compute/google/requests/add_instance_group_instances.rb +3 -3
  34. data/lib/fog/compute/google/requests/add_server_access_config.rb +3 -3
  35. data/lib/fog/compute/google/requests/add_target_pool_health_checks.rb +2 -2
  36. data/lib/fog/compute/google/requests/add_target_pool_instances.rb +2 -2
  37. data/lib/fog/compute/google/requests/attach_disk.rb +1 -1
  38. data/lib/fog/compute/google/requests/create_disk_snapshot.rb +1 -1
  39. data/lib/fog/compute/google/requests/expand_subnetwork_ip_cidr_range.rb +1 -1
  40. data/lib/fog/compute/google/requests/get_backend_service_health.rb +1 -1
  41. data/lib/fog/compute/google/requests/get_server_serial_port_output.rb +2 -2
  42. data/lib/fog/compute/google/requests/get_target_pool_health.rb +1 -1
  43. data/lib/fog/compute/google/requests/insert_address.rb +2 -2
  44. data/lib/fog/compute/google/requests/insert_backend_service.rb +1 -1
  45. data/lib/fog/compute/google/requests/insert_disk.rb +1 -1
  46. data/lib/fog/compute/google/requests/insert_firewall.rb +1 -1
  47. data/lib/fog/compute/google/requests/insert_forwarding_rule.rb +1 -1
  48. data/lib/fog/compute/google/requests/insert_global_address.rb +1 -1
  49. data/lib/fog/compute/google/requests/insert_global_forwarding_rule.rb +1 -1
  50. data/lib/fog/compute/google/requests/insert_http_health_check.rb +1 -1
  51. data/lib/fog/compute/google/requests/insert_image.rb +1 -1
  52. data/lib/fog/compute/google/requests/insert_instance_group.rb +3 -3
  53. data/lib/fog/compute/google/requests/insert_instance_group_manager.rb +7 -7
  54. data/lib/fog/compute/google/requests/insert_instance_template.rb +3 -3
  55. data/lib/fog/compute/google/requests/insert_network.rb +1 -1
  56. data/lib/fog/compute/google/requests/insert_route.rb +10 -10
  57. data/lib/fog/compute/google/requests/insert_server.rb +12 -8
  58. data/lib/fog/compute/google/requests/insert_ssl_certificate.rb +4 -4
  59. data/lib/fog/compute/google/requests/insert_subnetwork.rb +1 -1
  60. data/lib/fog/compute/google/requests/insert_target_http_proxy.rb +3 -3
  61. data/lib/fog/compute/google/requests/insert_target_https_proxy.rb +4 -4
  62. data/lib/fog/compute/google/requests/insert_target_instance.rb +1 -1
  63. data/lib/fog/compute/google/requests/insert_target_pool.rb +1 -1
  64. data/lib/fog/compute/google/requests/insert_url_map.rb +1 -1
  65. data/lib/fog/compute/google/requests/invalidate_url_map_cache.rb +1 -1
  66. data/lib/fog/compute/google/requests/list_addresses.rb +4 -4
  67. data/lib/fog/compute/google/requests/list_aggregated_addresses.rb +1 -1
  68. data/lib/fog/compute/google/requests/list_aggregated_disk_types.rb +2 -2
  69. data/lib/fog/compute/google/requests/list_aggregated_disks.rb +2 -2
  70. data/lib/fog/compute/google/requests/list_aggregated_forwarding_rules.rb +2 -2
  71. data/lib/fog/compute/google/requests/list_aggregated_instance_group_managers.rb +4 -4
  72. data/lib/fog/compute/google/requests/list_aggregated_instance_groups.rb +1 -1
  73. data/lib/fog/compute/google/requests/list_aggregated_machine_types.rb +2 -2
  74. data/lib/fog/compute/google/requests/list_aggregated_servers.rb +2 -2
  75. data/lib/fog/compute/google/requests/list_aggregated_subnetworks.rb +4 -4
  76. data/lib/fog/compute/google/requests/list_aggregated_target_instances.rb +4 -4
  77. data/lib/fog/compute/google/requests/list_aggregated_target_pools.rb +4 -4
  78. data/lib/fog/compute/google/requests/list_disk_types.rb +2 -2
  79. data/lib/fog/compute/google/requests/list_disks.rb +2 -2
  80. data/lib/fog/compute/google/requests/list_firewalls.rb +4 -4
  81. data/lib/fog/compute/google/requests/list_forwarding_rules.rb +2 -2
  82. data/lib/fog/compute/google/requests/list_global_addresses.rb +5 -5
  83. data/lib/fog/compute/google/requests/list_global_forwarding_rules.rb +2 -2
  84. data/lib/fog/compute/google/requests/list_global_operations.rb +4 -4
  85. data/lib/fog/compute/google/requests/list_http_health_checks.rb +2 -2
  86. data/lib/fog/compute/google/requests/list_images.rb +2 -2
  87. data/lib/fog/compute/google/requests/list_instance_group_managers.rb +2 -2
  88. data/lib/fog/compute/google/requests/list_instance_templates.rb +4 -4
  89. data/lib/fog/compute/google/requests/list_machine_types.rb +4 -4
  90. data/lib/fog/compute/google/requests/list_networks.rb +4 -4
  91. data/lib/fog/compute/google/requests/list_subnetworks.rb +4 -4
  92. data/lib/fog/compute/google/requests/list_target_pools.rb +4 -4
  93. data/lib/fog/compute/google/requests/list_url_maps.rb +2 -2
  94. data/lib/fog/compute/google/requests/patch_firewall.rb +1 -1
  95. data/lib/fog/compute/google/requests/remove_instance_group_instances.rb +3 -3
  96. data/lib/fog/compute/google/requests/remove_target_pool_health_checks.rb +2 -2
  97. data/lib/fog/compute/google/requests/remove_target_pool_instance.rb +2 -2
  98. data/lib/fog/compute/google/requests/remove_target_pool_instances.rb +2 -2
  99. data/lib/fog/compute/google/requests/set_common_instance_metadata.rb +2 -2
  100. data/lib/fog/compute/google/requests/set_forwarding_rule_target.rb +1 -1
  101. data/lib/fog/compute/google/requests/set_global_forwarding_rule_target.rb +1 -1
  102. data/lib/fog/compute/google/requests/set_server_metadata.rb +3 -3
  103. data/lib/fog/compute/google/requests/set_server_tags.rb +2 -2
  104. data/lib/fog/compute/google/requests/set_snapshot_labels.rb +2 -2
  105. data/lib/fog/compute/google/requests/set_subnetwork_private_ip_google_access.rb +1 -1
  106. data/lib/fog/compute/google/requests/set_target_http_proxy_url_map.rb +1 -1
  107. data/lib/fog/compute/google/requests/set_target_https_proxy_ssl_certificates.rb +1 -1
  108. data/lib/fog/compute/google/requests/set_target_https_proxy_url_map.rb +1 -1
  109. data/lib/fog/compute/google/requests/set_target_pool_backup.rb +2 -2
  110. data/lib/fog/compute/google/requests/update_firewall.rb +1 -1
  111. data/lib/fog/compute/google/requests/update_http_health_check.rb +1 -1
  112. data/lib/fog/compute/google/requests/update_url_map.rb +1 -1
  113. data/lib/fog/compute/google/requests/validate_url_map.rb +1 -1
  114. data/lib/fog/dns/google/requests/create_change.rb +2 -2
  115. data/lib/fog/google/models/sql/instance.rb +2 -2
  116. data/lib/fog/google/requests/monitoring/create_metric_descriptor.rb +8 -8
  117. data/lib/fog/google/requests/monitoring/create_timeseries.rb +1 -1
  118. data/lib/fog/google/requests/monitoring/list_timeseries.rb +1 -1
  119. data/lib/fog/google/requests/pubsub/acknowledge_subscription.rb +1 -1
  120. data/lib/fog/google/requests/pubsub/create_subscription.rb +3 -3
  121. data/lib/fog/google/requests/pubsub/pull_subscription.rb +5 -1
  122. data/lib/fog/google/requests/sql/clone_instance.rb +4 -4
  123. data/lib/fog/google/requests/sql/delete_user.rb +1 -1
  124. data/lib/fog/google/requests/sql/export_instance.rb +3 -3
  125. data/lib/fog/google/requests/sql/import_instance.rb +2 -2
  126. data/lib/fog/google/requests/sql/insert_backup_run.rb +1 -1
  127. data/lib/fog/google/requests/sql/insert_instance.rb +2 -2
  128. data/lib/fog/google/requests/sql/insert_ssl_cert.rb +1 -1
  129. data/lib/fog/google/requests/sql/insert_user.rb +1 -1
  130. data/lib/fog/google/requests/sql/restore_instance_backup.rb +4 -4
  131. data/lib/fog/google/requests/sql/update_instance.rb +2 -2
  132. data/lib/fog/google/shared.rb +10 -5
  133. data/lib/fog/google/version.rb +1 -1
  134. data/lib/fog/storage/google_json.rb +4 -0
  135. data/lib/fog/storage/google_json/mock.rb +6 -0
  136. data/lib/fog/storage/google_json/models/directories.rb +1 -1
  137. data/lib/fog/storage/google_json/models/directory.rb +1 -1
  138. data/lib/fog/storage/google_json/models/file.rb +1 -1
  139. data/lib/fog/storage/google_json/models/files.rb +1 -1
  140. data/lib/fog/storage/google_json/real.rb +106 -3
  141. data/lib/fog/storage/google_json/requests/copy_object.rb +12 -1
  142. data/lib/fog/storage/google_json/requests/get_object.rb +5 -3
  143. data/lib/fog/storage/google_json/requests/list_buckets.rb +4 -4
  144. data/lib/fog/storage/google_json/requests/list_objects.rb +1 -1
  145. data/lib/fog/storage/google_json/requests/put_bucket.rb +1 -1
  146. data/lib/fog/storage/google_json/requests/put_bucket_acl.rb +1 -1
  147. data/lib/fog/storage/google_json/requests/put_object.rb +1 -1
  148. data/lib/fog/storage/google_json/requests/put_object_acl.rb +1 -1
  149. data/lib/fog/storage/google_json/utils.rb +6 -2
  150. data/lib/fog/storage/google_xml/models/file.rb +2 -2
  151. data/lib/fog/storage/google_xml/requests/get_bucket.rb +0 -1
  152. data/lib/fog/storage/google_xml/requests/head_object.rb +7 -6
  153. data/tasks/changelog.rake +10 -1
  154. data/test/helpers/integration_test_helper.rb +15 -1
  155. data/test/integration/monitoring/test_metric_descriptors.rb +1 -1
  156. data/test/integration/monitoring/test_timeseries.rb +11 -25
  157. data/test/integration/pubsub/test_pubsub_models.rb +3 -3
  158. data/test/integration/pubsub/test_pubsub_requests.rb +2 -2
  159. data/test/integration/sql/test_certs.rb +0 -1
  160. data/test/integration/storage/test_objects.rb +36 -0
  161. data/test/unit/storage/test_common_xml_collections.rb +11 -0
  162. data/test/unit/storage/test_json_requests.rb +8 -0
  163. metadata +28 -13
  164. data/.travis.yml +0 -16
@@ -13,7 +13,14 @@ module Fog
13
13
  options[:google_api_scope_url] = GOOGLE_STORAGE_JSON_API_SCOPE_URLS.join(" ")
14
14
  @host = options[:host] || "storage.googleapis.com"
15
15
 
16
+ # TODO(temikus): Do we even need this client?
16
17
  @client = initialize_google_client(options)
18
+ # IAM client used for SignBlob API
19
+ @iam_service = ::Google::Apis::IamcredentialsV1::IAMCredentialsService.new
20
+ apply_client_options(@iam_service, {
21
+ google_api_scope_url: GOOGLE_STORAGE_JSON_IAM_API_SCOPE_URLS.join(" ")
22
+ })
23
+
17
24
  @storage_json = ::Google::Apis::StorageV1::StorageService.new
18
25
  apply_client_options(@storage_json, options)
19
26
 
@@ -56,12 +63,108 @@ DATA
56
63
  canonical_resource.chop!
57
64
  string_to_sign << canonical_resource.to_s
58
65
 
59
- key = OpenSSL::PKey::RSA.new(@client.signing_key)
60
- digest = OpenSSL::Digest::SHA256.new
61
- signed_string = key.sign(digest, string_to_sign)
66
+ # TODO(temikus): make signer configurable or add ability to supply your own via lambda
67
+ if !@storage_json.authorization.signing_key.nil?
68
+ signed_string = default_signer(string_to_sign)
69
+ else
70
+ # If client doesn't contain signing key attempt to auth via IAM SignBlob API
71
+ signed_string = iam_signer(string_to_sign)
72
+ end
62
73
 
63
74
  Base64.encode64(signed_string).chomp!
64
75
  end
76
+
77
+ private
78
+
79
+ def google_access_id
80
+ @google_access_id ||= get_google_access_id
81
+ end
82
+
83
+ ##
84
+ # Fetches the google service account name
85
+ #
86
+ # @return [String] Service account name, typically needed for GoogleAccessId, e.g.
87
+ # my-account@project.iam.gserviceaccount
88
+ # @raises [Fog::Errors::Error] If authorisation is incorrect or inapplicable for current action
89
+ def get_google_access_id
90
+ if @storage_json.authorization.is_a?(::Google::Auth::UserRefreshCredentials)
91
+ raise Fog::Errors::Error.new("User / Application Default Credentials are not supported for storage"\
92
+ "url signing, please use a service account or metadata authentication.")
93
+ end
94
+
95
+ if !@storage_json.authorization.issuer.nil?
96
+ return @storage_json.authorization.issuer
97
+ else
98
+ get_access_id_from_metadata
99
+ end
100
+ end
101
+
102
+ ##
103
+ # Attempts to fetch the google service account name from metadata using Google::Cloud::Env
104
+ #
105
+ # @return [String] Service account name, typically needed for GoogleAccessId, e.g.
106
+ # my-account@project.iam.gserviceaccount
107
+ # @raises [Fog::Errors::Error] If Metadata service is not available or returns an invalid response
108
+ def get_access_id_from_metadata
109
+ if @google_cloud_env.metadata?
110
+ access_id = @google_cloud_env.lookup_metadata("instance", "service-accounts/default/email")
111
+ else
112
+ raise Fog::Errors::Error.new("Metadata service not available, unable to retrieve service account info.")
113
+ end
114
+
115
+ if access_id.nil?
116
+ raise Fog::Errors::Error.new("Metadata service found but didn't return data." \
117
+ "Please file a bug: https://github.com/fog/fog-google")
118
+ end
119
+
120
+ return access_id
121
+ end
122
+
123
+ ##
124
+ # Default url signer using service account keys
125
+ #
126
+ # @param [String] string_to_sign Special collection of headers and options for V2 storage signing, e.g.:
127
+ #
128
+ # StringToSign = HTTP_Verb + "\n" +
129
+ # Content_MD5 + "\n" +
130
+ # Content_Type + "\n" +
131
+ # Expires + "\n" +
132
+ # Canonicalized_Extension_Headers +
133
+ # Canonicalized_Resource
134
+ #
135
+ # See https://cloud.google.com/storage/docs/access-control/signed-urls-v2
136
+ # @return [String] Signature binary blob
137
+ def default_signer(string_to_sign)
138
+ key = OpenSSL::PKey::RSA.new(@storage_json.authorization.signing_key)
139
+ digest = OpenSSL::Digest::SHA256.new
140
+ return key.sign(digest, string_to_sign)
141
+ end
142
+
143
+ ##
144
+ # Fallback URL signer using the IAM SignServiceAccountBlob API, see
145
+ # Google::Apis::IamcredentialsV1::IAMCredentialsService#sign_service_account_blob
146
+ #
147
+ # @param [String] string_to_sign Special collection of headers and options for V2 storage signing, e.g.:
148
+ #
149
+ # StringToSign = HTTP_Verb + "\n" +
150
+ # Content_MD5 + "\n" +
151
+ # Content_Type + "\n" +
152
+ # Expires + "\n" +
153
+ # Canonicalized_Extension_Headers +
154
+ # Canonicalized_Resource
155
+ #
156
+ # See https://cloud.google.com/storage/docs/access-control/signed-urls-v2
157
+ # @return [String] Signature binary blob
158
+ def iam_signer(string_to_sign)
159
+ request = {
160
+ "payload": string_to_sign
161
+ }
162
+
163
+ resource = "projects/-/serviceAccounts/#{google_access_id}"
164
+ response = @iam_service.sign_service_account_blob resource, request, {}
165
+
166
+ return response.signed_blob
167
+ end
65
168
  end
66
169
  end
67
170
  end
@@ -14,9 +14,20 @@ module Fog
14
14
  def copy_object(source_bucket, source_object,
15
15
  target_bucket, target_object, options = {})
16
16
  request_options = ::Google::Apis::RequestOptions.default.merge(options)
17
+
18
+ object = ::Google::Apis::StorageV1::Object.new(**options)
19
+
17
20
  @storage_json.copy_object(source_bucket, source_object,
18
21
  target_bucket, target_object,
19
- request_options)
22
+ object, options: request_options, **filter_keyword_args(options))
23
+ end
24
+
25
+ private
26
+
27
+ def filter_keyword_args(options)
28
+ method = @storage_json.method(:copy_object)
29
+ allowed = method.parameters.filter { |param| %i(key keyreq).include?(param[0]) }.map { |param| param[1] }.compact
30
+ options.filter { |key, _| allowed.include?(key) }
20
31
  end
21
32
  end
22
33
 
@@ -39,6 +39,7 @@ module Fog
39
39
  raise ArgumentError.new("object_name is required") unless object_name
40
40
 
41
41
  buf = Tempfile.new("fog-google-storage-temp")
42
+ buf.unlink
42
43
 
43
44
  # Two requests are necessary, first for metadata, then for content.
44
45
  # google-api-ruby-client doesn't allow fetching both metadata and content
@@ -53,18 +54,19 @@ module Fog
53
54
  :options => request_options
54
55
  }
55
56
 
56
- object = @storage_json.get_object(bucket_name, object_name, all_opts).to_h
57
+ object = @storage_json.get_object(bucket_name, object_name, **all_opts).to_h
57
58
  @storage_json.get_object(
58
59
  bucket_name,
59
60
  object_name,
60
- all_opts.merge(:download_dest => buf.path)
61
+ **all_opts.merge(:download_dest => buf)
61
62
  )
62
63
 
64
+ buf.seek(0)
65
+
63
66
  if block_given?
64
67
  yield buf.read, nil, nil
65
68
  else
66
69
  object[:body] = buf.read
67
- buf.unlink
68
70
  end
69
71
 
70
72
  object
@@ -11,10 +11,10 @@ module Fog
11
11
  prefix: nil, projection: nil)
12
12
  @storage_json.list_buckets(
13
13
  @project,
14
- :max_results => max_results,
15
- :page_token => page_token,
16
- :prefix => prefix,
17
- :projection => projection
14
+ max_results: max_results,
15
+ page_token: page_token,
16
+ prefix: prefix,
17
+ projection: projection
18
18
  )
19
19
  end
20
20
  end
@@ -31,7 +31,7 @@ module Fog
31
31
 
32
32
  @storage_json.list_objects(
33
33
  bucket,
34
- options.select { |k, _| allowed_opts.include? k }
34
+ **options.select { |k, _| allowed_opts.include? k }
35
35
  )
36
36
  end
37
37
  end
@@ -19,7 +19,7 @@ module Fog
19
19
  predefined_default_object_acl: nil,
20
20
  **options)
21
21
  bucket = ::Google::Apis::StorageV1::Bucket.new(
22
- options.merge(:name => bucket_name)
22
+ **options.merge(:name => bucket_name)
23
23
  )
24
24
 
25
25
  @storage_json.insert_bucket(
@@ -12,7 +12,7 @@ module Fog
12
12
  raise ArgumentError.new("bucket_name is required") unless bucket_name
13
13
  raise ArgumentError.new("acl is required") unless acl
14
14
 
15
- acl_update = ::Google::Apis::StorageV1::BucketAccessControl.new(acl)
15
+ acl_update = ::Google::Apis::StorageV1::BucketAccessControl.new(**acl)
16
16
  @storage_json.insert_bucket_access_control(bucket_name, acl_update)
17
17
  end
18
18
  end
@@ -51,7 +51,7 @@ module Fog
51
51
  data, options = normalize_data(data, options)
52
52
 
53
53
  object_config = ::Google::Apis::StorageV1::Object.new(
54
- options.merge(:name => object_name)
54
+ **options.merge(:name => object_name)
55
55
  )
56
56
 
57
57
  @storage_json.insert_object(
@@ -15,7 +15,7 @@ module Fog
15
15
  raise ArgumentError.new("object_name is required") unless object_name
16
16
  raise ArgumentError.new("acl is required") unless acl
17
17
 
18
- acl_object = ::Google::Apis::StorageV1::ObjectAccessControl.new(acl)
18
+ acl_object = ::Google::Apis::StorageV1::ObjectAccessControl.new(**acl)
19
19
 
20
20
  @storage_json.insert_object_access_control(
21
21
  bucket_name, object_name, acl_object
@@ -19,7 +19,11 @@ module Fog
19
19
 
20
20
  def host_path_query(params, expires)
21
21
  params[:headers]["Date"] = expires.to_i
22
- params[:path] = URI.encode(params[:path]).gsub("%2F", "/")
22
+ # implementation from CGI.escape, but without ' ' to '+' conversion
23
+ params[:path] = params[:path].b.gsub(/([^a-zA-Z0-9_.\-~]+)/) { |m|
24
+ '%' + m.unpack('H2' * m.bytesize).join('%').upcase
25
+ }.gsub("%2F", "/")
26
+
23
27
  query = []
24
28
 
25
29
  if params[:query]
@@ -27,7 +31,7 @@ module Fog
27
31
  query = filtered.map { |k, v| [k.to_s, Fog::Google.escape(v)].join("=") }
28
32
  end
29
33
 
30
- query << "GoogleAccessId=#{@client.issuer}"
34
+ query << "GoogleAccessId=#{google_access_id}"
31
35
  query << "Signature=#{CGI.escape(signature(params))}"
32
36
  query << "Expires=#{params[:headers]['Date']}"
33
37
  "#{params[:host]}/#{params[:path]}?#{query.join('&')}"
@@ -51,7 +51,7 @@ module Fog
51
51
 
52
52
  remove_method :metadata
53
53
  def metadata
54
- attributes.reject { |key, _value| key.to_s =~ /^x-goog-meta-/ }
54
+ attributes.select { |key, _value| key.to_s =~ /^x-goog-meta-/ }
55
55
  end
56
56
 
57
57
  remove_method :metadata=
@@ -109,7 +109,7 @@ module Fog
109
109
  options["Expires"] = expires if expires
110
110
  options.merge!(metadata)
111
111
 
112
- data = service.put_object(directory.key, key, body, options)
112
+ data = service.put_object(directory.key, key, body, **options)
113
113
  merge_attributes(data.headers.reject { |key, _value| ["Content-Length", "Content-Type"].include?(key) })
114
114
  self.content_length = Fog::Storage.get_body_size(body)
115
115
  self.content_type ||= Fog::Storage.get_content_type(body)
@@ -1,4 +1,3 @@
1
- require "pp"
2
1
  module Fog
3
2
  module Storage
4
3
  class GoogleXML
@@ -33,12 +33,13 @@ module Fog
33
33
  headers["If-Modified-Since"] = Fog::Time.at(options["If-Modified-Since"].to_i).to_date_header if options["If-Modified-Since"]
34
34
  headers["If-Unmodified-Since"] = Fog::Time.at(options["If-Unmodified-Since"].to_i).to_date_header if options["If-Modified-Since"]
35
35
  headers.merge!(options)
36
- request(:expects => [200, 206],
37
- :headers => headers,
38
- :host => "#{bucket_name}.#{@host}",
39
- :method => "HEAD",
40
- :path => Fog::Google.escape(object_name),
41
- :query => query)
36
+ request(:expects => [200, 206],
37
+ :headers => headers,
38
+ :host => "#{bucket_name}.#{@host}",
39
+ :idempotent => true,
40
+ :method => "HEAD",
41
+ :path => Fog::Google.escape(object_name),
42
+ :query => query)
42
43
  end
43
44
  end
44
45
 
data/tasks/changelog.rake CHANGED
@@ -20,11 +20,20 @@ end
20
20
 
21
21
  # Extracts all changes that have been made after the latest pushed tag
22
22
  def changes_since_last_tag
23
- `git --no-pager log $(git describe --tags --abbrev=0)..HEAD --oneline`
23
+ `git --no-pager log $(git describe --tags --abbrev=0)..HEAD --grep="Merge" --pretty=format:"%t - %s%n%b%n"`
24
+ end
25
+
26
+ # Extracts all github users contributed since last tag
27
+ def users_since_last_tag
28
+ `git --no-pager log $(git describe --tags --abbrev=0)..HEAD --grep="Merge" --pretty=format:"%s" | cut -d' ' -f 6 | cut -d/ -f1 | sort | uniq`
24
29
  end
25
30
 
26
31
  namespace :changelog do
27
32
  task :generate do
28
33
  insert_after_line("CHANGELOG.md", changes_since_last_tag, /^## Next/)
34
+ contributors = users_since_last_tag.split("\n").map { |name| "@" + name }
35
+ printf("Huge thanks to all our contributors 🎆\n")
36
+ printf("Special thanks to: " + contributors.join(" ") + "\n")
37
+ printf("\nI'll merge this and release the gem once all tests pass.\n")
29
38
  end
30
39
  end
@@ -1,5 +1,6 @@
1
1
  require "helpers/test_helper"
2
2
  require "helpers/test_collection"
3
+ require "retriable"
3
4
 
4
5
  # Use :test credentials in ~/.fog for live integration testing
5
6
  # XXX not sure if this will work on Travis CI or not
@@ -22,7 +23,7 @@ TEST_IMAGE_FAMILY = "debian-9".freeze
22
23
 
23
24
  # XXX This depends on a public image in gs://fog-test-bucket; there may be a better way to do this
24
25
  # The image was created like so: https://cloud.google.com/compute/docs/images#export_an_image_to_google_cloud_storage
25
- TEST_RAW_DISK_SOURCE = "http://storage.googleapis.com/fog-test-bucket/fog-test-raw-disk-source.image.tar.gz".freeze
26
+ TEST_RAW_DISK_SOURCE = "https://storage.googleapis.com/fog-testing-bucket/fog-test-raw-disk-source.image.tar.gz".freeze
26
27
 
27
28
  TEST_SQL_TIER = "db-n1-standard-1".freeze
28
29
  TEST_SQL_REGION = TEST_REGION
@@ -87,8 +88,21 @@ wLjafhPTSAIS0jijglJ7uzaSbFUW11fw1/EIqIFNe0R0Xf9lsyPxFA==
87
88
  -----END RSA PRIVATE KEY-----
88
89
  KEY
89
90
 
91
+ # Retry module config - standard retriable gem settings
92
+ # see: https://github.com/kamui/retriable
93
+ RETRIABLE_TRIES = 3
94
+ RETRIABLE_BASE_INTERVAL = 50
95
+
90
96
  class FogIntegrationTest < MiniTest::Test
91
97
  def namespaced_name
92
98
  "#{self.class}_#{name}"
93
99
  end
100
+
101
+ def retry_on(klass)
102
+ Retriable.retriable(on: klass,
103
+ tries: RETRIABLE_TRIES,
104
+ base_interval: RETRIABLE_BASE_INTERVAL) do
105
+ yield
106
+ end
107
+ end
94
108
  end
@@ -68,7 +68,7 @@ class TestMetricDescriptors < FogIntegrationTest
68
68
  :labels => [label]
69
69
  }
70
70
 
71
- created = @client.create_metric_descriptor(options)
71
+ created = @client.create_metric_descriptor(**options)
72
72
 
73
73
  # Check created metric descriptor
74
74
  assert_equal(_full_name(metric_type), created.name)
@@ -1,12 +1,11 @@
1
1
  require "helpers/integration_test_helper"
2
- require "retriable"
3
2
 
4
3
  class TestMetricDescriptors < FogIntegrationTest
5
- # Retriable is used to wrap each request in this test due to Stackdriver API being slow with
6
- # metric propagation (sometimes 80+ seconds) and client returning
7
- # Google::Apis::ClientError: badRequest if the metric hasn't yet been created instead of a 404.
8
- RETRIABLE_TRIES = 3
9
- RETRIABLE_BASE_INTERVAL = 50
4
+ # This module has a decent amount of retry wrappers as the Stackdriver API
5
+ # can be quite slow with metric propagation (sometimes 80+ seconds) and client
6
+ # returning errors, e.g. Google::Apis::ClientError: badRequest if the metric
7
+ # hasn't yet been created instead of a 404.
8
+
10
9
  TEST_METRIC_PREFIX = "custom.googleapis.com/fog-google-test/timeseries".freeze
11
10
  LABEL_DESCRIPTORS = [
12
11
  {
@@ -51,10 +50,7 @@ class TestMetricDescriptors < FogIntegrationTest
51
50
  assert_empty(resp.to_h)
52
51
 
53
52
  # Wait for metric to be created
54
- # TODO: Dedup retries into a helper method
55
- Retriable.retriable(on: Google::Apis::ClientError,
56
- tries: RETRIABLE_TRIES,
57
- base_interval: RETRIABLE_BASE_INTERVAL) do
53
+ retry_on(Google::Apis::ClientError) do
58
54
  @client.list_timeseries(
59
55
  :filter => "metric.type = \"#{metric_type}\"",
60
56
  :interval => {
@@ -67,9 +63,7 @@ class TestMetricDescriptors < FogIntegrationTest
67
63
  ).time_series
68
64
  end
69
65
 
70
- series = Retriable.retriable(on: Google::Apis::ClientError,
71
- tries: RETRIABLE_TRIES,
72
- base_interval: RETRIABLE_BASE_INTERVAL) do
66
+ series = retry_on(Google::Apis::ClientError) do
73
67
  @client.timeseries_collection.all(
74
68
  :filter => "metric.type = \"#{metric_type}\"",
75
69
  :interval => {
@@ -115,9 +109,7 @@ class TestMetricDescriptors < FogIntegrationTest
115
109
  _some_timeseries(start_time, metric_type, labels)
116
110
  end
117
111
 
118
- Retriable.retriable(on: Google::Apis::ServerError,
119
- tries: RETRIABLE_TRIES,
120
- base_interval: RETRIABLE_BASE_INTERVAL) do
112
+ retry_on(Google::Apis::ServerError) do
121
113
  @client.create_timeseries(:timeseries => timeseries)
122
114
  end
123
115
  interval = {
@@ -132,9 +124,7 @@ class TestMetricDescriptors < FogIntegrationTest
132
124
  # Wait for metric to be created
133
125
  # Retriable is used instead of wait_for due to API client returning Google::Apis::ClientError: badRequest if the
134
126
  # metric hasn't yet been created
135
- Retriable.retriable(on: Google::Apis::ClientError,
136
- tries: RETRIABLE_TRIES,
137
- base_interval: RETRIABLE_BASE_INTERVAL) do
127
+ retry_on(Google::Apis::ClientError) do
138
128
  @client.list_timeseries(
139
129
  :filter => "metric.type = \"#{metric_type}\"",
140
130
  :interval => interval
@@ -142,9 +132,7 @@ class TestMetricDescriptors < FogIntegrationTest
142
132
  end
143
133
 
144
134
  # Test page size
145
- resp = Retriable.retriable(on: Google::Apis::ClientError,
146
- tries: RETRIABLE_TRIES,
147
- base_interval: RETRIABLE_BASE_INTERVAL) do
135
+ resp = retry_on(Google::Apis::ClientError) do
148
136
  @client.list_timeseries(
149
137
  :filter => "metric.type = \"#{metric_type}\"",
150
138
  :interval => interval,
@@ -170,9 +158,7 @@ class TestMetricDescriptors < FogIntegrationTest
170
158
  "expected different timeseries when using page_token")
171
159
 
172
160
  # Test filter
173
- series = Retriable.retriable(on: Google::Apis::ClientError,
174
- tries: RETRIABLE_TRIES,
175
- base_interval: RETRIABLE_BASE_INTERVAL) do
161
+ series = retry_on(Google::Apis::ClientError) do
176
162
  @client.timeseries_collection.all(
177
163
  :filter => %[
178
164
  metric.type = "#{metric_type}" AND