1
0
Fork 0
mirror of https://github.com/fog/fog.git synced 2022-11-09 13:51:43 -05:00

[google] Implement operation model

Check that server and disk destroy operation starts successfully
Implement get and delete requests
Handle 204 responses without body
Return excon response with same status as the api returned
Delete delete_operation api method that doesn't exist
Add mocks for operations and use them in disk and server
This commit is contained in:
Carlos Sanchez 2013-11-27 13:01:59 +01:00
parent a7c4ce3971
commit 8db39e3637
14 changed files with 270 additions and 43 deletions

View file

@ -29,13 +29,16 @@ module Fog
request :get_network
request :get_zone
request :get_snapshot
request :get_global_operation
request :get_zone_operation
request :delete_disk
request :delete_firewall
request :delete_image
request :delete_network
request :delete_operation
request :delete_server
request :delete_global_operation
request :delete_zone_operation
request :insert_disk
request :insert_firewall
@ -59,6 +62,9 @@ module Fog
model :disk
collection :disks
model :operation
collection :operations
model :snapshot
collection :snapshots
@ -73,10 +79,10 @@ module Fog
@api_version = 'v1beta16'
end
def build_excon_response(body)
def build_excon_response(body, status=200)
response = Excon::Response.new
response.body = body
if response.body["error"]
if response.body and response.body["error"]
response.status = response.body["error"]["code"]
msg = response.body["error"]["errors"].map{|error| error["message"]}.join(", ")
case response.status
@ -86,7 +92,7 @@ module Fog
raise Fog::Errors::Error.new(msg)
end
else
response.status = 200
response.status = status
end
response
end
@ -763,7 +769,8 @@ module Fog
}
end,
:images => {},
:disks => {}
:disks => {},
:operations => {}
}
end
end
@ -782,6 +789,9 @@ module Fog
self.class.data(api_version).delete(@project)
end
def random_operation
"operation-#{Fog::Mock.random_numbers(13)}-#{Fog::Mock.random_hex(13)}-#{Fog::Mock.random_hex(8)}"
end
end
class Real
@ -842,7 +852,7 @@ module Fog
# result = Google::APIClient::Result
# returns Excon::Response
def build_response(result)
build_excon_response(Fog::JSON.decode(result.body))
build_excon_response(result.body.nil? ? nil : Fog::JSON.decode(result.body), result.status)
end
end

View file

@ -38,7 +38,13 @@ module Fog
def destroy
requires :name, :zone_name
service.delete_disk(name, zone_name)
operation = service.delete_disk(name, zone_name)
# wait until "RUNNING" or "DONE" to ensure the operation doesn't fail, raises exception on error
Fog.wait_for do
operation = service.get_zone_operation(zone_name, operation.body["name"])
operation.body["status"] != "PENDING"
end
operation
end
def zone

View file

@ -0,0 +1,42 @@
require 'fog/core/model'
module Fog
module Compute
class Google
class Operation < Fog::Model
identity :name
attribute :kind, :aliases => 'kind'
attribute :id, :aliases => 'id'
attribute :creation_timestamp, :aliases => 'creationTimestamp'
attribute :zone_name, :aliases => 'zone'
attribute :status, :aliases => 'status'
attribute :self_link, :aliases => 'selfLink'
def ready?
self.status == DONE_STATE
end
def pending?
self.status == PENDING_STATE
end
def reload
requires :identity
data = collection.get(identity, zone)
new_attributes = data.attributes
merge_attributes(new_attributes)
self
end
PENDING_STATE = "PENDING"
RUNNING_STATE = "RUNNING"
DONE_STATE = "DONE"
end
end
end
end

View file

@ -0,0 +1,26 @@
require 'fog/core/collection'
require 'fog/google/models/compute/operation'
module Fog
module Compute
class Google
class Operations < Fog::Collection
model Fog::Compute::Google::Operation
def get(identity, zone=nil)
if zone.nil?
response = service.get_global_operation(identity)
else
response = service.get_zone_operation(zone, identity)
end
return nil if response.nil?
new(response.body)
end
end
end
end
end

View file

@ -30,7 +30,13 @@ module Fog
def destroy
requires :name, :zone
service.delete_server(name, zone)
operation = service.delete_server(name, zone)
# wait until "RUNNING" or "DONE" to ensure the operation doesn't fail, raises exception on error
Fog.wait_for do
operation = service.get_zone_operation(zone_name, operation.body["name"])
operation.body["status"] != "PENDING"
end
operation
end
def image

View file

@ -6,23 +6,26 @@ module Fog
def delete_disk(disk_name, zone_name)
get_disk(disk_name, zone_name)
self.data[:disks].delete disk_name
build_response(:body => {
operation = self.random_operation
self.data[:operations][operation] = {
"kind" => "compute#operation",
"id" => "7145812689701515415",
"name" => "operation-1385125998242-4ebc3c7173e70-11e1ad0b",
"id" => Fog::Mock.random_numbers(19).to_s,
"name" => operation,
"zone" => "https://www.googleapis.com/compute/#{api_version}/projects/#{@project}/zones/#{zone_name}",
"operationType" => "delete",
"targetLink" => "https://www.googleapis.com/compute/#{api_version}/projects/#{@project}/zones/#{zone_name}/disks/#{disk_name}",
"targetId" => "6817095360746367667",
"status" => "PENDING",
"targetId" => self.data[:disks][disk_name]["id"],
"status" => Fog::Compute::Google::Operation::PENDING_STATE,
"user" => "123456789012-qwertyuiopasdfghjkl1234567890qwe@developer.gserviceaccount.com",
"progress" => 0,
"insertTime" => Time.now.iso8601,
"startTime" => Time.now.iso8601,
"selfLink" => "https://www.googleapis.com/compute/#{api_version}/projects/#{@project}/zones/#{zone_name}/operations/operation-1385125998242-4ebc3c7173e70-11e1ad0b"
})
"selfLink" => "https://www.googleapis.com/compute/#{api_version}/projects/#{@project}/zones/#{zone_name}/operations/#{operation}"
}
self.data[:disks].delete disk_name
build_response(:body => self.data[:operations][operation])
end
end

View file

@ -0,0 +1,29 @@
module Fog
module Compute
class Google
class Mock
def delete_global_operation(operation)
Fog::Mock.not_implemented
end
end
class Real
# https://developers.google.com/compute/docs/reference/latest/globalOperations
def delete_global_operation(operation)
api_method = @compute.global_operations.delete
parameters = {
'project' => @project,
'operation' => operation
}
result = self.build_result(api_method, parameters)
response = self.build_response(result)
end
end
end
end
end

View file

@ -28,21 +28,25 @@ module Fog
server = self.data[:servers][server_name]
server["status"] = "STOPPED"
server["mock-deletionTimestamp"] = Time.now.iso8601
build_response(:body => {
operation = self.random_operation
self.data[:operations][operation] = {
"kind" => "compute#operation",
"id" => "10035781241131638365",
"name" => "operation-1380213292196-4e74bf2fbc3c1-ae707d47",
"id" => Fog::Mock.random_numbers(19).to_s,
"name" => operation,
"zone" => "https://www.googleapis.com/compute/#{api_version}/projects/#{@project}/zones/#{zone_name}",
"operationType" => "delete",
"targetLink" => "https://www.googleapis.com/compute/#{api_version}/projects/#{@project}/zones/#{zone_name}/instances/#{server_name}",
"targetId" => "14544909043643897380",
"status" => "PENDING",
"targetId" => self.data[:servers][server_name]["id"],
"status" => Fog::Compute::Google::Operation::PENDING_STATE,
"user" => "123456789012-qwertyuiopasdfghjkl1234567890qwe@developer.gserviceaccount.com",
"progress" => 0,
"insertTime" => Time.now.iso8601,
"startTime" => Time.now.iso8601,
"selfLink" => "https://www.googleapis.com/compute/#{api_version}/projects/#{@project}/zones/#{zone_name}/operations/operation-1380213292196-4e74bf2fbc3c1-ae707d47"
})
"selfLink" => "https://www.googleapis.com/compute/#{api_version}/projects/#{@project}/zones/#{zone_name}/operations/#{operation}"
}
build_response(:body => self.data[:operations][operation])
end
end

View file

@ -0,0 +1,33 @@
module Fog
module Compute
class Google
class Mock
def delete_zone_operation(zone, operation)
Fog::Mock.not_implemented
end
end
class Real
# https://developers.google.com/compute/docs/reference/latest/zoneOperations
def delete_zone_operation(zone_name, operation)
if zone_name.start_with? 'http'
zone_name = zone_name.split('/')[-1]
end
api_method = @compute.zone_operations.delete
parameters = {
'project' => @project,
'zone' => zone_name,
'operation' => operation
}
result = self.build_result(api_method, parameters)
response = self.build_response(result)
end
end
end
end
end

View file

@ -4,27 +4,26 @@ module Fog
class Mock
def delete_operation(operation_name)
def get_global_operation(operation)
Fog::Mock.not_implemented
end
end
class Real
# https://developers.google.com/compute/docs/reference/latest/globalOperations
def delete_operation(operation_name)
api_method = @compute.operations.delete
def get_global_operation(operation)
api_method = @compute.global_operations.get
parameters = {
'project' => @project,
'operation' => operation_name
'operation' => operation
}
result = self.build_result(api_method, parameters)
response = self.build_response(result)
end
end
end
end
end

View file

@ -0,0 +1,58 @@
module Fog
module Compute
class Google
class Mock
def get_zone_operation(zone_name, operation)
operation = self.data[:operations][operation]
if operation
case operation["status"]
when Fog::Compute::Google::Operation::PENDING_STATE
operation["status"] = Fog::Compute::Google::Operation::RUNNING_STATE
operation["progress"] = 50
else
operation["status"] = Fog::Compute::Google::Operation::DONE_STATE
operation["progress"] = 100
end
else
operation = {
"error" => {
"errors" => [
{
"domain" => "global",
"reason" => "notFound",
"message" => "The resource 'projects/#{project}/zones/#{zone_name}/operations/#{operation}' was not found"
}
],
"code" => 404,
"message" => "The resource 'projects/#{project}/zones/#{zone_name}/operations/#{operation}' was not found"
}
}
end
build_response(:body => operation)
end
end
class Real
# https://developers.google.com/compute/docs/reference/latest/zoneOperations
def get_zone_operation(zone_name, operation)
if zone_name.start_with? 'http'
zone_name = zone_name.split('/')[-1]
end
api_method = @compute.zone_operations.get
parameters = {
'project' => @project,
'zone' => zone_name,
'operation' => operation
}
result = self.build_result(api_method, parameters)
response = self.build_response(result)
end
end
end
end
end

View file

@ -16,9 +16,10 @@ module Fog
end
get_zone(zone_name)
id = Fog::Mock.random_numbers(19).to_s
self.data[:disks][disk_name] = {
"kind" => "compute#disk",
"id" => Fog::Mock.random_numbers(19),
"id" => id,
"creationTimestamp" => Time.now.iso8601,
"zone" => "https://www.googleapis.com/compute/#{api_version}/projects/#{@project}/zones/#{zone_name}",
"status" => "READY",
@ -27,20 +28,24 @@ module Fog
"selfLink" => "https://www.googleapis.com/compute/#{api_version}/projects/#{@project}/zones/#{zone_name}/disks/#{disk_name}"
}
build_response(:body => {
operation = self.random_operation
self.data[:operations][operation] = {
"kind" => "compute#operation",
"id" => "12498846269172327286",
"name" => "operation-1385124218076-4ebc35cfbe9f1-476486c5",
"id" => Fog::Mock.random_numbers(19).to_s,
"name" => operation,
"zone" => "https://www.googleapis.com/compute/#{api_version}/projects/#{@project}/zones/#{zone_name}",
"operationType" => "insert",
"targetLink" => "https://www.googleapis.com/compute/#{api_version}/projects/#{@project}/zones/#{zone_name}/disks/#{disk_name}",
"status" => "PENDING",
"targetId" => id,
"status" => Fog::Compute::Google::Operation::PENDING_STATE,
"user" => "123456789012-qwertyuiopasdfghjkl1234567890qwe@developer.gserviceaccount.com",
"progress" => 0,
"insertTime" => Time.now.iso8601,
"startTime" => Time.now.iso8601,
"selfLink" => "https://www.googleapis.com/compute/#{api_version}/projects/#{@project}/zones/#{zone_name}/operations/operation-1385124218076-4ebc35cfbe9f1-476486c5"
})
"selfLink" => "https://www.googleapis.com/compute/#{api_version}/projects/#{@project}/zones/#{zone_name}/operations/#{operation}"
}
build_response(:body => self.data[:operations][operation])
end
end

View file

@ -37,9 +37,10 @@ module Fog
end
get_zone(zone_name)
id = Fog::Mock.random_numbers(19).to_s
self.data[:servers][server_name] = {
"kind" => "compute#instance",
"id" => Fog::Mock.random_numbers(19),
"id" => id,
"creationTimestamp" => Time.now.iso8601,
"zone" => "https://www.googleapis.com/compute/#{api_version}/projects/#{@project}/zones/#{zone_name}",
"status" => "PROVISIONING",
@ -85,20 +86,24 @@ module Fog
"selfLink" => "https://www.googleapis.com/compute/#{api_version}/projects/#{@project}/zones/#{zone_name}/instances/#{server_name}"
}
build_response(:body => {
operation = self.random_operation
self.data[:operations][operation] = {
"kind" => "compute#operation",
"id" => "4639689000254420481",
"name" => "operation-1380213292196-4e74bf2fbc3c1-ae707d47",
"id" => Fog::Mock.random_numbers(19).to_s,
"name" => operation,
"zone" => "https://www.googleapis.com/compute/#{api_version}/projects/#{@project}/zones/#{zone_name}",
"operationType" => "insert",
"targetLink" => "https://www.googleapis.com/compute/#{api_version}/projects/#{@project}/zones/#{zone_name}/instances/#{server_name}",
"status" => "PENDING",
"targetId" => id,
"status" => Fog::Compute::Google::Operation::PENDING_STATE,
"user" => "123456789012-qwertyuiopasdfghjkl1234567890qwe@developer.gserviceaccount.com",
"progress" => 0,
"insertTime" => Time.now.iso8601,
"startTime" => Time.now.iso8601,
"selfLink" => "https://www.googleapis.com/compute/#{api_version}/projects/#{@project}/zones/#{zone_name}/operations/operation-1380213292196-4e74bf2fbc3c1-ae707d47"
})
"selfLink" => "https://www.googleapis.com/compute/#{api_version}/projects/#{@project}/zones/#{zone_name}/operations/#{operation}"
}
build_response(:body => self.data[:operations][operation])
end
end

View file

@ -11,6 +11,7 @@ module Fog
end
class Real
# https://developers.google.com/compute/docs/reference/latest/zoneOperations
def list_zone_operations(zone)
api_method = @compute.zone_operations.list