summaryrefslogtreecommitdiffstats
path: root/ipapython/dogtag.py
diff options
context:
space:
mode:
authorPetr Viktorin <pviktori@redhat.com>2012-09-25 09:57:03 -0400
committerRob Crittenden <rcritten@redhat.com>2012-10-23 22:02:21 -0400
commitd6fbbd530ee94bc4cdd00c9106fd789e50fb81cf (patch)
treef1042737da4ef5784943222be87b97a550371461 /ipapython/dogtag.py
parente4853ebc5910a526c74cc422fd3c1806708bc7aa (diff)
downloadfreeipa-d6fbbd530ee94bc4cdd00c9106fd789e50fb81cf.tar.gz
freeipa-d6fbbd530ee94bc4cdd00c9106fd789e50fb81cf.tar.xz
freeipa-d6fbbd530ee94bc4cdd00c9106fd789e50fb81cf.zip
Make sure the CA is running when starting services
- Provide a function for determinig the CA status using Dogtag 10's new getStatus endpoint. This must be done over HTTPS, but since our client certificate may not be set up yet, we need HTTPS without client authentication. Rather than copying from the existing http_request and https_request function, shared code is factored out to a common helper. - Call the new function when restarting the CA service. Since our Service can only be extended in platform-specific code, do this for Fedora only. Also, the status is only checked with Dogtag 10+. - When a restart call in cainstance failed, users were refered to the installation log, but no info was actually logged. Log the exception. https://fedorahosted.org/freeipa/ticket/3084
Diffstat (limited to 'ipapython/dogtag.py')
-rw-r--r--ipapython/dogtag.py164
1 files changed, 105 insertions, 59 deletions
diff --git a/ipapython/dogtag.py b/ipapython/dogtag.py
index 907cebc61..5cf5a9df8 100644
--- a/ipapython/dogtag.py
+++ b/ipapython/dogtag.py
@@ -130,6 +130,15 @@ def configured_constants(api=None):
return Dogtag9Constants
+def error_from_xml(doc, message_template):
+ try:
+ item_node = doc.getElementsByTagName("Error")
+ reason = item_node[0].childNodes[0].data
+ return errors.RemoteRetrieveError(reason=reason)
+ except Exception, e:
+ return errors.RemoteRetrieveError(reason=message_template % e)
+
+
def get_ca_certchain(ca_host=None):
"""
Retrieve the CA Certificate chain from the configured Dogtag server.
@@ -151,13 +160,8 @@ def get_ca_certchain(ca_host=None):
item_node = doc.getElementsByTagName("ChainBase64")
chain = item_node[0].childNodes[0].data
except IndexError:
- try:
- item_node = doc.getElementsByTagName("Error")
- reason = item_node[0].childNodes[0].data
- raise errors.RemoteRetrieveError(reason=reason)
- except Exception, e:
- raise errors.RemoteRetrieveError(
- reason=_("Retrieving CA cert chain failed: %s") % e)
+ raise error_from_xml(
+ doc, _("Retrieving CA cert chain failed: %s"))
finally:
if doc:
doc.unlink()
@@ -167,32 +171,107 @@ def get_ca_certchain(ca_host=None):
return chain
+
+def ca_status(ca_host=None):
+ """Return the status of the CA, and the httpd proxy in front of it
+
+ The returned status can be:
+ - running
+ - starting
+ - Service Temporarily Unavailable
+ """
+ if ca_host is None:
+ ca_host = api.env.ca_host
+ # Use port 443 to test the proxy as well
+ status, reason, headers, body = unauthenticated_https_request(
+ ca_host, 443, '/ca/admin/ca/getStatus')
+ if status == 503:
+ # Service temporarily unavailable
+ return reason
+ elif status != 200:
+ raise errors.RemoteRetrieveError(
+ reason=_("Retrieving CA status failed: %s") % reason)
+ doc = xml.dom.minidom.parseString(body)
+ try:
+ item_node = doc.getElementsByTagName("XMLResponse")[0]
+ item_node = item_node.getElementsByTagName("Status")[0]
+ return item_node.childNodes[0].data
+ except IndexError:
+ raise error_from_xml(doc, _("Retrieving CA status failed: %s"))
+
+
def https_request(host, port, url, secdir, password, nickname, **kw):
"""
- :param url: The URL to post to.
+ :param url: The path (not complete URL!) to post to.
:param kw: Keyword arguments to encode into POST body.
:return: (http_status, http_reason_phrase, http_headers, http_body)
as (integer, unicode, dict, str)
Perform a client authenticated HTTPS request
"""
- if isinstance(host, unicode):
- host = host.encode('utf-8')
- uri = 'https://%s%s' % (ipautil.format_netloc(host, port), url)
- post = urlencode(kw)
- root_logger.debug('https_request %r', uri)
- root_logger.debug('https_request post %r', post)
- request_headers = {"Content-type": "application/x-www-form-urlencoded",
- "Accept": "text/plain"}
- try:
+
+ def connection_factory(host, port):
conn = nsslib.NSSConnection(host, port, dbdir=secdir)
conn.set_debuglevel(0)
conn.connect()
- conn.sock.set_client_auth_data_callback(nsslib.client_auth_data_callback,
- nickname,
- password, nss.get_default_certdb())
- conn.request("POST", url, post, request_headers)
+ conn.sock.set_client_auth_data_callback(
+ nsslib.client_auth_data_callback,
+ nickname, password, nss.get_default_certdb())
+ return conn
+
+ body = urlencode(kw)
+ return _httplib_request(
+ 'https', host, port, url, connection_factory, body)
+
+
+def http_request(host, port, url, **kw):
+ """
+ :param url: The path (not complete URL!) to post to.
+ :param kw: Keyword arguments to encode into POST body.
+ :return: (http_status, http_reason_phrase, http_headers, http_body)
+ as (integer, unicode, dict, str)
+
+ Perform an HTTP request.
+ """
+ body = urlencode(kw)
+ return _httplib_request(
+ 'http', host, port, url, httplib.HTTPConnection, body)
+
+
+def unauthenticated_https_request(host, port, url, **kw):
+ """
+ :param url: The path (not complete URL!) to post to.
+ :param kw: Keyword arguments to encode into POST body.
+ :return: (http_status, http_reason_phrase, http_headers, http_body)
+ as (integer, unicode, dict, str)
+
+ Perform an unauthenticated HTTPS request.
+ """
+ body = urlencode(kw)
+ return _httplib_request(
+ 'https', host, port, url, httplib.HTTPSConnection, body)
+
+def _httplib_request(
+ protocol, host, port, path, connection_factory, request_body):
+ """
+ :param request_body: Request body
+ :param connection_factory: Connection class to use. Will be called
+ with the host and port arguments.
+
+ Perform a HTTP(s) request.
+ """
+ if isinstance(host, unicode):
+ host = host.encode('utf-8')
+ uri = '%s://%s%s' % (protocol, ipautil.format_netloc(host, port), path)
+ root_logger.info('request %r', uri)
+ root_logger.debug('request body %r', request_body)
+ try:
+ conn = connection_factory(host, port)
+ conn.request('POST', uri,
+ body=request_body,
+ headers={'Content-type': 'application/x-www-form-urlencoded'},
+ )
res = conn.getresponse()
http_status = res.status
@@ -203,42 +282,9 @@ def https_request(host, port, url, secdir, password, nickname, **kw):
except Exception, e:
raise NetworkError(uri=uri, error=str(e))
- return http_status, http_reason_phrase, http_headers, http_body
+ root_logger.debug('request status %d', http_status)
+ root_logger.debug('request reason_phrase %r', http_reason_phrase)
+ root_logger.debug('request headers %s', http_headers)
+ root_logger.debug('request body %r', http_body)
-def http_request(host, port, url, **kw):
- """
- :param url: The URL to post to.
- :param kw: Keyword arguments to encode into POST body.
- :return: (http_status, http_reason_phrase, http_headers, http_body)
- as (integer, unicode, dict, str)
-
- Perform an HTTP request.
- """
- if isinstance(host, unicode):
- host = host.encode('utf-8')
- uri = 'http://%s%s' % (ipautil.format_netloc(host, port), url)
- post = urlencode(kw)
- root_logger.info('request %r', uri)
- root_logger.debug('request post %r', post)
- conn = httplib.HTTPConnection(host, port)
- try:
- conn.request('POST', url,
- body=post,
- headers={'Content-type': 'application/x-www-form-urlencoded'},
- )
- res = conn.getresponse()
-
- http_status = res.status
- http_reason_phrase = unicode(res.reason, 'utf-8')
- http_headers = res.msg.dict
- http_body = res.read()
- conn.close()
- except NSPRError, e:
- raise NetworkError(uri=uri, error=str(e))
-
- root_logger.debug('request status %d', http_status)
- root_logger.debug('request reason_phrase %r', http_reason_phrase)
- root_logger.debug('request headers %s', http_headers)
- root_logger.debug('request body %r', http_body)
-
- return http_status, http_reason_phrase, http_headers, http_body
+ return http_status, http_reason_phrase, http_headers, http_body