fog-google 1.3.3 → 1.4.0

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