diff --git a/lib/fog/digitalocean/compute_v2.rb b/lib/fog/digitalocean/compute_v2.rb new file mode 100644 index 000000000..680d4c5ff --- /dev/null +++ b/lib/fog/digitalocean/compute_v2.rb @@ -0,0 +1,108 @@ +require 'fog/digitalocean/core' + +module Fog + module Compute + class DigitalOceanV2 < Fog::Service + requires :digitalocean_token + + model_path 'fog/digitalocean/models/compute_v2' + model :server + collection :servers + model :image + collection :images + model :region + collection :regions + model :flavor + collection :flavors + model :ssh_key + collection :ssh_keys + + request_path 'fog/digitalocean/requests/compute_v2' + request :change_kernel + request :create_server + request :create_ssh_key + request :delete_server + request :delete_ssh_key + request :disable_backups + request :enable_ipv6 + request :enable_private_networking + request :get_droplet_action + request :get_server_details + request :get_ssh_key + request :list_droplet_actions + request :list_flavors + request :list_images + request :list_regions + request :list_servers + request :list_ssh_keys + request :password_reset + request :power_cycle + request :power_off + request :power_on + request :reboot_server + request :rebuild + request :rename + request :resize + request :restore + request :shutdown + request :snapshot + request :update_ssh_key + request :upgrade + + + class Mock + def self.data + @data ||= Hash.new do |hash, key| + hash[key] = { + :servers => [], + :ssh_keys => [] + } + end + end + + def initialize(options={}) + @digitalocean_token = options[:digitalocean_token] + end + + def data + self.class.data[@digitalocean_token] + end + + def reset_data + self.class.data.delete(@digitalocean_token) + end + end + + class Real + def initialize(options={}) + digitalocean_token = options[:digitalocean_token] + persistent = false + options = { + headers: { + 'Authorization' => "Bearer #{digitalocean_token}", + } + } + @connection = Fog::Core::Connection.new 'https://api.digitalocean.com', persistent, options + end + + def request(params) + params[:headers] ||= {} + begin + response = @connection.request(params) + rescue Excon::Errors::HTTPStatusError => error + raise case error + when Excon::Errors::NotFound + Fog::Compute::Bluebox::NotFound.slurp(error) + else + error + end + end + unless response.body.empty? + response.body = Fog::JSON.decode(response.body) + end + response + end + end + end + end +end \ No newline at end of file diff --git a/lib/fog/digitalocean/models/compute_v2/flavor.rb b/lib/fog/digitalocean/models/compute_v2/flavor.rb new file mode 100644 index 000000000..e9a356dcd --- /dev/null +++ b/lib/fog/digitalocean/models/compute_v2/flavor.rb @@ -0,0 +1,17 @@ +module Fog + module Compute + class DigitalOceanV2 + class Flavor < Fog::Model + identity :slug + attribute :available + attribute :transfer + attribute :price_monthly + attribute :price_hourly + attribute :memory + attribute :vcpus + attribute :disk + attribute :regions + end + end + end +end \ No newline at end of file diff --git a/lib/fog/digitalocean/models/compute_v2/flavors.rb b/lib/fog/digitalocean/models/compute_v2/flavors.rb new file mode 100644 index 000000000..ef7316659 --- /dev/null +++ b/lib/fog/digitalocean/models/compute_v2/flavors.rb @@ -0,0 +1,14 @@ +module Fog + module Compute + class DigitalOceanV2 + class Flavors < Fog::Collection + model Fog::Compute::DigitalOceanV2::Flavor + + def all(filters = {}) + data = service.list_flavors.body["sizes"] + load(data) + end + end + end + end +end \ No newline at end of file diff --git a/lib/fog/digitalocean/models/compute_v2/image.rb b/lib/fog/digitalocean/models/compute_v2/image.rb new file mode 100644 index 000000000..5b594506d --- /dev/null +++ b/lib/fog/digitalocean/models/compute_v2/image.rb @@ -0,0 +1,17 @@ +module Fog + module Compute + class DigitalOceanV2 + class Image < Fog::Model + identity :id + attribute :name + attribute :type + attribute :distribution + attribute :slug + attribute :public + attribute :regions + attribute :min_disk_size + attribute :created_at + end + end + end +end \ No newline at end of file diff --git a/lib/fog/digitalocean/models/compute_v2/images.rb b/lib/fog/digitalocean/models/compute_v2/images.rb new file mode 100644 index 000000000..ae5e7ab77 --- /dev/null +++ b/lib/fog/digitalocean/models/compute_v2/images.rb @@ -0,0 +1,14 @@ +module Fog + module Compute + class DigitalOceanV2 + class Images < Fog::Collection + model Fog::Compute::DigitalOceanV2::Image + + def all(filters = {}) + data = service.list_images.body["images"] + load(data) + end + end + end + end +end \ No newline at end of file diff --git a/lib/fog/digitalocean/models/compute_v2/region.rb b/lib/fog/digitalocean/models/compute_v2/region.rb new file mode 100644 index 000000000..82a2fb529 --- /dev/null +++ b/lib/fog/digitalocean/models/compute_v2/region.rb @@ -0,0 +1,13 @@ +module Fog + module Compute + class DigitalOceanV2 + class Region < Fog::Model + identity :slug + attribute :name + attribute :sizes + attribute :available + attribute :features + end + end + end +end \ No newline at end of file diff --git a/lib/fog/digitalocean/models/compute_v2/regions.rb b/lib/fog/digitalocean/models/compute_v2/regions.rb new file mode 100644 index 000000000..e1a04996b --- /dev/null +++ b/lib/fog/digitalocean/models/compute_v2/regions.rb @@ -0,0 +1,14 @@ +module Fog + module Compute + class DigitalOceanV2 + class Regions < Fog::Collection + model Fog::Compute::DigitalOceanV2::Region + + def all(filters = {}) + data = service.list_regions.body["regions"] + load(data) + end + end + end + end +end \ No newline at end of file diff --git a/lib/fog/digitalocean/models/compute_v2/server.rb b/lib/fog/digitalocean/models/compute_v2/server.rb new file mode 100644 index 000000000..d62544f78 --- /dev/null +++ b/lib/fog/digitalocean/models/compute_v2/server.rb @@ -0,0 +1,156 @@ +require 'fog/compute/models/server' + +module Fog + module Compute + class DigitalOceanV2 + # A DigitalOcean Droplet + # + class Server < Fog::Compute::Server + identity :id + attribute :name + attribute :memory + attribute :vcpus + attribute :disk + attribute :locked + attribute :created_at + attribute :status + attribute :backup_ids + attribute :snapshot_ids + attribute :features + attribute :region + attribute :image + attribute :size + attribute :size_slug + attribute :networks + attribute :kernel + attribute :next_backup_window + attribute :private_networking + attribute :backups + attribute :ipv6 + attribute :ssh_keys + + def public_ip_address + if (pub_net = networks['v4'].find { |n| n['type'] == 'public' }) + pub_net['ip_address'] + end + end + + def save + raise Fog::Errors::Error.new('Re-saving an existing object may create a duplicate') if persisted? + requires :name, :region, :size, :image + + options = {} + if attributes[:ssh_keys] + options[:ssh_keys] = attributes[:ssh_keys] + elsif @ssh_keys + options[:ssh_keys] = @ssh_keys.map(&:id) + end + + options[:private_networking] = private_networking + options[:backups] = backups + options[:ipv6] = ipv6 + + data = service.create_server(name, size, image, region, options) + + merge_attributes(data.body['droplet']) + true + end + + def delete + requires :id + response = service.delete_server id + response.body + end + + def ready? + status == 'active' + end + + def actions + requires :id + response = service.list_droplet_actions id + response.body + end + + def action(action_id) + requires :id + response = service.get_droplet_action(id, action_id) + response.body + end + + def reboot + perform_action :reboot_server + end + + def disable_backups + perform_action :disable_backups + end + + def power_cycle + perform_action :power_cycle + end + + def shutdown + perform_action :shutdown + end + + def power_off + perform_action :power_off + end + + def power_on + perform_action :power_on + end + + def restore(image) + perform_action :restore, image + end + + def password_reset + perform_action :password_reset + end + + def resize(resize_disk, size) + perform_action :resize, resize_disk, size + end + + def rebuild(image) + perform_action :rebuild, image + end + + def rename(name) + perform_action :rename, name + end + + def change_kernel(kernel) + perform_action :change_kernel, kernel + end + + def enable_ipv6 + perform_action :enable_ipv6 + end + + def enable_private_networking + perform_action :enable_private_networking + end + + def snapshot(name) + perform_action :snapshot, name + end + + def upgrade + perform_action :upgrade + end + + private + + # Performs a droplet action with the given set of arguments. + def perform_action(action, *args) + requires :id + response = service.send(action, id, *args) + response.body + end + end + end + end +end diff --git a/lib/fog/digitalocean/models/compute_v2/servers.rb b/lib/fog/digitalocean/models/compute_v2/servers.rb new file mode 100644 index 000000000..77e4e7372 --- /dev/null +++ b/lib/fog/digitalocean/models/compute_v2/servers.rb @@ -0,0 +1,26 @@ +require 'fog/core/collection' +require 'fog/digitalocean/models/compute/server' + +module Fog + module Compute + class DigitalOceanV2 + class Servers < Fog::Collection + model Fog::Compute::DigitalOceanV2::Server + + # Returns list of servers + def all(filters = {}) + data = service.list_servers.body['droplets'] + load(data) + end + + # Retrieves server + def get(id) + server = service.get_server_details(id).body['droplet'] + new(server) if server + rescue Fog::Errors::NotFound + nil + end + end + end + end +end diff --git a/lib/fog/digitalocean/models/compute_v2/ssh_key.rb b/lib/fog/digitalocean/models/compute_v2/ssh_key.rb new file mode 100644 index 000000000..105d9a2d7 --- /dev/null +++ b/lib/fog/digitalocean/models/compute_v2/ssh_key.rb @@ -0,0 +1,30 @@ +module Fog + module Compute + class DigitalOceanV2 + class SshKey < Fog::Model + identity :id + attribute :fingerprint + attribute :public_key + attribute :name + end + + def save + requires :name, :public_key + merge_attributes(service.create_ssh_key(name, public_key).body['ssh_key']) + true + end + + def destroy + requires :id + service.delete_ssh_key id + end + + def update + requires :id, :name + data = service.update_server(id, name) + merge_attributes(data.body['ssh_key']) + true + end + end + end +end \ No newline at end of file diff --git a/lib/fog/digitalocean/models/compute_v2/ssh_keys.rb b/lib/fog/digitalocean/models/compute_v2/ssh_keys.rb new file mode 100644 index 000000000..1f01eefbb --- /dev/null +++ b/lib/fog/digitalocean/models/compute_v2/ssh_keys.rb @@ -0,0 +1,21 @@ +module Fog + module Compute + class DigitalOceanV2 + class SshKeys < Fog::Collection + model Fog::Compute::DigitalOceanV2::SshKey + + def all(filters={}) + data = service.list_ssh_keys.body['ssh_keys'] + load(data) + end + + def get(id) + key = service.get_ssh_key(id).body['ssh_key'] + new(key) if key + rescue Fog::Errors::NotFound + nil + end + end + end + end +end \ No newline at end of file diff --git a/lib/fog/digitalocean/requests/compute_v2/change_kernel.rb b/lib/fog/digitalocean/requests/compute_v2/change_kernel.rb new file mode 100644 index 000000000..6f059eb64 --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/change_kernel.rb @@ -0,0 +1,44 @@ +module Fog + module Compute + class DigitalOceanV2 + class Real + def change_kernel(id, kernel) + body = { :type => "change_kernel", :kernel => kernel } + + encoded_body = Fog::JSON.encode(body) + + request( + :expects => [201], + :headers => { + 'Content-Type' => "application/json; charset=UTF-8", + }, + :method => 'POST', + :path => "v2/droplets/#{id}/actions", + :body => encoded_body, + ) + end + end + + class Mock + def change_kernel(id, kernel) + response = Excon::Response.new + response.status = 201 + response.body = { + 'action' => { + 'id' => Fog::Mock.random_numbers(1).to_i, + 'status' => "in-progress", + 'type' => "change_kernel", + 'started_at' => "2014-11-14T16:31:00Z", + 'completed_at' => null, + 'resource_id' => id, + 'resource_type' => "droplet", + 'region' => "nyc3", + 'region_slug' => "nyc3" + } + } + response + end + end + end + end +end diff --git a/lib/fog/digitalocean/requests/compute_v2/create_server.rb b/lib/fog/digitalocean/requests/compute_v2/create_server.rb new file mode 100644 index 000000000..49fa2d0ee --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/create_server.rb @@ -0,0 +1,93 @@ +module Fog + module Compute + class DigitalOceanV2 + # noinspection RubyStringKeysInHashInspection + class Real + + def create_server(name, + size, + image, + region, + options = {}) + + create_options = { + :name => name, + :region => region, + :size => size, + :image => image, + } + + [:backups, :ipv6, :private_networking].each do |opt| + create_options[opt] = !!options[opt] if options[opt] + end + + [:user_data, :ssh_keys].each do |opt| + create_options[opt] = options[opt] if options[opt] + end + + encoded_body = Fog::JSON.encode(create_options) + + request( + :expects => [202], + :headers => { + 'Content-Type' => "application/json; charset=UTF-8", + }, + :method => 'POST', + :path => '/v2/droplets', + :body => encoded_body, + ) + end + end + + # noinspection RubyStringKeysInHashInspection + class Mock + def create_server(name, + size, + image, + region, + options = {}) + + response = Excon::Response.new + response.status = 202 + + response.body = { + 'droplet' => { + 'id' => 3164494, + 'name' => name, + 'memory' => 512, + 'vcpus' => 1, + 'disk' => 20, + 'locked' => true, + 'status' => 'new', + 'kernel' => { + 'id' => 2233, + 'name' => 'Ubuntu 14.04 x64 vmlinuz-3.13.0-37-generic', + 'version' => '3.13.0-37-generic' + }, + 'created_at' => '2014-11-14T16:36:31Z', + 'features' => %w(virtio), + 'backup_ids' => [], + 'snapshot_ids' => [], + 'image' => {}, + 'size' => {}, + 'size_slug' => '512mb', + 'networks' => {}, + 'region' => {} + }, + 'links' => { + 'actions' => [ + { + 'id' => 36805096, + 'rel' => "create", + 'href' => "https://api.digitalocean.com/v2/actions/36805096" + } + ] + } + } + + response + end + end + end + end +end diff --git a/lib/fog/digitalocean/requests/compute_v2/create_ssh_key.rb b/lib/fog/digitalocean/requests/compute_v2/create_ssh_key.rb new file mode 100644 index 000000000..f6744fc96 --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/create_ssh_key.rb @@ -0,0 +1,47 @@ +module Fog + module Compute + class DigitalOceanV2 + # noinspection RubyStringKeysInHashInspection + class Real + + def create_ssh_key(name, public_key) + create_options = { + :name => name, + :public_key => public_key, + } + + encoded_body = Fog::JSON.encode(create_options) + + request( + :expects => [202], + :headers => { + 'Content-Type' => "application/json; charset=UTF-8", + }, + :method => 'POST', + :path => '/v2/account/keys', + :body => encoded_body, + ) + end + end + + # noinspection RubyStringKeysInHashInspection + class Mock + def create_server(name, public_key) + response = Excon::Response.new + response.status = 202 + + response.body ={ + 'ssh_key' => { + 'id' => 512190, + 'fingerprint' => "3b:16:bf:e4:8b:00:8b:b8:59:8c:a9:d3:f0:19:45:fa", + 'public_key' => "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAQQDDHr/jh2Jy4yALcK4JyWbVkPRaWmhck3IgCoeOO3z1e2dBowLh64QAM+Qb72pxekALga2oi4GvT+TlWNhzPH4V example", + 'name' => "My SSH Public Key" + } + } + + response + end + end + end + end +end diff --git a/lib/fog/digitalocean/requests/compute_v2/delete_server.rb b/lib/fog/digitalocean/requests/compute_v2/delete_server.rb new file mode 100644 index 000000000..c2c893e03 --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/delete_server.rb @@ -0,0 +1,26 @@ +module Fog + module Compute + class DigitalOceanV2 + # noinspection RubyStringKeysInHashInspection + class Real + def delete_server(server_id) + request( + :expects => [204], + :headers => { + 'Content-Type' => "application/json; charset=UTF-8", + }, + :method => 'DELETE', + :path => "/v2/droplets/#{server_id}", + ) + end + end + + # noinspection RubyStringKeysInHashInspection + class Mock + def delete_server(_) + response(:status => 204) + end + end + end + end +end \ No newline at end of file diff --git a/lib/fog/digitalocean/requests/compute_v2/delete_ssh_key.rb b/lib/fog/digitalocean/requests/compute_v2/delete_ssh_key.rb new file mode 100644 index 000000000..3fc25758c --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/delete_ssh_key.rb @@ -0,0 +1,26 @@ +module Fog + module Compute + class DigitalOceanV2 + # noinspection RubyStringKeysInHashInspection + class Real + def delete_ssh_key(id) + request( + :expects => [204], + :headers => { + 'Content-Type' => "application/json; charset=UTF-8", + }, + :method => 'DELETE', + :path => "/v2/account/keys#{id}", + ) + end + end + + # noinspection RubyStringKeysInHashInspection + class Mock + def delete_ssh_key(_) + response(:status => 204) + end + end + end + end +end \ No newline at end of file diff --git a/lib/fog/digitalocean/requests/compute_v2/disable_backups.rb b/lib/fog/digitalocean/requests/compute_v2/disable_backups.rb new file mode 100644 index 000000000..e432bb539 --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/disable_backups.rb @@ -0,0 +1,45 @@ +module Fog + module Compute + class DigitalOceanV2 + class Real + def disable_backups(id) + body = { :type => "disable_backups" } + + encoded_body = Fog::JSON.encode(body) + + request( + :expects => [201], + :headers => { + 'Content-Type' => "application/json; charset=UTF-8", + }, + :method => 'POST', + :path => "v2/droplets/#{id}/actions", + :body => encoded_body, + ) + end + end + + class Mock + def disable_backups(id) + response = Excon::Response.new + response.status = 201 + response.body = { + 'action' => { + 'id' => Fog::Mock.random_numbers(1).to_i, + 'status' => "in-progress", + 'type' => "disable_backups", + 'started_at' => "2014-11-14T16:31:00Z", + 'completed_at' => null, + 'resource_id' => id, + 'resource_type' => "droplet", + 'region' => "nyc3", + 'region_slug' => "nyc3" + } + } + response + end + end + end + end +end + diff --git a/lib/fog/digitalocean/requests/compute_v2/enable_ipv6.rb b/lib/fog/digitalocean/requests/compute_v2/enable_ipv6.rb new file mode 100644 index 000000000..3f532f8ab --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/enable_ipv6.rb @@ -0,0 +1,44 @@ +module Fog + module Compute + class DigitalOceanV2 + class Real + def enable_ipv6(id) + body = { :type => "enable_ipv6" } + + encoded_body = Fog::JSON.encode(body) + + request( + :expects => [201], + :headers => { + 'Content-Type' => "application/json; charset=UTF-8", + }, + :method => 'POST', + :path => "v2/droplets/#{id}/actions", + :body => encoded_body, + ) + end + end + + class Mock + def enable_ipv6(id) + response = Excon::Response.new + response.status = 201 + response.body = { + 'action' => { + 'id' => Fog::Mock.random_numbers(1).to_i, + 'status' => "in-progress", + 'type' => "enable_ipv6", + 'started_at' => "2014-11-14T16:31:00Z", + 'completed_at' => null, + 'resource_id' => id, + 'resource_type' => "droplet", + 'region' => "nyc3", + 'region_slug' => "nyc3" + } + } + response + end + end + end + end +end diff --git a/lib/fog/digitalocean/requests/compute_v2/enable_private_networking.rb b/lib/fog/digitalocean/requests/compute_v2/enable_private_networking.rb new file mode 100644 index 000000000..eb780e8ca --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/enable_private_networking.rb @@ -0,0 +1,44 @@ +module Fog + module Compute + class DigitalOceanV2 + class Real + def enable_private_networking(id) + body = { :type => "enable_private_networking" } + + encoded_body = Fog::JSON.encode(body) + + request( + :expects => [201], + :headers => { + 'Content-Type' => "application/json; charset=UTF-8", + }, + :method => 'POST', + :path => "v2/droplets/#{id}/actions", + :body => encoded_body, + ) + end + end + + class Mock + def enable_private_networking(id) + response = Excon::Response.new + response.status = 201 + response.body = { + 'action' => { + 'id' => Fog::Mock.random_numbers(1).to_i, + 'status' => "in-progress", + 'type' => "enable_private_networking", + 'started_at' => "2014-11-14T16:31:00Z", + 'completed_at' => null, + 'resource_id' => id, + 'resource_type' => "droplet", + 'region' => "nyc3", + 'region_slug' => "nyc3" + } + } + response + end + end + end + end +end diff --git a/lib/fog/digitalocean/requests/compute_v2/get_droplet_action.rb b/lib/fog/digitalocean/requests/compute_v2/get_droplet_action.rb new file mode 100644 index 000000000..af6e9fd68 --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/get_droplet_action.rb @@ -0,0 +1,36 @@ +module Fog + module Compute + class DigitalOceanV2 + class Real + def get_droplet_action(droplet_id, action_id) + request( + :expects => [200], + :method => 'GET', + :path => "v2/droplets/#{droplet_id}/actions/#{action_id}", + ) + end + end + + class Mock + def get_droplet_action(droplet_id, action) + response = Excon::Response.new + response.status = 201 + response.body = { + 'action' => { + 'id' => Fog::Mock.random_numbers(1).to_i, + 'status' => "in-progress", + 'type' => "change_kernel", + 'started_at' => "2014-11-14T16:31:00Z", + 'completed_at' => null, + 'resource_id' => id, + 'resource_type' => "droplet", + 'region' => "nyc3", + 'region_slug' => "nyc3" + } + } + response + end + end + end + end +end diff --git a/lib/fog/digitalocean/requests/compute_v2/get_server_details.rb b/lib/fog/digitalocean/requests/compute_v2/get_server_details.rb new file mode 100644 index 000000000..b50c3a59f --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/get_server_details.rb @@ -0,0 +1,84 @@ +module Fog + module Compute + class DigitalOceanV2 + class Real + def get_server_details(server_id) + request( + :expects => [200], + :method => 'GET', + :path => "/v2/droplets/#{server_id}" + ) + end + end + + # noinspection RubyStringKeysInHashInspection + class Mock + def get_server_details(_) + response = Excon::Response.new + response.status = 200 + + response.body = { + 'droplet' => { + 'id' => 3164494, + 'name' => 'example.com', + 'memory' => 512, + 'vcpus' => 1, + 'disk' => 20, + 'locked' => false, + 'status' => 'active', + 'kernel' => { + 'id' => 2233, + 'name' => 'Ubuntu 14.04 x64 vmlinuz-3.13.0-37-generic', + 'version' => '3.13.0-37-generic' + }, + 'created_at' => '2014-11-14T16:36:31Z', + 'features' => %w(ipv6 virtio), + 'backup_ids' => [], + 'snapshot_ids' => [7938206], + 'image' => { + 'id' => 6918990, + 'name' => '14.04 x64', + 'distribution' => 'Ubuntu', + 'slug' => 'ubuntu-14-04-x64', + 'public' => true, + 'regions' => %w(nyc1 ams1 sfo1 nyc2 ams2 sgp1 lon1 nyc3 ams3 nyc3), + 'created_at' => '2014-10-17T20:24:33Z', + 'type' => 'snapshot', + 'min_disk_size' => 20 + }, + 'size' => {}, + 'size_slug' => '512mb', + 'networks' => { + 'v4' => [ + { + 'ip_address' => '104.131.186.241', + 'netmask' => '255.255.240.0', + 'gateway' => '104.131.176.1', + 'type' => 'public' + } + ], + 'v6' => [ + { + 'ip_address' => '2604:A880:0800:0010:0000:0000:031D:2001', + 'netmask' => 64, + 'gateway' => '2604:A880:0800:0010:0000:0000:0000:0001', + 'type' => 'public' + } + ] + }, + 'region' => { + 'name' => 'New York 3', + 'slug' => 'nyc3', + 'sizes' => %w(32gb 16gb 2gb 1gb 4gb 8gb 512mb 64gb 48gb), + 'features' => %w(virtio private_networking backups ipv6 metadata), + 'available' => true + } + } + } + + response + end + end + end + end +end diff --git a/lib/fog/digitalocean/requests/compute_v2/get_ssh_key.rb b/lib/fog/digitalocean/requests/compute_v2/get_ssh_key.rb new file mode 100644 index 000000000..034d74573 --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/get_ssh_key.rb @@ -0,0 +1,34 @@ +module Fog + module Compute + class DigitalOceanV2 + class Real + def get_ssh_key(key_id) + request( + :expects => [200], + :method => 'GET', + :path => "/v2/account/keys/#{key_id}" + ) + end + end + + # noinspection RubyStringKeysInHashInspection + class Mock + def get_ssh_key(_) + response = Excon::Response.new + response.status = 200 + + response.body = { + 'ssh_key' => { + 'id' => 512190, + 'fingerprint' => '3b:16:bf:e4:8b:00:8b:b8:59:8c:a9:d3:f0:19:45:fa', + 'public_key' => 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAQQDDHr/jh2Jy4yALcK4JyWbVkPRaWmhck3IgCoeOO3z1e2dBowLh64QAM+Qb72pxekALga2oi4GvT+TlWNhzPH4V example', + 'name' => 'My SSH Public Key' + } + } + + response + end + end + end + end +end diff --git a/lib/fog/digitalocean/requests/compute_v2/list_droplet_actions.rb b/lib/fog/digitalocean/requests/compute_v2/list_droplet_actions.rb new file mode 100644 index 000000000..4f2b36995 --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/list_droplet_actions.rb @@ -0,0 +1,38 @@ +module Fog + module Compute + class DigitalOceanV2 + class Real + def list_droplet_actions(id) + request( + :expects => [200], + :method => 'GET', + :path => "v2/droplets/#{id}/actions", + ) + end + end + + class Mock + def list_droplet_actions(id) + response = Excon::Response.new + response.status = 201 + response.body = { + 'actions' => [ + 'action' => { + 'id' => Fog::Mock.random_numbers(1).to_i, + 'status' => "in-progress", + 'type' => "change_kernel", + 'started_at' => "2014-11-14T16:31:00Z", + 'completed_at' => null, + 'resource_id' => id, + 'resource_type' => "droplet", + 'region' => "nyc3", + 'region_slug' => "nyc3" + } + ] + } + response + end + end + end + end +end diff --git a/lib/fog/digitalocean/requests/compute_v2/list_flavors.rb b/lib/fog/digitalocean/requests/compute_v2/list_flavors.rb new file mode 100644 index 000000000..24b6789a0 --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/list_flavors.rb @@ -0,0 +1,131 @@ +module Fog + module Compute + class DigitalOceanV2 + class Real + def list_flavors + request( + :expects => [200], + :method => 'GET', + :path => '/v2/sizes' + ) + end + end + end + + # noinspection RubyStringKeysInHashInspection + class Mock + def list_flavors + response = Excon::Response.new + response.status = 200 + response.body = { + + 'sizes' => [ + { + 'slug' => '512mb', + 'memory' => 512, + 'vcpus' => 1, + 'disk' => 20, + 'transfer' => 1.0, + 'price_monthly' => 5.0, + 'price_hourly' => 0.00744, + 'regions' => %w(nyc1 sgp1 ams1 ams2 sfo1 nyc2 lon1 nyc3 ams3), + 'available' => true + }, + { + 'slug' => '1gb', + 'memory' => 1024, + 'vcpus' => 1, + 'disk' => 30, + 'transfer' => 2.0, + 'price_monthly' => 10.0, + 'price_hourly' => 0.01488, + 'regions' => %w(nyc2 sgp1 ams1 sfo1 lon1 nyc3 ams3 ams2 nyc1), + 'available' => true + }, + { + 'slug' => '2gb', + 'memory' => 2048, + 'vcpus' => 2, + 'disk' => 40, + 'transfer' => 3.0, + 'price_monthly' => 20.0, + 'price_hourly' => 0.02976, + 'regions' => %w(nyc2 sfo1 ams1 sgp1 ams2 lon1 nyc3 ams3 nyc1), + 'available' => true + }, + { + 'slug' => '4gb', + 'memory' => 4096, + 'vcpus' => 2, + 'disk' => 60, + 'transfer' => 4.0, + 'price_monthly' => 40.0, + 'price_hourly' => 0.05952, + 'regions' => %w(nyc2 sfo1 ams1 sgp1 ams2 lon1 nyc3 ams3 nyc1), + 'available' => true + }, + { + 'slug' => '8gb', + 'memory' => 8192, + 'vcpus' => 4, + 'disk' => 80, + 'transfer' => 5.0, + 'price_monthly' => 80.0, + 'price_hourly' => 0.11905, + 'regions' => %w(nyc2 sfo1 sgp1 ams1 ams2 nyc1 lon1 nyc3 ams3), + 'available' => true + }, + { + 'slug' => '16gb', + 'memory' => 16384, + 'vcpus' => 8, + 'disk' => 160, + 'transfer' => 6.0, + 'price_monthly' => 160.0, + 'price_hourly' => 0.2381, + 'regions' => %w(sgp1 nyc1 sfo1 ams2 nyc3 lon1 nyc2 ams1 ams3), + 'available' => true + }, + { + 'slug' => '32gb', + 'memory' => 32768, + 'vcpus' => 12, + 'disk' => 320, + 'transfer' => 7.0, + 'price_monthly' => 320.0, + 'price_hourly' => 0.47619, + 'regions' => %w(nyc2 sgp1 ams2 nyc1 sfo1 lon1 ams3 nyc3), + 'available' => true + }, + { + 'slug' => '48gb', + 'memory' => 49152, + 'vcpus' => 16, + 'disk' => 480, + 'transfer' => 8.0, + 'price_monthly' => 480.0, + 'price_hourly' => 0.71429, + 'regions' => %w(sgp1 ams2 sfo1 nyc1 lon1 nyc2 ams3 nyc3), + 'available' => true + }, + { + 'slug' => '64gb', + 'memory' => 65536, + 'vcpus' => 20, + 'disk' => 640, + 'transfer' => 9.0, + 'price_monthly' => 640.0, + 'price_hourly' => 0.95238, + 'regions' => %w(sgp1 nyc1 nyc2 sfo1 lon1 ams3 ams2 nyc3), + 'available' => true + } + ], + 'links' => {}, + 'meta' => {'total' => 9} + } + + response + end + end + end +end \ No newline at end of file diff --git a/lib/fog/digitalocean/requests/compute_v2/list_images.rb b/lib/fog/digitalocean/requests/compute_v2/list_images.rb new file mode 100644 index 000000000..da3b127cd --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/list_images.rb @@ -0,0 +1,50 @@ +module Fog + module Compute + class DigitalOceanV2 + class Real + def list_images + request( + :expects => [200], + :method => 'GET', + :path => '/v2/images' + ) + end + end + end + + # noinspection RubyStringKeysInHashInspection + class Mock + def list_images + response = Excon::Response.new + response.status = 200 + response.body = { + + 'images' => [ + { + 'id' => 7555620, + 'name' => 'Nifty New Snapshot', + 'distribution' => 'Ubuntu', + 'slug' => null, + 'public' => false, + 'regions' => %w(nyc2 nyc3), + 'created_at' => '2014-11-04T22:23:02Z', + 'type' => 'snapshot', + 'min_disk_size' => 20, + } + ], + 'links' => { + 'pages' => { + 'last' => 'https://api.digitalocean.com/v2/images?page=56&per_page=1', + 'next' => 'https://api.digitalocean.com/v2/images?page=2&per_page=1' + } + }, + 'meta' => { + 'total' => 56 + } + } + + response + end + end + end +end \ No newline at end of file diff --git a/lib/fog/digitalocean/requests/compute_v2/list_regions.rb b/lib/fog/digitalocean/requests/compute_v2/list_regions.rb new file mode 100644 index 000000000..324ede814 --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/list_regions.rb @@ -0,0 +1,94 @@ +module Fog + module Compute + class DigitalOceanV2 + class Real + def list_regions + request( + :expects => [200], + :method => 'GET', + :path => '/v2/regions' + ) + end + end + end + + # noinspection RubyStringKeysInHashInspection + class Mock + def list_images + response = Excon::Response.new + response.status = 200 + response.body = { + 'regions' => [ + { + 'name' => 'New York 1', + 'slug' => 'nyc1', + 'sizes' => [], + 'features' => %w(virtio backups), + 'available' => false + }, + { + 'name' => 'Amsterdam 1', + 'slug' => 'ams1', + 'sizes' => [], + 'features' => %w(virtio backups), + 'available' => false + }, + { + 'name' => 'San Francisco 1', + 'slug' => 'sfo1', + 'sizes' => %w(32gb 16gb 2gb 1gb 4gb 8gb 512mb 64gb 48gb), + 'features' => %w(virtio backups metadata), + 'available' => true + }, + { + 'name' => 'New York 2', + 'slug' => 'nyc2', + 'sizes' => %w(32gb 16gb 2gb 1gb 4gb 8gb 512mb 64gb 48gb), + 'features' => %w(virtio private_networking backups), + 'available' => true + }, + { + 'name' => 'Amsterdam 2', + 'slug' => 'ams2', + 'sizes' => %w(32gb 16gb 2gb 1gb 4gb 8gb 512mb 64gb 48gb), + 'features' => %w(virtio private_networking backups metadata), + 'available' => true + }, + { + 'name' => 'Singapore 1', + 'slug' => 'sgp1', + 'sizes' => %w(32gb 16gb 2gb 1gb 4gb 8gb 512mb 64gb 48gb), + 'features' => %w(virtio private_networking backups ipv6 metadata), + 'available' => true + }, + { + 'name' => 'London 1', + 'slug' => 'lon1', + 'sizes' => %w(32gb 16gb 2gb 1gb 4gb 8gb 512mb 64gb 48gb), + 'features' => %w(virtio private_networking backups ipv6 metadata), + 'available' => true + }, + { + 'name' => 'New York 3', + 'slug' => 'nyc3', + 'sizes' => %w(32gb 16gb 2gb 1gb 4gb 8gb 512mb 64gb 48gb), + 'features' => %w(virtio private_networking backups ipv6 metadata), + 'available' => true + }, + { + 'name' => 'Amsterdam 3', + 'slug' => 'ams3', + 'sizes' => %w(32gb 16gb 2gb 1gb 4gb 8gb 512mb 64gb 48gb), + 'features' => %w(virtio private_networking backups ipv6 metadata), + 'available' => true + } + ], + 'links' => {}, + 'meta' => {'total' => 9} + } + + response + end + end + end +end \ No newline at end of file diff --git a/lib/fog/digitalocean/requests/compute_v2/list_servers.rb b/lib/fog/digitalocean/requests/compute_v2/list_servers.rb new file mode 100644 index 000000000..fb57cfbad --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/list_servers.rb @@ -0,0 +1,28 @@ +module Fog + module Compute + class DigitalOceanV2 + class Real + def list_servers + request( + :expects => [200], + :method => 'GET', + :path => '/v2/droplets' + ) + end + end + + # noinspection RubyStringKeysInHashInspection + class Mock + def list_servers + response = Excon::Response.new + response.status = 200 + response.body = { + "status" => "OK", + "droplets" => self.data[:servers] + } + response + end + end + end + end +end \ No newline at end of file diff --git a/lib/fog/digitalocean/requests/compute_v2/list_ssh_keys.rb b/lib/fog/digitalocean/requests/compute_v2/list_ssh_keys.rb new file mode 100644 index 000000000..50adc7c83 --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/list_ssh_keys.rb @@ -0,0 +1,26 @@ +module Fog + module Compute + class DigitalOceanV2 + class Real + def list_ssh_keys + request( + :expects => [200], + :method => 'GET', + :path => 'v2/account/keys', + ) + end + end + + # noinspection RubyStringKeysInHashInspection + class Mock + def list_ssh_keys + response = Excon::Response.new + response.status = 200 + response.body = { + } + response + end + end + end + end +end \ No newline at end of file diff --git a/lib/fog/digitalocean/requests/compute_v2/password_reset.rb b/lib/fog/digitalocean/requests/compute_v2/password_reset.rb new file mode 100644 index 000000000..a74bea0ed --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/password_reset.rb @@ -0,0 +1,44 @@ +module Fog + module Compute + class DigitalOceanV2 + class Real + def password_reset(id) + body = { :type => "password_reset" } + + encoded_body = Fog::JSON.encode(body) + + request( + :expects => [201], + :headers => { + 'Content-Type' => "application/json; charset=UTF-8", + }, + :method => 'POST', + :path => "v2/droplets/#{id}/actions", + :body => encoded_body, + ) + end + end + + class Mock + def password_reset(id) + response = Excon::Response.new + response.status = 201 + response.body = { + 'action' => { + 'id' => Fog::Mock.random_numbers(1).to_i, + 'status' => "in-progress", + 'type' => "password_reset", + 'started_at' => "2014-11-14T16:31:00Z", + 'completed_at' => null, + 'resource_id' => id, + 'resource_type' => "droplet", + 'region' => "nyc3", + 'region_slug' => "nyc3" + } + } + response + end + end + end + end +end diff --git a/lib/fog/digitalocean/requests/compute_v2/power_cycle.rb b/lib/fog/digitalocean/requests/compute_v2/power_cycle.rb new file mode 100644 index 000000000..ea52da2f3 --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/power_cycle.rb @@ -0,0 +1,44 @@ +module Fog + module Compute + class DigitalOceanV2 + class Real + def power_cycle(id) + body = { :type => "power_cycle" } + + encoded_body = Fog::JSON.encode(body) + + request( + :expects => [201], + :headers => { + 'Content-Type' => "application/json; charset=UTF-8", + }, + :method => 'POST', + :path => "v2/droplets/#{id}/actions", + :body => encoded_body, + ) + end + end + + class Mock + def power_cycle(id) + response = Excon::Response.new + response.status = 201 + response.body = { + 'action' => { + 'id' => Fog::Mock.random_numbers(1).to_i, + 'status' => "in-progress", + 'type' => "power_cycle", + 'started_at' => "2014-11-14T16:31:00Z", + 'completed_at' => null, + 'resource_id' => id, + 'resource_type' => "droplet", + 'region' => "nyc3", + 'region_slug' => "nyc3" + } + } + response + end + end + end + end +end diff --git a/lib/fog/digitalocean/requests/compute_v2/power_off.rb b/lib/fog/digitalocean/requests/compute_v2/power_off.rb new file mode 100644 index 000000000..a81b41e19 --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/power_off.rb @@ -0,0 +1,44 @@ +module Fog + module Compute + class DigitalOceanV2 + class Real + def power_off(id) + body = { :type => "power_off" } + + encoded_body = Fog::JSON.encode(body) + + request( + :expects => [201], + :headers => { + 'Content-Type' => "application/json; charset=UTF-8", + }, + :method => 'POST', + :path => "v2/droplets/#{id}/actions", + :body => encoded_body, + ) + end + end + + class Mock + def power_off(id) + response = Excon::Response.new + response.status = 201 + response.body = { + 'action' => { + 'id' => Fog::Mock.random_numbers(1).to_i, + 'status' => "in-progress", + 'type' => "power_off", + 'started_at' => "2014-11-14T16:31:00Z", + 'completed_at' => null, + 'resource_id' => id, + 'resource_type' => "droplet", + 'region' => "nyc3", + 'region_slug' => "nyc3" + } + } + response + end + end + end + end +end diff --git a/lib/fog/digitalocean/requests/compute_v2/power_on.rb b/lib/fog/digitalocean/requests/compute_v2/power_on.rb new file mode 100644 index 000000000..5a7ca71cb --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/power_on.rb @@ -0,0 +1,44 @@ +module Fog + module Compute + class DigitalOceanV2 + class Real + def power_on(id) + body = { :type => "power_on" } + + encoded_body = Fog::JSON.encode(body) + + request( + :expects => [201], + :headers => { + 'Content-Type' => "application/json; charset=UTF-8", + }, + :method => 'POST', + :path => "v2/droplets/#{id}/actions", + :body => encoded_body, + ) + end + end + + class Mock + def power_on(id) + response = Excon::Response.new + response.status = 201 + response.body = { + 'action' => { + 'id' => Fog::Mock.random_numbers(1).to_i, + 'status' => "in-progress", + 'type' => "power_on", + 'started_at' => "2014-11-14T16:31:00Z", + 'completed_at' => null, + 'resource_id' => id, + 'resource_type' => "droplet", + 'region' => "nyc3", + 'region_slug' => "nyc3" + } + } + response + end + end + end + end +end diff --git a/lib/fog/digitalocean/requests/compute_v2/reboot_server.rb b/lib/fog/digitalocean/requests/compute_v2/reboot_server.rb new file mode 100644 index 000000000..ef0b67e09 --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/reboot_server.rb @@ -0,0 +1,44 @@ +module Fog + module Compute + class DigitalOceanV2 + class Real + def reboot_server(id) + body = { :type => "reboot" } + + encoded_body = Fog::JSON.encode(body) + + request( + :expects => [201], + :headers => { + 'Content-Type' => "application/json; charset=UTF-8", + }, + :method => 'POST', + :path => "v2/droplets/#{id}/actions", + :body => encoded_body, + ) + end + end + + class Mock + def reboot_server(id) + response = Excon::Response.new + response.status = 201 + response.body = { + 'action' => { + 'id' => Fog::Mock.random_numbers(1).to_i, + 'status' => "in-progress", + 'type' => "reboot", + 'started_at' => "2014-11-14T16:31:00Z", + 'completed_at' => null, + 'resource_id' => id, + 'resource_type' => "droplet", + 'region' => "nyc3", + 'region_slug' => "nyc3" + } + } + response + end + end + end + end +end diff --git a/lib/fog/digitalocean/requests/compute_v2/rebuild.rb b/lib/fog/digitalocean/requests/compute_v2/rebuild.rb new file mode 100644 index 000000000..8cf9a1c89 --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/rebuild.rb @@ -0,0 +1,44 @@ +module Fog + module Compute + class DigitalOceanV2 + class Real + def rebuild(id, image) + body = { :type => "rebuild", :image => image } + + encoded_body = Fog::JSON.encode(body) + + request( + :expects => [201], + :headers => { + 'Content-Type' => "application/json; charset=UTF-8", + }, + :method => 'POST', + :path => "v2/droplets/#{id}/actions", + :body => encoded_body, + ) + end + end + + class Mock + def rebuild(id, image) + response = Excon::Response.new + response.status = 201 + response.body = { + 'action' => { + 'id' => Fog::Mock.random_numbers(1).to_i, + 'status' => "in-progress", + 'type' => "rebuild", + 'started_at' => "2014-11-14T16:31:00Z", + 'completed_at' => null, + 'resource_id' => id, + 'resource_type' => "droplet", + 'region' => "nyc3", + 'region_slug' => "nyc3" + } + } + response + end + end + end + end +end diff --git a/lib/fog/digitalocean/requests/compute_v2/rename.rb b/lib/fog/digitalocean/requests/compute_v2/rename.rb new file mode 100644 index 000000000..3a6539787 --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/rename.rb @@ -0,0 +1,44 @@ +module Fog + module Compute + class DigitalOceanV2 + class Real + def rename(id, name) + body = { :type => "rename", :name => name } + + encoded_body = Fog::JSON.encode(body) + + request( + :expects => [201], + :headers => { + 'Content-Type' => "application/json; charset=UTF-8", + }, + :method => 'POST', + :path => "v2/droplets/#{id}/actions", + :body => encoded_body, + ) + end + end + + class Mock + def rename(id, name) + response = Excon::Response.new + response.status = 201 + response.body = { + 'action' => { + 'id' => Fog::Mock.random_numbers(1).to_i, + 'status' => "in-progress", + 'type' => "rename", + 'started_at' => "2014-11-14T16:31:00Z", + 'completed_at' => null, + 'resource_id' => id, + 'resource_type' => "droplet", + 'region' => "nyc3", + 'region_slug' => "nyc3" + } + } + response + end + end + end + end +end diff --git a/lib/fog/digitalocean/requests/compute_v2/resize.rb b/lib/fog/digitalocean/requests/compute_v2/resize.rb new file mode 100644 index 000000000..e0df5a1e3 --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/resize.rb @@ -0,0 +1,48 @@ +module Fog + module Compute + class DigitalOceanV2 + class Real + def resize(id, resize_disk, size) + body = { + :type => "resize", + :disk => resize_disk, + :size => size + } + + encoded_body = Fog::JSON.encode(body) + + request( + :expects => [201], + :headers => { + 'Content-Type' => "application/json; charset=UTF-8", + }, + :method => 'POST', + :path => "v2/droplets/#{id}/actions", + :body => encoded_body, + ) + end + end + + class Mock + def resize(id, resize_disk, size) + response = Excon::Response.new + response.status = 201 + response.body = { + 'action' => { + 'id' => Fog::Mock.random_numbers(1).to_i, + 'status' => "in-progress", + 'type' => "resize", + 'started_at' => "2014-11-14T16:31:00Z", + 'completed_at' => null, + 'resource_id' => id, + 'resource_type' => "droplet", + 'region' => "nyc3", + 'region_slug' => "nyc3" + } + } + response + end + end + end + end +end diff --git a/lib/fog/digitalocean/requests/compute_v2/restore.rb b/lib/fog/digitalocean/requests/compute_v2/restore.rb new file mode 100644 index 000000000..87bae13d2 --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/restore.rb @@ -0,0 +1,44 @@ +module Fog + module Compute + class DigitalOceanV2 + class Real + def restore(id, image) + body = { :type => "restore", :image => image } + + encoded_body = Fog::JSON.encode(body) + + request( + :expects => [201], + :headers => { + 'Content-Type' => "application/json; charset=UTF-8", + }, + :method => 'POST', + :path => "v2/droplets/#{id}/actions", + :body => encoded_body, + ) + end + end + + class Mock + def restore(id, image) + response = Excon::Response.new + response.status = 201 + response.body = { + 'action' => { + 'id' => Fog::Mock.random_numbers(1).to_i, + 'status' => "in-progress", + 'type' => "restore", + 'started_at' => "2014-11-14T16:31:00Z", + 'completed_at' => null, + 'resource_id' => id, + 'resource_type' => "droplet", + 'region' => "nyc3", + 'region_slug' => "nyc3" + } + } + response + end + end + end + end +end diff --git a/lib/fog/digitalocean/requests/compute_v2/shutdown.rb b/lib/fog/digitalocean/requests/compute_v2/shutdown.rb new file mode 100644 index 000000000..bf9f397d5 --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/shutdown.rb @@ -0,0 +1,44 @@ +module Fog + module Compute + class DigitalOceanV2 + class Real + def shutdown(id) + body = { :type => "shutdown" } + + encoded_body = Fog::JSON.encode(body) + + request( + :expects => [201], + :headers => { + 'Content-Type' => "application/json; charset=UTF-8", + }, + :method => 'POST', + :path => "v2/droplets/#{id}/actions", + :body => encoded_body, + ) + end + end + + class Mock + def shutdown(id) + response = Excon::Response.new + response.status = 201 + response.body = { + 'action' => { + 'id' => Fog::Mock.random_numbers(1).to_i, + 'status' => "in-progress", + 'type' => "shutdown", + 'started_at' => "2014-11-14T16:31:00Z", + 'completed_at' => null, + 'resource_id' => id, + 'resource_type' => "droplet", + 'region' => "nyc3", + 'region_slug' => "nyc3" + } + } + response + end + end + end + end +end diff --git a/lib/fog/digitalocean/requests/compute_v2/snapshot.rb b/lib/fog/digitalocean/requests/compute_v2/snapshot.rb new file mode 100644 index 000000000..4bc4bf42b --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/snapshot.rb @@ -0,0 +1,44 @@ +module Fog + module Compute + class DigitalOceanV2 + class Real + def snapshot(id, name) + body = { :type => "snapshot", :name => name } + + encoded_body = Fog::JSON.encode(body) + + request( + :expects => [201], + :headers => { + 'Content-Type' => "application/json; charset=UTF-8", + }, + :method => 'POST', + :path => "v2/droplets/#{id}/actions", + :body => encoded_body, + ) + end + end + + class Mock + def snapshot(id, name) + response = Excon::Response.new + response.status = 201 + response.body = { + 'action' => { + 'id' => Fog::Mock.random_numbers(1).to_i, + 'status' => "in-progress", + 'type' => "snapshot", + 'started_at' => "2014-11-14T16:31:00Z", + 'completed_at' => null, + 'resource_id' => id, + 'resource_type' => "droplet", + 'region' => "nyc3", + 'region_slug' => "nyc3" + } + } + response + end + end + end + end +end diff --git a/lib/fog/digitalocean/requests/compute_v2/update_ssh_key.rb b/lib/fog/digitalocean/requests/compute_v2/update_ssh_key.rb new file mode 100644 index 000000000..ac2d9de62 --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/update_ssh_key.rb @@ -0,0 +1,46 @@ +module Fog + module Compute + class DigitalOceanV2 + # noinspection RubyStringKeysInHashInspection + class Real + + def update_ssh_key(key_id, name) + update_options = { + :name => name, + } + + encoded_body = Fog::JSON.encode(update_options) + + request( + :expects => [200], + :headers => { + 'Content-Type' => "application/json; charset=UTF-8", + }, + :method => 'PUT', + :path => "/v2/account/keys/#{key_id}", + :body => encoded_body, + ) + end + end + + # noinspection RubyStringKeysInHashInspection + class Mock + def update_server(key_id, name) + response = Excon::Response.new + response.status = 200 + + response.body ={ + 'ssh_key' => { + 'id' => 512190, + 'fingerprint' => "3b:16:bf:e4:8b:00:8b:b8:59:8c:a9:d3:f0:19:45:fa", + 'public_key' => "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAQQDDHr/jh2Jy4yALcK4JyWbVkPRaWmhck3IgCoeOO3z1e2dBowLh64QAM+Qb72pxekALga2oi4GvT+TlWNhzPH4V example", + 'name' => "My SSH Public Key" + } + } + + response + end + end + end + end +end diff --git a/lib/fog/digitalocean/requests/compute_v2/upgrade.rb b/lib/fog/digitalocean/requests/compute_v2/upgrade.rb new file mode 100644 index 000000000..153721d67 --- /dev/null +++ b/lib/fog/digitalocean/requests/compute_v2/upgrade.rb @@ -0,0 +1,44 @@ +module Fog + module Compute + class DigitalOceanV2 + class Real + def upgrade(id) + body = { :type => "upgrade" } + + encoded_body = Fog::JSON.encode(body) + + request( + :expects => [201], + :headers => { + 'Content-Type' => "application/json; charset=UTF-8", + }, + :method => 'POST', + :path => "v2/droplets/#{id}/actions", + :body => encoded_body, + ) + end + end + + class Mock + def upgrade(id) + response = Excon::Response.new + response.status = 201 + response.body = { + 'action' => { + 'id' => Fog::Mock.random_numbers(1).to_i, + 'status' => "in-progress", + 'type' => "upgrade", + 'started_at' => "2014-11-14T16:31:00Z", + 'completed_at' => null, + 'resource_id' => id, + 'resource_type' => "droplet", + 'region' => "nyc3", + 'region_slug' => "nyc3" + } + } + response + end + end + end + end +end diff --git a/lib/fog/digitalocean/service.rb b/lib/fog/digitalocean/service.rb new file mode 100644 index 000000000..68da3e27a --- /dev/null +++ b/lib/fog/digitalocean/service.rb @@ -0,0 +1,51 @@ +module Fog + module DigitalOcean + class Service + + def request(params, parse_json = true) + first_attempt = true + begin + response = @connection.request(request_params(params)) + rescue Excon::Errors::Unauthorized => error + raise error unless first_attempt + first_attempt = false + authenticate + retry + end + + process_response(response) if parse_json + response + end + + private + + def process_response(response) + if response && + response.body && + response.body.is_a?(String) && + !response.body.strip.empty? + begin + response.body = Fog::JSON.decode(response.body) + rescue Fog::JSON::DecodeError => e + Fog::Logger.warning("Error Parsing response json - #{e}") + response.body = {} + end + end + end + + def headers(options={}) + {'Content-Type' => 'application/json', + 'Accept' => 'application/json', + }.merge(options[:headers] || {}) + end + + def request_params(params) + params.merge({ + :headers => headers(params), + :path => "#{params[:path]}" + }) + end + + end + end +end \ No newline at end of file diff --git a/tests/digitalocean/requests/compute_v2/list_flavors_tests.rb b/tests/digitalocean/requests/compute_v2/list_flavors_tests.rb new file mode 100644 index 000000000..ac2fe851d --- /dev/null +++ b/tests/digitalocean/requests/compute_v2/list_flavors_tests.rb @@ -0,0 +1,25 @@ +Shindo.tests('Fog::Compute::DigitalOceanV2 | list_flavors request', ['digitalocean', 'compute']) do + service = Fog::Compute.new(:provider => 'DigitalOcean', :version => 'V2') + + size_format = { + 'slug' => String, + 'memory' => Integer, + 'vcpus' => Integer, + 'disk' => Integer, + 'transfer' => Float, + 'price_monthly' => Float, + 'price_hourly' => Float, + 'regions' => Array, + 'available' => Fog::Boolean, + } + + tests('success') do + tests('#list_flavors') do + service.list_flavors.body['sizes'].each do |size| + tests('format').data_matches_schema(size_format) do + size + end + end + end + end +end \ No newline at end of file diff --git a/tests/digitalocean/requests/compute_v2/list_images_tests.rb b/tests/digitalocean/requests/compute_v2/list_images_tests.rb new file mode 100644 index 000000000..10b9459c1 --- /dev/null +++ b/tests/digitalocean/requests/compute_v2/list_images_tests.rb @@ -0,0 +1,25 @@ +Shindo.tests('Fog::Compute::DigitalOceanV2 | list_images request', ['digitalocean', 'compute']) do + service = Fog::Compute.new(:provider => 'DigitalOcean', :version => 'V2') + + image_format = { + 'id' => Integer, + 'name' => String, + 'type' => String, + 'distribution' => String, + 'slug' => Fog::Nullable::String, + 'public' => Fog::Boolean, + 'regions' => Array, + 'min_disk_size' => Fog::Nullable::Integer, + 'created_at' => String, + } + + tests('success') do + tests('#list_images') do + service.list_images.body['images'].each do |image| + tests('format').data_matches_schema(image_format) do + image + end + end + end + end +end \ No newline at end of file diff --git a/tests/digitalocean/requests/compute_v2/list_regions_tests.rb b/tests/digitalocean/requests/compute_v2/list_regions_tests.rb new file mode 100644 index 000000000..633921129 --- /dev/null +++ b/tests/digitalocean/requests/compute_v2/list_regions_tests.rb @@ -0,0 +1,21 @@ +Shindo.tests('Fog::Compute::DigitalOceanV2 | list_regions request', ['digitalocean', 'compute']) do + service = Fog::Compute.new(:provider => 'DigitalOcean', :version => 'V2') + + region_format = { + 'slug' => String, + 'name' => String, + 'sizes' => Array, + 'available' => Fog::Boolean, + 'features' => Array, + } + + tests('success') do + tests('#list_regions') do + service.list_regions.body['regions'].each do |region| + tests('format').data_matches_schema(region_format) do + region + end + end + end + end +end \ No newline at end of file diff --git a/tests/digitalocean/requests/compute_v2/server_tests.rb b/tests/digitalocean/requests/compute_v2/server_tests.rb new file mode 100644 index 000000000..1e6731042 --- /dev/null +++ b/tests/digitalocean/requests/compute_v2/server_tests.rb @@ -0,0 +1,75 @@ +Shindo.tests('Fog::Compute::DigitalOceanV2 | create_server request', ['digitalocean', 'compute']) do + service = Fog::Compute.new(:provider => 'DigitalOcean', :version => 'V2') + + server_format = { + 'id' => Integer, + 'name' => String, + 'memory' => Integer, + 'vcpus' => Integer, + 'disk' => Integer, + 'locked' => Fog::Boolean, + 'created_at' => String, + } + + create_server_format = { + 'droplet' => { + 'id' => Integer, + 'name' => String, + 'memory' => Integer, + 'vcpus' => Integer, + 'disk' => Integer, + 'locked' => Fog::Boolean, + 'status' => String, + 'kernel' => Hash, + "created_at" => String, + "features" => Array, + "backup_ids" => Array, + "snapshot_ids" => Array, + "image" => Hash, + "size" => Hash, + "size_slug" => String, + "networks" => Hash, + "region" => Hash, + }, + + 'links' => { + "actions" => Array, + } + + } + + tests('success') do + + server_id = nil + server_name = "fog-#{Time.now.to_i.to_s}" + image = "ubuntu-14-04-x64" + region = "nyc3" + size = "512mb" + + tests("#create_server(#{server_name}, #{size}, #{image}, #{region})").formats(create_server_format) do + body = service.create_server(server_name, size, image, region).body + server_id = body['droplet']['id'] + body + end + + test('#get_server_details can retrieve by id') do + body = service.get_server_details(server_id).body + body['droplet']['name'] == server_name + end + + server = service.servers.get(server_id) + server.wait_for { ready? } + + tests('#delete_server').succeeds do + server.delete + end + + tests('#list_servers') do + service.list_servers.body['droplets'].each do |droplet| + tests('format').data_matches_schema(server_format) do + droplet + end + end + end + end +end \ No newline at end of file