From 722b33cdadfa9bd7e00d93603efcfec20fa7fc16 Mon Sep 17 00:00:00 2001 From: Josh Lane & Jason Hansen Date: Tue, 17 Jul 2012 15:24:04 -0700 Subject: [PATCH] [cloudstack|security_groups] add groups and rules * add volume tests back into tests/cloudstack/models/ * represent rules as a resource * fix job representations --- lib/fog/cloudstack/compute.rb | 41 ++++++----- lib/fog/cloudstack/models/compute/image.rb | 68 +++++++++--------- lib/fog/cloudstack/models/compute/job.rb | 15 +++- lib/fog/cloudstack/models/compute/jobs.rb | 2 +- .../models/compute/security_group.rb | 50 ++++++++++++++ .../models/compute/security_group_rule.rb | 57 +++++++++++++++ .../models/compute/security_group_rules.rb | 37 ++++++++++ .../models/compute/security_groups.rb | 27 ++++++++ lib/fog/cloudstack/models/compute/server.rb | 4 +- lib/fog/cloudstack/models/compute/volume.rb | 10 +-- .../authorize_security_group_egress.rb | 69 +++++++++++++++++++ .../authorize_security_group_ingress.rb | 60 ++++++++++++++-- .../requests/compute/create_security_group.rb | 16 +++-- .../requests/compute/delete_security_group.rb | 17 +++++ .../requests/compute/list_firewall_rules.rb | 15 ++++ .../requests/compute/list_security_groups.rb | 26 +++++-- .../compute/query_async_job_result.rb | 18 ++++- .../compute/revoke_security_group_egress.rb | 43 ++++++++++++ .../compute/revoke_security_group_ingress.rb | 33 ++++++++- .../models/security_group_rule_tests.rb | 29 ++++++++ .../compute/models/security_group_tests.rb | 16 +++++ .../compute/models/security_groups_tests.rb | 19 +++++ .../cloudstack/compute/models/volume_tests.rb | 34 +++++++++ .../compute/models/volumes_tests.rb | 17 +++++ tests/compute/helper.rb | 9 ++- 25 files changed, 649 insertions(+), 83 deletions(-) create mode 100644 lib/fog/cloudstack/models/compute/security_group.rb create mode 100644 lib/fog/cloudstack/models/compute/security_group_rule.rb create mode 100644 lib/fog/cloudstack/models/compute/security_group_rules.rb create mode 100644 lib/fog/cloudstack/models/compute/security_groups.rb create mode 100644 lib/fog/cloudstack/requests/compute/authorize_security_group_egress.rb create mode 100644 lib/fog/cloudstack/requests/compute/list_firewall_rules.rb create mode 100644 lib/fog/cloudstack/requests/compute/revoke_security_group_egress.rb create mode 100644 tests/cloudstack/compute/models/security_group_rule_tests.rb create mode 100644 tests/cloudstack/compute/models/security_group_tests.rb create mode 100644 tests/cloudstack/compute/models/security_groups_tests.rb create mode 100644 tests/cloudstack/compute/models/volume_tests.rb create mode 100644 tests/cloudstack/compute/models/volumes_tests.rb diff --git a/lib/fog/cloudstack/compute.rb b/lib/fog/cloudstack/compute.rb index 7a68dae33..c1c7c5f05 100644 --- a/lib/fog/cloudstack/compute.rb +++ b/lib/fog/cloudstack/compute.rb @@ -27,6 +27,10 @@ module Fog collection :servers model :image collection :images + model :security_group + collection :security_groups + model :security_group_rule + collection :security_group_rules model :volume collection :volumes model :zone @@ -35,6 +39,7 @@ module Fog request :acquire_ip_address request :assign_to_load_balancer_rule request :attach_volume + request :authorize_security_group_egress request :authorize_security_group_ingress request :change_service_for_virtual_machine request :create_account @@ -80,6 +85,7 @@ module Fog request :list_events request :list_external_firewalls request :list_external_load_balancers + request :list_firewall_rules request :list_hosts request :list_hypervisors request :list_instance_groups @@ -115,6 +121,7 @@ module Fog request :remove_from_load_balancer_rule request :reset_password_for_virtual_machine request :revoke_security_group_ingress + request :revoke_security_group_egress request :start_virtual_machine request :stop_virtual_machine request :update_account @@ -247,23 +254,20 @@ module Fog def self.data @data ||= begin - rc_options = Fog.credentials[:cloudstack] || {} - zone_id = rc_options[:zone_id] ||"c554c592-e09c-9df5-7688-4a32754a4305" - image_id = rc_options[:image_id] || "8a31cf9c-f248-0588-256e-9dbf58785216" - flavor_id = rc_options[:flavor_id] || "4437ac6c-9fe3-477a-57ec-60a5a45896a4" - account_id = "8bec6f15-e2b8-44fc-a8f3-a022b2873440" - user_id = Fog::Cloudstack.uuid - domain_id = Fog::Cloudstack.uuid - network_id = (Array(rc_options[:network_ids]) || [Fog::Cloudstack.uuid]).first + zone_id = Fog.credentials[:cloudstack_zone_id] || Fog::Cloudstack.uuid + image_id = Fog.credentials[:cloudstack_template_id] || Fog::Cloudstack.uuid + flavor_id = Fog.credentials[:cloudstack_service_offering_id] || Fog::Cloudstack.uuid + network_id = (Array(Fog.credentials[:cloudstack_network_ids]) || [Fog::Cloudstack.uuid]).first domain_name = "exampleorg" + account_id, user_id, domain_id = Fog::Cloudstack.uuid, Fog::Cloudstack.uuid, Fog::Cloudstack.uuid domain = { - "id" => domain_id, - "name" => domain_name, - "level" => 1, - "parentdomainid" => Fog::Cloudstack.uuid, + "id" => domain_id, + "name" => domain_name, + "level" => 1, + "parentdomainid" => Fog::Cloudstack.uuid, "parentdomainname" => "ROOT", - "haschild" => false, - "path" => "ROOT/accountname" + "haschild" => false, + "path" => "ROOT/accountname" } user = { "id" => user_id, @@ -406,10 +410,11 @@ module Fog "state" => "enabled", "user" => [user]} }, - :domains => { domain_id => domain }, - :servers => {}, - :jobs => {}, - :volumes => {} + :domains => {domain_id => domain}, + :servers => {}, + :jobs => {}, + :volumes => {}, + :security_groups => {}, } end end diff --git a/lib/fog/cloudstack/models/compute/image.rb b/lib/fog/cloudstack/models/compute/image.rb index 1033c32ca..ceae76d9d 100644 --- a/lib/fog/cloudstack/models/compute/image.rb +++ b/lib/fog/cloudstack/models/compute/image.rb @@ -2,60 +2,60 @@ module Fog module Compute class Cloudstack class Image < Fog::Model - identity :id, :aliases => 'id' + identity :id, :aliases => 'id' attribute :account - attribute :account_id, :aliases => 'accountid' + attribute :account_id, :aliases => 'accountid' attribute :bootable attribute :checksum attribute :created - attribute :cross_zones, :aliases => 'crossZones' + attribute :cross_zones, :aliases => 'crossZones' attribute :details - attribute :display_text, :aliases => 'displaytext' + attribute :display_text, :aliases => 'displaytext' attribute :domain - attribute :domain_id, :aliases => 'domainid' + attribute :domain_id, :aliases => 'domainid' attribute :format - attribute :host_id, :aliases => 'hostid' - attribute :host_name, :aliases => 'hostname' + attribute :host_id, :aliases => 'hostid' + attribute :host_name, :aliases => 'hostname' attribute :hypervisor - attribute :job_id, :aliases => 'jobid' - attribute :job_status, :aliases => 'jobstatus' - attribute :is_extractable, :aliases => 'isextractable' - attribute :is_featured, :aliases => 'isfeatured' - attribute :is_public, :aliases => 'ispublic' - attribute :is_ready, :aliases => 'isready' + attribute :job_id, :aliases => 'jobid' + attribute :job_status, :aliases => 'jobstatus' + attribute :is_extractable, :aliases => 'isextractable' + attribute :is_featured, :aliases => 'isfeatured' + attribute :is_public, :aliases => 'ispublic' + attribute :is_ready, :aliases => 'isready' attribute :name - attribute :os_type_id, :aliases => 'ostypeid' - attribute :os_type_name, :aliases => 'ostypename' - attribute :password_enabled, :aliases => 'ostypename' + attribute :os_type_id, :aliases => 'ostypeid' + attribute :os_type_name, :aliases => 'ostypename' + attribute :password_enabled, :aliases => 'ostypename' attribute :project - attribute :project_id, :aliases => 'projectid' + attribute :project_id, :aliases => 'projectid' attribute :removed attribute :size attribute :source_template_id, :aliases => 'sourcetemplateid' attribute :status - attribute :template_tag, :aliases => 'templatetag' - attribute :template_type, :aliases => 'templatetype' - attribute :zone_id, :aliases => 'zoneid' - attribute :zone_name, :aliases => 'zonename' + attribute :template_tag, :aliases => 'templatetag' + attribute :template_type, :aliases => 'templatetype' + attribute :zone_id, :aliases => 'zoneid' + attribute :zone_name, :aliases => 'zonename' attr_accessor :bits, :requires_hvm, :snapshot_id, :url, :virtual_machine_id, :volume_id def save options = { - 'displaytext' => display_text, - 'name' => name, - 'ostypeid' => os_type_id, - 'bits' => bits, - 'details' => details, - 'isfeatured' => is_featured, - 'ispublic' => is_public, - 'passwordenabled' => password_enabled, - 'requireshvm' => requires_hvm, - 'snapshotid' => snapshot_id, - 'templatetag' => template_tag, - 'url' => url, + 'displaytext' => display_text, + 'name' => name, + 'ostypeid' => os_type_id, + 'bits' => bits, + 'details' => details, + 'isfeatured' => is_featured, + 'ispublic' => is_public, + 'passwordenabled' => password_enabled, + 'requireshvm' => requires_hvm, + 'snapshotid' => snapshot_id, + 'templatetag' => template_tag, + 'url' => url, 'virtualmachineid' => virtual_machine_id, - 'volumeid' => volume_id + 'volumeid' => volume_id } data = connection.create_template(options) merge_attributes(data['createtemplateresponse']) diff --git a/lib/fog/cloudstack/models/compute/job.rb b/lib/fog/cloudstack/models/compute/job.rb index 6ddf803a6..71cea9a50 100644 --- a/lib/fog/cloudstack/models/compute/job.rb +++ b/lib/fog/cloudstack/models/compute/job.rb @@ -20,9 +20,22 @@ module Fog merge_attributes(connection.query_async_job_result('jobid' => self.id)['queryasyncjobresultresponse']) end - def finished? + def ready? self.job_status != 0 end + + def successful? + self.job_result_code == 0 + end + + # so dirty + def result + if successful? && model = Fog::Compute::Cloudstack.constants.find{|c| c.to_s.downcase == self.job_result.keys.first.to_s}.to_s + collection = model.gsub(/.[A-Z]/){|w| "#{w[0]}_#{w[1].downcase}"}.downcase + "s" # cheap underscorize, assume simple pluralization + connection.send(collection).new(self.job_result.values.first) + else self.job_result + end + end end # Job end # Cloudstack end # Compute diff --git a/lib/fog/cloudstack/models/compute/jobs.rb b/lib/fog/cloudstack/models/compute/jobs.rb index cbbba3242..eec3c71b7 100644 --- a/lib/fog/cloudstack/models/compute/jobs.rb +++ b/lib/fog/cloudstack/models/compute/jobs.rb @@ -15,7 +15,7 @@ module Fog end def get(job_id) - if job = connection.query_async_job_result('jobid' => job_id)["listasyncjobsresponse"]["asyncjobs"].first + if job = connection.query_async_job_result('jobid' => job_id)["queryasyncjobresultresponse"] new(job) end rescue Fog::Compute::Cloudstack::BadRequest diff --git a/lib/fog/cloudstack/models/compute/security_group.rb b/lib/fog/cloudstack/models/compute/security_group.rb new file mode 100644 index 000000000..c2e4a68f1 --- /dev/null +++ b/lib/fog/cloudstack/models/compute/security_group.rb @@ -0,0 +1,50 @@ +module Fog + module Compute + class Cloudstack + class SecurityGroup < Fog::Model + identity :id, :aliases => 'id' + attribute :name, :type => :string + attribute :description, :type => :string + attribute :account, :type => :string + attribute :domain_id, :aliases => "domainid", :type => :string + attribute :domain_name, :aliases => "domain", :type => :string + attribute :project_id, :aliases => "projectid", :type => :string + attribute :project_name, :aliases => "project", :type => :string + attribute :ingress_rules, :aliases => "ingressrule", :type => :array + attribute :egress_rules, :aliases => "egressrule", :type => :array + + def save + requires :name + + options = { + 'name' => self.name, + 'account' => self.account, + 'description' => self.description, + 'projectid' => self.project_id, + 'domainid' => self.domain_id, + } + data = connection.create_security_group(options) + merge_attributes(data['createsecuritygroupresponse']['securitygroup']) + end + + def destroy + requires :id + connection.delete_security_group('id' => self.id) + true + end + + def egress_rules + attributes[:egress_rules] || [] + end + + def ingress_rules + attributes[:ingress_rules] || [] + end + + def rules + connection.security_group_rules.all("security_group_id" => self.id) + end + end # SecurityGroup + end # Cloudstack + end # Compute +end # Fog diff --git a/lib/fog/cloudstack/models/compute/security_group_rule.rb b/lib/fog/cloudstack/models/compute/security_group_rule.rb new file mode 100644 index 000000000..944a40c55 --- /dev/null +++ b/lib/fog/cloudstack/models/compute/security_group_rule.rb @@ -0,0 +1,57 @@ +module Fog + module Compute + class Cloudstack + class SecurityGroupRule < Fog::Model + + identity :id, :aliases => 'ruleid' + + attribute :security_group_id, :type => :string + attribute :protocol, :type => :string + attribute :start_port, :type => :integer + attribute :end_port, :type => :integer + attribute :cidr, :type => :string + attribute :direction, :type => :string + + def destroy + data = connection.send("revoke_security_group_#{self.direction}", "id" => self.id) + job = connection.jobs.new(data["revokesecuritygroup#{self.direction}"]) + job.wait_for { ready? } + job.successful? + end + + def save + requires :security_group_id, :cidr, :direction + + data = connection.send("authorize_security_group_#{self.direction}".to_sym, params) + job = connection.jobs.new(data["authorizesecuritygroup#{self.direction}response"]) + job.wait_for { ready? } + # durty + merge_attributes(job.result.send("#{self.direction}_rules").last) + self + end + + def security_group + connection.security_groups.get(self.security_group_id) + end + + def reload + requires :id, :security_group_id, :cidr + merge_attributes(security_group.rules.get(self.id)) + end + + private + + def params + options = { + "securitygroupid" => self.security_group_id, + "protocol" => self.protocol, + "cidrlist" => self.cidr + } + options.merge!("startport" => self.start_port) unless self.start_port.nil? + options.merge("endport" => self.end_port) unless self.end_port.nil? + end + + end # SecurityGroupRule + end # Cloudstack + end # Compute +end # Fog diff --git a/lib/fog/cloudstack/models/compute/security_group_rules.rb b/lib/fog/cloudstack/models/compute/security_group_rules.rb new file mode 100644 index 000000000..44434a075 --- /dev/null +++ b/lib/fog/cloudstack/models/compute/security_group_rules.rb @@ -0,0 +1,37 @@ +require 'fog/core/collection' +require 'fog/cloudstack/models/compute/security_group_rule' + +module Fog + module Compute + class Cloudstack + + class SecurityGroupRules < Fog::Collection + + model Fog::Compute::Cloudstack::SecurityGroupRule + + attribute :security_group_id, :type => :string + + def security_group + connection.security_groups.get(self.security_group_id) + end + + def create(attributes) + model = self.new(attributes.merge(:security_group_id => self.security_group_id)) + model.save + end + + def all(options={}) + merge_attributes(options) + security_group = self.security_group + rules = security_group.ingress_rules.map{|r| r.merge("direction" => "ingress", "security_group_id" => security_group_id)} + rules += security_group.egress_rules.map{|r| r.merge("direction" => "egress", "security_group_id" => security_group_id)} + load(rules) + end + + def get(rule_id) + all.find{|r| r.id == rule_id} + end + end + end + end +end diff --git a/lib/fog/cloudstack/models/compute/security_groups.rb b/lib/fog/cloudstack/models/compute/security_groups.rb new file mode 100644 index 000000000..31d7cdb48 --- /dev/null +++ b/lib/fog/cloudstack/models/compute/security_groups.rb @@ -0,0 +1,27 @@ +require 'fog/core/collection' +require 'fog/cloudstack/models/compute/security_group' + +module Fog + module Compute + class Cloudstack + class SecurityGroups < Fog::Collection + + model Fog::Compute::Cloudstack::SecurityGroup + + def all(options={}) + data = connection.list_security_groups(options)["listsecuritygroupsresponse"]["securitygroup"] || [] + load(data) + end + + def get(security_group_id) + if security_group = connection.list_security_groups('id' => security_group_id)["listsecuritygroupsresponse"]["securitygroup"].first + new(security_group) + end + rescue Fog::Compute::Cloudstack::BadRequest + nil + end + end + + end + end +end diff --git a/lib/fog/cloudstack/models/compute/server.rb b/lib/fog/cloudstack/models/compute/server.rb index 25008b1eb..98eee8d7e 100644 --- a/lib/fog/cloudstack/models/compute/server.rb +++ b/lib/fog/cloudstack/models/compute/server.rb @@ -45,9 +45,7 @@ module Fog def reboot requires :id data = connection.reboot_virtual_machine('id' => self.id) # FIXME: does this ever fail? - job = Job.new(data["rebootvirtualmachineresponse"]) - job.connection= self.connection - job + connection.jobs.new(data["rebootvirtualmachineresponse"]) end def save diff --git a/lib/fog/cloudstack/models/compute/volume.rb b/lib/fog/cloudstack/models/compute/volume.rb index 574343b6b..bfe85bc8b 100644 --- a/lib/fog/cloudstack/models/compute/volume.rb +++ b/lib/fog/cloudstack/models/compute/volume.rb @@ -86,16 +86,14 @@ module Fog end options = { - 'id' => id, + 'id' => id, 'virtualmachineid' => instance_id, } options.merge!('deviceid' => mountpoint) if mountpoint data = connection.attach_volume(options) - Job.new(data["attachvolumeresponse"]).tap do |job| - job.connection= self.connection - end + connection.jobs.new(data["attachvolumeresponse"]) end def detach @@ -103,9 +101,7 @@ module Fog data = connection.detach_volume('id' => id) - Job.new(data["detachvolumeresponse"]).tap do |job| - job.connection= self.connection - end + connection.jobs.new(data["detachvolumeresponse"]) end def destroy diff --git a/lib/fog/cloudstack/requests/compute/authorize_security_group_egress.rb b/lib/fog/cloudstack/requests/compute/authorize_security_group_egress.rb new file mode 100644 index 000000000..fad6c8aa0 --- /dev/null +++ b/lib/fog/cloudstack/requests/compute/authorize_security_group_egress.rb @@ -0,0 +1,69 @@ +module Fog + module Compute + class Cloudstack + class Real + def authorize_security_group_egress(options={}) + options.merge!( + 'command' => 'authorizeSecurityGroupEgress' + ) + + request(options) + end + end # Real + class Mock + def authorize_security_group_egress(options={}) + security_group_id = options['securitygroupid'] + security_group_rule_id = Fog::Cloudstack.uuid + + unless cidr = options['cidrlist'] + raise Fog::Compute::Cloudstack::BadRequest.new('Unable to execute API command missing parameter cidr') + end + + unless start_port = options['startport'] + raise Fog::Compute::Cloudstack::BadRequest.new('Unable to execute API command missing parameter start_port') + end + + unless end_port = options['endport'] + raise Fog::Compute::Cloudstack::BadRequest.new('Unable to execute API command missing parameter end_port') + end + + unless protocol = options['protocol'] + raise Fog::Compute::Cloudstack::BadRequest.new('Unable to execute API command missing parameter protocol') + end + + rule = { + "ruleid" => security_group_rule_id, + "cidr" => cidr, + "startport" => start_port, + "endport" => end_port, + "protocol" => protocol + } + + unless security_group = self.data[:security_groups][security_group_id] + raise Fog::Compute::Cloudstack::BadRequest.new("Security group id #{security_group_id} does not exist") + end + + security_group["egressrule"] ||= [] + security_group["egressrule"] << rule + + job_id = Fog::Cloudstack.uuid + job = { + "cmd" => "com.cloud.api.commands.authorizeSecurityGroupEgress", + "created" => Time.now.iso8601, + "jobid" => job_id, + "jobstatus" => 1, + "jobprocstatus" => 0, + "jobresultcode" => 0, + "jobresulttype" => "object", + "jobresult" => { "securitygroup" => security_group } + } + + self.data[:jobs][job_id]= job + self.data[:security_groups][security_group_id] = security_group + + { "authorizesecuritygroupegressresponse" => { "jobid" => job_id } } + end + end # Mock + end + end +end diff --git a/lib/fog/cloudstack/requests/compute/authorize_security_group_ingress.rb b/lib/fog/cloudstack/requests/compute/authorize_security_group_ingress.rb index 72ec8ead2..4244ffa46 100644 --- a/lib/fog/cloudstack/requests/compute/authorize_security_group_ingress.rb +++ b/lib/fog/cloudstack/requests/compute/authorize_security_group_ingress.rb @@ -3,9 +3,6 @@ module Fog class Cloudstack class Real - # Creates an account. - # - # {CloudStack API Reference}[http://download.cloud.com/releases/2.2.0/api_2.2.4/global_admin/authorizeSecurityGroupIngress.html] def authorize_security_group_ingress(options={}) options.merge!( 'command' => 'authorizeSecurityGroupIngress' @@ -14,7 +11,62 @@ module Fog request(options) end - end + end # Real + + class Mock + def authorize_security_group_ingress(options={}) + security_group_id = options['securitygroupid'] + security_group_rule_id = Fog::Cloudstack.uuid + + unless cidr = options['cidrlist'] + raise Fog::Compute::Cloudstack::BadRequest.new('Unable to execute API command missing parameter cidr') + end + + unless start_port = options['startport'] + raise Fog::Compute::Cloudstack::BadRequest.new('Unable to execute API command missing parameter start_port') + end + + unless end_port = options['endport'] + raise Fog::Compute::Cloudstack::BadRequest.new('Unable to execute API command missing parameter end_port') + end + + unless protocol = options['protocol'] + raise Fog::Compute::Cloudstack::BadRequest.new('Unable to execute API command missing parameter protocol') + end + + rule = { + "ruleid" => security_group_rule_id, + "cidr" => cidr, + "startport" => start_port, + "endport" => end_port, + "protocol" => protocol + } + + unless security_group = self.data[:security_groups][security_group_id] + raise Fog::Compute::Cloudstack::BadRequest.new("Security group id #{security_group_id} does not exist") + end + + security_group["ingressrule"] ||= [] + security_group["ingressrule"] << rule + + job_id = Fog::Cloudstack.uuid + job = { + "cmd" => "com.cloud.api.commands.authorizeSecurityGroupIngress", + "created" => Time.now.iso8601, + "jobid" => job_id, + "jobstatus" => 1, + "jobprocstatus" => 0, + "jobresultcode" => 0, + "jobresulttype" => "object", + "jobresult" => { "securitygroup" => security_group } + } + + self.data[:jobs][job_id]= job + self.data[:security_groups][security_group_id] = security_group + + { "authorizesecuritygroupingressresponse" => { "jobid" => job_id } } + end + end # Mock end end end diff --git a/lib/fog/cloudstack/requests/compute/create_security_group.rb b/lib/fog/cloudstack/requests/compute/create_security_group.rb index 2b7005ce0..c2cbc32b6 100644 --- a/lib/fog/cloudstack/requests/compute/create_security_group.rb +++ b/lib/fog/cloudstack/requests/compute/create_security_group.rb @@ -2,10 +2,6 @@ module Fog module Compute class Cloudstack class Real - - # Creates an account. - # - # {CloudStack API Reference}[http://download.cloud.com/releases/2.2.0/api_2.2.4/global_admin/createSecurityGroup.html] def create_security_group(options={}) options.merge!( 'command' => 'createSecurityGroup' @@ -13,7 +9,19 @@ module Fog request(options) end + end # Real + class Mock + def create_security_group(options={}) + security_group_id = Fog::Cloudstack.uuid + + security_group = { + "id" => security_group_id, + }.merge(options) + + self.data[:security_groups][security_group_id]= security_group + {"createsecuritygroupresponse" => { "securitygroup" => security_group}} + end end end end diff --git a/lib/fog/cloudstack/requests/compute/delete_security_group.rb b/lib/fog/cloudstack/requests/compute/delete_security_group.rb index 54adcc197..6022682fe 100644 --- a/lib/fog/cloudstack/requests/compute/delete_security_group.rb +++ b/lib/fog/cloudstack/requests/compute/delete_security_group.rb @@ -14,7 +14,24 @@ module Fog request(options) end + end # Real + + class Mock + def delete_security_group(options={}) + security_group_id = options['id'] + if self.data[:security_groups][security_group_id] + self.data[:security_groups].delete(security_group_id) + { + "deletesecuritygroupresponse" => { + "success" => "true" + } + } + else + raise Fog::Compute::Cloudstack::BadRequest.new('No security_group found') + end + end end + end end end diff --git a/lib/fog/cloudstack/requests/compute/list_firewall_rules.rb b/lib/fog/cloudstack/requests/compute/list_firewall_rules.rb new file mode 100644 index 000000000..c1459b120 --- /dev/null +++ b/lib/fog/cloudstack/requests/compute/list_firewall_rules.rb @@ -0,0 +1,15 @@ +module Fog + module Compute + class Cloudstack + class Real + def list_firewall_rules(options={}) + options.merge!( + 'command' => 'listFirewallRules' + ) + request(options) + end + + end + end + end +end diff --git a/lib/fog/cloudstack/requests/compute/list_security_groups.rb b/lib/fog/cloudstack/requests/compute/list_security_groups.rb index bddedf51f..5a14110d3 100644 --- a/lib/fog/cloudstack/requests/compute/list_security_groups.rb +++ b/lib/fog/cloudstack/requests/compute/list_security_groups.rb @@ -3,17 +3,35 @@ module Fog class Cloudstack class Real - # Lists security groups. - # - # {CloudStack API Reference}[http://download.cloud.com/releases/2.2.0/api_2.2.4/global_admin/listSecurityGroups.html] def list_security_groups(options={}) options.merge!( 'command' => 'listSecurityGroups' ) - + request(options) end + end # Real + + class Mock + def list_security_groups(options={}) + security_groups = [] + if security_group_id = options['id'] + security_group = self.data[:security_groups][security_group_id] + raise Fog::Compute::Cloudstack::BadRequest unless security_group + security_groups = [security_group] + else + security_groups = self.data[:security_groups].values + end + + { + "listsecuritygroupsresponse" => + { + "count" => security_groups.size, + "securitygroup" => security_groups + } + } + end end end end diff --git a/lib/fog/cloudstack/requests/compute/query_async_job_result.rb b/lib/fog/cloudstack/requests/compute/query_async_job_result.rb index 87135d304..b83ac5662 100644 --- a/lib/fog/cloudstack/requests/compute/query_async_job_result.rb +++ b/lib/fog/cloudstack/requests/compute/query_async_job_result.rb @@ -3,9 +3,6 @@ module Fog class Cloudstack class Real - # Creates a domain. - # - # {CloudStack API Reference}[http://download.cloud.com/releases/2.2.0/api_2.2.4/global_admin/queryAsyncJobResult.html] def query_async_job_result(options={}) options.merge!( 'command' => 'queryAsyncJobResult' @@ -14,7 +11,22 @@ module Fog request(options) end + end # Real + + class Mock + def query_async_job_result(options={}) + unless job_id = options['jobid'] + raise Fog::Compute::Cloudstack::BadRequest.new("Missing required parameter jobid") + end + + unless job = self.data[:jobs][job_id] + raise Fog::Compute::Cloudstack::BadRequest.new("Unknown job id #{job_id}") + end + + {'queryasyncjobresultresponse' => job } + end end + end end end diff --git a/lib/fog/cloudstack/requests/compute/revoke_security_group_egress.rb b/lib/fog/cloudstack/requests/compute/revoke_security_group_egress.rb new file mode 100644 index 000000000..f88c654d8 --- /dev/null +++ b/lib/fog/cloudstack/requests/compute/revoke_security_group_egress.rb @@ -0,0 +1,43 @@ +module Fog + module Compute + class Cloudstack + class Real + def revoke_security_group_egress(options={}) + options.merge!( + 'command' => 'revokeSecurityGroupEgress' + ) + + request(options) + end + end # Real + class Mock + def revoke_security_group_egress(options={}) + unless security_group_rule_id = options['id'] + raise Fog::Compute::Cloudstack::BadRequest.new('Unable to execute API command missing parameter id') + end + + security_group_id, security_group = self.data[:security_groups].find do |id,group| + group['egressrule'] && group['egressrule'].delete_if { |r| r['id'] == security_group_rule_id } + end + + job_id = Fog::Cloudstack.uuid + job = { + "cmd" => "com.cloud.api.commands.revokeSecurityGroupEgress", + "created" => Time.now.iso8601, + "jobid" => job_id, + "jobstatus" => 1, + "jobprocstatus" => 0, + "jobresultcode" => 0, + "jobresulttype" => "object", + "jobresult" => { "securitygroup" => security_group } + } + + self.data[:jobs][job_id]= job + self.data[:security_groups][security_group_id] = security_group + + {"revokesecuritygroupegress" => { "jobid" => job_id }} + end + end # Mock + end + end +end diff --git a/lib/fog/cloudstack/requests/compute/revoke_security_group_ingress.rb b/lib/fog/cloudstack/requests/compute/revoke_security_group_ingress.rb index 577f056a3..fdbbab9d2 100644 --- a/lib/fog/cloudstack/requests/compute/revoke_security_group_ingress.rb +++ b/lib/fog/cloudstack/requests/compute/revoke_security_group_ingress.rb @@ -3,9 +3,6 @@ module Fog class Cloudstack class Real - # Creates an account. - # - # {CloudStack API Reference}[http://download.cloud.com/releases/2.2.0/api_2.2.4/global_admin/authorizeSecurityGroupIngress.html] def revoke_security_group_ingress(options={}) options.merge!( 'command' => 'revokeSecurityGroupIngress' @@ -14,6 +11,36 @@ module Fog request(options) end + end # Real + + class Mock + def revoke_security_group_ingress(options={}) + unless security_group_rule_id = options['id'] + raise Fog::Compute::Cloudstack::BadRequest.new('Unable to execute API command missing parameter id') + end + + security_group_id, security_group = self.data[:security_groups].find do |id,group| + group['ingressrule'] && group['ingressrule'].delete_if { |r| r['id'] == security_group_rule_id } + end + + job_id = Fog::Cloudstack.uuid + job = { + "cmd" => "com.cloud.api.commands.revokeSecurityGroupIngress", + "created" => Time.now.iso8601, + "jobid" => job_id, + "jobstatus" => 1, + "jobprocstatus" => 0, + "jobresultcode" => 0, + "jobresulttype" => "object", + "jobresult" => { "securitygroup" => security_group } + } + + self.data[:jobs][job_id]= job + self.data[:security_groups][security_group_id] = security_group + + {"revokesecuritygroupingress" => { "jobid" => job_id }} + end + end end end diff --git a/tests/cloudstack/compute/models/security_group_rule_tests.rb b/tests/cloudstack/compute/models/security_group_rule_tests.rb new file mode 100644 index 000000000..1e5e712ee --- /dev/null +++ b/tests/cloudstack/compute/models/security_group_rule_tests.rb @@ -0,0 +1,29 @@ +def security_group_rule_tests(connection, params, direction, mocks_implemented = true) + @security_group = connection.security_groups.create(params[:security_group_attributes]) + + rule_params = params[:security_group_rule_attributes].merge(:security_group_id => @security_group.id, :direction => direction) + + model_tests(connection.security_group_rules, rule_params, mocks_implemented) do + + if Fog.mocking? && !mocks_implemented + pending + end + + end + @security_group.destroy +end + +provider, config = :cloudstack, compute_providers[:cloudstack] + +Shindo.tests("Fog::Compute[:#{provider}] | security_group_rules | ingress", [provider.to_s]) do + + security_group_rule_tests(Fog::Compute[:cloudstack], config, "ingress", config[:mocked]) + +end + + +Shindo.tests("Fog::Compute[:#{provider}] | security_group_rules | egress", [provider.to_s]) do + + security_group_rule_tests(Fog::Compute[:cloudstack], config, "egress", config[:mocked]) + +end diff --git a/tests/cloudstack/compute/models/security_group_tests.rb b/tests/cloudstack/compute/models/security_group_tests.rb new file mode 100644 index 000000000..e32cf3d7b --- /dev/null +++ b/tests/cloudstack/compute/models/security_group_tests.rb @@ -0,0 +1,16 @@ +def security_group_tests(connection, params, mocks_implemented = true) + model_tests(connection.security_groups, params, mocks_implemented) do + if Fog.mocking? && !mocks_implemented + pending + else + responds_to(:rules) + end + end +end + +provider, config = :cloudstack, compute_providers[:cloudstack] +Shindo.tests("Fog::Compute[:#{provider}] | security_groups", [provider.to_s]) do + + security_group_tests(Fog::Compute[:cloudstack], config[:security_group_attributes], config[:mocked]) + +end diff --git a/tests/cloudstack/compute/models/security_groups_tests.rb b/tests/cloudstack/compute/models/security_groups_tests.rb new file mode 100644 index 000000000..c8a9a67e3 --- /dev/null +++ b/tests/cloudstack/compute/models/security_groups_tests.rb @@ -0,0 +1,19 @@ +def security_group_tests(provider, params, mocks_implemented = true) + collection_tests(provider.security_groups, params, mocks_implemented) do + + if Fog.mocking? && !mocks_implemented + pending + else + responds_to(:rules) + end + + end +end + + +provider, config = :cloudstack, compute_providers[:cloudstack] +Shindo.tests("Fog::Compute[:#{provider}] | security_group", [provider.to_s]) do + + security_group_tests(Fog::Compute[provider], (config[:security_group_attributes] || {}), config[:mocked]) + +end diff --git a/tests/cloudstack/compute/models/volume_tests.rb b/tests/cloudstack/compute/models/volume_tests.rb new file mode 100644 index 000000000..6676860e2 --- /dev/null +++ b/tests/cloudstack/compute/models/volume_tests.rb @@ -0,0 +1,34 @@ +def volume_tests(connection, params, mocks_implemented = true) + model_tests(connection.volumes, params[:volume_attributes], mocks_implemented) do + if !Fog.mocking? || mocks_implemented + @instance.wait_for { ready? } + end + + @server = @instance.connection.servers.create(params[:server_attributes]) + @server.wait_for { ready? } + + tests('attach').succeeds do + @instance.attach(@server) + end + + tests('detach').succeeds do + @instance.detach + end + + @server.destroy + end +end + +Shindo.tests("Fog::Compute[:cloudstack] | volume", :cloudstack) do + + config = compute_providers[:cloudstack] + + volume_tests(Fog::Compute[:cloudstack], config, config[:mocked]) do + if Fog.mocking? && !mocks_implemented + pending + else + responds_to(:ready?) + responds_to(:flavor) + end + end +end diff --git a/tests/cloudstack/compute/models/volumes_tests.rb b/tests/cloudstack/compute/models/volumes_tests.rb new file mode 100644 index 000000000..c293214ed --- /dev/null +++ b/tests/cloudstack/compute/models/volumes_tests.rb @@ -0,0 +1,17 @@ +def volumes_tests(connection, params = {}, mocks_implemented = true) + + collection_tests(connection.volumes, params, mocks_implemented) do + + if !Fog.mocking? || mocks_implemented + @instance.wait_for { ready? } + end + + end + +end + +config = compute_providers[:cloudstack] + +Shindo.tests("Fog::Compute[:cloudstack] | volumes", ["cloudstack"]) do + volumes_tests(Fog::Compute[:cloudstack], config[:volume_attributes], config[:mocked]) +end diff --git a/tests/compute/helper.rb b/tests/compute/helper.rb index 913f64962..efeaaeffc 100644 --- a/tests/compute/helper.rb +++ b/tests/compute/helper.rb @@ -38,9 +38,16 @@ def compute_providers end, :volume_attributes => {:name => "somevolume"}.tap do |hash| [:zone_id, :disk_offering_id].each do |k| - hash[k]= Fog.credentials[:cloudstack] && Fog.credentials[:cloudstack][k] + hash[k]= Fog.credentials["cloudstack_#{k}".to_sym] end end, + :security_group_attributes => {:name => "somesecuritygroup"}, + :security_group_rule_attributes => { + :cidr => '0.0.0.0/0', + :start_port => 123, + :end_port => 456, + :protocol => 'tcp' + }, :mocked => true }, :glesys => {