diff --git a/install.sh b/install.sh
index 70dfc3f939..bc5d6a6505 100755
--- a/install.sh
+++ b/install.sh
@@ -1320,6 +1320,7 @@ ECO_LIB_FILES="src/cloud/ec2/lib/EC2QueryClient.rb \
src/cloud/ec2/lib/ImageEC2.rb \
src/cloud/ec2/lib/elastic_ip.rb \
src/cloud/ec2/lib/ebs.rb \
+ src/cloud/ec2/lib/tags.rb \
src/cloud/ec2/lib/instance.rb \
src/cloud/ec2/lib/keypair.rb \
src/cloud/ec2/lib/net_ssh_replacement.rb \
@@ -1332,7 +1333,14 @@ ECO_LIB_VIEW_FILES="src/cloud/ec2/lib/views/describe_images.erb \
src/cloud/ec2/lib/views/describe_instances.erb \
src/cloud/ec2/lib/views/describe_regions.erb \
src/cloud/ec2/lib/views/describe_availability_zones.erb \
+ src/cloud/ec2/lib/views/create_tags.erb \
+ src/cloud/ec2/lib/views/delete_tags.erb \
+ src/cloud/ec2/lib/views/describe_tags.erb \
src/cloud/ec2/lib/views/create_volume.erb \
+ src/cloud/ec2/lib/views/create_snapshot.erb \
+ src/cloud/ec2/lib/views/delete_snapshot.erb \
+ src/cloud/ec2/lib/views/describe_snapshots.erb \
+ src/cloud/ec2/lib/views/create_image.erb \
src/cloud/ec2/lib/views/describe_volumes.erb \
src/cloud/ec2/lib/views/attach_volume.erb \
src/cloud/ec2/lib/views/detach_volume.erb \
diff --git a/src/cloud/ec2/etc/econe.conf b/src/cloud/ec2/etc/econe.conf
index ee43a6a706..c8bb64e440 100644
--- a/src/cloud/ec2/etc/econe.conf
+++ b/src/cloud/ec2/etc/econe.conf
@@ -64,6 +64,20 @@
# default 1
#:datastore_id:
+# Include terminated instances in the describe_instances xml
+:describe_with_terminated_instances: = true
+# Terminated VMs will be included in the list
+# till the termination date + TERMINATED_INSTANCES_EXPIRATION_TIME is reached
+:terminated_instances_expiration_time: 900
+
+
+#############################################################
+# [DEPRECATED] File based templates
+#############################################################
+
+# Use former file based templates for instance types instead
+# of OpenNebula templates
+:use_file_templates: false
# VM types allowed and its template file (inside templates directory)
:instance_types:
diff --git a/src/cloud/ec2/lib/EC2QueryServer.rb b/src/cloud/ec2/lib/EC2QueryServer.rb
index f40d406825..bd8b4c460e 100644
--- a/src/cloud/ec2/lib/EC2QueryServer.rb
+++ b/src/cloud/ec2/lib/EC2QueryServer.rb
@@ -28,6 +28,7 @@ require 'ebs'
require 'elastic_ip'
require 'instance'
require 'keypair'
+require 'tags'
################################################################################
# Extends the OpenNebula::Error class to include an EC2 render of error
@@ -126,20 +127,30 @@ class EC2QueryServer < CloudServer
return response.result(binding), 200
end
+ # TODO Kernel, Ramdisk, Arch, BlockDeviceMapping
def register_image(params)
# Get the Image ID
- tmp, img=params['ImageLocation'].split('-')
+ image_id = params['ImageLocation']
+ image = ImageEC2.new(Image.build_xml(image_id.to_i), @client)
- image = Image.new(Image.build_xml(img.to_i), @client)
-
- # Enable the new Image
rc = image.info
if OpenNebula.is_error?(rc)
- rc.ec2_code = "InvalidAMIID.NotFound"
return rc
end
- image.enable
+ if image["EBS_VOLUME"] == "YES"
+ return OpenNebula::Error.new("The image you are trying to register"\
+ " is already a volume")
+ elsif image["EBS_SNAPSHOT"] == "YES"
+ return OpenNebula::Error.new("The image you are trying to register"\
+ " is already an snapshot")
+ end
+
+ image.add_element('TEMPLATE', {"EC2_AMI" => "YES"})
+ rc = image.update
+ if OpenNebula.is_error?(rc)
+ return rc
+ end
erb_version = params['Version']
@@ -148,11 +159,34 @@ class EC2QueryServer < CloudServer
end
def describe_images(params)
- user_flag = OpenNebula::Pool::INFO_ALL
- impool = ImageEC2Pool.new(@client, user_flag)
+ impool = []
+ params.each { |key, value|
+ if key =~ /ImageId\./
+ if value =~ /ami\-(.+)/
+ image = ImageEC2.new(Image.build_xml($1), @client)
+ rc = image.info
+ if OpenNebula.is_error?(rc) || !image.ec2_ami?
+ rc ||= OpenNebula::Error.new()
+ rc.ec2_code = "InvalidAMIID.NotFound"
+ return rc
+ else
+ impool << image
+ end
+ else
+ rc = OpenNebula::Error.new("InvalidAMIID.Malformed #{value}")
+ rc.ec2_code = "InvalidAMIID.Malformed"
+ return rc
+ end
+ end
+ }
- rc = impool.info
- return rc if OpenNebula::is_error?(rc)
+ if impool.empty?
+ user_flag = OpenNebula::Pool::INFO_ALL
+ impool = ImageEC2Pool.new(@client, user_flag)
+
+ rc = impool.info
+ return rc if OpenNebula::is_error?(rc)
+ end
erb_version = params['Version']
@@ -160,6 +194,43 @@ class EC2QueryServer < CloudServer
return response.result(binding), 200
end
+ # TODO: NoReboot = false, cleanly shut down the instance before image
+ # creation and then reboots the instance.
+ # TODO: If you customized your instance with instance store volumes
+ # or EBS volumes in addition to the root device volume, the
+ # new AMI contains block device mapping information for those volumes
+ def create_image(params)
+ instance_id = params['InstanceId']
+ instance_id = instance_id.split('-')[1]
+
+ vm = VirtualMachine.new(
+ VirtualMachine.build_xml(instance_id),
+ @client)
+
+ rc = vm.info
+ if OpenNebula::is_error?(rc)
+ rc.ec2_code = "InvalidInstanceID.NotFound"
+ return rc
+ end
+
+ image_id = vm.disk_snapshot(1,
+ params["Name"],
+ OpenNebula::Image::IMAGE_TYPES[0],
+ true)
+
+ # TODO Add AMI Tags
+ # TODO A new persistent image should be created for each instance
+
+ if OpenNebula::is_error?(image_id)
+ return image_id
+ end
+
+ erb_version = params['Version']
+
+ response = ERB.new(File.read(@config[:views]+"/create_image.erb"))
+ return response.result(binding), 200
+ end
+
###########################################################################
# Helper functions
###########################################################################
diff --git a/src/cloud/ec2/lib/ImageEC2.rb b/src/cloud/ec2/lib/ImageEC2.rb
index 448ad07fd1..6939b67d1e 100644
--- a/src/cloud/ec2/lib/ImageEC2.rb
+++ b/src/cloud/ec2/lib/ImageEC2.rb
@@ -44,7 +44,7 @@ class ImageEC2 < Image
}
ONE_IMAGE = %q{
- NAME = "ec2-<%= uuid %>"
+ NAME = "<%= ImageEC2.generate_uuid %>"
TYPE = <%= @image_info[:type] %>
<% if @image_info[:size] != nil %>
SIZE = "<%= @image_info[:size] %>"
@@ -55,7 +55,7 @@ class ImageEC2 < Image
<% if @image_info[:persistent] != nil %>
PERSISTENT = "YES"
<% end %>
- <% if @image_info[:ebs] != nil %>
+ <% if @image_info[:ebs_volume] != nil %>
EBS_VOLUME = "YES"
<% end %>
<% if @image_file != nil %>
@@ -74,8 +74,6 @@ class ImageEC2 < Image
end
def to_one_template()
- uuid = UUIDTools::UUID.random_create.to_s
-
one = ERB.new(ONE_IMAGE)
return one.result(binding)
end
@@ -91,4 +89,40 @@ class ImageEC2 < Image
def render_create_time
Time.at(self["REGTIME"].to_i).xmlschema
end
+
+ def self.generate_uuid
+ "ec2-" + UUIDTools::UUID.random_create.to_s
+ end
+
+ def ebs_volume?
+ self["TEMPLATE/EBS_VOLUME"] == "YES"
+ end
+
+ def ec2_ami?
+ self["TEMPLATE/EC2_AMI"] == "YES"
+ end
+
+ def ebs_snapshot?
+ self["TEMPLATE/EBS_SNAPSHOT"] == "YES"
+ end
+
+ def ec2_id
+ if self.ebs_snapshot?
+ "snap-" + sprintf('%08i', self.id)
+ elsif self.ec2_ami?
+ "ami-" + sprintf('%08i', self.id)
+ elsif self.ebs_volume?
+ "vol-" + sprintf('%08i', self.id)
+ end
+ end
+
+ def resource_type
+ if self.ebs_snapshot?
+ "snapshot"
+ elsif self.ec2_ami?
+ "image"
+ elsif self.ebs_volume?
+ "volume"
+ end
+ end
end
diff --git a/src/cloud/ec2/lib/ebs.rb b/src/cloud/ec2/lib/ebs.rb
index e5c2ed7a63..c2b7b3a26e 100644
--- a/src/cloud/ec2/lib/ebs.rb
+++ b/src/cloud/ec2/lib/ebs.rb
@@ -168,34 +168,65 @@ module EBS
# the new volume (unsupported).
# @option params [String] AvailabilityZone The Availability Zone in which
# to create the new volume (unsupported)
+ # TODO: Availability zone
def create_volume(params)
- size = params['Size'].to_i # in GiBs
- size *= 1024
+ snapshot_id = params['SnapshotId']
+ if snapshot_id
+ snapshot_id = snapshot_id.split('-')[1]
- opts = {
- :type => "DATABLOCK",
- :size => size,
- :fstype => @config[:ebs_fstype]||DEFAULT_FSTYPE,
- :persistent => "YES",
- :ebs => "YES"
- }
+ snapshot = ImageEC2.new(Image.build_xml(snapshot_id.to_i), @client)
+ rc = snapshot.info
+ if OpenNebula::is_error?(rc) || !snapshot.ebs_snapshot?
+ rc ||= OpenNebula::Error.new()
+ rc.ec2_code = "InvalidSnapshot.NotFound"
+ return rc
+ end
- image = ImageEC2.new(Image.build_xml, @client, nil, opts)
- template = image.to_one_template
+ # Clone
+ volume_id = snapshot.clone(ImageEC2.generate_uuid)
+ if OpenNebula::is_error?(volume_id)
+ return volume_id
+ end
- if OpenNebula.is_error?(template)
- return template
+ volume = ImageEC2.new(Image.build_xml(volume_id.to_i), @client)
+ rc = volume.info
+ if OpenNebula::is_error?(rc)
+ return rc
+ end
+
+ volume.delete_element("TEMPLATE/EBS_SNAPSHOT")
+ volume.add_element('TEMPLATE', {
+ "EBS_VOLUME" => "YES",
+ "EBS_FROM_SNAPSHOT_ID" => snapshot.ec2_id})
+ volume.update
+ else
+ size = params['Size'].to_i # in GiBs
+ size *= 1024
+
+ opts = {
+ :type => "DATABLOCK",
+ :size => size,
+ :fstype => @config[:ebs_fstype]||DEFAULT_FSTYPE,
+ :persistent => "YES",
+ :ebs_volume => "YES"
+ }
+
+ volume = ImageEC2.new(Image.build_xml, @client, nil, opts)
+ template = volume.to_one_template
+
+ if OpenNebula.is_error?(template)
+ return template
+ end
+
+ rc = volume.allocate(template, @config[:datastore_id]||1)
+
+ if OpenNebula.is_error?(rc)
+ return rc
+ end
+
+ volume.info
end
- rc = image.allocate(template, @config[:datastore_id]||1)
-
- if OpenNebula.is_error?(rc)
- return rc
- end
-
- # Response
- image.info
-
erb_version = params['Version']
response = ERB.new(File.read(@config[:views]+"/create_volume.erb"))
@@ -237,4 +268,134 @@ module EBS
return response.result(binding), 200
end
+ # Creates a snapshot of an Amazon EBS volume
+ #
+ # @param [Hash] params
+ # @option params [String] VolumeId The ID of the Amazon EBS volume.
+ # @option params [String] Description A description for the snapshot.
+ def create_snapshot(params)
+ image_id = params['VolumeId']
+ image_id = image_id.split('-')[1]
+
+ image = ImageEC2.new(Image.build_xml(image_id.to_i), @client)
+ rc = image.info
+ if OpenNebula::is_error?(rc) || !image.ebs_volume?
+ rc ||= OpenNebula::Error.new()
+ rc.ec2_code = "InvalidVolume.NotFound"
+ return rc
+ end
+
+ instance_id = image["TEMPLATE/EBS/INSTANCE_ID"]
+
+ if instance_id
+ # Disk snapshot
+ instance_id = instance_id.split('-')[1]
+ vm = VirtualMachine.new(
+ VirtualMachine.build_xml(instance_id),
+ @client)
+
+ rc = vm.info
+ if OpenNebula::is_error?(rc)
+ rc.ec2_code = "InvalidInstanceID.NotFound"
+ return rc
+ end
+
+ disk_id = vm["TEMPLATE/DISK[IMAGE_ID=#{image_id}]/DISK_ID"]
+ if !disk_id.nil?
+ snapshot_id = vm.disk_snapshot(disk_id.to_i,
+ params["Description"]||ImageEC2.generate_uuid,
+ OpenNebula::Image::IMAGE_TYPES[image["TYPE"].to_i],
+ true)
+
+ if OpenNebula::is_error?(snapshot_id)
+ return snapshot_id
+ end
+ end
+ end
+
+ if snapshot_id.nil?
+ # Clone
+ snapshot_id = image.clone(params["Description"]||ImageEC2.generate_uuid)
+ if OpenNebula::is_error?(snapshot_id)
+ return snapshot_id
+ end
+ end
+
+ snapshot = ImageEC2.new(Image.build_xml(snapshot_id.to_i), @client)
+ rc = snapshot.info
+ if OpenNebula::is_error?(rc)
+ return rc
+ end
+
+ snapshot.delete_element("TEMPLATE/EBS_VOLUME")
+ snapshot.add_element('TEMPLATE', {"EBS_SNAPSHOT" => "YES"})
+ snapshot.update
+
+ erb_version = params['Version']
+
+ response = ERB.new(File.read(@config[:views]+"/create_snapshot.erb"))
+ return response.result(binding), 200
+ end
+
+ # Deletes the specified snapshot.
+ #
+ # @param [Hash] params
+ # @option params [String] SnapshotId The ID of the Amazon EBS snapshot.
+ def delete_snapshot(params)
+ snapshot_id = params['SnapshotId']
+ snapshot_id = snapshot_id.split('-')[1]
+
+ snapshot = ImageEC2.new(Image.build_xml(snapshot_id.to_i), @client)
+ rc = snapshot.info
+ if OpenNebula::is_error?(rc) || !snapshot.ebs_snapshot?
+ rc ||= OpenNebula::Error.new()
+ rc.ec2_code = "InvalidSnapshot.NotFound"
+ return rc
+ end
+
+ rc = snapshot.delete
+ if OpenNebula::is_error?(rc)
+ return rc
+ end
+
+ erb_version = params['Version']
+
+ response = ERB.new(File.read(@config[:views]+"/delete_snapshot.erb"))
+ return response.result(binding), 200
+ end
+
+ def describe_snapshots(params)
+ impool = []
+ params.each { |key, value|
+ if key =~ /SnapshotId\./
+ if value =~ /snap\-(.+)/
+ image = ImageEC2.new(Image.build_xml($1), @client)
+ rc = image.info
+ if OpenNebula.is_error?(rc) || !image.ebs_snapshot?
+ rc.ec2_code = "InvalidSnapshot.NotFound"
+ return rc
+ else
+ impool << image
+ end
+ else
+ rc = OpenNebula::Error.new("InvalidSnapshot.Malformed #{value}")
+ rc.ec2_code = "InvalidSnapshot.Malformed"
+ return rc
+ end
+ end
+ }
+
+ if impool.empty?
+ user_flag = OpenNebula::Pool::INFO_ALL
+ impool = ImageEC2Pool.new(@client, user_flag)
+
+ rc = impool.info
+ return rc if OpenNebula::is_error?(rc)
+ end
+
+ erb_version = params['Version']
+
+ response = ERB.new(File.read(@config[:views]+"/describe_snapshots.erb"))
+ return response.result(binding), 200
+ end
end
diff --git a/src/cloud/ec2/lib/econe_application.rb b/src/cloud/ec2/lib/econe_application.rb
index 7360f720c3..c6de59116e 100644
--- a/src/cloud/ec2/lib/econe_application.rb
+++ b/src/cloud/ec2/lib/econe_application.rb
@@ -134,6 +134,20 @@ class EC2Application
result,rc = econe_server.describe_regions(params)
when 'DescribeAvailabilityZones'
result,rc = econe_server.describe_availability_zones(params)
+ when 'CreateSnapshot'
+ result,rc = econe_server.create_snapshot(params)
+ when 'DeleteSnapshot'
+ result,rc = econe_server.delete_snapshot(params)
+ when 'DescribeSnapshots'
+ result,rc = econe_server.describe_snapshots(params)
+ when 'CreateTags'
+ result,rc = econe_server.create_tags(params)
+ when 'DeleteTags'
+ result,rc = econe_server.delete_tags(params)
+ when 'DescribeTags'
+ result,rc = econe_server.describe_tags(params)
+ #when 'CreateImage'
+ # result,rc = econe_server.create_image(params)
when 'CreateVolume'
result,rc = econe_server.create_volume(params)
when 'DescribeVolumes'
diff --git a/src/cloud/ec2/lib/instance.rb b/src/cloud/ec2/lib/instance.rb
index 5a49f739ae..6586969ffa 100644
--- a/src/cloud/ec2/lib/instance.rb
+++ b/src/cloud/ec2/lib/instance.rb
@@ -47,58 +47,147 @@ module Instance
'unkn' => :terminated
}
- def run_instances(params)
- # Get the instance type and path
- if params['InstanceType'] != nil
- instance_type_name = params['InstanceType']
- instance_type = @config[:instance_types][instance_type_name.to_sym]
+ EC2_ACTIONS = {
+ :start => :resume,
+ :stop => :poweroff,
+ :terminate => :shutdown,
+ :reboot => :reboot
+ }
- if instance_type != nil
- path = @config[:template_location] + "/#{instance_type[:template]}"
- end
+ # Include terminated instances in the describe_instances xml
+ DESCRIBE_WITH_TERMINATED_INSTANCES = true
+ # Terminated VMs will be included in the list
+ # till the termination date + TERMINATED_INSTANCES_EXPIRATION_TIME is reached
+ TERMINATED_INSTANCES_EXPIRATION_TIME = 900
+
+ def run_instances(params)
+ # Get the image
+ img = nil
+ if params['ImageId'] =~ /ami\-(.+)/
+ img = $1
+ else
+ rc = OpenNebula::Error.new("InvalidAMIID.Malformed #{params['ImageId']}")
+ rc.ec2_code = "InvalidAMIID.Malformed"
+ return rc
end
- # Get the image
- tmp, img = params['ImageId'].split('-')
+ if @config[:use_file_templates]
+ # Get the instance type and path
+ if params['InstanceType'] != nil
+ instance_type_name = params['InstanceType']
+ instance_type = @config[:instance_types][instance_type_name.to_sym]
- # Build the VM
- erb_vm_info = Hash.new
-
- erb_vm_info[:img_id] = img.to_i
- erb_vm_info[:ec2_img_id] = params['ImageId']
- erb_vm_info[:instance_type] = instance_type_name
- erb_vm_info[:template] = path
- erb_vm_info[:user_data] = params['UserData']
- erb_vm_info[:public_key] = fetch_publickey(params)
- erb_vm_info[:key_name] = params['KeyName']
-
- template = ERB.new(File.read(erb_vm_info[:template]))
- template_text = template.result(binding)
-
- erb_vms = Array.new
-
- min_count = params['MinCount'] || 1
- max_count = params['MaxCount'] || min_count
-
- max_count.to_i.times {
- # Start the VM.
- instance = VirtualMachine.new(VirtualMachine.build_xml, @client)
-
- rc = instance.allocate(template_text)
- if OpenNebula::is_error?(rc)
- if erb_vms.size < min_count.to_i
- erb_vms.each { |vm|
- vm.finalize
- }
-
- return rc
+ if instance_type != nil
+ path = @config[:template_location] + "/#{instance_type[:template]}"
end
- else
- instance.info
-
- erb_vms << instance
end
- }
+
+ # Build the VM
+ erb_vm_info = Hash.new
+
+ erb_vm_info[:img_id] = img.to_i
+ erb_vm_info[:ec2_img_id] = params['ImageId']
+ erb_vm_info[:instance_type] = instance_type_name
+ erb_vm_info[:template] = path
+ erb_vm_info[:user_data] = params['UserData']
+ erb_vm_info[:public_key] = fetch_publickey(params)
+ erb_vm_info[:key_name] = params['KeyName']
+
+ template = ERB.new(File.read(erb_vm_info[:template]))
+ template_text = template.result(binding)
+
+ erb_vms = Array.new
+
+ min_count = params['MinCount'] || 1
+ max_count = params['MaxCount'] || min_count
+
+ max_count.to_i.times {
+ # Start the VM.
+ instance = VirtualMachine.new(VirtualMachine.build_xml, @client)
+
+ rc = instance.allocate(template_text)
+ if OpenNebula::is_error?(rc)
+ if erb_vms.size < min_count.to_i
+ erb_vms.each { |vm|
+ vm.finalize
+ }
+
+ return rc
+ end
+ else
+ instance.info
+
+ erb_vms << instance
+ end
+ }
+ else
+ template_pool = TemplatePool.new(@client)
+ rc = template_pool.info
+ if OpenNebula::is_error?(rc)
+ return rc
+ end
+
+ template_id = template_pool["VMTEMPLATE/TEMPLATE[EC2_INSTANCE_TYPE=\'#{params['InstanceType']}\']/../ID"]
+ if template_id.nil?
+ rc.ec2_code = "InvalidInstanceID.NotFound"
+ return rc
+ end
+
+ template = Template.new(Template.build_xml(template_id), @client)
+ rc = template.info
+ if OpenNebula.is_error?(rc)
+ rc.ec2_code = "InvalidInstanceID.NotFound"
+ return rc
+ end
+
+ merge_info = {}
+ merge_info["DISK"] = []
+ merge_info["DISK"] << {"IMAGE_ID" => img.to_i}
+
+
+ template.each("TEMPLATE/DISK") { |e|
+ merge_info["DISK"] << e.to_hash["DISK"]
+ }
+
+ merge_info["CONTEXT"] = {}
+ template.each("TEMPLATE/CONTEXT") { |e|
+ merge_info["CONTEXT"] = e.to_hash["CONTEXT"]
+ }
+
+ context = merge_info["CONTEXT"]
+
+ public_key = fetch_publickey(params)
+ context["EC2_PUBLIC_KEY"] = public_key if public_key
+ context["EC2_KEYNAME"] = params['KeyName'] if params['KeyName']
+ context["EC2_USER_DATA"] = params['UserData'] if params['UserData']
+
+ template_str = template_to_str(merge_info)
+ vm_id =
+
+ erb_vms = Array.new
+
+ min_count = params['MinCount'] || 1
+ max_count = params['MaxCount'] || min_count
+
+ max_count.to_i.times {
+ # Start the VM.
+ rc = template.instantiate("", false, template_str)
+ if OpenNebula::is_error?(rc)
+ if erb_vms.size < min_count.to_i
+ erb_vms.each { |vm|
+ vm.finalize
+ }
+
+ return rc
+ end
+ else
+ instance = VirtualMachine.new(VirtualMachine.build_xml(rc), @client)
+ instance.info
+
+ erb_vms << instance
+ end
+ }
+ end
erb_user_name = params['AWSAccessKeyId']
erb_version = params['Version']
@@ -108,11 +197,39 @@ module Instance
end
def describe_instances(params)
- user_flag = OpenNebula::Pool::INFO_ALL
- vmpool = VirtualMachinePool.new(@client, user_flag)
+ vmpool = []
+ params.each { |key, value|
+ if key =~ /InstanceId\./
+ if value =~ /i\-(.+)/
+ vm = VirtualMachine.new(VirtualMachine.build_xml($1), @client)
+ rc = vm.info
+ if OpenNebula.is_error?(rc)
+ rc.ec2_code = "InvalidInstanceID.NotFound"
+ return rc
+ else
+ vmpool << vm
+ end
+ else
+ rc = OpenNebula::Error.new("InvalidInstanceID.Malformed #{value}")
+ rc.ec2_code = "InvalidInstanceID.Malformed"
+ return rc
+ end
+ end
+ }
- rc = vmpool.info
- return rc if OpenNebula::is_error?(rc)
+ if vmpool.empty?
+ user_flag = OpenNebula::Pool::INFO_ALL
+ vmpool = VirtualMachinePool.new(@client, user_flag)
+
+ if include_terminated_instances?
+ rc = vmpool.info(user_flag, -1, -1,
+ OpenNebula::VirtualMachinePool::INFO_ALL_VM)
+ else
+ rc = vmpool.info
+ end
+
+ return rc if OpenNebula::is_error?(rc)
+ end
erb_version = params['Version']
erb_user_name = params['AWSAccessKeyId']
@@ -124,7 +241,7 @@ module Instance
def terminate_instances(params)
perform_action(params, "terminate_instances.erb") { |vm|
if vm.status == 'runn'
- vm.shutdown
+ vm.send(EC2_ACTIONS[:terminate])
else
vm.finalize
end
@@ -133,19 +250,19 @@ module Instance
def start_instances(params)
perform_action(params, "start_instances.erb") { |vm|
- vm.resume
+ vm.send(EC2_ACTIONS[:start])
}
end
def stop_instances(params)
perform_action(params, "stop_instances.erb") { |vm|
- vm.stop
+ vm.send(EC2_ACTIONS[:stop])
}
end
def reboot_instances(params)
perform_action(params, "reboot_instances.erb") { |vm|
- vm.reboot
+ vm.send(EC2_ACTIONS[:reboot])
}
end
@@ -171,6 +288,7 @@ module Instance
rc = vm.info
if OpenNebula::is_error?(rc)
+ rc.ec2_code = "InvalidInstanceID.NotFound"
return rc
end
@@ -208,4 +326,68 @@ module Instance
instance_id = "i-" + sprintf('%08i', vm.id)
return "#{instance_id}"
end
+
+ def include_terminated_instances?
+ @config[:describe_with_terminated_instances] || DESCRIBE_WITH_TERMINATED_INSTANCES
+ end
+
+ def include_terminated_instance?(vm)
+ if include_terminated_instances?
+ if EC2_STATES[ONE_STATES[vm.status]||:pending][:name] == "terminated"
+ if (Time.now.getutc.to_i - vm["ETIME"].to_i) <= TERMINATED_INSTANCES_EXPIRATION_TIME
+ return true
+ else
+ return false
+ end
+ end
+ end
+
+ return true
+ end
+
+ def template_to_str(attributes, indent=true)
+ if indent
+ ind_enter="\n"
+ ind_tab=' '
+ else
+ ind_enter=''
+ ind_tab=' '
+ end
+
+ str=attributes.collect do |key, value|
+ if value
+ str_line=""
+ if value.class==Array && !value.empty?
+ value.each do |value2|
+ str_line << key.to_s.upcase << "=[" << ind_enter
+ if value2 && value2.class==Hash
+ str_line << value2.collect do |key3, value3|
+ str = ind_tab + key3.to_s.upcase + "="
+ str += "\"#{value3.to_s}\"" if value3
+ str
+ end.compact.join(",\n")
+ end
+ str_line << "\n]\n"
+ end
+
+ elsif value.class==Hash && !value.empty?
+ str_line << key.to_s.upcase << "=[" << ind_enter
+
+ str_line << value.collect do |key3, value3|
+ str = ind_tab + key3.to_s.upcase + "="
+ str += "\"#{value3.to_s}\"" if value3
+ str
+ end.compact.join(",\n")
+
+ str_line << "\n]\n"
+
+ else
+ str_line< former_tags.merge(tags)})
+
+ rc = resource.update(resource.template_like_str(template_key))
+ return rc if OpenNebula::is_error?(rc)
+ }
+
+ erb_version = params['Version']
+
+ response = ERB.new(File.read(@config[:views]+"/create_tags.erb"))
+ return response.result(binding), 200
+ end
+
+ # Deletes the specified set of tags from the specified set of resources.
+ #
+ # @param [Hash] params
+ # @option params [String] ResourceId.n The IDs of one or more resources
+ # to tag. For example, ami-1a2b3c4d.
+ # @option params [String] Tag.n.Key The key for a tag.
+ # @option params [String] Tag.n.Value The value for a tag. If you don't
+ # want the tag to have a value, specify the parameter with no value,
+ # and we set the value to an empty string.
+ #
+ # TODO: return if error or continue
+ def delete_tags(params)
+ resources = []
+ tags = {}
+
+ params.each { |key, value|
+ case key
+ when /ResourceId\./
+ resources << case value
+ when /ami\-(.+)/
+ image = ImageEC2.new(Image.build_xml($1), @client)
+ rc = image.info
+ if OpenNebula.is_error?(rc) || !image.ec2_ami?
+ rc ||= OpenNebula::Error.new()
+ rc.ec2_code = "InvalidAMIID.NotFound"
+ return rc
+ else
+ image
+ end
+ when /vol\-(.+)/
+ image = ImageEC2.new(Image.build_xml($1), @client)
+ rc = image.info
+ if OpenNebula.is_error?(rc) || !image.ebs_volume?
+ rc ||= OpenNebula::Error.new()
+ rc.ec2_code = "InvalidVolume.NotFound"
+ return rc
+ else
+ image
+ end
+ when /snap\-(.+)/
+ image = ImageEC2.new(Image.build_xml($1), @client)
+ rc = image.info
+ if OpenNebula.is_error?(rc) || !image.ebs_snapshot?
+ rc ||= OpenNebula::Error.new()
+ rc.ec2_code = "InvalidSnapshot.NotFound"
+ return rc
+ else
+ image
+ end
+ when /i\-(.+)/
+ vm = VirtualMachine.new(VirtualMachine.build_xml($1), @client)
+ rc = vm.info
+ if OpenNebula.is_error?(rc)
+ rc.ec2_code = "InvalidInstanceID.NotFound"
+ return rc
+ else
+ vm
+ end
+ end
+ when /Tag\.(\d+)\.Key/
+ tags[value] = params["Tag.#{$1}.Value"] || ""
+ end
+ }
+
+ resources.each {|resource|
+ if resource.is_a?(VirtualMachine)
+ template_key = "USER_TEMPLATE"
+ elsif resource.is_a?(Image)
+ template_key = "TEMPLATE"
+ end
+
+ tags.each { |key,value|
+ resource.delete_element("#{template_key}/EC2_TAGS/#{key}")
+ }
+
+ rc = resource.update(resource.template_like_str(template_key))
+ return rc if OpenNebula::is_error?(rc)
+ }
+
+ erb_version = params['Version']
+
+ response = ERB.new(File.read(@config[:views]+"/delete_tags.erb"))
+ return response.result(binding), 200
+ end
+
+ def describe_tags(params)
+ user_flag = OpenNebula::Pool::INFO_ALL
+ impool = ImageEC2Pool.new(@client, user_flag)
+
+ rc = impool.info
+ return rc if OpenNebula::is_error?(rc)
+
+ user_flag = OpenNebula::Pool::INFO_ALL
+ vmpool = VirtualMachinePool.new(@client, user_flag)
+
+ if include_terminated_instances?
+ rc = vmpool.info(user_flag, -1, -1,
+ OpenNebula::VirtualMachinePool::INFO_ALL_VM)
+ else
+ rc = vmpool.info
+ end
+
+ return rc if OpenNebula::is_error?(rc)
+
+ erb_version = params['Version']
+
+ response = ERB.new(File.read(@config[:views]+"/describe_tags.erb"))
+ return response.result(binding), 200
+ end
+end
diff --git a/src/cloud/ec2/lib/views/create_image.erb b/src/cloud/ec2/lib/views/create_image.erb
new file mode 100644
index 0000000000..480183aeb8
--- /dev/null
+++ b/src/cloud/ec2/lib/views/create_image.erb
@@ -0,0 +1,4 @@
+
+ <%= @request_id %>
+ ami-<%= sprintf('%08i', image_id) %>
+
diff --git a/src/cloud/ec2/lib/views/create_snapshot.erb b/src/cloud/ec2/lib/views/create_snapshot.erb
new file mode 100644
index 0000000000..4cc5996b14
--- /dev/null
+++ b/src/cloud/ec2/lib/views/create_snapshot.erb
@@ -0,0 +1,11 @@
+
+ <%= @request_id %>
+ snap-<%= sprintf('%08i', snapshot["ID"]) %>
+ <%= params["VolumeId"] %>
+ <%= snapshot.render_state %>
+ <%= snapshot.render_create_time %>
+
+ <%= snapshot["UNAME"] %>
+ <%= snapshot.render_size %>
+ <%= snapshot["NAME"] %>
+
diff --git a/src/cloud/ec2/lib/views/create_tags.erb b/src/cloud/ec2/lib/views/create_tags.erb
new file mode 100644
index 0000000000..9ab943b935
--- /dev/null
+++ b/src/cloud/ec2/lib/views/create_tags.erb
@@ -0,0 +1,4 @@
+
+ <%= @request_id %>
+ true
+
diff --git a/src/cloud/ec2/lib/views/create_volume.erb b/src/cloud/ec2/lib/views/create_volume.erb
index c43a0b5471..f5ea114cec 100644
--- a/src/cloud/ec2/lib/views/create_volume.erb
+++ b/src/cloud/ec2/lib/views/create_volume.erb
@@ -1,10 +1,10 @@
- <%= @request_id %>
- vol-<%= sprintf('%08i', image.id) %>
- <%= image.render_size %>
+ <%= @request_id %>
+ <%= volume.ec2_id %>
+ <%= volume.render_size %>
- <%= image.render_state %>
- <%= image.render_create_time %>
-
\ No newline at end of file
+ <%= volume.render_state %>
+ <%= volume.render_create_time %>
+
diff --git a/src/cloud/ec2/lib/views/delete_snapshot.erb b/src/cloud/ec2/lib/views/delete_snapshot.erb
new file mode 100644
index 0000000000..d18ed90271
--- /dev/null
+++ b/src/cloud/ec2/lib/views/delete_snapshot.erb
@@ -0,0 +1,4 @@
+
+ <%= @request_id %>
+ true
+
diff --git a/src/cloud/ec2/lib/views/delete_tags.erb b/src/cloud/ec2/lib/views/delete_tags.erb
new file mode 100644
index 0000000000..468b087a44
--- /dev/null
+++ b/src/cloud/ec2/lib/views/delete_tags.erb
@@ -0,0 +1,4 @@
+
+ <%= @request_id %>
+ true
+
diff --git a/src/cloud/ec2/lib/views/describe_images.erb b/src/cloud/ec2/lib/views/describe_images.erb
index 921ff139c5..f4fe95a0ee 100644
--- a/src/cloud/ec2/lib/views/describe_images.erb
+++ b/src/cloud/ec2/lib/views/describe_images.erb
@@ -3,7 +3,7 @@
<%= @request_id %>
<% impool.each do |im| %>
- <% if (state_image = im.render_state) && (im['TEMPLATE/EBS_VOLUME'] != 'YES') %>
+ <% if (state_image = im.render_state) && im.ec2_ami? %>
-
<%= im['NAME'] %>
<% if im['TEMPLATE/DESCRIPTION'] %>
@@ -12,7 +12,7 @@
<% if im['TEMPLATE/PLATFORM'] %>
<%= im['TEMPLATE/PLATFORM'] %>
<% end %>
- ami-<%= sprintf('%08i', im.id) %>
+ <%= im.ec2_id %>
<%= im['SOURCE'].split('/').last %>
<%= state_image %>
<%= im['UNAME'] %>
diff --git a/src/cloud/ec2/lib/views/describe_instances.erb b/src/cloud/ec2/lib/views/describe_instances.erb
index bb8141a963..ef5d59cc20 100644
--- a/src/cloud/ec2/lib/views/describe_instances.erb
+++ b/src/cloud/ec2/lib/views/describe_instances.erb
@@ -12,6 +12,7 @@
<% vmpool.each do |vm| %>
+ <% if include_terminated_instance?(vm) %>
-
<%= render_instance_id(vm) %>
<%= vm['USER_TEMPLATE/IMAGE_ID'] %>
@@ -45,6 +46,7 @@
<% end %>
+ <% end %>
diff --git a/src/cloud/ec2/lib/views/describe_snapshots.erb b/src/cloud/ec2/lib/views/describe_snapshots.erb
new file mode 100644
index 0000000000..4c4aa51504
--- /dev/null
+++ b/src/cloud/ec2/lib/views/describe_snapshots.erb
@@ -0,0 +1,23 @@
+
+ <%= @request_id %>
+
+ <% impool.each do |im| %>
+ <% logger.debug(im.id) %>
+ <% if (state_image = im.render_state) && im.ebs_snapshot? %>
+ -
+ snap-<%= sprintf('%08i', im.id) %>
+
+ <%= state_image %>
+ <%= im.render_create_time %>
+
+ <%= im["UNAME"] %>
+ <%= im.render_size %>
+ <%= im["NAME"] %>
+
+
+ <% else
+ next
+ end
+ end %>
+
+
diff --git a/src/cloud/ec2/lib/views/describe_tags.erb b/src/cloud/ec2/lib/views/describe_tags.erb
new file mode 100644
index 0000000000..2933f6cc60
--- /dev/null
+++ b/src/cloud/ec2/lib/views/describe_tags.erb
@@ -0,0 +1,31 @@
+
+ <%= @request_id %>
+
+ <% impool.each do |im| %>
+ <% if (state_image = im.render_state) && im.has_elements?("TEMPLATE/EC2_TAGS") %>
+ <% image_hash = im.to_hash %>
+ <% image_hash["IMAGE"]["TEMPLATE"]["EC2_TAGS"].each do |key, value| %>
+ -
+ <%= im.ec2_id %>
+ image
+ <%= key %>
+ <%= value %>
+
+ <% end
+ end
+ end %>
+ <% vmpool.each do |vm| %>
+ <% if include_terminated_instance?(vm) && vm.has_elements?("USER_TEMPLATE/EC2_TAGS") %>
+ <% vm_hash = vm.to_hash %>
+ <% vm_hash["VM"]["USER_TEMPLATE"]["EC2_TAGS"].each do |key, value| %>
+ -
+ i-<%= sprintf('%08i', vm.id) %>
+ instance
+ <%= key %>
+ <%= value %>
+
+ <% end
+ end
+ end %>
+
+
diff --git a/src/cloud/ec2/lib/views/describe_volumes.erb b/src/cloud/ec2/lib/views/describe_volumes.erb
index 77f935cb5f..778925574c 100644
--- a/src/cloud/ec2/lib/views/describe_volumes.erb
+++ b/src/cloud/ec2/lib/views/describe_volumes.erb
@@ -3,11 +3,11 @@
<%= @request_id %>
<% impool.each do |im| %>
- <% if (state_image = im.render_state) && (im['TEMPLATE/EBS_VOLUME'] == 'YES') %>
+ <% if (state_image = im.render_state) && im.ebs_volume? %>
-
vol-<%= sprintf('%08i', im.id) %>
<%= im.render_size %>
-
+ <%= im["TEMPLATE/EBS_FROM_SNAPSHOT_ID"] %>
<%= state_image %>
<%= im.render_create_time %>
@@ -30,4 +30,4 @@
end
end %>
-
\ No newline at end of file
+
diff --git a/src/cloud/ec2/lib/views/run_instances.erb b/src/cloud/ec2/lib/views/run_instances.erb
index f7306ff70c..e80e5a108a 100644
--- a/src/cloud/ec2/lib/views/run_instances.erb
+++ b/src/cloud/ec2/lib/views/run_instances.erb
@@ -11,7 +11,7 @@
<% erb_vms.each { |vm| %>
-
<%= render_instance_id(vm) %>
- <%= erb_vm_info[:ec2_img_id] %>
+ <%= params['ImageId'] %>
<%= render_state(vm) %>
<% if vm.has_elements?("TEMPLATE/NIC/IP") %>
<% ips_str = vm.retrieve_elements("TEMPLATE/NIC/IP").join(', ') %>
@@ -25,7 +25,7 @@
<%= vm['TEMPLATE/CONTEXT/EC2_KEYNAME'] %>
<% end %>
<%= vm.id %>
- <%= erb_vm_info[:instance_type] %>
+ <%= params['InstanceType'] %>
<%= render_launch_time(vm) %>
default