Use from Python
Connect to the server
Before you can do anything useful, you need to create a TomcatManager
object
and connect to a server.
- TomcatManager.connect(url: str, user: str = '', password: str = '', *, cert: str | Tuple[str, str] = None, verify: str | bool = True, timeout: float = None) TomcatManagerResponse
Connect to the manager application running in a Tomcat server.
- Parameters:
url – url where the Tomcat Manager web application is deployed
user – (optional) user to authenticate with
password – (optional) password to authenticate with
cert – client side certificates to use for SSL/TLS authentication
verify – verify server SSL/TLS certificates
timeout – timeout in seconds for network operations
- Returns:
TomcatManagerResponse
object with an additionalserver_info
attribute
The
server_info
attribute of the returned object contains aServerInfo
object, which is a dictionary with some added properties for well-known values returned from the Tomcat server.This method:
sets or changes the url, credentials, and certificates on an existing object
provides a convenient mechanism to validate you can actually connect to the server
returns a response object that includes information about the server you are connected to
allows you to inspect the response so you can see why you can’t connect
Usage
>>> import tomcatmanager as tm >>> url = "http://localhost:808099/manager" >>> user = "ace" >>> password = "newenglandclamchowder" >>> tomcat = tm.TomcatManager() >>> try: ... r = tomcat.connect(url, user, password) ... if r.ok: ... print("connected") ... else: ... print("not connected") ... except Exception as err: ... # handle exception ... print("not connected") not connected
Many things can go wrong when requesting url’s via http. tomcatmanager uses the requests library for all network communication, and follows that library’s approach for raising exceptions and checking the response to your request. Therefore:
Some exceptions will always be raised by this method. If you give a URL where no web server is listening,
requests.connections.ConnectionError
will be raised.Other exceptions will only be raised if you call
TomcatManagerResponse.raise_for_status()
. For example, if the credentials are incorrect, you won’t get an exception unless you ask for it.The
TomcatManagerResponse.ok
attribute is the easiest and most rigerous way to check whether you connected successfully. However, as the example usage above shows, you still have to catch exceptions because requests can raise exceptions from inside theconnect()
method and this library doesn’t attempt to catch them so that you can do specific error handling if you want to.
All communications between this library and a Tomcat server happen over HTTP, which means there isn’t a persistent connection. A new HTTP GET request is issued for each method call on this object (i.e.
deploy_localwar()
,stop()
). However, the mental model for this library is connection based: use theconnect()
method to establish the URL and authentication credentials, then call other methods to perform actions on the server you are connected to. If you try and call other methods before you callconnect()
,TomcatNotConnected
will be raised. Because there is no persistent connection of any kind, there is no disconnect method and no cleanup to perform when you are done using a server.If you discard or don’t save the return object from this method, you can call
is_connected()
to check if you are connected.Authentication
The only way to validate the URL and authentication credentials is to make an HTTP request to the server and see if it returns successfully. Internally this method tries to retrieve
/manager/text/serverinfo
.Typically authentication is done via user and password. Pass those parameters to utilize HTTP Basic authentication.
To authenticate with a SSL/TLS server using a client certificate and key, pass the path to a single file containing the private key and certificate in the
cert
parameter. As an alternative, you can pass a tuple containing the path to the certificate, and the path to the key.Warning
The private key for your local certificate must be unencrypted. The Requests library used for network communication does not support using encrypted keys.
If the URL uses the
https
protocol, the default behavior is to validate the server SSL/TLS certificate chain.To validate with your own certificate authority bundle, set the
verify
parameter to the path to a certificate authority bundle file or a directory of certificates of trusted certificate authorities. You can disable server certificate validation by settingverify
toFalse
.See Authentication for more details.
Side Effects
Passing a
timeout
parameter to this method has the side effect of setting thetimeout
attribute on this object.Requesting url’s via http can also result in redirection to another url. If that occurs, the new url, not the one you passed, will be stored in the
url
attribute.If you pass user and password credentials and the connection is successful, the user will be stored in the
user
attribute.If you pass an authentication key and certificate in the
cert
parameter and the connection is successful, the information will be stored in thecert
attribute.Upon successful connection, an instance of
TomcatMajorMinor
will be stored intomcat_major_minor
indicating the major version of Tomcat running on the server. Further details about the server are available in theserver_info
attribute of the returned response.Changed in version 3.0.0:
Returned
TomcatManagerResponse
now includes aserver_info
attribute containing aServerInfo
object describing the server we are connected toSets
tomcat_major_minor
attributetimeout
is now a keyword only argument
Responses from the server
All the methods of TomcatManager
which interact with the server
return a response in the form of a TomcatManagerResponse
object.
Use this object to check whether the command completed successfully, and to
get any results generated by the command.
- class tomcatmanager.models.TomcatManagerResponse(response: Response = None)
Returned as the response for
TomcatManager
commands.After running a command, it’s a good idea to check and make sure that the command completed succesfully before relying on the results:
>>> import tomcatmanager as tm >>> tomcat = getfixture("tomcat") >>> try: ... r = tomcat.server_info() ... r.raise_for_status() ... if r.ok: ... print(f"Operating System: {r.server_info.os_name}") ... else: ... print(f"Error: {r.status_message}") ... except Exception as err: ... # handle exception ... pass Operating System: ...
- status_code
Status of the Tomcat Manager command from the first line of text.
The preferred way to check for success is to use the
ok()
method, because it checks for http errors as well as tomcat errors. However, if you want specific access to the status of the tomcat command, use this method.The status codes are enumerated in
StatusCode
.>>> import tomcatmanager as tm >>> tomcat = getfixture("tomcat") >>> r = tomcat.server_info() >>> r.status_code == tm.StatusCode.OK True
- status_message
The message on the first line of the response from the Tomcat Server.
- result
The text of the response from the Tomcat server, without the first line (which contains the status code and message).
- property ok
- Returns:
True if the request completed with no errors.
For this property to return True:
The HTTP request must return a status code of
200 OK
The first line of the response from the Tomcat Manager web application must begin with
OK
.
- raise_for_status()
Raise exceptions for server errors.
First this method calls
requests.Response.raise_for_status()
which raises exceptions if a 4xx or 5xx response is received from the server.If that doesn’t raise anything, then it raises a
TomcatError
if there is not anOK
response from the first line of text back from the Tomcat Manager web app.
- property response: Response
The server’s response to an HTTP request.
TomcatManager
uses the excellent Requests package for HTTP communication. This property returns therequests.Response
object which contains the server’s response to the HTTP request.Of particular use is
requests.Response.text
which contains the content of the response in unicode. If you want raw access to the content returned by the Tomcat Server, this is where you can get it.
Managing Applications
This library provides a robust API to manage applications in a tomcat server. The following methods are available:
TomcatManager.list()
- return a list of all installed applicationsTomcatManager.deploy_localwar()
- deploy a warfile on the local filesystem to the Tomcat serverTomcatManager.deploy_serverwar()
- deploy a war file from the server filesystem to the Tomcat serverTomcatManager.deploy_servercontext()
- deploy an application defined by a context file from the server filesystem to the Tomcat serverTomcatManager.undeploy()
- undeploy an application in the Tomcat serverTomcatManager.start()
- start an application already deployed in the Tomcat serverTomcatManager.stop()
- stop an application already deployed in the Tomcat serverTomcatManager.reload()
- stop and start a tomcat applicationTomcatManager.sessions()
- get the age of the sessions for an application.TomcatManager.expire()
- expire idle sessions
Parallel Deployment
Tomcat supports a parallel deployment feature which allows multiple versions of the same WAR to be deployed simultaneously at the same URL. To utilize this feature, you need to deploy an application with a version string. The combination of path and version string uniquely identify the application:
>>> tomcat = getfixture("tomcat")
>>> safe_path = getfixture("safe_path")
>>> localwar_file = getfixture("localwar_file")
>>> with open(localwar_file, "rb") as localwar_fileobj:
... r = tomcat.deploy_localwar(safe_path, localwar_fileobj, version="42")
... r.ok
True
>>> with open(localwar_file, "rb") as localwar_fileobj:
... r = tomcat.deploy_localwar(safe_path, localwar_fileobj, version="43")
... r.ok
True
We now have two instances of the same application, deployed at the same location, but with different version strings. To do anything to either of those applications, you must supply both the path and the version string:
>>> r = tomcat.stop(path=safe_path, version="42")
>>> r.ok
True
>>> r = tomcat.undeploy(path=safe_path, version="42")
>>> r.ok
True
>>> r = tomcat.undeploy(path=safe_path, version="43")
>>> r.ok
True
The following methods include an optional version parameter to support parallel deployments:
Information about Tomcat
There are a number of methods which just return information about the Tomcat
server. With the exception of TomcatManager.find_leakers()
(which
triggers garbage collection), these methods don’t effect any change on the
server.
TomcatManager.find_leakers()
- find applications that are leaking memoryTomcatManager.resources()
- get global JNDI resourcesTomcatManager.server_info()
- get information about the tomcat serverTomcatManager.status_xml()
- get server status information in xml formatTomcatManager.thread_dump()
- get a jvm thread dumpTomcatManager.vm_info()
- get diagnostic information about the jvm
SSL/TLS
Tomcat servers can be configured to serve their applications over SSL/TLS. This library includes a few related methods:
TomcatManager.ssl_connector_ciphers()
- get SSL/TLS ciphers for eac connectorTomcatManager.ssl_connector_certs()
- get the certificate chain for each virtual hostTomcatManager.ssl_connector_trusted_certs()
- get the trusted certificates for each virtual hostTomcatManager.ssl_reload()
- reload certificates and keys
The TomcatManager.ssl_reload()
is the only one of these methods that
causes the server to take any action, the rest are informational only.
Differences in Tomcat Versions
As Tomcat matured, it added new capabilities. For example, Tomcat 8.5 added
a new command ssl_reload
. This library added support for that command
in version 2.0.0. However, if the server you were connected to happened to
be running Tomcat 8.0, a somewhat rather generic exception was thrown.
In version 3.0.0, this library was enhanced so it understood all the supported
versions of Tomcat (see TomcatMajorMinor
), and which versions of
Tomcat supported each of the available API calls.
If you call a method that is not implemented by the particular server you are
connected to, TomcatNotImplementedError
will be raised.
Note
In version 6.0.0 of this library and higher, all python API methods are available in
all supported Tomcat versions. Therefore, this version of the library will not raise
TomcatNotImplementedError
exceptions.
However, you should still check for these exceptions in your code, and if you are
already checking for them, you definitely shouldn’t delete those checks. This
exception, and the related TomcatManager.implements()
and
TomcatManager.implemented_by()
methods are not deprecated in case they are
needed in future versions.
If you prefer to check whether a method is supported before calling it, you
can do so using TomcatManager.implements()
:
>>> tomcat = getfixture("tomcat")
>>> if tomcat.implements(tomcat.list):
... print("list is implemented")
... else:
... print("list is not implemented")
list is implemented
If you call TomcatManager.implements()
and are not connected to a
server, TomcatNotConnected
will be raised.
There is a way to check whether a method is supported without connecting
to a server. You must specify the version of the Tomcat server and the
method you want to check is implemented. Use one of the values in the enumeration
TomcatMajorMinor
to specify the version of Tomcat you
want to check:
>>> import tomcatmanager as tm
>>> tomcat = tm.TomcatManager()
>>> tver = tm.TomcatMajorMinor.V8_5
>>> print(tomcat.implemented_by(tomcat.ssl_reload, tver))
True
Specifying As A Dependency
If you incorporate tomcatmanager
into your own package, you will need to specify
it as a dependency. I strongly recommend you specify the dependency such that it
limits usage to a single major version of this library. This way when a new major
version of this library is released, it won’t break your code. You should specify your
pyproject.toml
dependency like this:
[project]
dependencies = [
"tomcatmanager>=5,<6"
]
When this library adds support for a new version of Tomcat or Python, we increment the minor version number. However, if support for these new versions requires API changes incompatible with prior releases of this software, then we increment the major version number.
When this library drops support for a version of Tomcat or Python, we increment the major version number. For example, when this project dropped support for Python 3.6, we released that version as 5.0.0 instead of 4.1.0, even though there were no incompatible API changes.
These versioning rules were chosen so that if you are using this library against a single version of Tomcat, and you specify your dependency rules as suggested above, you will not have to worry about a future release of this software breaking your setup.
For example, say you are using Tomcat 8.0, which is supported by version 5.x of this
library. You should specify your pyproject.toml
dependency rules:
[project]
dependencies = [
"tomcatmanager>=5,<6"
]
When version 6.x of this library was released it dropped support for Tomcat 8.0.
Without this dependency rule, pip
would upgrade to the new version of this
library, which would break your application which needs to talk to a Tomcat 8.0
server.
Once you have migrated your server infrastructure to a newer version of Tomcat, you can change your dependency rules:
[project]
dependencies = [
"tomcatmanager>=6,<7"
]