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

[cloudstack|security_groups] add groups and rules

* add volume tests back into tests/cloudstack/models/
* represent rules as a resource
* fix job representations
This commit is contained in:
Josh Lane & Jason Hansen 2012-07-17 15:24:04 -07:00
parent e026c2e3de
commit 722b33cdad
25 changed files with 649 additions and 83 deletions

View file

@ -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,15 +254,12 @@ 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,
@ -406,10 +410,11 @@ module Fog
"state" => "enabled",
"user" => [user]}
},
:domains => { domain_id => domain },
:domains => {domain_id => domain},
:servers => {},
:jobs => {},
:volumes => {}
:volumes => {},
:security_groups => {},
}
end
end

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -93,9 +93,7 @@ module Fog
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

View file

@ -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

View file

@ -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 # 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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -3,9 +3,6 @@ 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'
@ -14,6 +11,27 @@ module Fog
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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 => {