From 29305800670e8a002859d6771637c012442c0b6d Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Fri, 9 Aug 2013 11:58:27 +0200 Subject: [PATCH 01/21] feature #2072: Improve describe-images function --- src/cloud/ec2/lib/EC2QueryServer.rb | 30 +++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/src/cloud/ec2/lib/EC2QueryServer.rb b/src/cloud/ec2/lib/EC2QueryServer.rb index f40d406825..2fb671920c 100644 --- a/src/cloud/ec2/lib/EC2QueryServer.rb +++ b/src/cloud/ec2/lib/EC2QueryServer.rb @@ -148,11 +148,33 @@ 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) + rc.ec2_code = "InvalidAMIID.NotFound" + return rc + else + impool << image + end + else + rc = OpenNebula::Error.new("InvalidAMIID #{value}") + rc.ec2_code = "InvalidAMIID" + 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'] From ded1202c955ab2d07b4e99188554e6d28f2c2cfb Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Fri, 9 Aug 2013 12:03:43 +0200 Subject: [PATCH 02/21] feature #2072: Change describe-images ec2_code --- src/cloud/ec2/lib/EC2QueryServer.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cloud/ec2/lib/EC2QueryServer.rb b/src/cloud/ec2/lib/EC2QueryServer.rb index 2fb671920c..bf22cbd931 100644 --- a/src/cloud/ec2/lib/EC2QueryServer.rb +++ b/src/cloud/ec2/lib/EC2QueryServer.rb @@ -161,8 +161,8 @@ class EC2QueryServer < CloudServer impool << image end else - rc = OpenNebula::Error.new("InvalidAMIID #{value}") - rc.ec2_code = "InvalidAMIID" + rc = OpenNebula::Error.new("InvalidAMIID.Malformed #{value}") + rc.ec2_code = "InvalidAMIID.Malformed" return rc end end From ef120e47d85e1cbf2027d0b35feb46112786e688 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Fri, 9 Aug 2013 12:04:07 +0200 Subject: [PATCH 03/21] feature #2072: Improve describe-instances function --- src/cloud/ec2/lib/instance.rb | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/src/cloud/ec2/lib/instance.rb b/src/cloud/ec2/lib/instance.rb index 5a49f739ae..9e7444bbf2 100644 --- a/src/cloud/ec2/lib/instance.rb +++ b/src/cloud/ec2/lib/instance.rb @@ -108,11 +108,33 @@ 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) + + rc = vmpool.info + return rc if OpenNebula::is_error?(rc) + end erb_version = params['Version'] erb_user_name = params['AWSAccessKeyId'] From a20e05c2639595ccf539ef1ee9fbf09230ef0ff0 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Mon, 12 Aug 2013 12:56:00 +0200 Subject: [PATCH 04/21] feature #2072: Include recently terminated instances in describe_instances xml --- src/cloud/ec2/etc/econe.conf | 6 ++++ src/cloud/ec2/lib/instance.rb | 33 ++++++++++++++++++- .../ec2/lib/views/describe_instances.erb | 2 ++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/cloud/ec2/etc/econe.conf b/src/cloud/ec2/etc/econe.conf index ee43a6a706..3fc67d7163 100644 --- a/src/cloud/ec2/etc/econe.conf +++ b/src/cloud/ec2/etc/econe.conf @@ -70,6 +70,12 @@ :m1.small: :template: m1.small.erb +# 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 + ############################################################# # Elastic IP ############################################################# diff --git a/src/cloud/ec2/lib/instance.rb b/src/cloud/ec2/lib/instance.rb index 9e7444bbf2..4327ad2afa 100644 --- a/src/cloud/ec2/lib/instance.rb +++ b/src/cloud/ec2/lib/instance.rb @@ -47,6 +47,12 @@ module Instance 'unkn' => :terminated } + # 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 instance type and path if params['InstanceType'] != nil @@ -132,7 +138,13 @@ module Instance user_flag = OpenNebula::Pool::INFO_ALL vmpool = VirtualMachinePool.new(@client, user_flag) - rc = vmpool.info + 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 @@ -230,4 +242,23 @@ 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" + end_time = vm.retrieve_elements("ETIME")[0].to_i + if (Time.now.getutc.to_i - end_time) <= TERMINATED_INSTANCES_EXPIRATION_TIME + return true + else + return false + end + end + end + + return true + end end 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 %> From 336b926ad893e8982d5a47105e3d06fbc46b1988 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Mon, 12 Aug 2013 13:09:59 +0200 Subject: [PATCH 05/21] feature #2072: Use first level ETIME --- src/cloud/ec2/lib/instance.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/cloud/ec2/lib/instance.rb b/src/cloud/ec2/lib/instance.rb index 4327ad2afa..cf63b68964 100644 --- a/src/cloud/ec2/lib/instance.rb +++ b/src/cloud/ec2/lib/instance.rb @@ -250,8 +250,7 @@ module Instance def include_terminated_instance?(vm) if include_terminated_instances? if EC2_STATES[ONE_STATES[vm.status]||:pending][:name] == "terminated" - end_time = vm.retrieve_elements("ETIME")[0].to_i - if (Time.now.getutc.to_i - end_time) <= TERMINATED_INSTANCES_EXPIRATION_TIME + if (Time.now.getutc.to_i - vm["ETIME"].to_i) <= TERMINATED_INSTANCES_EXPIRATION_TIME return true else return false From 0b68e9b59a3dc82b3f16b2569806ea78722672dc Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Tue, 13 Aug 2013 13:00:25 +0200 Subject: [PATCH 06/21] feature #2259: Add CreateImage --- install.sh | 1 + src/cloud/ec2/lib/EC2QueryServer.rb | 34 ++++++++++++++++++++++++ src/cloud/ec2/lib/econe_application.rb | 2 ++ src/cloud/ec2/lib/instance.rb | 1 + src/cloud/ec2/lib/views/create_image.erb | 4 +++ 5 files changed, 42 insertions(+) create mode 100644 src/cloud/ec2/lib/views/create_image.erb diff --git a/install.sh b/install.sh index 141abc4113..a0e92e1845 100755 --- a/install.sh +++ b/install.sh @@ -1296,6 +1296,7 @@ ECO_LIB_VIEW_FILES="src/cloud/ec2/lib/views/describe_images.erb \ src/cloud/ec2/lib/views/describe_regions.erb \ src/cloud/ec2/lib/views/describe_availability_zones.erb \ src/cloud/ec2/lib/views/create_volume.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/lib/EC2QueryServer.rb b/src/cloud/ec2/lib/EC2QueryServer.rb index bf22cbd931..525454f80e 100644 --- a/src/cloud/ec2/lib/EC2QueryServer.rb +++ b/src/cloud/ec2/lib/EC2QueryServer.rb @@ -182,6 +182,40 @@ 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) + + 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/econe_application.rb b/src/cloud/ec2/lib/econe_application.rb index 7360f720c3..43a3284153 100644 --- a/src/cloud/ec2/lib/econe_application.rb +++ b/src/cloud/ec2/lib/econe_application.rb @@ -134,6 +134,8 @@ class EC2Application result,rc = econe_server.describe_regions(params) when 'DescribeAvailabilityZones' result,rc = econe_server.describe_availability_zones(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 cf63b68964..a9bfacadaa 100644 --- a/src/cloud/ec2/lib/instance.rb +++ b/src/cloud/ec2/lib/instance.rb @@ -205,6 +205,7 @@ module Instance rc = vm.info if OpenNebula::is_error?(rc) + rc.ec2_code = "InvalidInstanceID.NotFound" return rc 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) %> + From 33648033aca21b0c48de88dda299180822e09e17 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Tue, 13 Aug 2013 18:04:40 +0200 Subject: [PATCH 07/21] feature #2259: Add CreateSnapshot --- install.sh | 1 + src/cloud/ec2/lib/ImageEC2.rb | 8 ++- src/cloud/ec2/lib/ebs.rb | 65 +++++++++++++++++++++ src/cloud/ec2/lib/econe_application.rb | 2 + src/cloud/ec2/lib/views/create_snapshot.erb | 11 ++++ src/cloud/ec2/lib/views/create_volume.erb | 4 +- 6 files changed, 86 insertions(+), 5 deletions(-) create mode 100644 src/cloud/ec2/lib/views/create_snapshot.erb diff --git a/install.sh b/install.sh index a0e92e1845..d02e05b1d4 100755 --- a/install.sh +++ b/install.sh @@ -1296,6 +1296,7 @@ ECO_LIB_VIEW_FILES="src/cloud/ec2/lib/views/describe_images.erb \ src/cloud/ec2/lib/views/describe_regions.erb \ src/cloud/ec2/lib/views/describe_availability_zones.erb \ src/cloud/ec2/lib/views/create_volume.erb \ + src/cloud/ec2/lib/views/create_snapshot.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 \ diff --git a/src/cloud/ec2/lib/ImageEC2.rb b/src/cloud/ec2/lib/ImageEC2.rb index 448ad07fd1..fa4a9aab5d 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] %>" @@ -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,8 @@ 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 end diff --git a/src/cloud/ec2/lib/ebs.rb b/src/cloud/ec2/lib/ebs.rb index e5c2ed7a63..d7c4afd69e 100644 --- a/src/cloud/ec2/lib/ebs.rb +++ b/src/cloud/ec2/lib/ebs.rb @@ -237,4 +237,69 @@ 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 [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["TEMPLATE/EBS_VOLUME"] != "YES" + 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 + + erb_version = params['Version'] + + response = ERB.new(File.read(@config[:views]+"/create_snapshot.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 43a3284153..eed88544d3 100644 --- a/src/cloud/ec2/lib/econe_application.rb +++ b/src/cloud/ec2/lib/econe_application.rb @@ -134,6 +134,8 @@ 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 'CreateImage' result,rc = econe_server.create_image(params) when 'CreateVolume' 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 %> + 100% + <%= snapshot["UNAME"] %> + <%= snapshot.render_size %> + <%= snapshot["NAME"] %> + diff --git a/src/cloud/ec2/lib/views/create_volume.erb b/src/cloud/ec2/lib/views/create_volume.erb index c43a0b5471..98b17534dd 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 %> + <%= @request_id %> vol-<%= sprintf('%08i', image.id) %> <%= image.render_size %> <%= image.render_state %> <%= image.render_create_time %> - \ No newline at end of file + From 83c29ef0e7c097cb6ae40155ae81ae968e5e3c22 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Wed, 14 Aug 2013 13:58:05 +0200 Subject: [PATCH 08/21] feature #2259: Delete EBS_VOLUME attar when creating a new snapshot --- src/cloud/ec2/lib/ebs.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/cloud/ec2/lib/ebs.rb b/src/cloud/ec2/lib/ebs.rb index d7c4afd69e..5b68fa8393 100644 --- a/src/cloud/ec2/lib/ebs.rb +++ b/src/cloud/ec2/lib/ebs.rb @@ -241,7 +241,7 @@ module EBS # # @param [Hash] params # @option params [String] VolumeId The ID of the Amazon EBS volume. - # @option params [Description] A description for the snapshot. + # @option params [String] Description A description for the snapshot. def create_snapshot(params) image_id = params['VolumeId'] image_id = image_id.split('-')[1] @@ -296,6 +296,9 @@ module EBS return rc end + snapshot.delete_element("TEMPLATE/EBS_VOLUME") + snapshot.update + erb_version = params['Version'] response = ERB.new(File.read(@config[:views]+"/create_snapshot.erb")) From c4fb4c6b7243f0544e2f62d57ec7273a57ea0c9d Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Wed, 14 Aug 2013 13:58:38 +0200 Subject: [PATCH 09/21] feature #2259: Add ebs and ami checks in EC2Image --- src/cloud/ec2/lib/ImageEC2.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/cloud/ec2/lib/ImageEC2.rb b/src/cloud/ec2/lib/ImageEC2.rb index fa4a9aab5d..bd2dc43774 100644 --- a/src/cloud/ec2/lib/ImageEC2.rb +++ b/src/cloud/ec2/lib/ImageEC2.rb @@ -93,4 +93,12 @@ class ImageEC2 < Image 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 end From 8132fd0cbea8a7d5cfd6d9c039a050b8a1f09ba3 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Wed, 14 Aug 2013 13:59:13 +0200 Subject: [PATCH 10/21] feature #2259: Add DeleteSnapshot --- install.sh | 1 + src/cloud/ec2/lib/ebs.rb | 28 ++++++++++++++++++++- src/cloud/ec2/lib/econe_application.rb | 2 ++ src/cloud/ec2/lib/views/delete_snapshot.erb | 4 +++ 4 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 src/cloud/ec2/lib/views/delete_snapshot.erb diff --git a/install.sh b/install.sh index d02e05b1d4..f7fb032b61 100755 --- a/install.sh +++ b/install.sh @@ -1297,6 +1297,7 @@ ECO_LIB_VIEW_FILES="src/cloud/ec2/lib/views/describe_images.erb \ src/cloud/ec2/lib/views/describe_availability_zones.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/create_image.erb \ src/cloud/ec2/lib/views/describe_volumes.erb \ src/cloud/ec2/lib/views/attach_volume.erb \ diff --git a/src/cloud/ec2/lib/ebs.rb b/src/cloud/ec2/lib/ebs.rb index 5b68fa8393..f075c3b3cb 100644 --- a/src/cloud/ec2/lib/ebs.rb +++ b/src/cloud/ec2/lib/ebs.rb @@ -248,7 +248,7 @@ module EBS image = ImageEC2.new(Image.build_xml(image_id.to_i), @client) rc = image.info - if OpenNebula::is_error?(rc) || image["TEMPLATE/EBS_VOLUME"] != "YES" + if OpenNebula::is_error?(rc) || !image.ebs_volume? rc ||= OpenNebula::Error.new() rc.ec2_code = "InvalidVolume.NotFound" return rc @@ -305,4 +305,30 @@ module EBS 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_volume? || snapshot.ec2_ami? + 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 end diff --git a/src/cloud/ec2/lib/econe_application.rb b/src/cloud/ec2/lib/econe_application.rb index eed88544d3..cf635fd355 100644 --- a/src/cloud/ec2/lib/econe_application.rb +++ b/src/cloud/ec2/lib/econe_application.rb @@ -136,6 +136,8 @@ class EC2Application 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 'CreateImage' result,rc = econe_server.create_image(params) when 'CreateVolume' 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 + From 6df3a5cf89b8c6aa42440d57e6c054b3de441c98 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Wed, 14 Aug 2013 18:52:07 +0200 Subject: [PATCH 11/21] feature #2259: Add DescribeSnapshots --- install.sh | 1 + src/cloud/ec2/lib/ImageEC2.rb | 4 ++ src/cloud/ec2/lib/ebs.rb | 37 ++++++++++++++++++- src/cloud/ec2/lib/econe_application.rb | 2 + .../ec2/lib/views/describe_snapshots.erb | 23 ++++++++++++ src/cloud/ec2/lib/views/describe_volumes.erb | 4 +- 6 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 src/cloud/ec2/lib/views/describe_snapshots.erb diff --git a/install.sh b/install.sh index f7fb032b61..6d8d3ba6f3 100755 --- a/install.sh +++ b/install.sh @@ -1298,6 +1298,7 @@ ECO_LIB_VIEW_FILES="src/cloud/ec2/lib/views/describe_images.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 \ diff --git a/src/cloud/ec2/lib/ImageEC2.rb b/src/cloud/ec2/lib/ImageEC2.rb index bd2dc43774..f376dac370 100644 --- a/src/cloud/ec2/lib/ImageEC2.rb +++ b/src/cloud/ec2/lib/ImageEC2.rb @@ -101,4 +101,8 @@ class ImageEC2 < Image def ec2_ami? self["TEMPLATE/EC2_AMI"] == "YES" end + + def ebs_snapshot? + !ebs_volume? && !ec2_ami? + end end diff --git a/src/cloud/ec2/lib/ebs.rb b/src/cloud/ec2/lib/ebs.rb index f075c3b3cb..3258b0403e 100644 --- a/src/cloud/ec2/lib/ebs.rb +++ b/src/cloud/ec2/lib/ebs.rb @@ -315,7 +315,7 @@ module EBS snapshot = ImageEC2.new(Image.build_xml(snapshot_id.to_i), @client) rc = snapshot.info - if OpenNebula::is_error?(rc) || snapshot.ebs_volume? || snapshot.ec2_ami? + if OpenNebula::is_error?(rc) || !snapshot.ebs_snapshot? rc ||= OpenNebula::Error.new() rc.ec2_code = "InvalidSnapshot.NotFound" return rc @@ -331,4 +331,39 @@ module EBS 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 cf635fd355..74046074de 100644 --- a/src/cloud/ec2/lib/econe_application.rb +++ b/src/cloud/ec2/lib/econe_application.rb @@ -138,6 +138,8 @@ class EC2Application 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 'CreateImage' result,rc = econe_server.create_image(params) when 'CreateVolume' 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 %> + 100% + <%= im["UNAME"] %> + <%= im.render_size %> + <%= im["NAME"] %> + + + <% else + next + end + end %> + + diff --git a/src/cloud/ec2/lib/views/describe_volumes.erb b/src/cloud/ec2/lib/views/describe_volumes.erb index 77f935cb5f..5acb7c8978 100644 --- a/src/cloud/ec2/lib/views/describe_volumes.erb +++ b/src/cloud/ec2/lib/views/describe_volumes.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.ebs_volume? %> vol-<%= sprintf('%08i', im.id) %> <%= im.render_size %> @@ -30,4 +30,4 @@ end end %> - \ No newline at end of file + From e7f12ea4744b3dfc22456b2fd5cb8aa6120b95f0 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Thu, 15 Aug 2013 18:45:21 +0200 Subject: [PATCH 12/21] feature #2259: Add CreateTags --- install.sh | 1 + src/cloud/ec2/lib/EC2QueryServer.rb | 90 ++++++++++++++++++++++++- src/cloud/ec2/lib/econe_application.rb | 2 + src/cloud/ec2/lib/views/create_tags.erb | 4 ++ 4 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 src/cloud/ec2/lib/views/create_tags.erb diff --git a/install.sh b/install.sh index 6d8d3ba6f3..7b3874a203 100755 --- a/install.sh +++ b/install.sh @@ -1295,6 +1295,7 @@ 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/create_volume.erb \ src/cloud/ec2/lib/views/create_snapshot.erb \ src/cloud/ec2/lib/views/delete_snapshot.erb \ diff --git a/src/cloud/ec2/lib/EC2QueryServer.rb b/src/cloud/ec2/lib/EC2QueryServer.rb index 525454f80e..f4b8e9f409 100644 --- a/src/cloud/ec2/lib/EC2QueryServer.rb +++ b/src/cloud/ec2/lib/EC2QueryServer.rb @@ -154,7 +154,8 @@ class EC2QueryServer < CloudServer if value =~ /ami\-(.+)/ image = ImageEC2.new(Image.build_xml($1), @client) rc = image.info - if OpenNebula.is_error?(rc) + if OpenNebula.is_error?(rc) || !image.ec2_ami? + rc ||= OpenNebula::Error.new() rc.ec2_code = "InvalidAMIID.NotFound" return rc else @@ -216,6 +217,93 @@ class EC2QueryServer < CloudServer return response.result(binding), 200 end + # Adds or overwrites one or more tags for the specified EC2 resource or + # resources. Each resource can have a maximum of 10 tags. Each tag + # consists of a key and optional value. Tag keys must be unique per resource. + # + # @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 create_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 + + former_tags = resource.to_hash.first[1][template_key]["EC2_TAGS"] || {} + resource.delete_element("#{template_key}/EC2_TAGS") + resource.add_element(template_key, {"EC2_TAGS" => 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 + ########################################################################### # Helper functions ########################################################################### diff --git a/src/cloud/ec2/lib/econe_application.rb b/src/cloud/ec2/lib/econe_application.rb index 74046074de..8414acc08d 100644 --- a/src/cloud/ec2/lib/econe_application.rb +++ b/src/cloud/ec2/lib/econe_application.rb @@ -140,6 +140,8 @@ class EC2Application 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 'CreateImage' result,rc = econe_server.create_image(params) when 'CreateVolume' 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 + From 4dad58d453169e1849ba290dea58323a1bafc20a Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Thu, 15 Aug 2013 18:45:46 +0200 Subject: [PATCH 13/21] feature #2259: Use EBS_SNAPSHOT attar --- src/cloud/ec2/lib/ImageEC2.rb | 3 ++- src/cloud/ec2/lib/ebs.rb | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cloud/ec2/lib/ImageEC2.rb b/src/cloud/ec2/lib/ImageEC2.rb index f376dac370..90a3318f26 100644 --- a/src/cloud/ec2/lib/ImageEC2.rb +++ b/src/cloud/ec2/lib/ImageEC2.rb @@ -100,9 +100,10 @@ class ImageEC2 < Image def ec2_ami? self["TEMPLATE/EC2_AMI"] == "YES" + true end def ebs_snapshot? - !ebs_volume? && !ec2_ami? + self["TEMPLATE/EBS_SNAPSHOT"] == "YES" end end diff --git a/src/cloud/ec2/lib/ebs.rb b/src/cloud/ec2/lib/ebs.rb index 3258b0403e..0a741a7ed8 100644 --- a/src/cloud/ec2/lib/ebs.rb +++ b/src/cloud/ec2/lib/ebs.rb @@ -297,6 +297,7 @@ module EBS end snapshot.delete_element("TEMPLATE/EBS_VOLUME") + snapshot.add_element('TEMPLATE', {"EBS_SNAPSHOT" => "YES"}) snapshot.update erb_version = params['Version'] From c2e4558040ab6461057b6841ebbb04359f272e4f Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Thu, 15 Aug 2013 19:06:37 +0200 Subject: [PATCH 14/21] feature #2259: Add DeleteTags --- install.sh | 1 + src/cloud/ec2/lib/EC2QueryServer.rb | 85 +++++++++++++++++++++++++ src/cloud/ec2/lib/econe_application.rb | 2 + src/cloud/ec2/lib/views/delete_tags.erb | 4 ++ 4 files changed, 92 insertions(+) create mode 100644 src/cloud/ec2/lib/views/delete_tags.erb diff --git a/install.sh b/install.sh index 7b3874a203..7916c50639 100755 --- a/install.sh +++ b/install.sh @@ -1296,6 +1296,7 @@ ECO_LIB_VIEW_FILES="src/cloud/ec2/lib/views/describe_images.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/create_volume.erb \ src/cloud/ec2/lib/views/create_snapshot.erb \ src/cloud/ec2/lib/views/delete_snapshot.erb \ diff --git a/src/cloud/ec2/lib/EC2QueryServer.rb b/src/cloud/ec2/lib/EC2QueryServer.rb index f4b8e9f409..bf23d53bb7 100644 --- a/src/cloud/ec2/lib/EC2QueryServer.rb +++ b/src/cloud/ec2/lib/EC2QueryServer.rb @@ -304,6 +304,91 @@ class EC2QueryServer < CloudServer 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 + ########################################################################### # Helper functions ########################################################################### diff --git a/src/cloud/ec2/lib/econe_application.rb b/src/cloud/ec2/lib/econe_application.rb index 8414acc08d..b43f0eaea9 100644 --- a/src/cloud/ec2/lib/econe_application.rb +++ b/src/cloud/ec2/lib/econe_application.rb @@ -142,6 +142,8 @@ class EC2Application 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 'CreateImage' result,rc = econe_server.create_image(params) when 'CreateVolume' 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 + From aa71c45a0a40e81ffe01ebe6a5cab708548445bf Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Fri, 16 Aug 2013 09:37:24 +0200 Subject: [PATCH 15/21] feature #2259: Add DescribeTags --- install.sh | 1 + src/cloud/ec2/lib/EC2QueryServer.rb | 25 ++++++++++++++++++ src/cloud/ec2/lib/ImageEC2.rb | 21 ++++++++++++++- src/cloud/ec2/lib/econe_application.rb | 2 ++ src/cloud/ec2/lib/views/describe_tags.erb | 31 +++++++++++++++++++++++ 5 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 src/cloud/ec2/lib/views/describe_tags.erb diff --git a/install.sh b/install.sh index 7916c50639..0a550a4781 100755 --- a/install.sh +++ b/install.sh @@ -1297,6 +1297,7 @@ ECO_LIB_VIEW_FILES="src/cloud/ec2/lib/views/describe_images.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 \ diff --git a/src/cloud/ec2/lib/EC2QueryServer.rb b/src/cloud/ec2/lib/EC2QueryServer.rb index bf23d53bb7..f788b4a71b 100644 --- a/src/cloud/ec2/lib/EC2QueryServer.rb +++ b/src/cloud/ec2/lib/EC2QueryServer.rb @@ -389,6 +389,31 @@ class EC2QueryServer < CloudServer 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 + ########################################################################### # Helper functions ########################################################################### diff --git a/src/cloud/ec2/lib/ImageEC2.rb b/src/cloud/ec2/lib/ImageEC2.rb index 90a3318f26..7919e7e3ff 100644 --- a/src/cloud/ec2/lib/ImageEC2.rb +++ b/src/cloud/ec2/lib/ImageEC2.rb @@ -100,10 +100,29 @@ class ImageEC2 < Image def ec2_ami? self["TEMPLATE/EC2_AMI"] == "YES" - true 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/econe_application.rb b/src/cloud/ec2/lib/econe_application.rb index b43f0eaea9..7ee84018fa 100644 --- a/src/cloud/ec2/lib/econe_application.rb +++ b/src/cloud/ec2/lib/econe_application.rb @@ -144,6 +144,8 @@ class EC2Application 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' 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 %> + + From f668b94e42e55b8ddaa85bf6e17839dba775cb55 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Fri, 16 Aug 2013 09:38:20 +0200 Subject: [PATCH 16/21] feature #2259: Move tags functionality to tags.rb --- install.sh | 1 + src/cloud/ec2/lib/EC2QueryServer.rb | 198 +------------------------ src/cloud/ec2/lib/tags.rb | 214 ++++++++++++++++++++++++++++ 3 files changed, 216 insertions(+), 197 deletions(-) create mode 100644 src/cloud/ec2/lib/tags.rb diff --git a/install.sh b/install.sh index 0a550a4781..d4d70ea59c 100755 --- a/install.sh +++ b/install.sh @@ -1283,6 +1283,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 \ diff --git a/src/cloud/ec2/lib/EC2QueryServer.rb b/src/cloud/ec2/lib/EC2QueryServer.rb index f788b4a71b..dd3a39375c 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 @@ -217,203 +218,6 @@ class EC2QueryServer < CloudServer return response.result(binding), 200 end - # Adds or overwrites one or more tags for the specified EC2 resource or - # resources. Each resource can have a maximum of 10 tags. Each tag - # consists of a key and optional value. Tag keys must be unique per resource. - # - # @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 create_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 - - former_tags = resource.to_hash.first[1][template_key]["EC2_TAGS"] || {} - resource.delete_element("#{template_key}/EC2_TAGS") - resource.add_element(template_key, {"EC2_TAGS" => 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 - ########################################################################### # Helper functions ########################################################################### diff --git a/src/cloud/ec2/lib/tags.rb b/src/cloud/ec2/lib/tags.rb new file mode 100644 index 0000000000..dbb14aceef --- /dev/null +++ b/src/cloud/ec2/lib/tags.rb @@ -0,0 +1,214 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#--------------------------------------------------------------------------- # + +module Tags + # Adds or overwrites one or more tags for the specified EC2 resource or + # resources. Each resource can have a maximum of 10 tags. Each tag + # consists of a key and optional value. Tag keys must be unique per resource. + # + # @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 create_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 + + former_tags = resource.to_hash.first[1][template_key]["EC2_TAGS"] || {} + resource.delete_element("#{template_key}/EC2_TAGS") + resource.add_element(template_key, {"EC2_TAGS" => 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 From 2052d9f63169c416b8d0c9de5f83503002192f01 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Fri, 16 Aug 2013 10:47:44 +0200 Subject: [PATCH 17/21] feature #2259: Now RegisterImage is required to use an image. It will include EC2_AMI attr --- src/cloud/ec2/lib/EC2QueryServer.rb | 22 +++++++++++++++------ src/cloud/ec2/lib/views/describe_images.erb | 4 ++-- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/cloud/ec2/lib/EC2QueryServer.rb b/src/cloud/ec2/lib/EC2QueryServer.rb index dd3a39375c..2b2a0a1960 100644 --- a/src/cloud/ec2/lib/EC2QueryServer.rb +++ b/src/cloud/ec2/lib/EC2QueryServer.rb @@ -127,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'] 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'] %> From 8f5a102248c952bd2f89da68c96d8df9ff3170de Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Fri, 16 Aug 2013 10:48:11 +0200 Subject: [PATCH 18/21] feature #2259: CreateVolume from Snapshot --- src/cloud/ec2/lib/ImageEC2.rb | 2 +- src/cloud/ec2/lib/ebs.rb | 75 ++++++++++++++------ src/cloud/ec2/lib/views/create_volume.erb | 8 +-- src/cloud/ec2/lib/views/describe_volumes.erb | 2 +- 4 files changed, 59 insertions(+), 28 deletions(-) diff --git a/src/cloud/ec2/lib/ImageEC2.rb b/src/cloud/ec2/lib/ImageEC2.rb index 7919e7e3ff..6939b67d1e 100644 --- a/src/cloud/ec2/lib/ImageEC2.rb +++ b/src/cloud/ec2/lib/ImageEC2.rb @@ -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 %> diff --git a/src/cloud/ec2/lib/ebs.rb b/src/cloud/ec2/lib/ebs.rb index 0a741a7ed8..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")) diff --git a/src/cloud/ec2/lib/views/create_volume.erb b/src/cloud/ec2/lib/views/create_volume.erb index 98b17534dd..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 %> + <%= volume.ec2_id %> + <%= volume.render_size %> - <%= image.render_state %> - <%= image.render_create_time %> + <%= volume.render_state %> + <%= volume.render_create_time %> diff --git a/src/cloud/ec2/lib/views/describe_volumes.erb b/src/cloud/ec2/lib/views/describe_volumes.erb index 5acb7c8978..778925574c 100644 --- a/src/cloud/ec2/lib/views/describe_volumes.erb +++ b/src/cloud/ec2/lib/views/describe_volumes.erb @@ -7,7 +7,7 @@ vol-<%= sprintf('%08i', im.id) %> <%= im.render_size %> - + <%= im["TEMPLATE/EBS_FROM_SNAPSHOT_ID"] %> <%= state_image %> <%= im.render_create_time %> From 35b2bbbd51edf8416028f728a4762696a7ebf3ca Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Thu, 3 Oct 2013 19:38:13 +0200 Subject: [PATCH 19/21] feature #2259: Use OpenNebula templates instead of file based erbs --- src/cloud/ec2/etc/econe.conf | 20 +- src/cloud/ec2/lib/instance.rb | 214 +++++++++++++++++----- src/cloud/ec2/lib/views/run_instances.erb | 4 +- 3 files changed, 184 insertions(+), 54 deletions(-) diff --git a/src/cloud/ec2/etc/econe.conf b/src/cloud/ec2/etc/econe.conf index 3fc67d7163..c8bb64e440 100644 --- a/src/cloud/ec2/etc/econe.conf +++ b/src/cloud/ec2/etc/econe.conf @@ -64,18 +64,26 @@ # default 1 #:datastore_id: - -# VM types allowed and its template file (inside templates directory) -:instance_types: - :m1.small: - :template: m1.small.erb - # 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: + :m1.small: + :template: m1.small.erb + ############################################################# # Elastic IP ############################################################# diff --git a/src/cloud/ec2/lib/instance.rb b/src/cloud/ec2/lib/instance.rb index a9bfacadaa..ab90112800 100644 --- a/src/cloud/ec2/lib/instance.rb +++ b/src/cloud/ec2/lib/instance.rb @@ -54,57 +54,133 @@ module Instance TERMINATED_INSTANCES_EXPIRATION_TIME = 900 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] - - if instance_type != nil - path = @config[:template_location] + "/#{instance_type[:template]}" - end + # 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'] @@ -261,4 +337,50 @@ module Instance 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< <%= 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 From afbec25583d4066673a1372272f38c36a5040a89 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Fri, 4 Oct 2013 13:21:13 +0200 Subject: [PATCH 20/21] feature #2259: Disable create-image functionality --- src/cloud/ec2/lib/EC2QueryServer.rb | 3 +++ src/cloud/ec2/lib/econe_application.rb | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/cloud/ec2/lib/EC2QueryServer.rb b/src/cloud/ec2/lib/EC2QueryServer.rb index 2b2a0a1960..bd8b4c460e 100644 --- a/src/cloud/ec2/lib/EC2QueryServer.rb +++ b/src/cloud/ec2/lib/EC2QueryServer.rb @@ -218,6 +218,9 @@ class EC2QueryServer < CloudServer 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 diff --git a/src/cloud/ec2/lib/econe_application.rb b/src/cloud/ec2/lib/econe_application.rb index 7ee84018fa..c6de59116e 100644 --- a/src/cloud/ec2/lib/econe_application.rb +++ b/src/cloud/ec2/lib/econe_application.rb @@ -146,8 +146,8 @@ class EC2Application 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 'CreateImage' + # result,rc = econe_server.create_image(params) when 'CreateVolume' result,rc = econe_server.create_volume(params) when 'DescribeVolumes' From eff878c69779aa0abea6d525af5d4557af600777 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Fri, 4 Oct 2013 14:45:55 +0200 Subject: [PATCH 21/21] feature #2259: Add configurable actions for instances --- src/cloud/ec2/lib/instance.rb | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/cloud/ec2/lib/instance.rb b/src/cloud/ec2/lib/instance.rb index ab90112800..6586969ffa 100644 --- a/src/cloud/ec2/lib/instance.rb +++ b/src/cloud/ec2/lib/instance.rb @@ -47,6 +47,13 @@ module Instance 'unkn' => :terminated } + EC2_ACTIONS = { + :start => :resume, + :stop => :poweroff, + :terminate => :shutdown, + :reboot => :reboot + } + # Include terminated instances in the describe_instances xml DESCRIBE_WITH_TERMINATED_INSTANCES = true # Terminated VMs will be included in the list @@ -234,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 @@ -243,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