From a5d72b936caede01ae8ef3362952021f7b3cb157 Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Tue, 14 Feb 2012 18:59:00 +0100 Subject: [PATCH 1/4] Improve Selfservice/OCCI upload. Wait until images have been successfully copied into the repository by opennebula to return from request. (cherry picked from commit 2630d1c6a7a630b26646107f88c33e2ae1500671) --- src/cloud/occi/lib/OCCIServer.rb | 11 ++++++++++- src/cloud/occi/lib/occi-server.rb | 6 +----- src/cloud/occi/lib/ui/public/js/plugins/storage.js | 2 +- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/cloud/occi/lib/OCCIServer.rb b/src/cloud/occi/lib/OCCIServer.rb index f762fe1fbc..1a1a6357d1 100755 --- a/src/cloud/occi/lib/OCCIServer.rb +++ b/src/cloud/occi/lib/OCCIServer.rb @@ -45,6 +45,9 @@ COLLECTIONS = ["compute", "instance_type", "network", "storage"] # 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 = 1 + class OCCIServer < CloudServer # Server initializer # config_file:: _String_ path of the config file @@ -410,8 +413,14 @@ class OCCIServer < CloudServer return rc, CloudServer::HTTP_ERROR_CODE[rc.errno] end - # --- Prepare XML Response --- 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 + + # --- Prepare XML Response --- return to_occi_xml(image, :status=>201) end diff --git a/src/cloud/occi/lib/occi-server.rb b/src/cloud/occi/lib/occi-server.rb index ad51901120..8bee03b296 100755 --- a/src/cloud/occi/lib/occi-server.rb +++ b/src/cloud/occi/lib/occi-server.rb @@ -366,13 +366,9 @@ get '/ui' do end post '/ui/upload' do - file = Tempfile.new('uploaded_image') - FileUtils.cp(request.env['rack.input'].path, file.path) - #so we can re-use occi post_storage() - request.params['file'] = {:tempfile => file} + request.params['file'] = {:tempfile => request.env['rack.input']} result,rc = @occi_server.post_storage(request) - treat_response(result,rc) end diff --git a/src/cloud/occi/lib/ui/public/js/plugins/storage.js b/src/cloud/occi/lib/ui/public/js/plugins/storage.js index 6e7b99d7fd..336a51d272 100644 --- a/src/cloud/occi/lib/ui/public/js/plugins/storage.js +++ b/src/cloud/occi/lib/ui/public/js/plugins/storage.js @@ -478,7 +478,7 @@ function popUpCreateImageDialog(){ multiple: false, params: {}, showMessage: function(message){ - notifyMessage(message); + //notifyMessage(message); }, onSubmit: function(id, fileName){ var xml = json2xml(img_obj,"STORAGE"); From c3931e8fc68c3cbeff9f1cbe157881895db3b67e Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Wed, 15 Feb 2012 00:32:37 +0100 Subject: [PATCH 2/4] Increase default image register polling in OCCI server to 5 secs --- src/cloud/occi/lib/OCCIServer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cloud/occi/lib/OCCIServer.rb b/src/cloud/occi/lib/OCCIServer.rb index 1a1a6357d1..1b38ca0807 100755 --- a/src/cloud/occi/lib/OCCIServer.rb +++ b/src/cloud/occi/lib/OCCIServer.rb @@ -46,7 +46,7 @@ COLLECTIONS = ["compute", "instance_type", "network", "storage"] POOL_FILTER = Pool::INFO_ALL # Secs to sleep between checks to see if image upload© to repo is finished -IMAGE_POLL_SLEEP_TIME = 1 +IMAGE_POLL_SLEEP_TIME = 5 class OCCIServer < CloudServer # Server initializer From fcb430e4a8cf7894d83cf9fd49a427e497ed7990 Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Wed, 15 Feb 2012 14:10:24 +0100 Subject: [PATCH 3/4] Feature #1089: Upload support for images in Sunstone. Follows the same principles as SelfService. (cherry picked from commit 5dbf040f9c91d3a965aab13e5e39e130a5b5e4f1) --- 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 0c21f8440d..1c810f7265 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 @@ + From 179487ac359950ef8e73f4423fcb6fea7e3b5263 Mon Sep 17 00:00:00 2001 From: Daniel Molina Date: Wed, 15 Feb 2012 19:55:41 +0100 Subject: [PATCH 4/4] bug #1130: Use period_to_str in onevm --- src/cli/one_helper/onevm_helper.rb | 33 ++++++++++++------------------ 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/src/cli/one_helper/onevm_helper.rb b/src/cli/one_helper/onevm_helper.rb index 10b7c75c3d..b772ce61bb 100644 --- a/src/cli/one_helper/onevm_helper.rb +++ b/src/cli/one_helper/onevm_helper.rb @@ -92,14 +92,10 @@ class OneVMHelper < OpenNebulaHelper::OneHelper end column :TIME, "Time since the VM was submitted", :size=>11 do |d| - stime = Time.at(d["STIME"].to_i) - etime = d["ETIME"]=="0" ? Time.now : Time.at(d["ETIME"].to_i) - dtime = Time.at(etime-stime).getgm - "%02d %02d:%02d:%02d" % [ - dtime.yday-1, - dtime.hour, - dtime.min, - dtime.sec] + stime = d["STIME"].to_i + etime = d["ETIME"]=="0" ? Time.now.to_i : d["ETIME"].to_i + dtime = etime-stime + OpenNebulaHelper.period_to_str(dtime) end default :ID, :USER, :GROUP, :NAME, :STAT, :CPU, :MEM, :HOSTNAME, @@ -201,24 +197,21 @@ class OneVMHelper < OpenNebulaHelper::OneHelper end column :TIME, "Total time in this state", :size=>11 do |d| - stime = Time.at(d["STIME"].to_i) - etime = d["ETIME"]=="0" ? Time.now : Time.at(d["ETIME"].to_i) - dtime = Time.at(etime-stime).getgm - "%02d %02d:%02d:%02d" % [dtime.yday-1, dtime.hour, - dtime.min, dtime.sec] + stime = d["STIME"].to_i + etime = d["ETIME"]=="0" ? Time.now.to_i : d["ETIME"].to_i + dtime = etime-stime + OpenNebulaHelper.period_to_str(dtime) end column :PTIME, "Prolog time for this state", :size=>11 do |d| - stime = Time.at(d["PSTIME"].to_i) + stime = d["PSTIME"].to_i if d["PSTIME"]=="0" - etime=Time.at(0) + etime=0 else - etime = d["PETIME"]=="0" ? Time.now : - Time.at(d["PETIME"].to_i) + etime = d["PETIME"]=="0" ? Time.now.to_i: d["PETIME"].to_i end - dtime = Time.at(etime-stime).getgm - "%02d %02d:%02d:%02d" % [dtime.yday-1, dtime.hour, - dtime.min, dtime.sec] + dtime = etime-stime + OpenNebulaHelper.period_to_str(dtime) end default :SEQ, :HOSTNAME, :REASON, :START, :TIME, :PTIME