freeipa/install/tools/ipactl
Ana Krivokapic dfcdd9c403 Always stop dirsrv in 'ipactl stop'
Ensure that 'ipactl stop' stops the dirsrv instance, even when no other
services are running.

https://fedorahosted.org/freeipa/ticket/3574
2013-04-29 09:38:30 -04:00

489 lines
16 KiB
Python
Executable File

#!/usr/bin/python
# Authors: Simo Sorce <ssorce@redhat.com>
#
# Copyright (C) 2008-2010 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import sys
import os
import json
import ldapurl
from ipaserver.install import service, installutils
from ipaserver.install.dsinstance import config_dirname, realm_to_serverid
from ipaserver.install.installutils import is_ipa_configured, ScriptError
from ipalib import api, errors
from ipapython.ipaldap import IPAdmin
from ipapython.ipautil import wait_for_open_ports, wait_for_open_socket
from ipapython import services as ipaservices
from ipapython import config, dogtag
from ipapython.dn import DN
class IpactlError(ScriptError):
pass
def check_IPA_configuration():
if not is_ipa_configured():
# LSB status code 6: program is not configured
raise IpactlError("IPA is not configured " +
"(see man pages of ipa-server-install for help)", 6)
def is_dirsrv_debugging_enabled():
"""
Check the IPA and PKI-CA 389-ds instances to see if debugging is
enabled. If so we suppress that in our output.
returns True or False
"""
debugging = False
serverid = realm_to_serverid(api.env.realm)
dselist = [config_dirname(serverid)]
if not dogtag.install_constants.SHARED_DB:
dselist.append('/etc/dirsrv/slapd-PKI-IPA/')
for dse in dselist:
try:
fd = open(dse + 'dse.ldif', 'r')
except IOError:
continue
lines = fd.readlines()
fd.close()
for line in lines:
if line.lower().startswith('nsslapd-errorlog-level'):
(option, value) = line.split(':')
if int(value) > 0:
debugging = True
return debugging
def get_capture_output(service, debug):
"""
We want to display any output of a start/stop command with the
exception of 389-ds when debugging is enabled because it outputs
tons and tons of information.
"""
if service == 'dirsrv' and not debug and is_dirsrv_debugging_enabled():
print ' debugging enabled, suppressing output.'
return True
else:
return False
def parse_options():
usage = "%prog start|stop|restart|status\n"
parser = config.IPAOptionParser(usage=usage,
formatter=config.IPAFormatter())
parser.add_option("-d", "--debug", action="store_true", dest="debug",
help="Display debugging information")
options, args = parser.parse_args()
safe_options = parser.get_safe_opts(options)
return safe_options, options, args
def emit_err(err):
sys.stderr.write(err + '\n')
def get_config(dirsrv):
base = DN(('cn', api.env.host), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
srcfilter = '(ipaConfigString=enabledService)'
attrs = ['cn', 'ipaConfigString']
if not dirsrv.is_running():
raise IpactlError("Failed to get list of services to probe status:\n" +
"Directory Server is stopped", 3)
try:
# The start/restart functions already wait for the server to be
# started. What we are doing with this wait is really checking to see
# if the server is listening at all.
lurl = ldapurl.LDAPUrl(api.env.ldap_uri)
if lurl.urlscheme == 'ldapi':
wait_for_open_socket(lurl.hostport, timeout=api.env.startup_timeout)
else:
(host, port) = lurl.hostport.split(':')
wait_for_open_ports(host, [int(port)], timeout=api.env.startup_timeout)
con = IPAdmin(ldap_uri=api.env.ldap_uri)
con.do_external_bind()
res, truncated = con.find_entries(
filter=srcfilter,
attrs_list=attrs,
base_dn=base,
scope=con.SCOPE_SUBTREE,
time_limit=10)
if truncated:
raise errors.LimitsExceeded()
except errors.NetworkError:
# LSB status code 3: program is not running
raise IpactlError("Failed to get list of services to probe status:\n" +
"Directory Server is stopped", 3)
except errors.NotFound:
masters_list = []
dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
attrs = ['cn']
try:
entries = con.get_entries(dn, con.SCOPE_ONELEVEL, attrs_list=attrs)
except Exception, e:
masters_list.append("No master found because of error: %s" % str(e))
else:
for dn, master_entry in entries:
masters_list.append(master_entry.single_value('cn'))
masters = "\n".join(masters_list)
raise IpactlError("Failed to get list of services to probe status!\n"
"Configured hostname '%s' does not match any master server in LDAP:\n%s"
% (api.env.host, masters))
except Exception, e:
raise IpactlError("Unknown error when retrieving list of services from LDAP: " + str(e))
svc_list = []
for entry in res:
name = entry.single_value('cn')
for p in entry['ipaConfigString']:
if p.startswith('startOrder '):
order = p.split()[1]
svc_list.append([order, name])
ordered_list = []
for (order, svc) in sorted(svc_list):
if svc in service.SERVICE_LIST:
ordered_list.append(service.SERVICE_LIST[svc][0])
return ordered_list
def get_config_from_file():
svc_list = []
try:
f = open(ipaservices.get_svc_list_file(), 'r')
svc_list = json.load(f)
except Exception, e:
raise IpactlError("Unknown error when retrieving list of services from file: " + str(e))
# the framework can start/stop a number of related services we are not
# authoritative for, so filter the list through SERVICES_LIST and order it
# accordingly too.
def_svc_list = []
for svc in service.SERVICE_LIST:
s = service.SERVICE_LIST[svc]
def_svc_list.append([s[1], s[0]])
ordered_list = []
for (order, svc) in sorted(def_svc_list):
if svc in svc_list:
ordered_list.append(svc)
return ordered_list
def ipa_start(options):
if os.path.isfile(ipaservices.get_svc_list_file()):
emit_err("Existing service file detected!")
emit_err("Assuming stale, cleaning and proceeding")
# remove file with list of started services
# This is ok as systemd will just skip services
# that are already running and just return, so that the
# stop() method of the base class will simply fill in the
# service file again
os.unlink(ipaservices.SVC_LIST_FILE)
dirsrv = ipaservices.knownservices.dirsrv
try:
print "Starting Directory Service"
dirsrv.start(capture_output=get_capture_output('dirsrv', options.debug))
except Exception, e:
raise IpactlError("Failed to start Directory Service: " + str(e))
ldap_list = []
try:
svc_list = get_config(dirsrv)
except Exception, e:
emit_err("Failed to data from service file: " + str(e))
emit_err("Shutting down")
try:
dirsrv.stop(capture_output=False)
except:
pass
if isinstance(e, IpactlError):
# do not display any other error message
raise IpactlError(rval=e.rval)
else:
raise IpactlError()
if len(svc_list) == 0:
# no service to start
return
for svc in svc_list:
svchandle = ipaservices.service(svc)
try:
print "Starting %s Service" % svc
svchandle.start(capture_output=get_capture_output(svc, options.debug))
except:
emit_err("Failed to start %s Service" % svc)
emit_err("Shutting down")
for svc in svc_list:
svc_off = ipaservices.service(svc)
try:
svc_off.stop(capture_output=False)
except:
pass
try:
dirsrv.stop(capture_output=False)
except:
pass
raise IpactlError("Aborting ipactl")
def ipa_stop(options):
dirsrv = ipaservices.knownservices.dirsrv
try:
svc_list = get_config_from_file()
except Exception, e:
# Issue reading the file ? Let's try to get data from LDAP as a
# fallback
try:
dirsrv.start(capture_output=False)
svc_list = get_config(dirsrv)
except Exception, e:
emit_err("Failed to read data from Directory Service: " + str(e))
emit_err("Shutting down")
try:
# just try to stop it, do not read a result
dirsrv.stop()
finally:
raise IpactlError()
try:
print "Stopping Directory Service"
dirsrv.stop(capture_output=False)
except:
raise IpactlError("Failed to stop Directory Service")
for svc in reversed(svc_list):
svchandle = ipaservices.service(svc)
try:
print "Stopping %s Service" % svc
svchandle.stop(capture_output=False)
except:
emit_err("Failed to stop %s Service" % svc)
# remove file with list of started services
try:
os.unlink(ipaservices.SVC_LIST_FILE)
except OSError:
pass
def ipa_restart(options):
dirsrv = ipaservices.knownservices.dirsrv
new_svc_list = []
try:
new_svc_list = get_config(dirsrv)
except Exception, e:
emit_err("Failed to read data from Directory Service: " + str(e))
emit_err("Shutting down")
try:
dirsrv.stop(capture_output=False)
except:
pass
if isinstance(e, IpactlError):
# do not display any other error message
raise IpactlError(rval=e.rval)
else:
raise IpactlError()
old_svc_list = []
try:
old_svc_list = get_config_from_file()
except Exception, e:
emit_err("Failed to get service list from file: " + str(e))
# fallback to what's in LDAP
old_svc_list = new_svc_list
# match service to start/stop
svc_list = []
for s in new_svc_list:
if s in old_svc_list:
svc_list.append(s)
#remove commons
for s in svc_list:
if s in old_svc_list:
old_svc_list.remove(s)
for s in svc_list:
if s in new_svc_list:
new_svc_list.remove(s)
if len(old_svc_list) != 0:
# we need to definitely stop some services
for svc in reversed(old_svc_list):
svchandle = ipaservices.service(svc)
try:
print "Stopping %s Service" % svc
svchandle.stop(capture_output=False)
except:
emit_err("Failed to stop %s Service" % svc)
try:
print "Restarting Directory Service"
dirsrv.restart(capture_output=get_capture_output('dirsrv', options.debug))
except Exception, e:
emit_err("Failed to restart Directory Service: " + str(e))
emit_err("Shutting down")
for svc in reversed(svc_list):
svc_off = ipaservices.service(svc)
try:
svc_off.stop(capture_output=False)
except:
pass
try:
dirsrv.stop(capture_output=False)
except:
pass
raise IpactlError("Aborting ipactl")
if len(svc_list) != 0:
# there are services to restart
for svc in svc_list:
svchandle = ipaservices.service(svc)
try:
print "Restarting %s Service" % svc
svchandle.restart(capture_output=get_capture_output(svc, options.debug))
except:
emit_err("Failed to restart %s Service" % svc)
emit_err("Shutting down")
for svc in reversed(svc_list):
svc_off = ipaservices.service(svc)
try:
svc_off.stop(capture_output=False)
except:
pass
try:
dirsrv.stop(capture_output=False)
except:
pass
raise IpactlError("Aborting ipactl")
if len(new_svc_list) != 0:
# we still need to start some services
for svc in new_svc_list:
svchandle = ipaservices.service(svc)
try:
print "Starting %s Service" % svc
svchandle.start(capture_output=get_capture_output(svc, options.debug))
except:
emit_err("Failed to start %s Service" % svc)
emit_err("Shutting down")
for svc in reversed(svc_list):
svc_off = ipaservices.service(svc)
try:
svc_off.stop(capture_output=False)
except:
pass
try:
dirsrv.stop(capture_output=False)
except:
pass
raise IpactlError("Aborting ipactl")
def ipa_status(options):
try:
svc_list = get_config_from_file()
except IpactlError, e:
if os.path.exists(ipaservices.get_svc_list_file()):
raise e
else:
svc_list = []
except Exception, e:
raise IpactlError("Failed to get list of services to probe status: " + str(e))
dirsrv = ipaservices.knownservices.dirsrv
try:
if dirsrv.is_running():
print "Directory Service: RUNNING"
else:
print "Directory Service: STOPPED"
if len(svc_list) == 0:
print ("Directory Service must be running in order to " +
"obtain status of other services")
except:
raise IpactlError("Failed to get Directory Service status")
if len(svc_list) == 0:
return
for svc in svc_list:
svchandle = ipaservices.service(svc)
try:
if svchandle.is_running():
print "%s Service: RUNNING" % svc
else:
print "%s Service: STOPPED" % svc
except:
emit_err("Failed to get %s Service status" % svc)
def main():
if not os.getegid() == 0:
# LSB status code 4: user had insufficient privilege
raise IpactlError("You must be root to run ipactl.", 4)
safe_options, options, args = parse_options()
if len(args) != 1:
# LSB status code 2: invalid or excess argument(s)
raise IpactlError("You must specify one action", 2)
elif args[0] != "start" and args[0] != "stop" and args[0] != "restart" and args[0] != "status":
raise IpactlError("Unrecognized action [" + args[0] + "]", 2)
# check if IPA is configured at all
try:
check_IPA_configuration()
except IpactlError, e:
if args[0].lower() == "status":
# Different LSB return code for status command:
# 4 - program or service status is unknown
# This should differentiate uninstalled IPA from status
# code 3 - program is not running
e.rval = 4
raise e
else:
raise e
api.bootstrap(context='ipactl', debug=options.debug)
api.finalize()
if '.' not in api.env.host:
raise IpactlError("Invalid hostname '%s' in IPA configuration!\n"
"The hostname must be fully-qualified" % api.env.host)
if args[0].lower() == "start":
ipa_start(options)
elif args[0].lower() == "stop":
ipa_stop(options)
elif args[0].lower() == "restart":
ipa_restart(options)
elif args[0].lower() == "status":
ipa_status(options)
if __name__ == '__main__':
installutils.run_script(main, operation_name='ipactl')