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 additional server_info attribute

The server_info attribute of the returned object contains a ServerInfo 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 the connect() 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 the connect() 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 call connect(), 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 setting verify to False.

See Authentication for more details.

Side Effects

Passing a timeout parameter to this method has the side effect of setting the timeout 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 the cert attribute.

Upon successful connection, an instance of TomcatMajorMinor will be stored in tomcat_major_minor indicating the major version of Tomcat running on the server. Further details about the server are available in the server_info attribute of the returned response.

Changed in version 3.0.0:

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 an OK 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 the requests.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:

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.

SSL/TLS

Tomcat servers can be configured to serve their applications over SSL/TLS. This library includes a few related methods:

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"
]