require "interact" require 'uri' require "ipaddress" module App42 module Base module Util # ask application name to user def ask_app_name input "Enter App Name", [], true print_new_line end # # Reading input from user # # @param message # @param choices # @param indexed # # @return +input string+ def input message, choices, indexed = true if choices.empty? ans = ask Paint["#{message}", :cyan] else list = choices.compact unless choices.empty? ans = ask Paint["#{message}", :cyan], :choices => list, :default => list[0], :indexed => indexed end print_new_line return ans end # # console message # # @param msg # @param new_line # @param color def message msg, new_line = true, color new_line ? (puts Paint["#{msg}\n", color.to_sym]) : (print Paint["#{msg}", color.to_sym]) end # json parser def json_parse(str) JSON.parse(str) if str end def request_failed?(status) #:nodoc: # TODO, if more than one error code # APP42_HTTP_ERROR_CODES.detect{|error_code| status >= error_code} APP42_HTTP_ERROR_CODES.include? status end # error message parser def parse_error_message(status, body) if status && body && body["message"] && body["details"] desc = body["details"].gsub("\"","'") # TODO, may need later # app42_client_info message "#{body["details"]}", true, 'red' exit! else # TODO, may need later # app42_client_info message "Error: Something wrong", true, 'red' exit! end end # return client info +ruby-version+, +os+ and +client-version+ details def app42_client_info puts Paint["INFO: #{App42.user_agent}", :red] end # return util instance def util_base util = App42::Client::RestUtil.new end # hash of params that will return API key, version and timestamp def params params = { 'apiKey'=> @api_key, 'version' => VERSION, 'timeStamp' => util_base.get_timestamp_utc, } end # build resource url as per requested params def resource_url resource, what what.nil? ? (resource_url = "/#{resource}") : (resource_url = "/#{resource}/#{what}") end # Generate signature using requested params and Secret key # # @params +requested params+ # # @ return +signature+ def signature params signature = util_base.sign(@secret_key, params ) end # Spinning code for latest status def show_wait_spinner(fps=10) chars = %w[| / - \\] delay = 1.0/fps iter = 0 spinner = Thread.new do while iter do print chars[(iter+=1) % chars.length] sleep delay print "\b" end end yield.tap{ iter = false spinner.join } end # checks transaction status # #REVIEW, need to verify FAILED use case def check_transaction_status transaction_id, previous_completed, what begin flag = false message "#{Message::LATEST_S_WAIT}", false, 'green' while flag == false do response = status_call transaction_id re_try ||= 1 if response["success"] == true && response["transactionStatus"] == "COMPLETED" print_new_line message "#{response["message"]}", true, 'green' return true elsif response["success"] == true && response["transactionStatus"] == "INPROGRESS" if previous_completed != response["completed"] print_new_line puts Paint["#{response["completed"]} out of #{response["requested"]} #{what}", :green] previous_completed = response["completed"] end show_wait_spinner{ sleep rand(4)+2 } unless what.to_s == 'Uploaded' if(re_try += 1 ) >= 25 message "#{Message::REQUEST_PROGRESS}", true, 'red' exit! end end else response["success"] == true && response["transactionStatus"] == "FAILED" print_new_line message "#{response["message"]}", true, 'red' exit! end sleep 5 end rescue Interrupt message "#{Message::LATEST_S_INTERRUPT}", true, 'red' exit! end end # checks transaction status of setup cloud API # #REVIEW, need to verify FAILED use case def check_transaction_status_of_setup transaction_id, previous_completed, what begin flag = false message "#{Message::LATEST_S_WAIT}", false, 'green' while flag == false do response = status_call transaction_id re_try ||= 1 if response["success"] == true && response["transactionStatus"] == "COMPLETED" print_new_line message "#{response["message"]}", true, 'green' return true elsif response["success"] == true && response["transactionStatus"] == "INPROGRESS" if previous_completed != response["completed"] print_new_line puts Paint["#{response["completed"]} out of #{response["requested"]} #{what}", :green] previous_completed = response["completed"] end show_wait_spinner{ sleep rand(4)+2 } unless what.to_s == 'Uploaded' if(re_try += 1 ) >= 250 message "#{Message::REQUEST_PROGRESS}", true, 'red' exit! end end else response["success"] == true && response["transactionStatus"] == "FAILED" print_new_line message "#{response["message"]}", true, 'red' exit! end sleep 5 end rescue Interrupt message "#{Message::LATEST_S_INTERRUPT}", true, 'red' exit! end end # rest call for transaction status check def status_call transaction_id begin query_params = params query_params.store('transactionId', transaction_id) @same_status_retry ||= 1 response = get_request signature(query_params), resource_url('info', 'transaction'), query_params return response rescue Interrupt message "#{Message::LATEST_S_INTERRUPT}", true, 'red' exit! end end # Escape white space and special character from path as per OS def escape_path(path) path = File.expand_path(path) if RUBY_PLATFORM =~ /mingw|mswin32|cygwin/ if path.include?(' ') #FIXME, should be universal for window os # return '"' + path + '"' return path.gsub(' ', '\ ') else return path end else return path.gsub(' ', '\ ') end end def print_new_line #:nodoc: puts "\n" end # regex for number excluding zero def numeric?(obj) obj.to_s.match(/^[-+]?[1-9]*\.?[1-9]+$/) == nil ? false : true end # regex for number including zero def numeric_including_zero?(obj) obj.to_s.match(/^[-+]?[0-9]*\.?[0-9]+$/) == nil ? false : true end # camel case to whitespace def camel_case_to_whitespace str str_cap = str.gsub(/::/, '/'). gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2'). gsub(/([a-z\d])([A-Z])/,'\1_\2'). tr("-", "_").downcase str_capitalize = str_cap.tr("_", " ").capitalize str_capitalize.split(' ').map(&:capitalize).join(' ') end # validate whether the value in the variable is really an IP def ip_address_valid? source_ip if source_ip == "0.0.0.0" || source_ip.match(App42::IP_REGEX) true else false end end # Check whether number is valid number def number_valid? num ((!numeric_including_zero? num) || (num.to_s =~ App42::REGEX) || (num.to_i == 0)) ? (return false) : (return num) end # Check whether +access_time+ is valid # +access time+ should be a valid number and # not be more than +720+ hours def time_valid? num ((!numeric_including_zero? num) || (num.to_i > 720)) ? (return false) : (return num) end # Check whether +app OR service+ name is valid OR not # +app OR service+ name length should not be more than 30 character # And should not contain any special character def validate_app_and_service_name name, str if str.match(App42::REGEX) || str.length > 30 message "#{name} should not contain any special character or white space and length should be less than 30.", true, 'red' return false else return str end end # Check whether +URL+ is valid OR not # +URL+ should start with +http+ and +https+ # And should not contain any special character def validate_url url # Using the URI module distributed with Ruby, We can write own URL_REGEX(defined in constant.rb) too. unless url =~ /^#{URI::regexp}$/ message "The provided URL (#{url}) is either not valid or contains white space and special character.", true, 'red' return false else return url end end # Check whether +uploadbackup+ path is valid OR not # predefined extension are allowed only like .sql, .zip, .dump etc def validate_upload_backup_path path if path.include?('.zip') || path.include?('.sql') || path.include?('.tar.gz') || path.include?('.gzip') || path.include?('.dump') || path.include?('.rdb') return path else message "Please provide valid file.", true, 'red' return false end end # Check whether +setup+ name is valid OR not # +setup+ name length should not be more than 30 character # And should not contain any special character def validate_setup_name name, str if str.match(App42::REGEX) || str.length > 30 message "#{name} should not contain any special character or white space and length should be less than 30.", true, 'red' return false else return str end end # Check whether +database name+ is valid OR not # +database name+ length should not be more than 64 character # And should not contain any special character def validate_database_name name, str if str.match(App42::DBNAME_REGEX) || str.length > 64 || (numeric_including_zero? str) message "Invalid database name. Should be less than 64 characters (Alphabets, alphanumeric and underscore(_) is allowed).", true, 'red' return false elsif App42::DATABASE_NAME_NOT_ALLOWED.include? str message "Database Name should not be '#{str}'.", true, 'red' return false else return str end end # Check whether +vm config+ is valid OR not # +vm config+ should be a valid number # And should not contain any special character def validate_vm_config kontena unless numeric?(kontena) message "#{Message::NOT_A_VALID_KONTENA}", true, 'red' false else return kontena end end # rest call to server to check whether +application+ exist OR not. # return true if +application+ exist else display ERROR message and exit def is_app_exist? app_name query_params = params query_params.store('appName', app_name) response = build_get_request query_params, 'app', 'availability' unless response["success"] return true else message "App with name '#{app_name}' does not exist.", true, 'red' exit! end end # rest call to server to check whether +service+ exist OR not. # return true if +service+ exist else display ERROR message and exit def is_service_exist? service_name query_params = params query_params.store('serviceName', service_name) response = build_get_request query_params, 'service', 'availability' unless response["success"] return true else message "Service with name '#{service_name}' does not exist.", true, 'red' exit! end end # rest call to server to check whether +setup name+ exist OR not. # return true if +setup name+ exist else display ERROR message and exit def is_setup_name_exist? setup_name query_params = params query_params.store('setupName', setup_name) response = build_get_request query_params, 'setup', 'availability' unless response["success"] return true else message "Setup with name '#{setup_name}' does not exist.", true, 'red' exit! end end # Check whether +git URL+ is valid OR not # given +git URL+ must end with +.git+ extension def validate_git_url git_url unless git_url.include?('.git') message "#{Message::GIT_URL_NOT_VALID}", true, 'red' return false else return git_url end end # Get flavour for upgrade def get_flavour_for_upgrade_or_downgrade setup_name, type flavour_hash = {} flavour_type = App42::Command::Config.new.get_flavour_type_fm_server_for_upgrade_or_downgrade setup_name, type flavour_type['flavours'].select {|each_flavour| flavour_hash["#{each_flavour['id']}"] = each_flavour['name']} flavour = input "Select Flavour", flavour_hash.values, true flavour_id = nil flavour_hash.each_pair{|fl| flavour_id = fl[0] if fl[1] == flavour} return flavour_id end # Get instance configuration def get_instance_config_for_upgrade_or_downgrade iaas, vm_type, setup_name, type instance_config_hash = {} instance_config_type = App42::Command::Config.new.get_instance_config_for_upgrade_or_downgrade iaas, vm_type, setup_name, type instance_config_type['IMList'].select {|each_instance_config| instance_config_hash["#{each_instance_config['id']}"] = each_instance_config['name']} instance_config = input "Select Instance Configuration", instance_config_hash.values, true instance_config_id = nil instance_config_hash.each_pair{|ic| instance_config_id = ic[0] if ic[1] == instance_config} return instance_config_id end end end end