Juju Python Library
The `juju` library provides a Pythonic interface for interacting with Juju controllers and models, allowing programmatic control over Juju deployments. As of version 3.6.1.3, the library is not under active development and primarily receives critical bug fixes. Releases are infrequent and typically address specific issues rather than introducing new features.
Common errors
-
AttributeError: '_WebSocketConnection' object has no attribute 'open' (or similar during connection)
cause Using `python-libjuju` version older than 3.5.2.1 with `websockets` version 14.0 or higher.fixUpgrade `python-libjuju` to 3.5.2.1 or newer. Alternatively, restrict `websockets` to version `<14.0,>=8.1` in your `requirements.txt`. -
ImportError: cannot import name 'run' from 'juju.jasyncio'
cause Attempting to import `run` from `juju.jasyncio` after it was deprecated and potentially removed or refactored.fixUpdate your import statement to `from juju.loop import run` or use `asyncio.run` directly for running async functions. -
Secret value appears truncated or modified (e.g., ends in 'P', 'Q', or '=')
cause A bug in `python-libjuju` versions prior to 3.6.1.3 incorrectly stripped certain trailing characters from secret values.fixUpgrade `python-libjuju` to version 3.6.1.3 or a later release.
Warnings
- breaking Direct dependency `websockets` version 14.0 breaks `python-libjuju` versions below 3.5.2.1 due to internal API changes and dropped Python 3.8 support.
- deprecated The `juju.jasyncio` module, particularly `juju.jasyncio.run`, was deprecated in favor of `juju.loop.run` or using `asyncio.run` directly.
- gotcha A bug in earlier versions incorrectly stripped trailing 'P', 'Q', and '=' characters from secret values when fetched or processed.
- gotcha The library is in maintenance mode, receiving only critical bug fixes. For Juju charm integration testing, it's recommended to migrate from `pytest-operator` to `jubilant` for better future compatibility and support.
Install
-
pip install juju
Imports
- Model
from juju.model import Model
- Controller
from juju.controller import Controller
- run
from juju.jasyncio import run
from juju.loop import run
Quickstart
import asyncio
import os
from juju.model import Model
async def main():
model_name = os.environ.get('JUJU_MODEL', 'controller:default') # e.g., 'controller:my-model'
model = Model()
try:
# Connect to a specific Juju model
await model.connect(model_name=model_name)
print(f"Connected to Juju model: {model.name}")
# Example: Get applications
applications = await model.get_applications()
print(f"Applications in model: {[app.name for app in applications]}")
except Exception as e:
print(f"Error connecting to Juju: {e}")
finally:
if model.is_connected:
await model.disconnect()
print("Disconnected from Juju model.")
if __name__ == '__main__':
# Ensure you have a Juju controller running and are logged in (e.g., via 'juju login')
# Optionally set JUJU_MODEL environment variable to connect to a specific model
asyncio.run(main())