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