fog-google 1.3.3 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +1 -5
  4. data/.travis.yml +3 -0
  5. data/CHANGELOG.md +79 -0
  6. data/CONTRIBUTING.md +9 -10
  7. data/README.md +5 -5
  8. data/ci/README.md +5 -10
  9. data/ci/credentials.yml.template +28 -0
  10. data/ci/pipeline.yml +72 -11
  11. data/ci/tasks/run-int.sh +2 -1
  12. data/ci/tasks/run-int.yml +1 -0
  13. data/examples/create_instance.rb +4 -4
  14. data/examples/get_list_images.rb +1 -1
  15. data/examples/load-balance.rb +1 -1
  16. data/examples/metadata.rb +1 -1
  17. data/examples/network.rb +1 -1
  18. data/examples/storage_json.rb +1 -1
  19. data/fog-google.gemspec +3 -1
  20. data/lib/fog/compute/google.rb +2 -0
  21. data/lib/fog/compute/google/mock.rb +0 -19
  22. data/lib/fog/compute/google/models/disk.rb +12 -5
  23. data/lib/fog/compute/google/models/instance_group.rb +4 -0
  24. data/lib/fog/compute/google/models/network.rb +8 -2
  25. data/lib/fog/compute/google/models/server.rb +28 -4
  26. data/lib/fog/compute/google/models/servers.rb +1 -0
  27. data/lib/fog/compute/google/models/subnetworks.rb +1 -1
  28. data/lib/fog/compute/google/models/target_pool.rb +12 -1
  29. data/lib/fog/compute/google/requests/insert_disk.rb +12 -5
  30. data/lib/fog/compute/google/requests/insert_server.rb +6 -1
  31. data/lib/fog/compute/google/requests/insert_url_map.rb +12 -1
  32. data/lib/fog/compute/google/requests/set_server_metadata.rb +2 -0
  33. data/lib/fog/google/shared.rb +1 -2
  34. data/lib/fog/google/version.rb +1 -1
  35. data/lib/fog/storage/google_json/models/file.rb +31 -1
  36. data/lib/fog/storage/google_json/requests/put_object.rb +22 -12
  37. data/lib/fog/storage/google_xml/models/directory.rb +2 -3
  38. data/lib/fog/storage/google_xml/models/file.rb +2 -13
  39. data/lib/fog/storage/google_xml/requests/put_bucket.rb +1 -1
  40. data/lib/fog/storage/google_xml/requests/put_object.rb +1 -1
  41. data/lib/fog/storage/google_xml/requests/put_object_acl.rb +11 -2
  42. data/lib/fog/storage/google_xml/utils.rb +11 -0
  43. data/tasks/test.rake +63 -1
  44. data/test/integration/compute/addresses/addresses_shared.rb +1 -1
  45. data/test/integration/compute/test_compute_addresses_collection.rb +4 -3
  46. data/test/integration/compute/test_compute_networks_collection.rb +9 -6
  47. data/test/integration/compute/test_servers.rb +9 -0
  48. data/test/integration/compute/test_target_pools.rb +22 -0
  49. data/test/integration/factories/collection_factory.rb +1 -1
  50. data/test/integration/monitoring/test_timeseries.rb +78 -28
  51. data/test/integration/storage/test_files.rb +1 -1
  52. data/test/integration/storage/test_objects.rb +6 -0
  53. data/test/integration/test_authentication.rb +0 -18
  54. data/test/unit/compute/test_common_collections.rb +31 -0
  55. data/test/unit/compute/test_common_models.rb +36 -0
  56. metadata +39 -6
  57. data/ci/credentials.yml.tpl +0 -13
@@ -23,7 +23,7 @@ def test
23
23
 
24
24
  puts "Fetching a single image from a global project..."
25
25
  puts "------------------------------------------------"
26
- img = connection.images.get("debian-8-jessie-v20161215")
26
+ img = connection.images.get("debian-8-jessie-v20180329")
27
27
  raise "Could not GET the image" unless img
28
28
  puts img.inspect
29
29
 
@@ -24,7 +24,7 @@ def test
24
24
  :name => "#{name}-#{i}",
25
25
  :size_gb => 10,
26
26
  :zone_name => zone,
27
- :source_image => "debian-8-jessie-v20160718"
27
+ :source_image => "debian-8-jessie-v20180329"
28
28
  )
29
29
  disk.wait_for { disk.ready? }
30
30
  rescue
data/examples/metadata.rb CHANGED
@@ -15,7 +15,7 @@ def test
15
15
  :name => name,
16
16
  :size_gb => 10,
17
17
  :zone_name => "us-central1-f",
18
- :source_image => "debian-8-jessie-v20161215"
18
+ :source_image => "debian-8-jessie-v20180329"
19
19
  )
20
20
 
21
21
  disk.wait_for { disk.ready? }
data/examples/network.rb CHANGED
@@ -24,7 +24,7 @@ def test
24
24
  :name => name,
25
25
  :size_gb => 10,
26
26
  :zone_name => "us-central1-a",
27
- :source_image => "debian-8-jessie-v20161215"
27
+ :source_image => "debian-8-jessie-v20180329"
28
28
  )
29
29
 
30
30
  disk.wait_for { disk.ready? }
@@ -15,7 +15,7 @@ def test
15
15
 
16
16
  puts "Put a bucket..."
17
17
  puts "----------------"
18
- connection.put_bucket("fog-smoke-test", options = { "predefinedAcl" => "publicReadWrite" })
18
+ connection.put_bucket("fog-smoke-test", predefined_acl: "publicReadWrite")
19
19
 
20
20
  puts "Get the bucket..."
21
21
  puts "-----------------"
data/fog-google.gemspec CHANGED
@@ -25,14 +25,16 @@ Gem::Specification.new do |spec|
25
25
  spec.add_dependency "fog-xml"
26
26
 
27
27
  # Hard Requirement as of 1.0
28
- spec.add_dependency "google-api-client", "~> 0.19.1"
28
+ spec.add_dependency "google-api-client", "~> 0.23.0"
29
29
 
30
30
  spec.add_development_dependency "coveralls"
31
31
  spec.add_development_dependency "mime-types"
32
32
  spec.add_development_dependency "minitest"
33
33
  spec.add_development_dependency "osrcry"
34
34
  spec.add_development_dependency "pry"
35
+ spec.add_development_dependency "pry-byebug"
35
36
  spec.add_development_dependency "rake"
37
+ spec.add_development_dependency "retriable"
36
38
  spec.add_development_dependency "rubocop"
37
39
  spec.add_development_dependency "shindo"
38
40
  spec.add_development_dependency "vcr"
@@ -26,8 +26,10 @@ module Fog
26
26
  https://www.googleapis.com/auth/ndev.cloudman
27
27
  https://www.googleapis.com/auth/cloud-platform).freeze
28
28
  GOOGLE_COMPUTE_DEFAULT_NETWORK = "default".freeze
29
+ # TODO: Do we need those constants?
29
30
  RUNNING = "RUNNING".freeze
30
31
  PROVISIONING = "PROVISIONING".freeze
32
+ STAGING = "STAGING".freeze
31
33
 
32
34
  request_path "fog/compute/google/requests"
33
35
  request :add_backend_service_backends
@@ -181,25 +181,6 @@ module Fog
181
181
 
182
182
  }
183
183
  },
184
- :backend_services => {
185
- "test-backend-service" => {
186
- "kind" => "compute#backend_service",
187
- "id" => "1361932147851415729",
188
- "creationTimestamp" => "2014-08-23T10:06:13.951-07:00",
189
- "name" => "test-backend-service",
190
- "description" => "",
191
- "backends" => [
192
- {
193
- "description" => "",
194
- "group" => "https://www.googleapis.com/resourceviews/v1beta1/projects#{@project}/zones/us-central1-a/zoneViews/name",
195
- "balancingMode" => "RATE",
196
- "capacityScaler" => 1.1,
197
- "maxRate" => 0.5
198
- }
199
- ],
200
- "selfLink" => "https://www.googleapis.com/compute/#{api_version}/projects/#{@project}/global/backendServices/test-backend-service"
201
- }
202
- },
203
184
  :servers => {
204
185
  "fog-1" => {
205
186
  "kind" => "compute#instance",
@@ -33,14 +33,21 @@ module Fog
33
33
 
34
34
  options = {
35
35
  :description => description || default_description,
36
- :source_image => source_image,
37
- :source_snapshot => source_snapshot,
38
- :size_gb => size_gb,
39
36
  :type => type,
40
- :zone => zone
37
+ :size_gb => size_gb,
38
+ :source_image => source_image,
39
+ :source_snapshot => source_snapshot
41
40
  }
42
41
 
43
- data = service.insert_disk(name, zone, source_image, options)
42
+ if options[:source_image]
43
+ unless source_image.include?("projects/")
44
+ options[:source_image] = service.images.get(source_image).self_link
45
+ end
46
+ end
47
+
48
+ # Request needs backward compatibility so source image is specified in
49
+ # method arguments
50
+ data = service.insert_disk(name, zone, options[:source_image], options)
44
51
  operation = Fog::Compute::Google::Operations.new(:service => service)
45
52
  .get(data.name, data.zone)
46
53
  operation.wait_for { !pending? }
@@ -33,6 +33,10 @@ module Fog
33
33
  service.delete_instance_group(name, zone_name)
34
34
  end
35
35
 
36
+ def add_instance(instance_id)
37
+ add_instances [instance_id]
38
+ end
39
+
36
40
  def add_instances(instances)
37
41
  requires :identity, :zone
38
42
 
@@ -11,8 +11,10 @@ module Fog
11
11
  attribute :auto_create_subnetworks, aliases => "autoCreateSubnetworks"
12
12
  attribute :creation_timestamp, aliases => "creationTimestamp"
13
13
  attribute :description
14
- attribute :gateway_ipv4, aliases => %w(gateway_i_pv4 gatewayIPv4)
15
- attribute :ipv4_range, aliases => %w(i_pv4_range IPv4Range)
14
+ # TODO: Naming issue in the client lib, rename after this is resolved:
15
+ # https://github.com/google/google-api-ruby-client/issues/666
16
+ attribute :gateway_i_pv4, aliases => %w(gateway_ipv4 gatewayIPv4)
17
+ attribute :i_pv4_range, aliases => %w(ipv4_range IPv4Range)
16
18
  attribute :id
17
19
  attribute :kind
18
20
  attribute :peerings
@@ -20,6 +22,10 @@ module Fog
20
22
  attribute :self_link, aliases => "selfLink"
21
23
  attribute :subnetworks
22
24
 
25
+ # TODO: Naming issue in the client lib, rename after this is resolved:
26
+ # https://github.com/google/google-api-ruby-client/issues/666
27
+ alias_method :ipv4_range, :i_pv4_range
28
+
23
29
  def save
24
30
  requires :identity, :ipv4_range
25
31
 
@@ -145,7 +145,7 @@ module Fog
145
145
  attribute :tags
146
146
 
147
147
  # @return [String]
148
- attribute :zone
148
+ attribute :zone, :aliases => :zone_name
149
149
 
150
150
  GCE_SCOPE_ALIASES = {
151
151
  "default" => %w(
@@ -200,6 +200,14 @@ module Fog
200
200
  operation
201
201
  end
202
202
 
203
+ # Helper method that returns first public ip address
204
+ # for Fog::Compute::Server.ssh default behavior
205
+ #
206
+ # @return [String]
207
+ def public_ip_address
208
+ public_ip_addresses.first
209
+ end
210
+
203
211
  def public_ip_addresses
204
212
  addresses = []
205
213
  if network_interfaces.respond_to? :flat_map
@@ -342,15 +350,25 @@ module Fog
342
350
  reload
343
351
  end
344
352
 
353
+ # Set an instance metadata
354
+ #
355
+ # @param [Bool] async Perform the operation asyncronously
356
+ # @param [Hash] new_metadata A new metadata object
357
+ # Format: {'foo' => 'bar', 'baz'=>'foo'}
358
+ #
359
+ # @returns [Fog::Compute::Google::Server] server object
345
360
  def set_metadata(new_metadata = {}, async = true)
346
361
  requires :identity, :zone
347
362
 
348
- if new_metadata[:items] && new_metadata[:items].is_a?(Hash)
349
- new_metadata[:items] = new_metadata[:items].map { |k, v| { :key => k, :value => v } }
363
+ unless new_metadata.is_a?(Hash)
364
+ raise Fog::Errors::Error.new("Instance metadata should be a hash")
350
365
  end
351
366
 
367
+ # If metadata is presented in {'foo' => 'bar', 'baz'=>'foo'}
368
+ new_metadata_items = new_metadata.each.map { |k, v| { :key => k.to_s, :value => v.to_s } }
369
+
352
370
  data = service.set_server_metadata(
353
- identity, zone_name, metadata[:fingerprint], new_metadata
371
+ identity, zone_name, metadata[:fingerprint], new_metadata_items
354
372
  )
355
373
  operation = Fog::Compute::Google::Operations
356
374
  .new(:service => service)
@@ -376,6 +394,12 @@ module Fog
376
394
  status == PROVISIONING
377
395
  end
378
396
 
397
+ # Check if instance is Staging. On staging vs. provisioning difference:
398
+ # https://cloud.google.com/compute/docs/instances/checking-instance-status
399
+ def staging?
400
+ status == STAGING
401
+ end
402
+
379
403
  def ready?
380
404
  status == RUNNING
381
405
  end
@@ -26,6 +26,7 @@ module Fog
26
26
  load(data)
27
27
  end
28
28
 
29
+ # TODO: This method needs to take self_links as well as names
29
30
  def get(identity, zone = nil)
30
31
  response = nil
31
32
  if zone
@@ -15,7 +15,7 @@ module Fog
15
15
  if region.nil?
16
16
  data = []
17
17
  service.list_aggregated_subnetworks(filters).to_h[:items].each_value do |region_obj|
18
- data.concat(region_obj["subnetworks"]) if region_obj["subnetworks"]
18
+ data.concat(region_obj[:subnetworks]) if region_obj[:subnetworks]
19
19
  end
20
20
  else
21
21
  data = service.list_subnetworks(region, filters).to_h[:items]
@@ -97,6 +97,15 @@ module Fog
97
97
  # behavior returns health checks for all instances associated with
98
98
  # this check.
99
99
  # @returns [Hash<String, Array<Hash>>] a map of instance URL to health checks
100
+ #
101
+ # Example Hash:
102
+ # {
103
+ # "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-f/instances/myinstance"=>
104
+ # [{:health_state=>"UNHEALTHY",
105
+ # :instance=>"https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-f/instances/myinstance"
106
+ # }]
107
+ # }
108
+ #
100
109
  def get_health(instance_name = nil)
101
110
  requires :identity, :region
102
111
 
@@ -104,9 +113,11 @@ module Fog
104
113
  instance = service.servers.get(instance_name)
105
114
  data = service.get_target_pool_health(identity, region, instance.self_link)
106
115
  .to_h[:health_status] || []
107
- results = [instance.self_link, data]
116
+ results = [[instance.self_link, data]]
108
117
  else
109
118
  results = instances.map do |self_link|
119
+ # TODO: Improve the returned object, current is hard to navigate
120
+ # [{instance => @instance, health_state => "HEALTHY"}, ...]
110
121
  data = service.get_target_pool_health(identity, region, self_link)
111
122
  .to_h[:health_status] || []
112
123
  [self_link, data]
@@ -13,24 +13,31 @@ module Fog
13
13
  #
14
14
  # @param disk_name [String] Name of the disk to create
15
15
  # @param zone_name [String] Zone the disk reside in
16
- # @param image_name [String] Optional image name to create the disk from
16
+ # @param source_image [String] Optional self_link or family formatted url of the image to
17
+ # create the disk from, see https://cloud.google.com/compute/docs/reference/latest/disks/insert
17
18
  # @param opts [Hash] Optional hash of options
18
19
  # @option options [String] size_gb Number of GB to allocate to an empty disk
19
20
  # @option options [String] source_snapshot Snapshot to create the disk from
20
21
  # @option options [String] description Human friendly description of the disk
21
22
  # @option options [String] type URL of the disk type resource describing which disk type to use
22
- def insert_disk(disk_name, zone, image_name = nil,
23
+ # TODO: change source_image to keyword argument in 2.0 and properly deprecate
24
+ def insert_disk(disk_name, zone, source_image = nil,
23
25
  description: nil, type: nil, size_gb: nil,
24
26
  source_snapshot: nil, **_opts)
27
+
28
+ if source_image && !source_image.include?("projects/")
29
+ raise ArgumentError.new("source_image needs to be self-link formatted or specify a family")
30
+ end
31
+
25
32
  disk = ::Google::Apis::ComputeV1::Disk.new(
26
33
  :name => disk_name,
27
34
  :description => description,
28
35
  :type => type,
29
36
  :size_gb => size_gb,
30
- :source_snapshot => source_snapshot
37
+ :source_snapshot => source_snapshot,
38
+ :source_image => source_image
31
39
  )
32
- @compute.insert_disk(@project, zone.split("/")[-1], disk,
33
- :source_image => image_name)
40
+ @compute.insert_disk(@project, zone.split("/")[-1], disk)
34
41
  end
35
42
  end
36
43
  end
@@ -99,7 +99,12 @@ module Fog
99
99
  end
100
100
 
101
101
  if data[:tags]
102
- data[:tags] = ::Google::Apis::ComputeV1::Tags.new(options[:tags])
102
+ if options[:tags].is_a?(Array)
103
+ # Process classic tag notation, i.e. ["fog"]
104
+ data[:tags] = ::Google::Apis::ComputeV1::Tags.new({ :items => options[:tags] })
105
+ else
106
+ data[:tags] = ::Google::Apis::ComputeV1::Tags.new(options[:tags])
107
+ end
103
108
  end
104
109
 
105
110
  instance = ::Google::Apis::ComputeV1::Instance.new(data)
@@ -16,7 +16,18 @@ module Fog
16
16
  url_map_obj = ::Google::Apis::ComputeV1::UrlMap.new(
17
17
  url_map.merge(:name => url_map_name)
18
18
  )
19
- @compute.insert_url_map(@project, url_map_obj)
19
+ # HACK: Currently URL map insert may fail even though the backend
20
+ # service operation is done. Retriable is not used to not add another
21
+ # runtime dependency.
22
+ # TODO: Remove after that has been corrected.
23
+ begin
24
+ retries ||= 0
25
+ @compute.insert_url_map(@project, url_map_obj)
26
+ rescue ::Google::Apis::ClientError
27
+ Fog::Logger.warning("URL map insert failed, retrying...")
28
+ sleep 10
29
+ retry if (retries += 1) < 2
30
+ end
20
31
  end
21
32
  end
22
33
  end
@@ -18,6 +18,8 @@ module Fog
18
18
  # instance.reload
19
19
  # fingerprint = instance.metadata['fingerprint']
20
20
  # @param [Hash] metadata A new metadata object
21
+ # Should have the following structure:
22
+ # {:items=>[{:key=>"foo", :value=>"bar"}, {:key=>"baz", :value=>"foo"}]}
21
23
  #
22
24
  # @returns [::Google::Apis::ComputeV1::Operation] set operation
23
25
  def set_server_metadata(instance, zone, fingerprint, metadata_items = [])
@@ -42,12 +42,11 @@ module Fog
42
42
  require "google/apis/compute_#{Fog::Compute::Google::GOOGLE_COMPUTE_API_VERSION}"
43
43
  require "google/apis/dns_#{Fog::DNS::Google::GOOGLE_DNS_API_VERSION}"
44
44
  require "google/apis/pubsub_#{Fog::Google::Pubsub::GOOGLE_PUBSUB_API_VERSION}"
45
- require "google/apis/resourceviews_v1beta2"
46
45
  require "google/apis/sqladmin_#{Fog::Google::SQL::GOOGLE_SQL_API_VERSION}"
47
46
  require "google/apis/storage_#{Fog::Storage::GoogleJSON::GOOGLE_STORAGE_JSON_API_VERSION}"
48
47
  require "googleauth"
49
48
  rescue LoadError => error
50
- Fog::Logger.error("Please install the google-api-client (>= 0.9) gem before using this provider")
49
+ Fog::Errors::Error.new("Please install the google-api-client (>= 0.9) gem before using this provider")
51
50
  raise error
52
51
  end
53
52
 
@@ -1,5 +1,5 @@
1
1
  module Fog
2
2
  module Google
3
- VERSION = "1.3.3".freeze
3
+ VERSION = "1.4.0".freeze
4
4
  end
5
5
  end
@@ -26,6 +26,24 @@ module Fog
26
26
 
27
27
  # attribute :body
28
28
 
29
+ # https://cloud.google.com/storage/docs/access-control/lists#predefined-acls
30
+ VALID_PREDEFINED_ACLS = [
31
+ "authenticatedRead",
32
+ "bucketOwnerFullControl",
33
+ "bucketOwnerRead",
34
+ "private",
35
+ "projectPrivate",
36
+ "publicRead",
37
+ "publicReadWrite"
38
+ ].freeze
39
+
40
+ def predefined_acl=(new_predefined_acl)
41
+ unless VALID_PREDEFINED_ACLS.include?(new_predefined_acl)
42
+ raise ArgumentError.new("acl must be one of [#{VALID_PREDEFINED_ACLS.join(', ')}]")
43
+ end
44
+ @predefined_acl = new_predefined_acl
45
+ end
46
+
29
47
  def body
30
48
  last_modified && (file = collection.get(identity)) ? attributes[:body] ||= file.body : attributes[:body] ||= ""
31
49
  end
@@ -52,6 +70,17 @@ module Fog
52
70
  false
53
71
  end
54
72
 
73
+ def public=(new_public)
74
+ unless new_public.nil?
75
+ if new_public
76
+ @predefined_acl = "publicRead"
77
+ else
78
+ @predefined_acl = "projectPrivate"
79
+ end
80
+ end
81
+ new_public
82
+ end
83
+
55
84
  def public_url
56
85
  requires :directory, :key
57
86
  "https://storage.googleapis.com/#{directory.key}/#{key}"
@@ -60,7 +89,6 @@ module Fog
60
89
  FILE_INSERTABLE_FIELDS = %i(
61
90
  content_type
62
91
  predefined_acl
63
- acl
64
92
  cache_control
65
93
  content_disposition
66
94
  content_encoding
@@ -74,6 +102,8 @@ module Fog
74
102
  FILE_INSERTABLE_FIELDS.map { |k| [k, attributes[k]] }
75
103
  .reject { |pair| pair[1].nil? }
76
104
  ]
105
+
106
+ options[:predefined_acl] ||= @predefined_acl
77
107
 
78
108
  service.put_object(directory.key, key, body, options)
79
109
  self.content_length = Fog::Storage.get_body_size(body)