From 5dbf040f9c91d3a965aab13e5e39e130a5b5e4f1 Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Wed, 15 Feb 2012 14:10:24 +0100 Subject: [PATCH] Feature #1089: Upload support for images in Sunstone. Follows the same principles as SelfService. --- install.sh | 2 + src/sunstone/models/SunstoneServer.rb | 30 +++++ src/sunstone/public/js/plugins/images-tab.js | 115 +++++++++++++++++-- src/sunstone/sunstone-server.rb | 7 ++ src/sunstone/views/index.erb | 1 + 5 files changed, 143 insertions(+), 12 deletions(-) diff --git a/install.sh b/install.sh index b0d21b42ff..fa2b593fe0 100755 --- a/install.sh +++ b/install.sh @@ -265,6 +265,7 @@ SUNSTONE_DIRS="$SUNSTONE_LOCATION/models \ $SUNSTONE_LOCATION/public/vendor/jQuery \ $SUNSTONE_LOCATION/public/vendor/jGrowl \ $SUNSTONE_LOCATION/public/vendor/flot \ + $SUNSTONE_LOCATION/public/vendor/fileuploader \ $SUNSTONE_LOCATION/public/images \ $SUNSTONE_LOCATION/templates \ $SUNSTONE_LOCATION/views" @@ -455,6 +456,7 @@ INSTALL_SUNSTONE_FILES=( SUNSTONE_PUBLIC_VENDOR_JQUERYUIIMAGES:$SUNSTONE_LOCATION/public/vendor/jQueryUI/images SUNSTONE_PUBLIC_VENDOR_JQUERYLAYOUT:$SUNSTONE_LOCATION/public/vendor/jQueryLayout SUNSTONE_PUBLIC_VENDOR_FLOT:$SUNSTONE_LOCATION/public/vendor/flot + SUNSTONE_PUBLIC_VENDOR_FILEUPLOADER:$SUNSTONE_LOCATION/public/vendor/fileuploader SUNSTONE_PUBLIC_IMAGES_FILES:$SUNSTONE_LOCATION/public/images SUNSTONE_PUBLIC_LOCALE_EN_US:$SUNSTONE_LOCATION/public/locale/en_US SUNSTONE_PUBLIC_LOCALE_RU:$SUNSTONE_LOCATION/public/locale/ru diff --git a/src/sunstone/models/SunstoneServer.rb b/src/sunstone/models/SunstoneServer.rb index c4049404e6..5829b95c4d 100644 --- a/src/sunstone/models/SunstoneServer.rb +++ b/src/sunstone/models/SunstoneServer.rb @@ -19,11 +19,16 @@ include OpenNebulaJSON require 'acct/watch_client' require 'OpenNebulaVNC' +require 'OpenNebulaJSON/JSONUtils' +include JSONUtils class SunstoneServer # FLAG that will filter the elements retrieved from the Pools POOL_FILTER = Pool::INFO_ALL + # Secs to sleep between checks to see if image upload to repo is finished + IMAGE_POLL_SLEEP_TIME = 5 + def initialize(client) @client = client end @@ -113,6 +118,31 @@ class SunstoneServer end end + ############################################################################ + # + ############################################################################ + def upload(template, file_path) + image_hash = parse_json(template, 'image') + image_hash['PATH'] = file_path + + new_template = {:image => image_hash}.to_json + image = ImageJSON.new(Image.build_xml, @client) + + rc = image.create(new_template) + + if OpenNebula.is_error?(rc) + return [500, rc.to_json] + end + + image.info + #wait until image is ready to return + while (image.state_str == 'LOCKED') && (image['RUNNING_VMS'] == '0') do + sleep IMAGE_POLL_SLEEP_TIME + image.info + end + return [201, image.to_json] + end + ############################################################################ # ############################################################################ diff --git a/src/sunstone/public/js/plugins/images-tab.js b/src/sunstone/public/js/plugins/images-tab.js index 62ab9f159c..02e441da56 100644 --- a/src/sunstone/public/js/plugins/images-tab.js +++ b/src/sunstone/public/js/plugins/images-tab.js @@ -100,14 +100,21 @@ var create_image_tmpl = \
\
\ - \ + \ +\ \
\ +\ \
\ +\ + \ +
\ +\ \ \
'+tr("Please choose path if you have a file-based image. Choose source otherwise or create an empty datablock disk.")+'

\ +\
\
\ \ @@ -129,6 +136,11 @@ var create_image_tmpl = \
'+tr("Type of file system to be built. This can be any value understood by mkfs unix command.")+'
\
\ +
\ + \ +
\ +
\ +
\
\
\
\ @@ -666,6 +678,7 @@ function updateImageInfo(request,img){ function setupCreateImageDialog(){ dialogs_context.append('
'); $create_image_dialog = $('#create_image_dialog',dialogs_context); + var dialog = $create_image_dialog; dialog.html(create_image_tmpl); @@ -694,12 +707,12 @@ function setupCreateImageDialog(){ default: $('#datablock_img',context).attr('disabled','disabled'); $('#path_img',context).attr('checked','checked'); - $('#img_source,#img_fstype,#img_size',context).parent().hide(); + $('#img_source,#img_fstype,#img_size,#file-uploader',context).parent().hide(); $('#img_path',context).parent().show(); } }); - $('#img_source,#img_fstype,#img_size',dialog).parent().hide(); + $('#img_source,#img_fstype,#img_size,#file-uploader',dialog).parent().hide(); $('#path_img',dialog).attr('checked','checked'); $('#img_path',dialog).parent().addClass("img_man"); @@ -708,24 +721,30 @@ function setupCreateImageDialog(){ var value = $(this).val(); switch (value){ case "path": - $('#img_source,#img_fstype,#img_size',context).parent().hide(); - $('#img_source,#img_fstype,#img_size',context).parent().removeClass("img_man"); + $('#img_source,#img_fstype,#img_size,#file-uploader',context).parent().hide(); + $('#img_source,#img_fstype,#img_size,#file-uploader',context).parent().removeClass("img_man"); $('#img_path',context).parent().show(); $('#img_path',context).parent().addClass("img_man"); break; case "source": - $('#img_path,#img_fstype,#img_size',context).parent().hide(); - $('#img_path,#img_fstype,#img_size',context).parent().removeClass("img_man"); + $('#img_path,#img_fstype,#img_size,#file-uploader',context).parent().hide(); + $('#img_path,#img_fstype,#img_size,#file-uploader',context).parent().removeClass("img_man"); $('#img_source',context).parent().show(); $('#img_source',context).parent().addClass("img_man"); break; case "datablock": - $('#img_source,#img_path',context).parent().hide(); - $('#img_source,#img_path',context).parent().removeClass("img_man"); + $('#img_source,#img_path,#file-uploader',context).parent().hide(); + $('#img_source,#img_path,#file-uploader',context).parent().removeClass("img_man"); $('#img_fstype,#img_size',context).parent().show(); $('#img_fstype,#img_size',context).parent().addClass("img_man"); break; - } + case "upload": + $('#img_path,#img_source,#img_fstype,#img_size',context).parent().hide(); + $('#img_path,#img_source,#img_fstype,#img_size',context).parent().removeClass("img_man"); + $('#file-uploader',context).parent().show(); + $('#file-uploader',context).parent().addClass("img_man"); + break; + }; }); @@ -752,9 +771,70 @@ function setupCreateImageDialog(){ } ); + $('#upload-progress',dialog).css({ + border: "1px solid #AAAAAA", + position: "relative", +// bottom: "29px", + width: "258px", +// left: "133px", + height: "15px", + display: "inline-block", + }); + $('#upload-progress div',dialog).css("border","1px solid #AAAAAA"); + + var img_obj; + + var uploader = new qq.FileUploaderBasic({ + button: $('#file-uploader',$create_image_dialog)[0], + action: 'upload', + multiple: false, + params: {}, + showMessage: function(message){ + //notifyMessage(message); + }, + onSubmit: function(id, fileName){ + uploader.setParams({ + img : JSON.stringify(img_obj), + file: fileName + }); + var pos_top = $(window).height() - 120; + var pos_left = 140; + var pb_dialog = $('
'+ + '
'+ + '
').dialog({ + draggable:true, + modal:false, + resizable:false, + buttons:{}, + width: 460, + minHeight: 50, + position: [pos_left, pos_top] + }); + + $('#upload-progress',pb_dialog).progressbar({value:0}); + }, + onProgress: function(id, fileName, loaded, total){ + $('div#pb_dialog #upload-progress').progressbar("option","value",Math.floor(loaded*100/total)); + }, + onComplete: function(id, fileName, responseJSON){ + notifyMessage("Image uploaded correctly"); + $('div#pb_dialog').dialog('destroy'); + Sunstone.runAction("Image.list"); + return false; + }, + onCancel: function(id, fileName){ + }, + }); + + var file_input = false; + uploader._button._options.onChange = function(input) { + file_input = input; return false; + }; $('#create_image_form_easy',dialog).submit(function(){ var exit = false; + var upload = false; $('.img_man',this).each(function(){ if (!$('input',this).val().length){ notifyError(tr("There are mandatory parameters missing")); @@ -805,6 +885,9 @@ function setupCreateImageDialog(){ img_json["SIZE"] = size; img_json["FSTYPE"] = fstype; break; + case "upload": + upload=true; + break; } //Time to add custom attributes @@ -815,8 +898,13 @@ function setupCreateImageDialog(){ }); - var obj = { "image" : img_json }; - Sunstone.runAction("Image.create", obj); + img_obj = { "image" : img_json }; + + if (upload){ + uploader._onInputChange(file_input); + } else { + Sunstone.runAction("Image.create", img_obj); + }; $create_image_dialog.dialog('close'); return false; @@ -831,6 +919,9 @@ function setupCreateImageDialog(){ } function popUpCreateImageDialog(){ + $('#file-uploader input',$create_image_dialog).removeAttr("style"); + $('#file-uploader input',$create_image_dialog).attr('style','margin:0;width:256px!important'); + $create_image_dialog.dialog('open'); } diff --git a/src/sunstone/sunstone-server.rb b/src/sunstone/sunstone-server.rb index a2636ed929..156c302248 100755 --- a/src/sunstone/sunstone-server.rb +++ b/src/sunstone/sunstone-server.rb @@ -308,6 +308,13 @@ delete '/:resource/:id' do @SunstoneServer.delete_resource(params[:resource], params[:id]) end +############################################################################## +# Upload image +############################################################################## +post '/upload'do + @SunstoneServer.upload(params[:img], request.env['rack.input'].path) +end + ############################################################################## # Create a new Resource ############################################################################## diff --git a/src/sunstone/views/index.erb b/src/sunstone/views/index.erb index c510722d46..85bfa4bc12 100644 --- a/src/sunstone/views/index.erb +++ b/src/sunstone/views/index.erb @@ -17,6 +17,7 @@ +