diff --git a/include/UserPool.h b/include/UserPool.h index e4ea069733..040aeea12e 100644 --- a/include/UserPool.h +++ b/include/UserPool.h @@ -177,6 +177,17 @@ private: int& group_id, string& uname, string& gname); + + /** + * Function to authenticate internal users using a server driver + */ + bool authenticate_server(User * user, + const string& token, + int& user_id, + int& group_id, + string& uname, + string& gname); + /** * Function to authenticate external (not known) users diff --git a/install.sh b/install.sh index 0ef1d692af..35d023fc1a 100755 --- a/install.sh +++ b/install.sh @@ -232,7 +232,7 @@ VAR_DIRS="$VAR_LOCATION/remotes \ $VAR_LOCATION/remotes/auth/plain \ $VAR_LOCATION/remotes/auth/ssh \ $VAR_LOCATION/remotes/auth/x509 \ - $VAR_LOCATION/remotes/auth/server \ + $VAR_LOCATION/remotes/auth/server_x509 \ $VAR_LOCATION/remotes/auth/server_cipher \ $VAR_LOCATION/remotes/auth/quota \ $VAR_LOCATION/remotes/auth/dummy" @@ -330,7 +330,7 @@ INSTALL_FILES=( IM_PROBES_GANGLIA_FILES:$VAR_LOCATION/remotes/im/ganglia.d AUTH_SSH_FILES:$VAR_LOCATION/remotes/auth/ssh AUTH_X509_FILES:$VAR_LOCATION/remotes/auth/x509 - AUTH_SERVER_FILES:$VAR_LOCATION/remotes/auth/server + AUTH_SERVER_X509_FILES:$VAR_LOCATION/remotes/auth/server_x509 AUTH_SERVER_CIPHER_FILES:$VAR_LOCATION/remotes/auth/server_cipher AUTH_DUMMY_FILES:$VAR_LOCATION/remotes/auth/dummy AUTH_PLAIN_FILES:$VAR_LOCATION/remotes/auth/plain @@ -503,7 +503,7 @@ RUBY_LIB_FILES="src/mad/ruby/ActionManager.rb \ src/tm_mad/TMScript.rb \ src/authm_mad/remotes/ssh/ssh_auth.rb \ src/authm_mad/remotes/quota/quota.rb \ - src/authm_mad/remotes/server/server_auth.rb \ + src/authm_mad/remotes/server_x509/server_x509_auth.rb \ src/authm_mad/remotes/server_cipher/server_cipher_auth.rb \ src/authm_mad/remotes/x509/x509_auth.rb" @@ -599,7 +599,7 @@ IM_PROBES_GANGLIA_FILES="src/im_mad/remotes/ganglia.d/ganglia_probe" AUTH_SERVER_CIPHER_FILES="src/authm_mad/remotes/server_cipher/authenticate" -AUTH_SERVER_FILES="src/authm_mad/remotes/server/authenticate" +AUTH_SERVER_X509_FILES="src/authm_mad/remotes/server_x509/authenticate" AUTH_X509_FILES="src/authm_mad/remotes/x509/authenticate" @@ -726,7 +726,7 @@ HM_ETC_FILES="src/hm_mad/hmrc" # Auth Manager drivers config. files, to be installed under $ETC_LOCATION/auth #------------------------------------------------------------------------------- -AUTH_ETC_FILES="src/authm_mad/remotes/server/server_auth.conf \ +AUTH_ETC_FILES="src/authm_mad/remotes/server_x509/server_x509_auth.conf \ src/authm_mad/remotes/quota/quota.conf \ src/authm_mad/remotes/x509/x509_auth.conf" diff --git a/share/etc/oned.conf b/share/etc/oned.conf index 621263c8a7..42a82437ff 100644 --- a/share/etc/oned.conf +++ b/share/etc/oned.conf @@ -552,12 +552,14 @@ HM_MAD = [ # --authz: authorization module # # SESSION_EXPIRATION_TIME: Time in seconds to keep an authenticated token as -# valid. During this time, the driver is not used. +# valid. During this time, the driver is not used. Use 0 to disable session +# caching #******************************************************************************* #AUTH_MAD = [ # executable = "one_auth_mad", -# arguments = "--authz quota --authn plain,ssh,x509" +# arguments = "--authn ssh, x509, server_cipher, server_x509" +# arguments = "--authz quota --authn plain,ssh,x509"ssh, x509, server_cipher, server_x509 #] -SESSION_EXPIRATION_TIME = 900 +SESSION_EXPIRATION_TIME = 900 \ No newline at end of file diff --git a/src/authm_mad/remotes/server_cipher/authenticate b/src/authm_mad/remotes/server_cipher/authenticate index 0f39d35c97..3bdcb496dc 100755 --- a/src/authm_mad/remotes/server_cipher/authenticate +++ b/src/authm_mad/remotes/server_cipher/authenticate @@ -38,17 +38,16 @@ secret = ARGV[2] # Base64 encoded secret as obtained from login_token #OpenNebula.log_debug("Authenticating #{user}, with password #{pass} (#{secret})") begin - server_auth = ServerCipherAuth.new - rc,user = server_auth.authenticate(user, pass, secret) + server_auth = ServerCipherAuth.new_driver + rc = server_auth.authenticate(user, pass, secret) rescue => e OpenNebula.error_message e.message exit -1 end if rc == true - puts user exit 0 else - OpenNebula.error_message user + OpenNebula.error_message rc exit -1 end \ No newline at end of file diff --git a/src/authm_mad/remotes/server_cipher/server_cipher_auth.rb b/src/authm_mad/remotes/server_cipher/server_cipher_auth.rb index 5a88203f45..e25bb3e74e 100644 --- a/src/authm_mad/remotes/server_cipher/server_cipher_auth.rb +++ b/src/authm_mad/remotes/server_cipher/server_cipher_auth.rb @@ -29,63 +29,72 @@ class ServerCipherAuth ########################################################################### CIPHER = "aes-256-cbc" - EXPIRE = 300 ########################################################################### - def initialize(one_auth = nil) - begin - if one_auth - auth = one_auth - elsif ENV["ONE_AUTH"] and !ENV["ONE_AUTH"].empty? and - File.file?(ENV["ONE_AUTH"]) - auth = File.read(ENV["ONE_AUTH"]) - elsif File.file?(ENV["HOME"]+"/.one/one_auth") - auth = File.read(ENV["HOME"]+"/.one/one_auth") - else - raise "ONE_AUTH file not present" - end - - auth.rstrip! - - @server_user, passwd = auth.split(':') - @key = Digest::SHA1.hexdigest(passwd) - - @cipher = OpenSSL::Cipher::Cipher.new(CIPHER) - rescue - raise + def initialize(srv_user, srv_passwd) + @srv_user = srv_user + @srv_passwd = srv_passwd + + if !srv_passwd.empty? + @key = Digest::SHA1.hexdigest(@srv_passwd) + else + @key = "" end + + @cipher = OpenSSL::Cipher::Cipher.new(CIPHER) + end + + ########################################################################### + # Client side + ########################################################################### + + # Creates a ServerCipher for client usage + def self.new_client(srv_user, srv_passwd) + self.new(srv_user, srv_passwd) end # Generates a login token in the form: # - server_user:target_user:time_expires # The token is then encrypted with the contents of one_auth - def login_token(target_user=nil) - target_user ||= @server_user - token_txt = "#{@server_user}:#{target_user}:#{Time.now.to_i + EXPIRE}" + def login_token(expire, target_user=nil) + target_user ||= @srv_user + token_txt = "#{@srv_user}:#{target_user}:#{expire}" - token = encrypt(token_txt) - token64 = Base64::encode64(token).strip.delete("\n") + token = encrypt(token_txt) + token64 = Base64::encode64(token).strip.delete("\n") - return "#{@server_user}:#{token64}" + return "#{@srv_user}:#{target_user}:#{token64}" + end + + # Returns a valid password string to create a user using this auth driver + def password + return @srv_passwd end ########################################################################### - # Server side + # Driver side ########################################################################### + + # Creates a ServerCipher for driver usage + def self.new_driver() + self.new("","") + end + # auth method for auth_mad - def authenticate(user, pass, signed_text) - begin - # Decryption demonstrates that the user posessed the private key. - s_user, t_user, expires = decrypt(signed_text,pass).split(':') - - return "User name missmatch" if s_user != @server_user + def authenticate(srv_user,srv_pass, signed_text) + begin + @key = srv_pass + + s_user, t_user, expires = decrypt(signed_text).split(':') + return "User name missmatch" if s_user != srv_user + return "login token expired" if Time.now.to_i >= expires.to_i - return true, t_user + return true rescue => e - return false, e.message + return e.message end end @@ -101,13 +110,13 @@ class ServerCipherAuth return rc end - def decrypt(data,pass) + def decrypt(data) @cipher.decrypt - @cipher.key = pass + @cipher.key = @key rc = @cipher.update(Base64::decode64(data)) rc << @cipher.final return rc end -end +end \ No newline at end of file diff --git a/src/authm_mad/remotes/server/authenticate b/src/authm_mad/remotes/server_x509/authenticate similarity index 96% rename from src/authm_mad/remotes/server/authenticate rename to src/authm_mad/remotes/server_x509/authenticate index 20f0a2ebe8..e9a7e84da1 100755 --- a/src/authm_mad/remotes/server/authenticate +++ b/src/authm_mad/remotes/server_x509/authenticate @@ -28,7 +28,7 @@ end $: << RUBY_LIB_LOCATION -require 'server_auth' +require 'server_x509_auth' require 'scripts_common' user = ARGV[0] # username as registered in OpenNebula @@ -38,7 +38,7 @@ secret = ARGV[2] # Base64 encoded secret as obtained from login_token #OpenNebula.log_debug("Authenticating #{user}, with password #{pass} (#{secret})") begin - server_auth = ServerAuth.new + server_auth = ServerX509Auth.new dsecret = Base64::decode64(secret) rc = server_auth.authenticate(user, pass, dsecret) diff --git a/src/authm_mad/remotes/server/server_auth.conf b/src/authm_mad/remotes/server_x509/server_x509_auth.conf similarity index 68% rename from src/authm_mad/remotes/server/server_auth.conf rename to src/authm_mad/remotes/server_x509/server_x509_auth.conf index 57b669e4eb..e5d3598022 100644 --- a/src/authm_mad/remotes/server/server_auth.conf +++ b/src/authm_mad/remotes/server_x509/server_x509_auth.conf @@ -1,3 +1,7 @@ +# User to be used for x509 server authentication + +#:srv_user: x509_server + # Path to the certificate used by the OpenNebula Services # Certificates must be in PEM format diff --git a/src/authm_mad/remotes/server/server_auth.rb b/src/authm_mad/remotes/server_x509/server_x509_auth.rb similarity index 69% rename from src/authm_mad/remotes/server/server_auth.rb rename to src/authm_mad/remotes/server_x509/server_x509_auth.rb index ba5f4ba3fd..6e7050e3c4 100644 --- a/src/authm_mad/remotes/server/server_auth.rb +++ b/src/authm_mad/remotes/server_x509/server_x509_auth.rb @@ -23,12 +23,12 @@ require 'x509_auth' # Server authentication class. This authmethod can be used by opennebula services # to let access authenticated users by other means. It is based on x509 server # certificates -class ServerAuth < X509Auth +class ServerX509Auth < X509Auth ########################################################################### #Constants with paths to relevant files and defaults ########################################################################### - SERVER_AUTH_CONF_PATH = ETC_LOCATION + "/auth/server_auth.conf" + SERVER_AUTH_CONF_PATH = ETC_LOCATION + "/auth/server_x509_auth.conf" SERVER_DEFAULTS = { :one_cert => ETC_LOCATION + "/auth/cert.pem", @@ -46,51 +46,46 @@ class ServerAuth < X509Auth certs = [ File.read(@options[:one_cert]) ] key = File.read(@options[:one_key]) - super(:certs_pem => certs, - :key_pem => key) + super(:certs_pem => certs, :key_pem => key) rescue raise - end + end + + if @options[:srv_user] == nil || @options[:srv_user].empty? + raise "User for x509 server not defined" + end end # Generates a login token in the form: - # user_name:server:user_name:user_pass:time_expires - # - user_name:user_pass:time_expires is encrypted with the server certificate - def login_token(user, user_pass, expire) + # - server_user:target_user:time_expires + def login_token(expire, target_user=nil) + target_user ||= @options[:srv_user] + token_txt = "#{@options[:srv_user]}:#{target_user}:#{expire}" - expires = Time.now.to_i+expire - - token_txt = "#{user}:#{user_pass}:#{expires}" + token = encrypt(token_txt) + token64 = Base64::encode64(token).strip.delete("\n") - token = encrypt(token_txt) - token64 = Base64::encode64(token).strip.delete("\n") - - login_out = "#{user}:#{token64}" - - login_out + return "#{@options[:srv_user]}:#{target_user}:#{token64}" end ########################################################################### # Server side ########################################################################### # auth method for auth_mad - def authenticate(user, pass, signed_text) - begin - # Decryption demonstrates that the user posessed the private key. - _user, user_pass, expires = decrypt(signed_text).split(':') - - return "User name missmatch" if user != _user + def authenticate(server_user, server_pass, signed_text) + begin + s_user, t_user, expires = decrypt(signed_text).split(':') + + return "Server password missmatch" if server_pass != password + return "User name missmatch" if ( s_user != server_user || + s_user != @options[:srv_user] ) + return "login token expired" if Time.now.to_i >= expires.to_i - # Check that the signed password matches one for the user. - if !pass.split('|').include?(user_pass) - return "User password missmatch" - end - return true rescue => e return e.message end end -end +end \ No newline at end of file diff --git a/src/authm_mad/remotes/ssh/ssh_auth.rb b/src/authm_mad/remotes/ssh/ssh_auth.rb index 3a48e8917c..2885f39da0 100644 --- a/src/authm_mad/remotes/ssh/ssh_auth.rb +++ b/src/authm_mad/remotes/ssh/ssh_auth.rb @@ -26,8 +26,6 @@ require 'fileutils' class SshAuth LOGIN_PATH = ENV['HOME']+'/.one/one_ssh' - attr_reader :public_key - # Initialize SshAuth object # # @param [Hash] default options for path @@ -91,6 +89,12 @@ class SshAuth secret_crypted end + # Returns a valid password string to create a user using this auth driver. + # In this case the ssh public key. + def password + @public_key + end + # Checks the proxy created with the login method def authenticate(user, token) begin diff --git a/src/authm_mad/remotes/x509/x509_auth.rb b/src/authm_mad/remotes/x509/x509_auth.rb index caf0cfdb3b..325027f25d 100644 --- a/src/authm_mad/remotes/x509/x509_auth.rb +++ b/src/authm_mad/remotes/x509/x509_auth.rb @@ -79,8 +79,9 @@ class X509Auth write_login(login_token(user,expire)) end - # Returns the dn of the user certificate - def dn + # Returns a valid password string to create a user using this auth driver. + # In this case the dn of the user certificate. + def password @cert_chain[0].subject.to_s.delete("\s") end diff --git a/src/cli/one_helper/oneuser_helper.rb b/src/cli/one_helper/oneuser_helper.rb index 185beb974e..d3a78b0955 100644 --- a/src/cli/one_helper/oneuser_helper.rb +++ b/src/cli/one_helper/oneuser_helper.rb @@ -37,11 +37,11 @@ class OneUserHelper < OpenNebulaHelper::OneHelper return -1, "Can not read file: #{arg}" end else - if options[:x509] - password = arg.delete("\s") - else - password = arg - end + password = arg + end + + if options[:x509] + password.delete!("\s") end return 0, password @@ -56,12 +56,10 @@ class OneUserHelper < OpenNebulaHelper::OneHelper require 'ssh_auth' begin - sshauth = SshAuth.new(:private_key=>options[:key]) + auth = SshAuth.new(:private_key=>options[:key]) rescue Exception => e return -1, e.message end - - return 0, sshauth.public_key elsif options[:x509] options[:cert] ||= ENV['X509_USER_CERT'] @@ -72,16 +70,16 @@ class OneUserHelper < OpenNebulaHelper::OneHelper require 'x509_auth' begin - cert = [File.read(options[:cert])] - x509auth = X509Auth.new(:certs_pem=>cert) + cert = [File.read(options[:cert])] + auth = X509Auth.new(:certs_pem=>cert) rescue Exception => e return -1, e.message end - - return 0, x509auth.dn else return -1, "You have to specify an Auth method or define a password" end + + return 0, auth.password end def self.login(username, options) diff --git a/src/cli/oneuser b/src/cli/oneuser index bed6e3ee80..9bb2ba4a70 100755 --- a/src/cli/oneuser +++ b/src/cli/oneuser @@ -275,7 +275,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do if rc.first == 0 pass = rc[1] else - exit_with_code *rc + pass = "" end end diff --git a/src/cloud/common/CloudAuth/X509CloudAuth.rb b/src/cloud/common/CloudAuth/X509CloudAuth.rb index 791adc2af8..627cb6ac1a 100644 --- a/src/cloud/common/CloudAuth/X509CloudAuth.rb +++ b/src/cloud/common/CloudAuth/X509CloudAuth.rb @@ -61,7 +61,7 @@ module X509CloudAuth cert_line = nil if cert_line == '(null)' # For Apache mod_ssl # Use the https credentials for authentication - require 'server_auth' + require 'server_x509_auth' while cert_line begin cert_array=cert_line.scan(/([^\s]*)\s/) @@ -98,7 +98,7 @@ module X509CloudAuth raise msg end - auth = ServerAuth.new + auth = ServerX509Auth.new @token = auth.login_token(username, subjectname, 300) @client = Client.new(@token, @conf[:one_xmlrpc]) diff --git a/src/oca/java/src/org/opennebula/client/user/User.java b/src/oca/java/src/org/opennebula/client/user/User.java index cfcd85d979..d8eb40c148 100644 --- a/src/oca/java/src/org/opennebula/client/user/User.java +++ b/src/oca/java/src/org/opennebula/client/user/User.java @@ -151,7 +151,8 @@ public class User extends PoolElement{ * @param client XML-RPC Client. * @param id The user id (uid) of the target user we want to modify. * @param auth The new auth driver. - * @param password The new password. + * @param password The new password. If it is an empty string, + * the user password is not changed * @return If an error occurs the error message contains the reason. */ public static OneResponse chauth(Client client, @@ -229,7 +230,8 @@ public class User extends PoolElement{ * Changes the auth driver and the password of the given user * * @param auth The new auth driver. - * @param password The new password. + * @param password The new password. If it is an empty string, + * the user password is not changed * @return If an error occurs the error message contains the reason. */ public OneResponse chauth(String auth, String password) @@ -237,6 +239,17 @@ public class User extends PoolElement{ return chauth(client, id, auth, password); } + /** + * Changes the auth driver of the given user + * + * @param auth The new auth driver. + * @return If an error occurs the error message contains the reason. + */ + public OneResponse chauth(String auth) + { + return chauth(auth, ""); + } + /** * Replaces the user template contents. * diff --git a/src/oca/ruby/OpenNebula/User.rb b/src/oca/ruby/OpenNebula/User.rb index 06f30a0331..8e71ff5c6b 100644 --- a/src/oca/ruby/OpenNebula/User.rb +++ b/src/oca/ruby/OpenNebula/User.rb @@ -119,10 +119,11 @@ module OpenNebula # Changes the auth driver and the password of the given User # # @param auth [String] the new auth driver - # @param password [String] the new password + # @param password [String] the new password. If it is an empty string, + # the user password is not changed # @return [nil, OpenNebula::Error] nil in case of success, Error # otherwise - def chauth(auth, password) + def chauth(auth, password="") return Error.new('ID not defined') if !@pe_id rc = @client.call(USER_METHODS[:chauth],@pe_id, auth, password) diff --git a/src/rm/RequestManagerUser.cc b/src/rm/RequestManagerUser.cc index 91f7bfc012..01376a1d4b 100644 --- a/src/rm/RequestManagerUser.cc +++ b/src/rm/RequestManagerUser.cc @@ -88,15 +88,18 @@ int UserChangeAuth::user_action(User * user, string new_auth = xmlrpc_c::value_string(paramList.getString(2)); string new_pass = xmlrpc_c::value_string(paramList.getString(3)); - int rc; + int rc = 0; - if (new_auth == UserPool::CORE_AUTH) + if ( !new_pass.empty() ) { - new_pass = SSLTools::sha1_digest(new_pass); - } + if ( new_auth == UserPool::CORE_AUTH) + { + new_pass = SSLTools::sha1_digest(new_pass); + } - // The password may be invalid, try to change it first - rc = user->set_password(new_pass, error_str); + // The password may be invalid, try to change it first + rc = user->set_password(new_pass, error_str); + } if ( rc == 0 ) { diff --git a/src/sunstone/models/OpenNebulaJSON/VirtualNetworkJSON.rb b/src/sunstone/models/OpenNebulaJSON/VirtualNetworkJSON.rb index 7a4669a5d5..b18230f2ac 100644 --- a/src/sunstone/models/OpenNebulaJSON/VirtualNetworkJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/VirtualNetworkJSON.rb @@ -31,7 +31,7 @@ module OpenNebulaJSON else template = template_to_str(vnet_hash) end - + self.allocate(template) end @@ -46,6 +46,7 @@ module OpenNebulaJSON when "rmleases" then self.rmleases(action_hash['params']) when "publish" then self.publish when "unpublish" then self.unpublish + when "update" then self.update(action_hash['params']) when "chown" then self.chown(action_hash['params']) else error_msg = "#{action_hash['perform']} action not " << @@ -62,6 +63,10 @@ module OpenNebulaJSON super(params['ip']) end + def update(params=Hash.new) + super(params['template_raw']) + end + def chown(params=Hash.new) super(params['owner_id'].to_i,params['group_id'].to_i) end diff --git a/src/sunstone/public/js/opennebula.js b/src/sunstone/public/js/opennebula.js index 12ea698981..8a7224d161 100644 --- a/src/sunstone/public/js/opennebula.js +++ b/src/sunstone/public/js/opennebula.js @@ -510,7 +510,17 @@ var OpenNebula = { OpenNebula.Network.resource, "rmleases", action_obj); - } + }, + "update": function(params){ + var action_obj = {"template_raw" : params.data.extra_param }; + OpenNebula.Action.simple_action(params, + OpenNebula.Network.resource, + "update", + action_obj); + }, + "fetch_template" : function(params){ + OpenNebula.Action.show(params,OpenNebula.Network.resource,"template"); + }, }, "VM": { diff --git a/src/sunstone/public/js/plugins/images-tab.js b/src/sunstone/public/js/plugins/images-tab.js index 8a70352d59..b2bb396b1a 100644 --- a/src/sunstone/public/js/plugins/images-tab.js +++ b/src/sunstone/public/js/plugins/images-tab.js @@ -169,6 +169,34 @@ var create_image_tmpl = \ '; +var update_image_tmpl = + '
'; + var images_select = ""; var dataTable_images; var $create_image_dialog; @@ -228,7 +256,7 @@ var image_actions = { type: "single", call: OpenNebula.Image.fetch_template, callback: function (request,response) { - $('#template_update_dialog #template_update_textarea').val(response.template); + $('#image_template_update_dialog #image_template_update_textarea').val(response.template); }, error: onError }, @@ -236,14 +264,7 @@ var image_actions = { "Image.update_dialog" : { type: "custom", call: function() { - popUpTemplateUpdateDialog("Image", - makeSelectOptions(dataTable_images, - 1,//id_col - 4,//name_col - [], - [] - ), - getSelectedNodes(dataTable_images)); + popUpImageTemplateUpdateDialog(); } }, @@ -450,6 +471,8 @@ function imageElements() { // Returns an array containing the values of the image_json and ready // to be inserted in the dataTable function imageElementArray(image_json){ + //Changing this? It may affect to the is_public and is_persistent + //variables in setupImageTemplateUpdateDialog(); var image = image_json.IMAGE; return [ '', @@ -775,6 +798,127 @@ function popUpCreateImageDialog(){ $create_image_dialog.dialog('open'); } + + +function setupImageTemplateUpdateDialog(){ + + //Append to DOM + dialogs_context.append(''); + var dialog = $('#image_template_update_dialog',dialogs_context); + + //Put HTML in place + dialog.html(update_image_tmpl); + + //Convert into jQuery + dialog.dialog({ + autoOpen:false, + width:700, + modal:true, + height:480, + resizable:false, + }); + + $('button',dialog).button(); + + $('#image_template_update_select',dialog).change(function(){ + var id = $(this).val(); + if (id && id.length){ + var dialog = $('#image_template_update_dialog'); + $('#image_template_update_textarea',dialog).val("Loading..."); + + var data = getElementData(id,"#image",dataTable_images); + var is_public = data[7] == "yes"; + var is_persistent = data[8] == "yes"; + + if (is_public){ + $('#image_template_update_public',dialog).attr("checked","checked") + } else { + $('#image_template_update_public',dialog).removeAttr("checked") + } + + if (is_persistent){ + $('#image_template_update_persistent',dialog).attr("checked","checked") + } else { + $('#image_template_update_persistent',dialog).removeAttr("checked") + } + + Sunstone.runAction("Image.fetch_template",id); + } else { + $('#image_template_update_textarea',dialog).val(""); + }; + }); + + $('#image_template_update_button',dialog).click(function(){ + var dialog = $('#image_template_update_dialog'); + var new_template = $('#image_template_update_textarea',dialog).val(); + var id = $('#image_template_update_select',dialog).val(); + if (!id || !id.length) { + dialog.dialog('close'); + return false; + }; + + var data = getElementData(id,"#image",dataTable_images); + var is_public = data[7] == "yes"; + var is_persistent = data[8] == "yes"; + + var new_public = $('#image_template_update_public:checked',dialog).length; + var new_persistent = $('#image_template_update_persistent:checked',dialog).length; + + if (is_public != new_public){ + if (new_public) Sunstone.runAction("Image.publish",id); + else Sunstone.runAction("Image.unpublish",id); + }; + + if (is_persistent != new_persistent){ + if (new_persistent) Sunstone.runAction("Image.persistent",id); + else Sunstone.runAction("Image.nonpersistent",id); + }; + + Sunstone.runAction("Image.update",id,new_template); + dialog.dialog('close'); + return false; + }); +} + + +function popUpImageTemplateUpdateDialog(){ + var select = makeSelectOptions(dataTable_images, + 1,//id_col + 4,//name_col + [], + [] + ); + var sel_elems = getSelectedNodes(dataTable_images); + + + var dialog = $('#image_template_update_dialog'); + $('#image_template_update_select',dialog).html(select); + $('#image_template_update_textarea',dialog).val(""); + $('#image_template_update_public',dialog).removeAttr("checked") + $('#image_template_update_persistent',dialog).removeAttr("checked") + + if (sel_elems.length >= 1){ //several items in the list are selected + //grep them + var new_select= sel_elems.length > 1? '' : ""; + $('option','').each(function(){ + var val = $(this).val(); + if ($.inArray(val,sel_elems) >= 0){ + new_select+=''; + }; + }); + $('#image_template_update_select',dialog).html(new_select); + if (sel_elems.length == 1) { + $('#image_template_update_select option',dialog).attr("selected","selected"); + $('#image_template_update_select',dialog).trigger("change"); + } + + }; + + dialog.dialog('open'); + return false; + +} + // Set the autorefresh interval for the datatable function setImageAutorefresh() { setInterval(function(){ @@ -811,6 +955,7 @@ $(document).ready(function(){ Sunstone.runAction("Image.list"); setupCreateImageDialog(); + setupImageTemplateUpdateDialog(); setupTips($create_image_dialog); setImageAutorefresh(); diff --git a/src/sunstone/public/js/plugins/vnets-tab.js b/src/sunstone/public/js/plugins/vnets-tab.js index 2151858d4c..84c7735406 100644 --- a/src/sunstone/public/js/plugins/vnets-tab.js +++ b/src/sunstone/public/js/plugins/vnets-tab.js @@ -135,6 +135,30 @@ var create_vn_tmpl = \ '; +var update_vnet_tmpl = + ''; + var vnetworks_select=""; var dataTable_vNetworks; var $create_vn_dialog; @@ -272,8 +296,34 @@ var vnet_actions = { elements: vnElements, error:onError, notify: true - } -} + }, + + "Network.fetch_template" : { + type: "single", + call: OpenNebula.Network.fetch_template, + callback: function (request,response) { + $('#vnet_template_update_dialog #vnet_template_update_textarea').val(response.template); + }, + error: onError + }, + + "Network.update_dialog" : { + type: "custom", + call: function() { + popUpVNetTemplateUpdateDialog(); + } + }, + + "Network.update" : { + type: "single", + call: OpenNebula.Network.update, + callback: function() { + notifyMessage("Template updated correctly"); + }, + error: onError + }, + +}; var vnet_buttons = { @@ -288,6 +338,12 @@ var vnet_buttons = { text: "+ New" }, + "Network.update_dialog" : { + type: "action", + text: "Update a template", + alwaysActive: true + }, + "Network.publish" : { type: "action", text: "Publish" @@ -684,6 +740,109 @@ function popUpCreateVnetDialog() { $create_vn_dialog.dialog('open'); } + +function setupVNetTemplateUpdateDialog(){ + //Append to DOM + dialogs_context.append(''); + var dialog = $('#vnet_template_update_dialog',dialogs_context); + + //Put HTML in place + dialog.html(update_vnet_tmpl); + + //Convert into jQuery + dialog.dialog({ + autoOpen:false, + width:700, + modal:true, + height:480, + resizable:false, + }); + + $('button',dialog).button(); + + $('#vnet_template_update_select',dialog).change(function(){ + var id = $(this).val(); + if (id && id.length){ + var dialog = $('#vnet_template_update_dialog'); + $('#vnet_template_update_textarea',dialog).val("Loading..."); + + var data = getElementData(id,"#vnetwork",dataTable_vNetworks); + var is_public = data[7] == "yes"; + + if (is_public){ + $('#vnet_template_update_public',dialog).attr("checked","checked") + } else { + $('#vnet_template_update_public',dialog).removeAttr("checked") + } + + Sunstone.runAction("Network.fetch_template",id); + } else { + $('#vnet_template_update_textarea',dialog).val(""); + }; + }); + + $('#vnet_template_update_button',dialog).click(function(){ + var dialog = $('#vnet_template_update_dialog'); + var new_template = $('#vnet_template_update_textarea',dialog).val(); + var id = $('#vnet_template_update_select',dialog).val(); + if (!id || !id.length) { + dialog.dialog('close'); + return false; + }; + + var data = getElementData(id,"#vnetwork",dataTable_vNetworks); + var is_public = data[7] == "yes"; + + var new_public = $('#vnet_template_update_public:checked',dialog).length; + + if (is_public != new_public){ + if (new_public) Sunstone.runAction("Network.publish",id); + else Sunstone.runAction("Network.unpublish",id); + }; + + Sunstone.runAction("Network.update",id,new_template); + dialog.dialog('close'); + return false; + }); +}; + +function popUpVNetTemplateUpdateDialog(){ + var select = makeSelectOptions(dataTable_vNetworks, + 1,//id_col + 4,//name_col + [], + [] + ); + var sel_elems = getSelectedNodes(dataTable_vNetworks); + + + var dialog = $('#vnet_template_update_dialog'); + $('#vnet_template_update_select',dialog).html(select); + $('#vnet_template_update_textarea',dialog).val(""); + $('#vnet_template_update_public',dialog).removeAttr("checked") + + if (sel_elems.length >= 1){ //several items in the list are selected + //grep them + var new_select= sel_elems.length > 1? '' : ""; + $('option','').each(function(){ + var val = $(this).val(); + if ($.inArray(val,sel_elems) >= 0){ + new_select+=''; + }; + }); + $('#vnet_template_update_select',dialog).html(new_select); + if (sel_elems.length == 1) { + $('#vnet_template_update_select option',dialog).attr("selected","selected"); + $('#vnet_template_update_select',dialog).trigger("change"); + } + + }; + + dialog.dialog('open'); + return false; + +} + function setupAddRemoveLeaseDialog() { dialogs_context.append(''); $lease_vn_dialog = $('#lease_vn_dialog',dialogs_context) @@ -786,6 +945,7 @@ $(document).ready(function(){ Sunstone.runAction("Network.list"); setupCreateVNetDialog(); + setupVNetTemplateUpdateDialog(); setupAddRemoveLeaseDialog(); setVNetAutorefresh(); diff --git a/src/sunstone/public/js/sunstone-util.js b/src/sunstone/public/js/sunstone-util.js index 25d1b6af3e..4caa9babfe 100644 --- a/src/sunstone/public/js/sunstone-util.js +++ b/src/sunstone/public/js/sunstone-util.js @@ -140,7 +140,7 @@ function tableCheckboxesListener(dataTable){ //listen to changes in the visible inputs $('tbody input',dataTable).live("change",function(){ var datatable = $(this).parents('table'); - recountCheckboxes(dataTable); + recountCheckboxes(datatable); }); } @@ -163,6 +163,12 @@ function updateSingleElement(element,dataTable,tag){ recountCheckboxes(dataTable); } +function getElementData(id, resource_tag, dataTable){ + var nodes = dataTable.fnGetNodes(); + var tr = $(resource_tag+'_'+id,nodes).parents('tr')[0]; + return dataTable.fnGetData(tr); +} + // Returns an string in the form key=value key=value ... // Does not explore objects in depth. function stringJSON(json){ @@ -657,6 +663,12 @@ function setupTemplateUpdateDialog(){ var dialog = $('#template_update_dialog'); var new_template = $('#template_update_textarea',dialog).val(); var id = $('#template_update_select',dialog).val(); + + if (!id || !id.length) { + dialog.dialog('close'); + return false; + }; + var resource = $(this).val(); Sunstone.runAction(resource+".update",id,new_template); dialog.dialog('close'); diff --git a/src/um/UserPool.cc b/src/um/UserPool.cc index c81cf4e215..68a7aa822e 100644 --- a/src/um/UserPool.cc +++ b/src/um/UserPool.cc @@ -28,9 +28,10 @@ #include