tessl install tessl/pypi-python-libmaas@0.6.0Python client library for MAAS 2.0+ with sync/async support, providing machine provisioning, network management, and storage configuration.
Establish connections to MAAS servers using various authentication methods and profile-based configuration management.
Connect to MAAS server using API key authentication for programmatic access.
from maas.client import connect
def connect(url: str, *, apikey: str | None = None, insecure: bool = False) -> Client:
"""
Connect to MAAS server using API key authentication.
Parameters:
url (str): MAAS server URL ending with /MAAS/ (e.g., 'http://maas.example.com:5240/MAAS/')
apikey (str, optional): API key in format 'consumer_key:token_key:token_secret'.
If not provided, uses default profile.
insecure (bool, optional): If True, disables SSL certificate verification. Default: False
Returns:
Client: High-level client facade object for accessing MAAS resources
Raises:
MAASException: If connection fails or URL is invalid
ConnectError: If server is unreachable or URL is malformed
Note:
Automatically adapts to execution context (sync/async).
In async context, returns a coroutine that must be awaited.
"""Usage:
from maas.client import connect
# Connect with explicit API key
client = connect(
'http://maas.example.com:5240/MAAS/',
apikey='consumer_key:token_key:token_secret'
)
# Connect using default profile (no apikey parameter)
client = connect('http://maas.example.com:5240/MAAS/')
# Connect with insecure SSL (for self-signed certificates)
client = connect(
'https://maas.example.com:5240/MAAS/',
apikey='key',
insecure=True
)Connect to MAAS server using username and password credentials.
from maas.client import login
def login(url: str, *, username: str | None = None, password: str | None = None, insecure: bool = False) -> Client:
"""
Connect to MAAS server using username/password authentication.
Parameters:
url (str): MAAS server URL ending with /MAAS/
username (str, optional): MAAS username. If not provided, prompts interactively.
password (str, optional): MAAS password. If not provided, prompts interactively.
insecure (bool, optional): If True, disables SSL certificate verification. Default: False
Returns:
Client: High-level client facade object for accessing MAAS resources
Raises:
MAASException: If authentication fails or URL is invalid
LoginError: If credentials are invalid
LoginNotSupported: If server doesn't support password authentication
PasswordWithoutUsername: If password provided without username
UsernameWithoutPassword: If username provided without password
Note:
Automatically adapts to execution context (sync/async).
In async context, returns a coroutine that must be awaited.
"""Usage:
from maas.client import login
# Login with explicit credentials
client = login(
'http://maas.example.com:5240/MAAS/',
username='admin',
password='password'
)
# Login with interactive prompts (no username/password provided)
client = login('http://maas.example.com:5240/MAAS/')Store and manage connection profiles for easy access to multiple MAAS servers.
from maas.client.utils.profiles import Profile, ProfileStore, ProfileNotFound
class Profile:
"""
Configuration profile for MAAS connection.
Attributes:
name (str): Profile name
url (str): MAAS server URL
credentials (Credentials): API credentials
description (str): Optional profile description
"""
def __init__(self, name: str, url: str, credentials: Credentials | None = None, description: str | None = None) -> None: ...
class ProfileStore:
"""Manage storage and retrieval of connection profiles."""
def load(self, name: str) -> Profile:
"""
Load profile by name.
Args:
name (str): Profile name
Returns:
Profile: Loaded profile
Raises:
ProfileNotFound: If profile doesn't exist
"""
def save(self, profile: Profile) -> None:
"""
Save profile to storage.
Args:
profile (Profile): Profile to save
"""
def delete(self, name: str) -> None:
"""
Delete profile by name.
Args:
name (str): Profile name to delete
Raises:
ProfileNotFound: If profile doesn't exist
"""
def list(self) -> list[str]:
"""
List all stored profiles.
Returns:
list[str]: List of profile names
"""
def open(self) -> dict:
"""
Open profile database for editing.
Returns:
dict: Profile database
"""
class ProfileNotFound(Exception):
"""Raised when requested profile is not found."""Use stored profiles to create API sessions without re-entering credentials.
from maas.client.bones import SessionAPI
class SessionAPI:
@classmethod
def fromProfile(cls, profile: Profile) -> SessionAPI:
"""
Create SessionAPI from a Profile object.
Args:
profile (Profile): Profile containing URL, credentials, and description
Returns:
SessionAPI: Configured session API instance
"""
@classmethod
def fromProfileName(cls, name: str) -> SessionAPI:
"""
Create SessionAPI from a profile name.
Args:
name (str): Name of stored profile to load
Returns:
SessionAPI: Configured session API instance
Raises:
ProfileNotFound: If profile with given name doesn't exist
"""Usage:
from maas.client.utils.profiles import Profile, ProfileStore
from maas.client.utils.creds import Credentials
from maas.client.bones import SessionAPI
from maas.client.viscera import Origin
# Create credentials
creds = Credentials(
consumer_key='key',
token_key='token',
token_secret='secret'
)
# Create and save profile
profile = Profile(
name='production',
url='http://maas.example.com:5240/MAAS/',
credentials=creds,
description='Production MAAS server'
)
store = ProfileStore()
store.save(profile)
# Method 1: Load profile and connect using SessionAPI
loaded_profile = store.load('production')
session = SessionAPI.fromProfile(loaded_profile)
# Method 2: Connect directly by profile name
session = SessionAPI.fromProfileName('production')
# Use with Viscera API (Origin also supports these methods)
origin = Origin.fromProfile(loaded_profile)
# or
origin = Origin.fromProfileName('production')
# Access resources
machines = await origin.Machines.read()
for machine in machines:
print(machine.hostname)Handle OAuth credentials for MAAS API authentication.
from collections import namedtuple
from maas.client.utils.creds import Credentials
Credentials = namedtuple('Credentials', ['consumer_key', 'token_key', 'token_secret'])from maas.client.utils.auth import obtain_credentials, try_getpass
def obtain_credentials(credentials: str) -> Credentials:
"""
Parse credentials from string format.
Args:
credentials (str): Credentials string in format 'consumer_key:token_key:token_secret'
Returns:
Credentials: Parsed credentials namedtuple
Raises:
ValueError: If credentials string is malformed
"""
def try_getpass(prompt: str) -> str:
"""
Safely get password from user with fallback to standard input.
Args:
prompt (str): Password prompt text
Returns:
str: Password entered by user
"""Usage:
from maas.client.utils.creds import Credentials
from maas.client.utils.auth import obtain_credentials
# Create credentials directly
creds = Credentials(
consumer_key='my_consumer_key',
token_key='my_token_key',
token_secret='my_token_secret'
)
# Parse from string
creds = obtain_credentials('consumer_key:token_key:token_secret')
# Access credential components
print(creds.consumer_key)
print(creds.token_key)
print(creds.token_secret)All connection methods support async/await when used in async contexts.
import asyncio
from maas.client import connect, login
async def connect_async() -> Client:
"""Connect to MAAS asynchronously."""
# Async connection
client = await connect('http://maas.example.com:5240/MAAS/', apikey='key')
return client
async def login_async() -> Client:
"""Login to MAAS asynchronously."""
# Async login
client = await login('http://maas.example.com:5240/MAAS/', username='admin', password='pass')
return client
# Run async
client = asyncio.run(connect_async())Utility functions for validating and normalizing MAAS API URLs.
from maas.client.utils import api_url, ensure_trailing_slash
def api_url(string: str) -> str:
"""
Validate and normalize MAAS API URL.
Args:
string (str): URL to validate
Returns:
str: Normalized URL
Raises:
ValueError: If URL is invalid
"""
def ensure_trailing_slash(string: str) -> str:
"""
Ensure string ends with trailing slash.
Args:
string (str): String to process
Returns:
str: String with trailing slash
"""Low-level OAuth request signing for direct API calls.
from maas.client.utils import OAuthSigner, sign
class OAuthSigner:
"""OAuth 1.0a request signer for MAAS API."""
def __init__(self, consumer_key: str, token_key: str, token_secret: str) -> None: ...
def sign(self, url: str, method: str = 'GET') -> dict: ...
def sign(uri: str, headers: dict, credentials: Credentials) -> dict:
"""
Sign HTTP request with OAuth credentials.
Args:
uri (str): Request URI
headers (dict): HTTP headers to sign
credentials (Credentials): OAuth credentials
Returns:
dict: Signed headers
"""from maas.client import connect
from maas.client.bones.helpers import ConnectError, RemoteError
try:
client = connect('http://maas.example.com:5240/MAAS/', apikey='key')
except ConnectError as e:
print(f"Connection failed: {e}")
# Possible causes:
# - Invalid URL format
# - Network connectivity issues
# - Server not responding
except RemoteError as e:
print(f"Server error (status {e.status}): {e.content}")
# Server returned error response
# Check API key validityfrom maas.client import login
from maas.client.bones.helpers import (
LoginError,
LoginNotSupported,
PasswordWithoutUsername,
UsernameWithoutPassword
)
try:
client = login('http://maas.example.com:5240/MAAS/', username='admin', password='pass')
except LoginNotSupported:
print("Server requires API key authentication")
# Use connect() with API key instead
except PasswordWithoutUsername:
print("Password provided without username")
except UsernameWithoutPassword:
print("Username provided without password")
except LoginError as e:
print(f"Login failed: {e}")
# Check credentials are correctfrom collections import namedtuple
Credentials = namedtuple('Credentials', ['consumer_key', 'token_key', 'token_secret'])