#!/usr/bin/env ruby # description: ManageIQ appliance console # require 'bundler' Bundler.setup require 'manageiq/appliance_console' require 'fileutils' # defines globally /via kernal: agree(), ask(), choose() and say() require 'highline/import' require 'rubygems' require 'bcrypt' require 'linux_admin' require 'awesome_spawn' require 'manageiq/appliance_console/i18n' HighLine.default_instance.tap do |highline| highline.wrap_at = 80 highline.page_at = 35 end def summary_entry(field, value) dfield = "#{field}:" "#{dfield.ljust(24)} #{value}" end def ensure_key_configured key_config = ManageIQ::ApplianceConsole::KeyConfiguration.new unless key_config.key_exist? say "No encryption key found.\n" say "For migrations, copy encryption key from a hardened appliance." say "For worker and multi-region setups, copy key from another appliance.\n" say "If this is your first appliance, just generate one now.\n\n" if key_config.ask_question_loop say("\nEncryption key now configured.\n\n") else say("\nEncryption key not configured.") press_any_key raise ManageIQ::ApplianceConsole::MiqSignalError end end end [:INT, :TERM, :ABRT, :TSTP].each { |s| trap(s) { raise ManageIQ::ApplianceConsole::MiqSignalError } } VERSION_FILE = ManageIQ::ApplianceConsole::RAILS_ROOT.join("VERSION") LOGFILE = ManageIQ::ApplianceConsole::RAILS_ROOT.join("log", "appliance_console.log") DB_RESTORE_FILE = "/tmp/evm_db.backup".freeze AS_OPTIONS = I18n.t("advanced_settings.menu_order").collect do |item| I18n.t("advanced_settings.#{item}") end require 'manageiq-password' ManageIQ::Password.key_root = ManageIQ::ApplianceConsole::RAILS_ROOT.join("certs").to_s # Load appliance_console libraries include ManageIQ::ApplianceConsole::Prompts # Restore database choices RESTORE_LOCAL = "Local file".freeze RESTORE_NFS = "Network File System (NFS)".freeze RESTORE_SMB = "Samba (SMB)".freeze RESTORE_OPTIONS = [RESTORE_LOCAL, RESTORE_NFS, RESTORE_SMB, ManageIQ::ApplianceConsole::CANCEL].freeze # Restart choices RE_RESTART = "Restart".freeze RE_DELLOGS = "Restart and Clean Logs".freeze RE_OPTIONS = [RE_RESTART, RE_DELLOGS, ManageIQ::ApplianceConsole::CANCEL].freeze NETWORK_INTERFACE = "eth0".freeze CLOUD_INIT_NETWORK_CONFIG_FILE = "/etc/cloud/cloud.cfg.d/99_miq_disable_network_config.cfg".freeze CLOUD_INIT_DISABLE_NETWORK_CONFIG = "network: {config: disabled}\n".freeze module ManageIQ module ApplianceConsole eth0 = LinuxAdmin::NetworkInterface.new(NETWORK_INTERFACE) # Because it takes a few seconds, get the region once in the outside loop region = ManageIQ::ApplianceConsole::DatabaseConfiguration.region # Calling stty to provide the equivalent line settings when the console is run via an ssh session or # over the virtual machine console. system("stty -echoprt ixany iexten echoe echok") loop do begin dns = LinuxAdmin::Dns.new eth0.reload eth0.parse_conf if eth0.respond_to?(:parse_conf) host = LinuxAdmin::Hosts.new.hostname ip = eth0.address mac = eth0.mac_address mask = eth0.netmask gw = eth0.gateway dns1, dns2 = dns.nameservers order = dns.search_order.join(' ') timezone = LinuxAdmin::TimeDate.system_timezone version = File.read(VERSION_FILE).chomp if File.exist?(VERSION_FILE) dbhost = ManageIQ::ApplianceConsole::DatabaseConfiguration.database_host database = ManageIQ::ApplianceConsole::DatabaseConfiguration.database_name messaging = ManageIQ::ApplianceConsole::MessageConfiguration.configured? messaging_broker = ManageIQ::ApplianceConsole::MessageServerConfiguration.configured? evm_status = if ManageIQ::ApplianceConsole::EvmServer.running? "running" elsif ManageIQ::ApplianceConsole::EvmServer.runnable? "not running" else "not configured" end summary_attributes = [ summary_entry("Hostname", host), summary_entry("IPv4 Address", "#{ip}/#{mask}"), summary_entry("IPv4 Gateway", gw), summary_entry("IPv6 Address", eth0.address6 ? "#{eth0.address6}/#{eth0.prefix6}" : ''), summary_entry("IPV6 Gateway", eth0.gateway6), summary_entry("Primary DNS", dns1), summary_entry("Secondary DNS", dns2), summary_entry("Search Order", order), summary_entry("MAC Address", mac), summary_entry("Timezone", timezone), summary_entry("Local Database Server", PostgresAdmin.local_server_status), summary_entry("#{I18n.t("product.name")} Server", evm_status), summary_entry("#{I18n.t("product.name")} Database", dbhost || "not configured"), summary_entry("Database/Region", database ? "#{database} / #{region.to_i}" : "not configured"), summary_entry("Messaging", messaging ? "configured" : "not configured"), summary_entry("Local Messaging Broker", messaging_broker ? "configured" : "not configured"), summary_entry("External Auth", ExternalHttpdAuthentication.config_status), summary_entry("#{I18n.t("product.name")} Version", version), ] clear_screen say(<<-EOL) Welcome to the #{I18n.t("product.name")} Virtual Appliance. To modify the configuration, use a web browser to access the management page. #{HighLine.default_instance.list(summary_attributes)} EOL press_any_key clear_screen selection = ask_with_menu("Advanced Setting", AS_OPTIONS, nil, true) case selection when I18n.t("advanced_settings.httpdauth") say("#{selection}\n\n") httpd_auth = ExternalHttpdAuthentication.new(host) if httpd_auth.ask_questions && httpd_auth.activate httpd_auth.post_activation say("\nExternal Authentication configured successfully.\n") press_any_key else say("\nExternal Authentication configuration failed!\n") press_any_key raise MiqSignalError end when I18n.t("advanced_settings.extauth_opts") say("#{selection}\n\n") extauth_options = ExternalAuthOptions.new if extauth_options.ask_questions && extauth_options.any_updates? extauth_options.update_configuration say("\nExternal Authentication Options updated successfully.\n") else say("\nExternal Authentication Options not updated.\n") end press_any_key when I18n.t("advanced_settings.evmstop") say("#{selection}\n\n") if ManageIQ::ApplianceConsole::EvmServer.running? if ask_yn? "\nNote: It may take up to a few minutes for all #{I18n.t("product.name")} server processes to exit gracefully. Stop #{I18n.t("product.name")}" say("\nStopping #{I18n.t("product.name")} Server...") logger.info("EVM server stop initiated by appliance console.") ManageIQ::ApplianceConsole::EvmServer.stop end else say("\n#{I18n.t("product.name")} Server is not running...") end press_any_key when I18n.t("advanced_settings.evmstart") say("#{selection}\n\n") if ask_yn?("\nStart #{I18n.t("product.name")}") say("\nStarting #{I18n.t("product.name")} Server...") logger.info("EVM server start initiated by appliance console.") ManageIQ::ApplianceConsole::EvmServer.start press_any_key end when I18n.t("advanced_settings.dbbackup") db_admin = ManageIQ::ApplianceConsole::DatabaseAdmin.new(:backup) db_admin.ask_questions && db_admin.activate when I18n.t("advanced_settings.dbdump") db_admin = ManageIQ::ApplianceConsole::DatabaseAdmin.new(:dump) db_admin.ask_questions && db_admin.activate when I18n.t("advanced_settings.dbrestore") db_admin = ManageIQ::ApplianceConsole::DatabaseAdmin.new(:restore) db_admin.ask_questions && db_admin.activate when I18n.t("advanced_settings.key_gen") say("#{selection}\n\n") key_config = ManageIQ::ApplianceConsole::KeyConfiguration.new if key_config.ask_question_loop say("\nEncryption key now configured.") press_any_key else say("\nEncryption key not configured.") press_any_key raise MiqSignalError end when I18n.t("advanced_settings.app_config") say("#{selection}\n\n") ensure_key_configured options = { "Create Internal Database" => "create_internal", "Create Region in External Database" => "create_external", "Join Region in External Database" => "join_external", "Reset Configured Database" => "reset_region", "Make No Database Changes" => "no_changes" } database_action = ask_with_menu("Database Operation", options) messaging_options = { "Configure this appliance as a messaging server" => "message_server", "Connect to an external messaging system" => "message_client", "Make No messaging changes" => "no_changes" } messaging_action = ask_with_menu("Configure Messaging", messaging_options) changes_requested = database_action != "no_changes" || messaging_action != "no_changes" # Stop evmserver while we make changes to the database and/or messaging configuration if changes_requested say("\nStopping #{I18n.t("product.name")} Server...") ManageIQ::ApplianceConsole::EvmServer.stop end database_configuration = case database_action when "create_internal" ManageIQ::ApplianceConsole::InternalDatabaseConfiguration.new when /_external/ ManageIQ::ApplianceConsole::ExternalDatabaseConfiguration.new(:action => database_action.split("_").first.to_sym) else ManageIQ::ApplianceConsole::DatabaseConfiguration.new end case database_action when "reset_region" if database_configuration.reset_region say("Database reset successfully") say("Start the server processes via '#{I18n.t("advanced_settings.evmstart")}'.") else say("Failed to reset database") end when "create_internal", /_external/ database_configuration.run_interactive end # Get the region again because it may have changed region = ManageIQ::ApplianceConsole::DatabaseConfiguration.region case messaging_action when "message_server" say("#{selection}\n\n") message_server = MessageServerConfiguration.new if !MessageServerConfiguration.available? say("\nMessage Server configuration is unavailable!\n") press_any_key raise MiqSignalError elsif message_server.ask_questions && message_server.configure say("\nMessage Server configured successfully.\n") else say("\nMessage Server configuration failed!\n") press_any_key raise MiqSignalError end when "message_client" say("#{selection}\n\n") message_client = MessageClientConfiguration.new if !MessageClientConfiguration.available? say("\nMessage Client configuration is unavailable!\n") press_any_key raise MiqSignalError elsif message_client.ask_questions && message_client.configure say("\nMessage Client configured successfully.\n") else say("\nMessage Client configuration failed!\n") press_any_key raise MiqSignalError end end # Start evmserverd if database and/or messaging were set up and we are supposed to run as an evmserver if changes_requested && database_configuration.run_as_evm_server say("\nStarting #{I18n.t("product.name")} Server...") ManageIQ::ApplianceConsole::EvmServer.start(:enable => true) end press_any_key when I18n.t("advanced_settings.db_replication") say("#{selection}\n\n") options = { "Configure Server as Primary" => "primary", "Configure Server as Standby" => "standby" } action = ask_with_menu("Database replication Operation", options) case action when "primary" db_replication = ManageIQ::ApplianceConsole::DatabaseReplicationPrimary.new logger.info("Configuring Server as Primary") when "standby" db_replication = ManageIQ::ApplianceConsole::DatabaseReplicationStandby.new logger.info("Configuring Server as Standby") ensure_key_configured end if db_replication.ask_questions && db_replication.activate say("Database Replication configured") logger.info("Database Replication configured") press_any_key else say("Database Replication not configured") logger.info("Database Replication not configured") press_any_key raise MiqSignalError end when I18n.t("advanced_settings.failover_monitor") say("#{selection}\n\n") options = { "Start Database Failover Monitor" => "start", "Stop Database Failover Monitor" => "stop" } action = ask_with_menu("Failover Monitor Configuration", options) failover_service = LinuxAdmin::Service.new("evm-failover-monitor") begin case action when "start" logger.info("Starting and enabling evm-failover-monitor service") failover_service.enable.start when "stop" logger.info("Stopping and disabling evm-failover-monitor service") failover_service.disable.stop end rescue AwesomeSpawn::CommandResultError => e say("Failed to configure failover monitor") logger.error("Failed to configure evm-failover-monitor service") say(e.result.output) say(e.result.error) say("") press_any_key raise MiqSignalError end say("Failover Monitor Service configured successfully") press_any_key when I18n.t("advanced_settings.log_config") say("#{selection}\n\n") log_config = ManageIQ::ApplianceConsole::LogfileConfiguration.new if log_config.ask_questions && log_config.activate say("Log file configuration updated.") say("The appliance may take a few minutes to fully restart.") press_any_key else say("Log file configuration unchanged") press_any_key raise MiqSignalError end when I18n.t("advanced_settings.tmp_config") say("#{selection}\n\n") tmp_config = ManageIQ::ApplianceConsole::TempStorageConfiguration.new if tmp_config.ask_questions && tmp_config.activate say("Temp storage disk configured") press_any_key else say("Temp storage disk not configured") press_any_key raise MiqSignalError end when I18n.t("advanced_settings.restart") case ask_with_menu("Restart Option", RE_OPTIONS, nil, false) when ManageIQ::ApplianceConsole::CANCEL # don't do anything when RE_RESTART if are_you_sure?("restart the appliance now") logger.info("Appliance restart initiated by appliance console.") ManageIQ::ApplianceConsole::EvmServer.stop LinuxAdmin::System.reboot! end when RE_DELLOGS if are_you_sure?("restart the appliance now") logger.info("Appliance restart with clean logs initiated by appliance console.") ManageIQ::ApplianceConsole::EvmServer.stop LinuxAdmin::Service.new("miqtop").stop LinuxAdmin::Service.new("miqvmstat").stop LinuxAdmin::Service.new("httpd").stop FileUtils.rm_rf(Dir.glob("/var/www/miq/vmdb/log/*.log*")) FileUtils.rm_rf(Dir.glob("/var/www/miq/vmdb/log/apache/*.log*")) logger.info("Logs cleaned and appliance rebooted by appliance console.") LinuxAdmin::System.reboot! end end when I18n.t("advanced_settings.shutdown") say("#{selection}\n\n") if are_you_sure?("shut down the appliance now") say("\nShutting down appliance... This process may take a few minutes.\n\n") logger.info("Appliance shutdown initiated by appliance console") ManageIQ::ApplianceConsole::EvmServer.stop LinuxAdmin::System.shutdown! end when I18n.t("advanced_settings.scap") say("#{selection}\n\n") ManageIQ::ApplianceConsole::Scap.new.lockdown press_any_key when I18n.t("advanced_settings.summary") # Do nothing when I18n.t("advanced_settings.quit") break end rescue MiqSignalError # If a signal is caught anywhere in the inner (after login) loop, go back to the summary screen next end end end end