From 5e68a7e2045e9adb228fb45a5e4ac4c0642b41af Mon Sep 17 00:00:00 2001 From: Jason Hansen & Josh Lane Date: Wed, 16 May 2012 11:12:08 -0700 Subject: [PATCH] [cloudstack|compute] zones,flavors,images,address --- lib/fog/cloudstack/compute.rb | 26 ++++--- lib/fog/cloudstack/models/compute/address.rb | 17 +++++ lib/fog/cloudstack/models/compute/flavor.rb | 33 +++++++++ lib/fog/cloudstack/models/compute/flavors.rb | 28 ++++++++ lib/fog/cloudstack/models/compute/image.rb | 72 +++++++++++++++++++ lib/fog/cloudstack/models/compute/images.rb | 32 +++++++++ lib/fog/cloudstack/models/compute/server.rb | 56 ++++++++++----- lib/fog/cloudstack/models/compute/servers.rb | 1 - lib/fog/cloudstack/models/compute/zone.rb | 39 ++++++++++ lib/fog/cloudstack/models/compute/zones.rb | 33 +++++++++ .../requests/compute/delete_template.rb | 20 ++++++ .../compute/deploy_virtual_machine.rb | 38 +++++----- .../compute/list_service_offerings.rb | 25 +++++-- .../requests/compute/list_templates.rb | 25 +++++-- .../cloudstack/requests/compute/list_zones.rb | 22 ++++-- 15 files changed, 404 insertions(+), 63 deletions(-) create mode 100644 lib/fog/cloudstack/models/compute/address.rb create mode 100644 lib/fog/cloudstack/models/compute/flavor.rb create mode 100644 lib/fog/cloudstack/models/compute/flavors.rb create mode 100644 lib/fog/cloudstack/models/compute/image.rb create mode 100644 lib/fog/cloudstack/models/compute/images.rb create mode 100644 lib/fog/cloudstack/models/compute/zone.rb create mode 100644 lib/fog/cloudstack/models/compute/zones.rb create mode 100644 lib/fog/cloudstack/requests/compute/delete_template.rb diff --git a/lib/fog/cloudstack/compute.rb b/lib/fog/cloudstack/compute.rb index 3ce9ab53c..01c45ba15 100644 --- a/lib/fog/cloudstack/compute.rb +++ b/lib/fog/cloudstack/compute.rb @@ -10,17 +10,24 @@ module Fog class Unauthorized < Fog::Compute::Cloudstack::Error; end requires :cloudstack_host - + recognizes :cloudstack_api_key, :cloudstack_secret_access_key, :cloudstack_session_key, :cloudstack_session_id, :cloudstack_port, :cloudstack_path, :cloudstack_scheme, :cloudstack_persistent - + request_path 'fog/cloudstack/requests/compute' model_path 'fog/cloudstack/models/compute' + model :address model :server collection :servers - + model :image + collection :images + model :flavor + collection :flavors + model :zone + collection :zones + request :acquire_ip_address request :assign_to_load_balancer_rule request :attach_volume @@ -45,6 +52,7 @@ module Fog request :delete_ssh_key_pair request :delete_snapshot request :delete_snapshot_policies + request :delete_template request :delete_user request :delete_volume request :detach_volume @@ -259,8 +267,8 @@ module Fog @data ||= begin rc_options = Fog.credentials[:cloudstack] || {} zone_id = rc_options[:zone_id] ||"c554c592-e09c-9df5-7688-4a32754a4305" - template_id = rc_options[:template_id] || "8a31cf9c-f248-0588-256e-9dbf58785216" - service_offering_id = rc_options[:service_offering_id] || "4437ac6c-9fe3-477a-57ec-60a5a45896a4" + 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 @@ -325,8 +333,8 @@ module Fog "allocationstate" => "Enabled", "zonetoken" => Fog::Cloudstack.uuid, "dhcpprovider" => "VirtualRouter"}}, - :templates => { template_id => { - "id" => template_id, + :images => { image_id => { + "id" => image_id, "name" => "CentOS 5.6(64-bit) no GUI (XenServer)", "displaytext" => "CentOS 5.6(64-bit) no GUI (XenServer)", "ispublic" => true, @@ -348,8 +356,8 @@ module Fog "domainid" => "6023b6fe-5bef-4358-bc76-9f4e75afa52f", "isextractable" => true, "checksum" => "905cec879afd9c9d22ecc8036131a180"}}, - :service_offerings => { service_offering_id => { - "id" => service_offering_id, + :flavors => { flavor_id => { + "id" => flavor_id, "name" => "Medium Instance", "displaytext" => "Medium Instance", "cpunumber" => 1, diff --git a/lib/fog/cloudstack/models/compute/address.rb b/lib/fog/cloudstack/models/compute/address.rb new file mode 100644 index 000000000..e3924cdf1 --- /dev/null +++ b/lib/fog/cloudstack/models/compute/address.rb @@ -0,0 +1,17 @@ +module Fog + module Compute + class Cloudstack + class Address < Fog::Model + identity :id, :aliases => 'id' + attribute :network_id, :aliases => 'networkid' + attribute :ip_address, :aliases => 'ipaddress' + attribute :traffic_type, :aliases => 'traffictype' + attribute :is_default, :aliases => 'isdefault' + attribute :mac_address, :aliases => 'macaddress' + attribute :netmask + attribute :gateway + attribute :type + end + end + end +end diff --git a/lib/fog/cloudstack/models/compute/flavor.rb b/lib/fog/cloudstack/models/compute/flavor.rb new file mode 100644 index 000000000..f255ac0a6 --- /dev/null +++ b/lib/fog/cloudstack/models/compute/flavor.rb @@ -0,0 +1,33 @@ +module Fog + module Compute + class Cloudstack + class Flavor < Fog::Model + identity :id, :aliases => 'id' + attribute :cpu_number, :aliases => 'cpunumber' + attribute :cpu_speed, :aliases => 'cpuspeed' + attribute :created + attribute :default_use, :aliases => 'defaultuse' + attribute :display_text, :aliases => 'display_text' + attribute :domain + attribute :host_tags, :aliases => 'host_tags' + attribute :is_system, :aliases => 'is_system' + attribute :limit_cpu_use, :aliases => 'limitcpuuse' + attribute :tags + attribute :system_vm_type, :aliases => 'systemvm' + attribute :storage_type, :aliases => 'storagetype' + attribute :offer_ha, :aliases => 'offerha' + attribute :network_rate, :aliases => 'networkrate' + attribute :name + attribute :memory + + def save + raise Fog::Errors::Error.new('Creating a flavor is not supported') + end + + def destroy + raise Fog::Errors::Error.new('Destroying a flavor is not supported') + end + end # Server + end # Cloudstack + end # Compute +end # Fog diff --git a/lib/fog/cloudstack/models/compute/flavors.rb b/lib/fog/cloudstack/models/compute/flavors.rb new file mode 100644 index 000000000..1125681f9 --- /dev/null +++ b/lib/fog/cloudstack/models/compute/flavors.rb @@ -0,0 +1,28 @@ +require 'fog/core/collection' +require 'fog/cloudstack/models/compute/flavor' + +module Fog + module Compute + class Cloudstack + + class Flavors < Fog::Collection + + model Fog::Compute::Cloudstack::Flavor + + def all + data = connection.list_service_offerings["listserviceofferingsresponse"]["serviceoffering"] || [] + load(data) + end + + def get(flavor_id) + if flavor = connection.list_service_offerings('id' => flavor_id)["listserviceofferingsresponse"]["serviceoffering"].first + new(flavor) + end + rescue Fog::Compute::Cloudstack::BadRequest + nil + end + end + + end + end +end diff --git a/lib/fog/cloudstack/models/compute/image.rb b/lib/fog/cloudstack/models/compute/image.rb new file mode 100644 index 000000000..1033c32ca --- /dev/null +++ b/lib/fog/cloudstack/models/compute/image.rb @@ -0,0 +1,72 @@ +module Fog + module Compute + class Cloudstack + class Image < Fog::Model + identity :id, :aliases => 'id' + attribute :account + attribute :account_id, :aliases => 'accountid' + attribute :bootable + attribute :checksum + attribute :created + attribute :cross_zones, :aliases => 'crossZones' + attribute :details + attribute :display_text, :aliases => 'displaytext' + attribute :domain + attribute :domain_id, :aliases => 'domainid' + attribute :format + 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 :name + 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 :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' + + 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, + 'virtualmachineid' => virtual_machine_id, + 'volumeid' => volume_id + } + data = connection.create_template(options) + merge_attributes(data['createtemplateresponse']) + end + + def destroy + requires :id + connection.delete_template('id' => self.id) + true + end + end # Server + end # Cloudstack + end # Compute +end # Fog diff --git a/lib/fog/cloudstack/models/compute/images.rb b/lib/fog/cloudstack/models/compute/images.rb new file mode 100644 index 000000000..363be52c2 --- /dev/null +++ b/lib/fog/cloudstack/models/compute/images.rb @@ -0,0 +1,32 @@ +require 'fog/core/collection' +require 'fog/cloudstack/models/compute/image' + +module Fog + module Compute + class Cloudstack + + class Images < Fog::Collection + + model Fog::Compute::Cloudstack::Image + + def all(filters={}) + options = { + 'templatefilter' => 'self' + }.merge(filters) + + data = connection.list_templates(options)["listtemplatesresponse"]["template"] || [] + load(data) + end + + def get(template_id) + if template = connection.list_templates('id' => template_id)["listtemplatesresponse"]["template"].first + new(template) + 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 c18838072..40d508dfd 100644 --- a/lib/fog/cloudstack/models/compute/server.rb +++ b/lib/fog/cloudstack/models/compute/server.rb @@ -4,27 +4,29 @@ module Fog module Compute class Cloudstack class Server < Fog::Compute::Server - extend Fog::Deprecation identity :id, :aliases => 'id' attribute :name - attribute :display_name, :aliases => 'displayname' attribute :account - attribute :domain_id, :aliases => 'domainid' attribute :domain attribute :created attribute :state attribute :haenable + attribute :memory + attribute :display_name, :aliases => 'displayname' + attribute :domain_id, :aliases => 'domainid' + attribute :host_id, :aliases => 'hostid' + attribute :host_name, :aliases => 'hostname' + attribute :project_id, :aliases => 'projectid' attribute :zone_id, :aliases => 'zoneid' attribute :zone_name, :aliases => 'zonename' - attribute :template_id, :aliases => 'templateid' - attribute :template_name, :aliases => 'templatename' + attribute :image_id, :aliases => ['templateid', :template_id] + attribute :image_name, :aliases => ['templatename', :template_name] attribute :templated_display_text, :aliases => 'templatedisplaytext' attribute :password_enabled, :aliases => 'passwordenabled' - attribute :service_offering_id, :aliases => 'serviceofferingid' - attribute :service_offering_name, :aliases => 'serviceofferingname' + attribute :flavor_id, :aliases => ['serviceofferingid', :service_offering_id] + attribute :flavor_name, :aliases => ['serviceofferingname', :service_offering_name] attribute :cpu_number, :aliases => 'cpunumber' attribute :cpu_speed, :aliases => 'cpuspeed' - attribute :memory attribute :cpu_used, :aliases => 'cpuused' attribute :network_kbs_read, :aliases => 'networkkbsread' attribute :network_kbs_write, :aliases => 'networkkbswrite' @@ -34,23 +36,43 @@ module Fog attribute :security_group, :aliases => 'securitygroup' attribute :nics, :aliases => 'nic' - attr_accessor :network_ids + attr_accessor :network_ids, :disk_offering_id, :ip_address, :ip_to_network_list def ready? - true + state == 'Running' end def save - requires :template_id, :service_offering_id, :zone_id - data = connection.deploy_virtual_machine( - :template_id => template_id, - :service_offering_id => service_offering_id, - :zone_id => zone_id, - :network_ids => network_ids - ) + requires :image_id, :flavor_id, :zone_id + + options = { + 'templateid' => image_id, + 'serviceofferingid' => flavor_id, + 'zoneid' => zone_id, + 'networkids' => network_ids, + 'diskofferingid' => disk_offering_id, + 'displayname' => display_name, + 'domainid' => domain_id, + 'hostid' => host_id, + 'ipaddress' => ip_address, + 'iptonetworklist' => ip_to_network_list, + 'projectid' => project_id + } + + options.merge!('networkids' => network_ids) if network_ids + + data = connection.deploy_virtual_machine(options) merge_attributes(data['deployvirtualmachineresponse']) end + def addresses + nics.map{|nic| Address.new(nic)} + end + + def flavor + connection.flavors.get(self.flavor_id) + end + def destroy requires :id connection.destroy_virtual_machine(:id => id) diff --git a/lib/fog/cloudstack/models/compute/servers.rb b/lib/fog/cloudstack/models/compute/servers.rb index c61ba380f..ea403d8d4 100644 --- a/lib/fog/cloudstack/models/compute/servers.rb +++ b/lib/fog/cloudstack/models/compute/servers.rb @@ -17,7 +17,6 @@ module Fog def bootstrap(new_attributes = {}) server = create(new_attributes) server.wait_for { ready? } - server.setup(:password => server.password) server end diff --git a/lib/fog/cloudstack/models/compute/zone.rb b/lib/fog/cloudstack/models/compute/zone.rb new file mode 100644 index 000000000..8676a01f1 --- /dev/null +++ b/lib/fog/cloudstack/models/compute/zone.rb @@ -0,0 +1,39 @@ +module Fog + module Compute + class Cloudstack + class Zone < Fog::Model + identity :id, :aliases => 'id' + attribute :name + attribute :domain_id, :aliases => 'domainid' + attribute :domain_name, :aliases => ['domainname', 'domain'] + attribute :network_type, :aliases => 'networktype' + attribute :security_groups_enabled, :aliases => ['securitygroupsenabled', 'securitygroupenabled'] + attribute :allocation_state, :aliases => 'allocationstate' + attribute :zone_token, :aliases => 'zonetoken' + attribute :dhcp_provider, :aliases => 'dhcpprovider' + + attr_accessor :dns1, :dns2, :internaldns1, :internaldns2, :guest_cidr_address + + def save + options = { + 'dns1' => dns1, + 'internaldns1' => internaldns1, + 'name' => name, + 'networktype' => network_type, + 'allocationstate' => allocation_state, + 'dns2' => dns2, + 'domain' => domain_name, + 'domainid' => domain_id, + 'guestcidraddress' => guest_cidr_address, + 'internaldns2' => internaldns2, + 'securitygroupenabled' => security_group_enabled, + } + data = connection.create_zone(options) + merge_attributes(data['createzoneresponse']) + end + + end # Zone + end # Cloudstack + end # Compute +end # Fog + diff --git a/lib/fog/cloudstack/models/compute/zones.rb b/lib/fog/cloudstack/models/compute/zones.rb new file mode 100644 index 000000000..38b46e1b6 --- /dev/null +++ b/lib/fog/cloudstack/models/compute/zones.rb @@ -0,0 +1,33 @@ +require 'fog/core/collection' +require 'fog/cloudstack/models/compute/zone' + +module Fog + module Compute + class Cloudstack + + class Zones < Fog::Collection + + model Fog::Compute::Cloudstack::Zone + + def all(filters={}) + options = { + 'templatefilter' => 'self' + }.merge(filters) + + data = connection.list_zones(options)["listzonesresponse"]["zone"] || [] + load(data) + end + + def get(zone_id) + if zone = connection.list_zones('id' => zone_id)["listzonesresponse"]["zone"].first + new(zone) + end + rescue Fog::Compute::Cloudstack::BadRequest + nil + end + end + + end + end +end + diff --git a/lib/fog/cloudstack/requests/compute/delete_template.rb b/lib/fog/cloudstack/requests/compute/delete_template.rb new file mode 100644 index 000000000..6e6c1125a --- /dev/null +++ b/lib/fog/cloudstack/requests/compute/delete_template.rb @@ -0,0 +1,20 @@ +module Fog + module Compute + class Cloudstack + class Real + + # Deletes a specified template. + # + # {CloudStack API Reference}[http://http://download.cloud.com/releases/3.0.0/api_3.0.0/user/deleteTemplate.html] + def delete_template(options={}) + options.merge!( + 'command' => 'deleteTemplate' + ) + + request(options) + end + + end + end + end +end diff --git a/lib/fog/cloudstack/requests/compute/deploy_virtual_machine.rb b/lib/fog/cloudstack/requests/compute/deploy_virtual_machine.rb index 2fb5db753..52aeb8574 100644 --- a/lib/fog/cloudstack/requests/compute/deploy_virtual_machine.rb +++ b/lib/fog/cloudstack/requests/compute/deploy_virtual_machine.rb @@ -11,25 +11,18 @@ module Fog 'command' => 'deployVirtualMachine' ) - security_group_ids = options.delete(:security_group_ids) - if security_group_ids + if security_group_ids = options.delete('securitygroupids') options.merge!('securitygroupids' => Array(security_group_ids).join(',')) end - security_group_names = options.delete(:security_group_names) - if security_group_names + if security_group_names = options.delete('securitygroupnames') options.merge!('securitygroupnames' => Array(security_group_names).join(',')) end - network_ids = options.delete(:network_ids) - if network_ids + if network_ids = options.delete('networkids') options.merge!('networkids' => Array(network_ids).join(',')) end - options["zoneid"]= options.delete(:zone_id) if options.key?(:zone_id) - options["templateid"]= options.delete(:template_id) if options.key?(:template_id) - options["serviceofferingid"]= options.delete(:service_offering_id) if options.key?(:service_offering_id) - request(options) end end # Real @@ -37,24 +30,24 @@ module Fog class Mock def deploy_virtual_machine(options={}) - zone_id = options[:zone_id] + zone_id = options['zoneid'] unless zone_id raise Fog::Compute::Cloudstack::BadRequest.new('Unable to execute API command deployvirtualmachine due to missing parameter zoneid') end unless zone = self.data[:zones][zone_id] - raise Fog::Compute::Cloudstack::BadRequest.new("Unable to execute API command deployvirtualmachine due to invalid value. Object networks(uuid: #{zone_id}) does not exist.") + raise Fog::Compute::Cloudstack::BadRequest.new("Unable to execute API command deployvirtualmachine due to invalid value. Object zone(uuid: #{zone_id}) does not exist.") end zone_name = zone[:name] - template_id = options[:template_id] - unless template = self.data[:templates][options[:template_id]] + template_id = options['templateid'] + unless template = self.data[:images][template_id] raise Fog::Compute::Cloudstack::BadRequest.new('Unable to execute API command deployvirtualmachine due to missing parameter templateid') end template_name = template[:name] template_display_text = template[:display_text] - service_offering_id = options[:service_offering_id] - unless service_offering = self.data[:service_offerings][options[:service_offering_id]] + service_offering_id = options['serviceofferingid'] + unless service_offering = self.data[:flavors][service_offering_id] raise Fog::Compute::Cloudstack::BadRequest.new('Unable to execute API command deployvirtualmachine due to missing parameter serviceofferingid') end @@ -64,11 +57,11 @@ module Fog service_offering_memory = service_offering[:cpumemory] identity = Fog::Cloudstack.uuid - name = options[:name] || Fog::Cloudstack.uuid - display_name = options[:display_name] || name - account_name = options[:account] || self.data[:accounts].first[1]["name"] + name = options['name'] || Fog::Cloudstack.uuid + display_name = options['displayname'] || name + account_name = options['account'] || self.data[:accounts].first[1]["name"] - domain = options[:domain_id] ? self.data[:domains][options[:domain_id]] : self.data[:domains].first[1] + domain = options['domainid'] ? self.data[:domains][options['domainid']] : self.data[:domains].first[1] domain_id = domain[:id] domain_name = domain[:name] @@ -78,9 +71,9 @@ module Fog guest_os_id = Fog::Cloudstack.uuid - security_group_ids = options[:security_group_ids] || [] # TODO: for now + security_group_ids = options['securitygroupids'] || [] # TODO: for now - network_ids = Array(options[:network_ids]) || [self.data[:networks].first[1]["id"]] + network_ids = Array(options['networkids']) || [self.data[:networks].first[1]["id"]] networks = network_ids.map{|nid| self.data[:networks][nid]} nic = networks.map do |network| { @@ -126,6 +119,7 @@ module Fog "securitygroup" => security_group_ids, # TODO: mayhaps? "nic" => nic } + self.data[:servers][identity]= virtual_machine {'deployvirtualmachineresponse' => virtual_machine} end diff --git a/lib/fog/cloudstack/requests/compute/list_service_offerings.rb b/lib/fog/cloudstack/requests/compute/list_service_offerings.rb index c7324c434..691caa4c2 100644 --- a/lib/fog/cloudstack/requests/compute/list_service_offerings.rb +++ b/lib/fog/cloudstack/requests/compute/list_service_offerings.rb @@ -10,11 +10,26 @@ module Fog options.merge!( 'command' => 'listServiceOfferings' ) - + request(options) end - end - end - end -end + end # Real + + class Mock + + def list_service_offerings(options={}) + flavors = self.data[:flavors].values + + { + "listserviceofferingsresponse" => + { + "count" => flavors.size, + "serviceoffering"=> flavors + } + } + end + end # Mock + end # Cloudstack + end # Compute +end # Fog diff --git a/lib/fog/cloudstack/requests/compute/list_templates.rb b/lib/fog/cloudstack/requests/compute/list_templates.rb index 1b230e0ef..09020f51e 100644 --- a/lib/fog/cloudstack/requests/compute/list_templates.rb +++ b/lib/fog/cloudstack/requests/compute/list_templates.rb @@ -10,11 +10,26 @@ module Fog options.merge!( 'command' => 'listTemplates' ) - + request(options) end - end - end - end -end + end # Real + + class Mock + + def list_templates(options={}) + templates = self.data[:images].values + + { + "listtemplatesresponse" => + { + "count" => templates.size, + "template"=> templates + } + } + end + end # Mock + end # Cloudstack + end # Compute +end # Fog diff --git a/lib/fog/cloudstack/requests/compute/list_zones.rb b/lib/fog/cloudstack/requests/compute/list_zones.rb index 639f1969c..e1b140c43 100644 --- a/lib/fog/cloudstack/requests/compute/list_zones.rb +++ b/lib/fog/cloudstack/requests/compute/list_zones.rb @@ -14,7 +14,21 @@ module Fog request(options) end - end - end - end -end + end # Real + + class Mock + def list_zones(options={}) + zones = self.data[:zones].values + + { + "listzonesresponse"=> + { + "count" => zones.size, + "zone" => zones + } + } + end + end # Mock + end # Cloudstack + end # Compute +end # Fog