lib/forj/process/ForjProcess.rb in forj-1.0.1 vs lib/forj/process/ForjProcess.rb in forj-1.0.2

- old
+ new

@@ -22,10 +22,11 @@ require 'find' require 'digest' require 'json' require 'encryptor' # gem install encryptor require 'base64' +require 'net/ssh' $INFRA_VERSION = "0.0.37" # Functions for boot class ForjCoreProcess @@ -39,16 +40,16 @@ :key => rand(36**10).to_s(36), :salt => Time.now.to_i.to_s, :iv => Base64::strict_encode64(OpenSSL::Cipher::Cipher.new('aes-256-cbc').random_iv) } - Logging.debug("Writing '%s' key file" % key_file) + PrcLib.debug("Writing '%s' key file" % key_file) File.open(key_file, 'w') do |out| out.write(Base64::encode64(entr.to_yaml)) end else - Logging.debug("Loading '%s' key file" % key_file) + PrcLib.debug("Loading '%s' key file" % key_file) encoded_key = IO.read(key_file) entr = YAML.load(Base64::decode64(encoded_key)) end os_enckey = hParams[:os_enckey] @@ -104,125 +105,227 @@ # Add init bootstrap additionnal steps hMeta['bootstrap'] = hParams[:bootstrap] if hParams[:bootstrap] config.set(:meta_data, hMeta) # Used by :server object - Logging.info("Metadata set:\n%s" % hMeta) + hMetaPrintable = hMeta.clone + hMetaPrintable['hpcloud_priv'] = "XXX - data hidden - XXX" + PrcLib.info("Metadata set:\n%s" % hMetaPrintable) oMetaData = register(hMeta, sObjectType) oMetaData[:meta_data] = hMeta oMetaData end def build_forge(sObjectType, hParams) + oForge = Get(sObjectType, config[:instance_name]) + if oForge.empty? or oForge[:servers].length == 0 + PrcLib.high_level_msg ("\nBuilding your forge...\n") + Create(:internet_server) + else + oForge[:servers].each { | oServerToFind | + Get(:server, oServerToFind[:id]) if /^maestro\./ =~ oServerToFind[:name] + } + PrcLib.high_level_msg ("\nChecking your forge...\n") + oServer = DataObjects(:server, :ObjectData) + if oServer + oIP = Query(:public_ip, :server_id => oServer[:id]) + if oIP.length > 0 + register oIP[0] + end + Create(:keypairs) + else + PrcLib.high_level_msg ("\nYour forge exist, without maestro. Building Maestro...\n") + Create(:internet_server) - object.Create(:internet_server) + PrcLib.high_level_msg ("\nBuilding your forge...\n") + end + end - Logging.high_level_msg ("\nBuilding your forge...\n") - oServer = DataObjects(:server, :ObjectData) + #Get keypairs + hKeys = keypair_detect(oServer[:key_name], File.join($FORJ_KEYPAIRS_PATH, oServer[:key_name])) + + private_key_file = File.join(hKeys[:keypair_path], hKeys[:private_key_name]) + public_key_file = File.join(hKeys[:keypair_path], hKeys[:public_key_name]) + + oServerKey = Get(:keypairs, oServer[:key_name]) + + keypair_coherent = coherent_keypair?(hKeys, oServerKey) + # Define the log lines to get and test. config.set(:log_lines, 5) - Logging.info("Maestro server '%s' id is '%s'." % [oServer[:name], oServer[:id]]) + PrcLib.info("Maestro server '%s' id is '%s'." % [oServer[:name], oServer[:id]]) # Waiting for server to come online before assigning a public IP. sStatus = :checking maestro_create_status(sStatus) oAddress = DataObjects(:public_ip, :ObjectData) if oServer[:attrs][:status] == :active sMsg = <<-END -Your server is up and running and is publically accessible through IP '#{oAddress[:public_ip]}'. +Your forj Maestro server is up and running and is publically accessible through IP '#{oAddress[:public_ip]}'. You can connect to '#{oServer[:name]}' with: -ssh ubuntu@#{oAddress[:public_ip]} -o StrictHostKeyChecking=no -i #{get_data(:keypairs, :private_key_file)} +ssh ubuntu@#{oAddress[:public_ip]} -o StrictHostKeyChecking=no -i #{private_key_file} END - if not object.get_data(:keypairs)[:coherent] + if not keypair_coherent sMsg += ANSI.bold("\nUnfortunatelly") + " your current keypair is not usable to connect to your server.\nYou need to fix this issue to gain access to your server." end - Logging.info(sMsg) - Logging.high_level_msg ("\n%s\nThe forge is still building...\n" % sMsg) + PrcLib.info(sMsg) - oLog = object.Get(:server_log, 5)[:attrs][:output] + oLog = Get(:server_log, 25)[:attrs][:output] if /cloud-init boot finished/ =~ oLog sStatus = :active + PrcLib.high_level_msg ("\n%s\nThe forge is ready...\n" % sMsg) else + PrcLib.high_level_msg ("\n%s\nThe forge is still building...\n" % sMsg) sStatus = :cloud_init end else sleep 5 sStatus = :starting end + mCloudInitError = [] + iCurAct = 0 + oOldLog = "" + while sStatus != :active - maestro_create_status(sStatus) + maestro_create_status(sStatus, iCurAct) + iCurAct += 1 + iCurAct = iCurAct % 4 begin - oServer = object.Get(:server, oServer[:attrs][:id]) + oServer = Get(:server, oServer[:attrs][:id]) rescue => e - Logging.error(e.message) + PrcLib.error(e.message) end if sStatus == :starting if oServer[:attrs][:status] == :active sStatus = :assign_ip end elsif sStatus == :assign_ip if oAddress.empty? query_cache_cleanup(:public_ip) # To be able to ask for server IP assigned - oAddresses = object.Query(:public_ip, :server_id => oServer[:id]) + oAddresses = Query(:public_ip, :server_id => oServer[:id]) if oAddresses.length == 0 # Assigning Public IP. - oAddress = object.Create(:public_ip) + oAddress = Create(:public_ip) else oAddress = oAddresses[0] end end sMsg = <<-END -Public IP for server '#{oServer[:name]}' is assigned' +Public IP for server '#{oServer[:name]}' is assigned. Now, as soon as the server respond to the ssh port, you will be able to get a tail of the build with: while [ 1 = 1 ] do - ssh ubuntu@#{oAddress[:public_ip]} -o StrictHostKeyChecking=no -i #{get_data(:keypairs, :private_key_file)} tail -f /var/log/cloud-init.log + ssh ubuntu@#{oAddress[:public_ip]} -o StrictHostKeyChecking=no -i #{private_key_file} tail -f /var/log/cloud-init.log sleep 5 done END - if not object.get_data(:keypairs)[:coherent] + if not keypair_coherent sMsg += ANSI.bold("\nUnfortunatelly") + " your current keypair is not usable to connect to your server.\nYou need to fix this issue to gain access to your server." end - Logging.info(sMsg) - Logging.high_level_msg ("\n%s\nThe forge is still building...\n" % sMsg) + PrcLib.info(sMsg) + PrcLib.high_level_msg ("\n%s\nThe forge is still building...\n" % sMsg) sStatus = :cloud_init - elsif sStatus == :cloud_init - oLog = object.Get(:server_log, 5)[:attrs][:output] + else #analyze the log output + oLog = Get(:server_log, 25)[:attrs][:output] + iCurAct = 4 if oLog == oOldLog + oOldLog = oLog if /cloud-init boot finished/ =~ oLog sStatus = :active + if mCloudInitError != [] + PrcLib.high_level_msg ("Critical error cleared. Cloud-init seems moving...") + PrcLib.info ("Critical error cleared. Cloud-init seems moving...") + mCloudInitError = [] + end + elsif /\[CRITICAL\]/ =~ oLog + mCritical = oLog.scan(/.*\[CRITICAL\].*\n/) + if not (mCloudInitError == mCritical) + sReported = oLog.clone + sReported['CRITICAL'] = ANSI.bold('CRITICAL') + PrcLib.error("cloud-init error detected:\n-----\n%s\n-----\nPlease connect to the box to decide what you need to do." % [sReported]) + mCloudInitError = mCritical + end + elsif sStatus == :cloud_init and /cloud-init-nonet gave up waiting for a network device/ =~ oLog + # Valid for ubuntu image 12.04 + PrcLib.warning("Cloud-init has gave up to configure the network. waiting...") + sStatus = :nonet + elsif sStatus == :nonet and /Booting system without full network configuration/ =~ oLog + # Valid for ubuntu image 12.04 + PrcLib.warning("forj has detected an issue to bring up your maestro server. Removing it and re-creating a new one. please be patient...") + sStatus = :restart + elsif sStatus == :restart + Delete(:server) + Create(:internet_server) + sStatus = :starting end end sleep(5) if sStatus != :active end - sMsg = "Server '%s' is now ACTIVE. Bootstrap done." % oServer[:name] - Logging.info(sMsg) + + oForge = get_forge(sObjectType, config[:instance_name], hParams) + sMsg = "Your Forge '%s' is ready and accessible from IP #{oAddress[:public_ip]}." % config[:instance_name] # TODO: read the blueprint/layout to identify which services are implemented and can be accessible. - Logging.high_level_msg ("Your Forge '%s' is over and accessible from IP #{oAddress[:public_ip]}. Enjoy!\n" % config[:instance_name]) - oServer + if config[:blueprint] + sMsg += "\nMaestro has implemented the following server(s) for your blueprint '%s':" % config[:blueprint] + iCount = 0 + oForge[:servers].each { | oServer| + next if /^maestro\./ =~ oServer[:name] + register(oServer) + oIP = Query(:public_ip, :server_id => oServer[:id]) + if oIP.length == 0 + sMsg += "\n- %s (No public IP)" % [oServer[:name]] + else + sMsg += "\n- %s (%s)" % [oServer[:name], oIP[0][:public_ip]] + end + iCount += 1 + } + if iCount > 0 + sMsg += "\n%d server(s) identified.\n" % iCount + else + sMsg = "No servers found except maestro" + PrcLib.warning("Something went wrong, while creating nodes for " \ + "blueprint '%s'. check maestro logs." % config[:blueprint]) + end + else + sMsg += "\nMaestro has NOT implemented any servers, because you did not provided a blueprint. Connect to Maestro, and ask Maestro to implement any kind of blueprint you need. (Feature currently under development)" + end + PrcLib.info(sMsg) + PrcLib.high_level_msg ("\n%s\nEnjoy!\n" % sMsg) + oForge end - def maestro_create_status(sStatus) + def maestro_create_status(sStatus, iCurAct = 4) + sActivity = "/-\\|?" + if iCurAct < 4 + sCurAct = "ACTIVE" + else + sCurAct = ANSI.bold("PENDING") + end + case sStatus when :checking - Logging.state("Checking server status") + PrcLib.state("Checking server status") when :starting - Logging.state("STARTING") + PrcLib.state("STARTING") when :assign_ip - Logging.state("ACTIVE - Assigning Public IP") + PrcLib.state("%s - %s - Assigning Public IP" % [sActivity[iCurAct], sCurAct]) when :cloud_init - Logging.state("ACTIVE - Currently running cloud-init. Be patient.") + PrcLib.state("%s - %s - Currently running cloud-init. Be patient." % [sActivity[iCurAct], sCurAct]) + when :nonet + PrcLib.state("%s - %s - Currently running cloud-init. Be patient." % [sActivity[iCurAct], sCurAct]) + when :restart + PrcLib.state("RESTARTING - Currently restarting maestro box. Be patient.") when :active - Logging.info("Server is active") + PrcLib.info("Server is active") end end def clone_or_use_maestro_repo(sObjectType, hParams) @@ -231,27 +334,27 @@ path_maestro = File.expand_path('~/.forj/') hResult = {} begin if maestro_repo and File.directory?(maestro_repo) - Logging.info("Using maestro repo '%s'" % maestro_repo) + PrcLib.info("Using maestro repo '%s'" % maestro_repo) hResult[:maestro_repo] = maestro_repo else hResult[:maestro_repo] = File.join(path_maestro, 'maestro') - Logging.state("Cloning maestro repo from '%s' to '%s'" % [maestro_url, File.join(path_maestro, 'maestro')]) + PrcLib.state("Cloning maestro repo from '%s' to '%s'" % [maestro_url, File.join(path_maestro, 'maestro')]) if File.directory?(path_maestro) if File.directory?(File.join(path_maestro, 'maestro')) FileUtils.rm_r File.join(path_maestro, 'maestro') end end git = Git.clone(maestro_url, 'maestro', :path => path_maestro) git.checkout(config[:branch]) if config[:branch] != 'master' - Logging.info("Maestro repo '%s' cloned on branch '%s'" % [File.join(path_maestro, 'maestro'), config[:branch]]) + PrcLib.info("Maestro repo '%s' cloned on branch '%s'" % [File.join(path_maestro, 'maestro'), config[:branch]]) end rescue => e - Logging.error("Error while cloning the repo from %s\n%s\n%s" % [maestro_url, e.message, e.backtrace.join("\n")]) - Logging.info("If this error persist you could clone the repo manually in ~/.forj/") + PrcLib.error("Error while cloning the repo from %s\n%s\n%s" % [maestro_url, e.message, e.backtrace.join("\n")]) + PrcLib.info("If this error persist you could clone the repo manually in ~/.forj/") end oMaestro = register(hResult, sObjectType) oMaestro[:maestro_repo] = hResult[:maestro_repo] oMaestro end @@ -269,20 +372,20 @@ AppInit.ensure_dir_exists(dest_cloud_init) bReBuildInfra = infra_is_original?(infra, maestro_repo) if bReBuildInfra - Logging.state("Building your infra workspace in '%s'" % [infra]) + PrcLib.state("Building your infra workspace in '%s'" % [infra]) - Logging.debug("Copying recursively '%s' to '%s'" % [cloud_init, infra]) + PrcLib.debug("Copying recursively '%s' to '%s'" % [cloud_init, infra]) FileUtils.copy_entry(cloud_init, dest_cloud_init) file_ver = File.join(infra, 'forj-cli.ver') File.write(file_ver, $INFRA_VERSION) - Logging.info("The infra workspace '%s' has been built from maestro predefined files." % [infra]) + PrcLib.info("The infra workspace '%s' has been built from maestro predefined files." % [infra]) else - Logging.info("Re-using your infra... in '%s'" % [infra]) + PrcLib.info("Re-using your infra... in '%s'" % [infra]) end oInfra = register(hInfra, sObjectType) oInfra[:infra_repo] = hInfra[:infra_repo] @@ -298,11 +401,11 @@ hResult = {} if File.exists?(sMD5List) begin hResult = YAML.load_file(sMD5List) rescue => e - Logging.error("Unable to load valid Original files list '%s'. Your infra workspace won't be migrated, until fixed." % sMD5List) + PrcLib.error("Unable to load valid Original files list '%s'. Your infra workspace won't be migrated, until fixed." % sMD5List) bResult = false end if not hResult hResult = {} bResult = false @@ -316,13 +419,13 @@ sInfra_path = File.join(dest_cloud_init, sMaestroRelPath) if File.exists?(sInfra_path) md5_file = Digest::MD5.file(sInfra_path).hexdigest if hResult.key?(sMaestroRelPath) and hResult[sMaestroRelPath] != md5_file bResult = false - Logging.info("'%s' infra file has changed from original template in maestro." % sInfra_path) + PrcLib.info("'%s' infra file has changed from original template in maestro." % sInfra_path) else - Logging.debug("'%s' infra file has not been updated." % sInfra_path) + PrcLib.debug("'%s' infra file has not been updated." % sInfra_path) end end md5_file = Digest::MD5.file(path).hexdigest hResult[sMaestroRelPath] = md5_file end @@ -330,16 +433,16 @@ begin File.open(sMD5List, 'w') do |out| YAML.dump(hResult, out) end rescue => e - Logging.error("%s\n%s" % [e.message, e.backtrace.join("\n")]) + PrcLib.error("%s\n%s" % [e.message, e.backtrace.join("\n")]) end if bResult - Logging.debug("No original files found has been updated. Infra workspace can be updated/created if needed.") + PrcLib.debug("No original files found has been updated. Infra workspace can be updated/created if needed.") else - Logging.warning("At least, one file has been updated. Infra workspace won't be updated by forj cli.") + PrcLib.warning("At least, one file has been updated. Infra workspace won't be updated by forj cli.") end bResult end def infra_rebuild(infra_dir) @@ -356,11 +459,11 @@ return(old_infra_data_update(oConfig, forj_infra_version, infra_dir)) end end def old_infra_data_update(oConfig, version, infra_dir) - Logging.info("Migrating your local infra repo (%s) to the latest version." % version) + PrcLib.info("Migrating your local infra repo (%s) to the latest version." % version) bRebuild = false # Be default migration is successful. No need to rebuild it. case version when '0.0.36' # Moving from 0.0.36 or less to 0.0.37 or higher. # SET_COMPUTE="{SET_COMPUTE!}" => Setting for Compute. ignored. Coming from HPC @@ -379,11 +482,11 @@ yDns = {} yDns = oConfig.oConfig.ExtraGet(:forj_accounts, sAccountName, :dns) if oConfig.oConfig.ExtraExist?(:forj_accounts, sAccountName, :dns) Dir.foreach(infra_dir) do | file | next if not /^maestro\.box\..*\.env$/ =~ file build_env = File.join(infra_dir, file) - Logging.debug("Reading data from '%s'" % build_env) + PrcLib.debug("Reading data from '%s'" % build_env) tags = {'SET_DNS_TENANTID' => :tenant_id, 'SET_DNS_ZONE' => :service, 'SET_DOMAIN' => :domain_name } begin @@ -391,28 +494,28 @@ File.open(build_env) do |f| f.each_line do |line| mObj = line.match(/^(SET_[A-Z_]+)=["'](.*)["'].*$/) if mObj - Logging.debug("Reviewing detected '%s' tag" % [mObj[1]]) + PrcLib.debug("Reviewing detected '%s' tag" % [mObj[1]]) tag = (tags[mObj[1]]? tags[mObj[1]] : nil) if tag and mObj[2] if bUpdate == nil and rhGet(yDns, tag) and rhGet(yDns, tag) != mObj[2] - Logging.message("Your account setup is different than build env.") - Logging.message("We suggest you to update your account setup with data from your build env.") + PrcLib.message("Your account setup is different than build env.") + PrcLib.message("We suggest you to update your account setup with data from your build env.") bUpdate = agree("Do you want to update your setup with those build environment data?") end if bUpdate != nil and bUpdate - Logging.debug("Saved: '%s' = '%s'" % [mObj[1],mObj[2]]) + PrcLib.debug("Saved: '%s' = '%s'" % [mObj[1],mObj[2]]) rhSet(yDns, mObj[2], tag) end end end end end rescue => e - Logging.fatal(1, "Failed to open the build environment file '%s'" % build_env, e) + PrcLib.fatal(1, "Failed to open the build environment file '%s'" % build_env, e) end end file_ver = File.join(infra_dir, 'forj-cli.ver') File.write(file_ver, $INFRA_VERSION) oConfig.oConfig.ExtraSet(:forj_accounts, sAccountName, :dns, yDns) @@ -435,11 +538,11 @@ meta_data = JSON.generate(hParams[:metadata, :meta_data]) build_tmpl_dir = File.expand_path(File.join($LIB_PATH, 'build_tmpl')) - Logging.state("Preparing user_data - file '%s'" % mime) + PrcLib.state("Preparing user_data - file '%s'" % mime) # generate boot_*.sh mime_cmd = "#{build_tmpl_dir}/write-mime-multipart.py" bootstrap = "#{build_tmpl_dir}/bootstrap_build.sh" cmd = "%s '%s' '%s' '%s' '%s' '%s' '%s' '%s'" % [ @@ -452,25 +555,25 @@ mime_cmd, # $6: mime script file to execute. mime # $7: mime file generated. ] # TODO: Replace shell script call to ruby functions - if $LIB_FORJ_DEBUG >=1 + if $LIB_FORJ_DEBUG >= 1 cmd += " >> #{$FORJ_DATA_PATH}/forj.log" else cmd += " | tee -a #{$FORJ_DATA_PATH}/forj.log" end raise ForjError.new, "#{bootstrap} script file is not found." if not File.exists?(bootstrap) - Logging.debug("Running '%s'" % cmd) + PrcLib.debug("Running '%s'" % cmd) Kernel.system(cmd) raise ForjError.new(), "mime file '%s' not found." % mime if not File.exists?(mime) begin user_data = File.read(mime) rescue => e - Logging.fatal(1, e.message) + PrcLib.fatal(1, e.message) end if $LIB_FORJ_DEBUG < 5 File.delete(mime) else ForjLib.debug(5, "user_data temp file '%s' kept" % mime) @@ -480,11 +583,11 @@ oUserData = register(hParams, sObjectType) oUserData[:user_data] = user_data oUserData[:user_data_encoded] = Base64.strict_encode64(user_data) oUserData[:mime] = mime - Logging.info("user_data prepared. File: '%s'" % mime) + PrcLib.info("user_data prepared. File: '%s'" % mime) oUserData end end @@ -514,19 +617,19 @@ end # keypair_files post setup def forj_setup_keypairs_files # Getting Account keypair information - key_name = config.get(:keypair_name) - key_path = File.expand_path(config.get(:keypair_files)) + key_name = config[:keypair_name] + key_path = File.expand_path(config[:keypair_files]) keys_imported = nil - keys_imported = keypair_detect(key_name, config.oConfig.LocalGet(key_name, :imported_keys)) if config.oConfig.LocalExist?(key_name, :imported_keys) + keys_imported = keypair_detect(key_name, config.oConfig.localGet(key_name, :imported_keys)) if config.oConfig.localExist?(key_name, :imported_keys) keys = keypair_detect(key_name, key_path) if keys_imported and keys_imported[:key_basename] != keys[:key_basename] and $FORJ_KEYPAIRS_PATH != keys[:keypair_path] - Logging.warning("The private key '%s' was assigned to a different private key file '%s'.\nTo not overwrite it, we recommend you to choose a different keypair name." % [key_name, keys_imported[:key_basename] ]) + PrcLib.warning("The private key '%s' was assigned to a different private key file '%s'.\nTo not overwrite it, we recommend you to choose a different keypair name." % [key_name, keys_imported[:key_basename] ]) new_key_name = key_name sMsg = "Please, provide a different keypair name:" while key_name == new_key_name new_key_name = ask (sMsg) do | q | q.validate = /.+/ @@ -544,64 +647,65 @@ # Creation sequences if not keys[:private_key_exist? ] # Need to create a key. ask if we need so. - Logging.message("The private key file attached to keypair named '%s' is not found. Running ssh-keygen to create it." % keys[:keypair_name]) + PrcLib.message("The private key file attached to keypair named '%s' is not found. Running ssh-keygen to create it." % keys[:keypair_name]) if not File.exists?(private_key_file) AppInit.ensure_dir_exists(File.dirname(private_key_file)) command = 'ssh-keygen -t rsa -f %s' % private_key_file - Logging.debug("Executing '%s'" % command) + PrcLib.debug("Executing '%s'" % command) system(command) end if not File.exists?(private_key_file) - Logging.fatal(1, "'%s' not found. Unable to add your keypair to hpcloud. Create it yourself and provide it with -p option. Then retry." % [private_key_file]) + PrcLib.fatal(1, "'%s' not found. Unable to add your keypair to hpcloud. Create it yourself and provide it with -p option. Then retry." % [private_key_file]) else - Logging.fatal(1, "ssh-keygen did not created your key pairs. Aborting. Please review errors in ~/.forj/forj.log") + PrcLib.fatal(1, "ssh-keygen did not created your key pairs. Aborting. Please review errors in ~/.forj/forj.log") end end if not keys[:public_key_exist? ] - Logging.message("Your public key '%s' was not found. Getting it from the private one. It may require your passphrase." % [public_key_file]) + PrcLib.message("Your public key '%s' was not found. Getting it from the private one. It may require your passphrase." % [public_key_file]) command = 'ssh-keygen -y -f %s > %s' % [private_key_file,public_key_file ] - Logging.debug("Executing '%s'" % command) + PrcLib.debug("Executing '%s'" % command) system(command) end forj_private_key_file = File.join($FORJ_KEYPAIRS_PATH, key_name ) forj_public_key_file = File.join($FORJ_KEYPAIRS_PATH, key_name + ".pub") # Saving sequences if keys[:keypair_path] != $FORJ_KEYPAIRS_PATH if not File.exists?(forj_private_key_file) or not File.exists?(forj_public_key_file) - Logging.info("Importing key pair to FORJ keypairs list.") + PrcLib.info("Importing key pair to FORJ keypairs list.") FileUtils.copy(private_key_file, forj_private_key_file) FileUtils.copy(public_key_file, forj_public_key_file) # Attaching this keypair to the account rhSet(@hAccountData, key_name, :credentials, 'keypair_name') rhSet(@hAccountData, forj_private_key_file, :credentials, 'keypair_path') config.oConfig.LocalSet(key_name.to_s, private_key_file, :imported_keys) else # Checking source/dest files content if Digest::MD5.file(private_key_file).hexdigest != Digest::MD5.file(forj_private_key_file).hexdigest - Logging.info("Updating private key keypair piece to FORJ keypairs list.") + PrcLib.info("Updating private key keypair piece to FORJ keypairs list.") FileUtils.copy(private_key_file, forj_private_key_file) else - Logging.info("Private key keypair up to date.") + PrcLib.info("Private key keypair up to date.") end if Digest::MD5.file(public_key_file).hexdigest != Digest::MD5.file(forj_public_key_file).hexdigest - Logging.info("Updating public key keypair piece to FORJ keypairs list.") + PrcLib.info("Updating public key keypair piece to FORJ keypairs list.") FileUtils.copy(public_key_file, forj_public_key_file) else - Logging.info("Public key keypair up to date.") + PrcLib.info("Public key keypair up to date.") end end end # Saving internal copy of private key file for forj use. config.set(:keypair_path, forj_private_key_file ) - Logging.info("Configured forj keypair '%s' with '%s'" % [ keys[:keypair_name], File.join(keys[:keypair_path], keys[:key_basename]) ] ) + PrcLib.info("Configured forj keypair '%s' with '%s'" % [ keys[:keypair_name], File.join(keys[:keypair_path], keys[:key_basename]) ] ) + true # forj_setup_keypairs_files successfull end def forj_DNS_settings() sAsk = "Optionally, you can ask Maestro to use/manage a domain name on your cloud. It requires your DNS cloud service to be enabled.\nDo you want to configure it?" config.set(:dns_settings, agree(sAsk)) @@ -618,27 +722,186 @@ end def setup_tenant_name() # TODO: To re-introduce with a Controller call instead. oSSLError=SSLErrorMgt.new # Retry object - Logging.debug("Getting tenants from hpcloud cli libraries") + PrcLib.debug("Getting tenants from hpcloud cli libraries") begin tenants = Connection.instance.tenants(@sAccountName) rescue => e if not oSSLError.ErrorDetected(e.message,e.backtrace, e) retry end - Logging.fatal(1, 'Network: Unable to connect.') + PrcLib.fatal(1, 'Network: Unable to connect.') end tenant_id = rhGet(@oConfig.ExtraGet(:hpc_accounts, @sAccountName, :credentials), :tenant_id) tenant_name = nil tenants.each { |elem| tenant_name = elem['name'] if elem['id'] == tenant_id } if tenant_name - Logging.debug("Tenant ID '%s': '%s' found." % [tenant_id, tenant_name]) + PrcLib.debug("Tenant ID '%s': '%s' found." % [tenant_id, tenant_name]) rhSet(@hAccountData, tenant_name, :maestro, :tenant_name) else - Logging.error("Unable to find the tenant Name for '%s' ID." % tenant_id) + PrcLib.error("Unable to find the tenant Name for '%s' ID." % tenant_id) end @oConfig.set('tenants', tenants) + end + +end + +#Funtions for get +class ForjCoreProcess + def get_forge(sCloudObj, sForgeId, hParams) + sQuery = {} + hServers = [] + sQuery[:name] = sForgeId + + oServers = Query(:server, sQuery ) + + regex = Regexp.new('\.%s$' % sForgeId) + + oServers.each { |oServer| + oName = oServer[:name] + hServers<<oServer if regex =~ oName + } + PrcLib.info("%s server(s) were found under instance name %s " % [hServers.count(), sQuery[:name]]) + + oForge = register(hServers, sCloudObj) + oForge[:servers] = hServers + oForge[:name] = sForgeId + oForge + end +end + +#Funtions for destroy +class ForjCoreProcess + def delete_forge(sCloudObj, hParams) + + PrcLib.state("Destroying server(s) of your forge") + + forge_serverid = config.get(:forge_server) + + oForge = hParams[:forge] + + oForge[:servers].each{|server| + next if forge_serverid and forge_serverid != server[:id] + register(server) + PrcLib.state("Destroying server '%s'" % server[:name]) + Delete(:server) + } + if forge_serverid.nil? + PrcLib.high_level_msg ("The forge '%s' has been destroyed. (all servers linked to the forge)\n" % oForge[:name] ) + else + PrcLib.high_level_msg ("Server(s) selected in the forge '%s' has been removed.\n" % [oForge[:name]]) + end + end +end + +# Functions for ssh +class ForjCoreProcess + def ssh_connection(sObjectType, hParams) + oForge = hParams[:forge] + oServer = nil + + oForge[:servers].each{|server| + next if hParams[:forge_server] != server[:id] + oServer = server + break + } + + #Get server information + PrcLib.state("Getting server information") + oServer = Get(:server, oServer[:id]) + register(oServer) + + # Get Public IP of the server. Needs the server to be loaded. + oAddress = Query(:public_ip, :server_id => oServer[:id]) + + if oAddress.length == 0 + PrcLib.fatal(1, "ip address for %s server was not found" % oServer[:name]) + else + public_ip = oAddress[0][:public_ip] + end + + if config[:identity].nil? or not config[:identity].is_a?(String) + hKeys = keypair_detect(oServer[:key_name], File.join($FORJ_KEYPAIRS_PATH, oServer[:key_name])) + else + hKeys = keypair_detect(oServer[:key_name], File.expand_path(config[:identity])) + end + + private_key_file = File.join(hKeys[:keypair_path], hKeys[:private_key_name]) + public_key_file = File.join(hKeys[:keypair_path], hKeys[:public_key_name]) + + PrcLib.info("Found openssh private key file '%s'." % private_key_file) if hKeys[:private_key_exist? ] + if hKeys[:public_key_exist? ] + PrcLib.info("Found openssh public key file '%s'." % public_key_file) + else + PrcLib.warning("Openssh public key file '%s' not found. Unable to verify keys coherence with remote server." % public_key_file) + end + + if hKeys[:private_key_exist? ] + ssh_options = { :keys => private_key_file} + PrcLib.debug("Using private key '%s'." % private_key_file) + else + PrcLib.fatal 1, <<-END +The server '#{oServer[:name]}' has been configured with a keypair '#{oServer[:key_name]}' which is not found locally. +You won't be able to connect to that server without '#{oServer[:key_name]}' private key. +To connect to this box, you need to provide the appropriate private key file with option -i + END + end + + # Get ssh user + image = Get(:image, oServer[:image_id]) + user = hParams[:ssh_user] + + if user.nil? + user = image[:ssh_user] + end + + PrcLib.debug("Using account '%s'." % user) + + begin + PrcLib.state("creating ssh connection with '%s' box" % oServer[:name]) + session = Net::SSH.start(public_ip, user, ssh_options) do |ssh| + ssh_login(ssh_options, user, public_ip) + end + PrcLib.debug("Error closing ssh connection, box %s " % oServer[:name]) if not session + rescue => e + PrcLib.fatal 1, <<-END +#{e.message} +You were not able to connect to this box. Please note that there is no garantuee that your local private key file '#{private_key_file}' is the one that was used while building this box. +You have to check with the user who created that box. + END + end + register({ :success => true }, sObjectType) + end + + def setup_ssh_user(sCloudObj, hParams) + images = Query(:image, { name: hParams[:image_name]} ) + case images.length + when 0 + sDefault = hParams[:default_value] + else + if images[0, :ssh_user].nil? + sDefault = hParams[:default_value] + else + sDefault = images[0, :ssh_user] + end + end + { default_value: sDefault, list: config[:users] } + end + + def ssh_login(options, user, public_ip) + sOpts = "-o StrictHostKeyChecking=no -o ServerAliveInterval=180" + sOpts += " -i %s" % options[:keys] if options[:keys] + + command = 'ssh %s %s@%s' % [sOpts, user, public_ip] + PrcLib.debug("Running '%s'" % command) + system(command) + end + + def ssh_user(image_name) + return "fedora" if image_name =~ /fedora/i + return "centos" if image_name =~ /centos/i + return "ubuntu" end end