# Phusion Passenger - https://www.phusionpassenger.com/# Copyright (c) 2013-2014 Phusion## "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.## Permission is hereby granted, free of charge, to any person obtaining a copy# of this software and associated documentation files (the "Software"), to deal# in the Software without restriction, including without limitation the rights# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell# copies of the Software, and to permit persons to whom the Software is# furnished to do so, subject to the following conditions:## The above copyright notice and this permission notice shall be included in# all copies or substantial portions of the Software.## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN# THE SOFTWARE.require'optparse'require'net/http'require'socket'require'rexml/document'PhusionPassenger.require_passenger_lib'constants'PhusionPassenger.require_passenger_lib'admin_tools/instance_registry'PhusionPassenger.require_passenger_lib'config/command'PhusionPassenger.require_passenger_lib'config/utils'PhusionPassenger.require_passenger_lib'utils/json'modulePhusionPassengermoduleConfigclassRestartAppCommand<CommandincludePhusionPassenger::Config::Utilsdefrunparse_optionsselect_passenger_instanceselect_app_group_nameperform_restartendprivatedefself.create_option_parser(options)OptionParser.newdo|opts|nl="\n"+' '*37opts.banner="Usage 1: passenger-config restart-app <APP PATH PREFIX> [OPTIONS]\n"+"Usage 2: passenger-config restart-app --name <APP GROUP NAME> [OPTIONS]"opts.separator""opts.separator" Restart an application. The syntax determines how the application that is to"opts.separator" be restarted, will be selected."opts.separator""opts.separator" 1. Selects all applications whose paths begin with the given prefix."opts.separator""opts.separator" Example: passenger-config restart-app /webapps"opts.separator" Restarts all apps whose path begin with /webapps, such as /webapps/foo,"opts.separator" /webapps/bar and /webapps123."opts.separator""opts.separator" 2. Selects a specific application based on an exact match of its app group"opts.separator" name."opts.separator""opts.separator" Example: passenger-config restart-app --name /webapps/foo"opts.separator" Restarts only /webapps/foo, but not for example /webapps/foo/bar or"opts.separator" /webapps/foo123."opts.separator""opts.separator"Options:"opts.on("--name APP_GROUP_NAME",String,"The app group name to select")do|value|options[:app_group_name]=valueendopts.on("--rolling-restart","Perform a rolling restart instead of a#{nl}"+"regular restart (Enterprise only). The#{nl}"+"default is a blocking restart")do|value|ifConfig::Utils.is_enterprise?options[:rolling_restart]=trueelseabort"--rolling-restart is only available in #{PROGRAM_NAME} Enterprise: #{ENTERPRISE_URL}"endendopts.on("--ignore-app-not-running","Exit successfully if the specified#{nl}"+"application is not currently running. The#{nl}"+"default is to exit with an error")dooptions[:ignore_app_not_running]=trueendopts.on("--instance NAME",String,"The #{PROGRAM_NAME} instance to select")do|value|options[:instance]=valueendopts.on("-h","--help","Show this help")dooptions[:help]=trueendendenddefhelpputs@parserenddefparse_optionssupercase@argv.sizewhen0if!@options[:app_group_name]abort"Please pass either an app path prefix or an app group name. "+"See --help for more information."endwhen1if@options[:app_group_name]abort"You've passed an app path prefix, but you cannot also pass an "+"app group name. Please use only either one of them. See --help "+"for more information."endelsehelpabortendenddefselect_app_group_name@groups=[]ifapp_group_name=@options[:app_group_name]select_app_group_name_exact(app_group_name)elseselect_app_group_name_by_app_root_regex(@argv.first)endenddefselect_app_group_name_exact(name)query_pool_xml.elements.each("info/supergroups/supergroup/group")do|group|ifgroup.elements["name"].text==name@groups<<groupendendif@groups.empty?abort_app_not_found"There is no #{PROGRAM_NAME}-served application running "+"with the app group name '#{name}'."endenddefselect_app_group_name_by_app_root_regex(app_root)regex=/^#{Regexp.escape(app_root)}/query_pool_xml.elements.each("info/supergroups/supergroup/group")do|group|ifgroup.elements["app_root"].text=~regex@groups<<groupendendif@groups.empty?abort_app_not_found"There are no #{PROGRAM_NAME}-served applications running "+"whose paths begin with '#{app_root}'."endenddefperform_restartrestart_method=@options[:rolling_restart]?"rolling":"blocking"@groups.eachdo|group|group_name=group.elements["name"].textputs"Restarting #{group_name}"request=Net::HTTP::Post.new("/pool/restart_app_group.json")request.basic_auth("admin",obtain_full_admin_password(@instance))request.content_type="application/json"request.body=PhusionPassenger::Utils::JSON.generate(:name=>group_name,:method=>restart_method)response=@instance.http_request("agents.s/server_admin",request)ifresponse.code.to_i/100==2returnREXML::Document.new(response.body)elseSTDERR.puts"*** An error occured while communicating with the #{PROGRAM_NAME} server:"STDERR.putsresponse.bodyabortendendenddefabort_app_not_found(message)if@options[:ignore_app_not_running]STDERR.puts(message)exitelseabort(message)endenddefquery_pool_xmlrequest=Net::HTTP::Get.new("/pool.xml")request.basic_auth("ro_admin",obtain_read_only_admin_password(@instance))response=@instance.http_request("agents.s/server_admin",request)ifresponse.code.to_i/100==2returnREXML::Document.new(response.body)elseSTDERR.puts"*** An error occured while querying the #{PROGRAM_NAME} server:"STDERR.putsresponse.bodyabortendendendend# module Configend# module PhusionPassenger