CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-awscli

Universal Command Line Environment for AWS.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

plugin-system.mddocs/

Plugin System

Event-driven plugin architecture for extending AWS CLI functionality with custom handlers, commands, and integrations. The plugin system enables seamless extension of AWS CLI capabilities without modifying core code.

Capabilities

Plugin Loading

Core function for loading and initializing plugins with the AWS CLI.

def load_plugins(plugin_mapping, event_hooks=None, include_builtins=True):
    """
    Load and initialize plugins for AWS CLI.
    
    Parameters:
        plugin_mapping: dict, mapping of plugin names to module paths
        event_hooks: botocore event emitter, optional event system
        include_builtins: bool, whether to load built-in plugins (default True)
    """

Built-in Plugins

Pre-defined plugins that are loaded by default.

BUILTIN_PLUGINS: dict  # {'__builtin__': 'awscli.handlers'}

Usage Example:

from awscli.plugin import load_plugins

# Load custom plugins
custom_plugins = {
    'my-plugin': 'mypackage.aws_plugin',
    'dev-tools': 'devtools.aws_extensions'
}

load_plugins(custom_plugins, include_builtins=True)

Plugin Development

Basic Plugin Structure

# mypackage/aws_plugin.py
def awscli_initialize(cli):
    """
    Plugin initialization function called by AWS CLI.
    
    Parameters:
        cli: AWS CLI instance for registration
    """
    # Register event handlers
    cli.register('before-call', modify_request)
    cli.register('after-call', process_response)
    
    # Register custom commands
    cli.register('building-command-table.main', add_commands)

def modify_request(event_name=None, **kwargs):
    """Handle before-call events."""
    print(f"Intercepting request: {event_name}")

def process_response(parsed, **kwargs):
    """Handle after-call events."""
    print(f"Processing response: {parsed}")

def add_commands(command_table, session, **kwargs):
    """Add custom commands to command table."""
    from mypackage.commands import CustomCommand
    command_table['custom'] = CustomCommand(session)

Event Registration Patterns

def register_handlers(cli):
    """Register various event handlers."""
    
    # Command table modification
    cli.register('building-command-table.main', add_main_commands)
    cli.register('building-command-table.s3', add_s3_commands)
    
    # Argument table modification
    cli.register('building-argument-table.s3.ls', add_s3_ls_args)
    
    # Request/response processing
    cli.register('before-call', modify_all_requests)
    cli.register('before-call.s3.ListObjects', modify_s3_list_request)
    cli.register('after-call', process_all_responses)
    
    # Output processing
    cli.register('doc-output', modify_documentation)

Advanced Plugin Features

Command Extension

def add_s3_commands(command_table, session, **kwargs):
    """Add custom S3 commands."""
    from mypackage.s3_commands import S3SyncAdvanced
    command_table['sync-advanced'] = S3SyncAdvanced(session)

def add_s3_ls_args(argument_table, **kwargs):
    """Add arguments to s3 ls command."""
    from awscli.arguments import CustomArgument
    
    argument_table['include-metadata'] = CustomArgument(
        'include-metadata',
        help_text='Include object metadata in output',
        action='store_true'
    )

Request Modification

def modify_requests(event_name, endpoint, request_dict, **kwargs):
    """Modify AWS service requests."""
    
    # Add custom headers
    if 'headers' not in request_dict:
        request_dict['headers'] = {}
    request_dict['headers']['X-Custom-Plugin'] = 'MyPlugin-1.0'
    
    # Modify parameters
    if 'params' in request_dict:
        # Add default parameters
        request_dict['params'].setdefault('MaxItems', 100)

Response Processing

def process_responses(parsed, **kwargs):
    """Process AWS service responses."""
    
    # Add custom fields
    if isinstance(parsed, dict):
        parsed['_plugin_processed'] = True
        parsed['_processing_time'] = time.time()
    
    # Transform data
    if 'Instances' in parsed:
        for instance in parsed['Instances']:
            # Add computed fields
            instance['_display_name'] = f"{instance.get('InstanceId', 'unknown')}"

Plugin Configuration

Plugin Discovery

Plugins can be configured through AWS CLI configuration:

# ~/.aws/config
[plugins]
my-plugin = mypackage.aws_plugin
dev-tools = devtools.aws_extensions

Environment-Based Loading

import os
from awscli.plugin import load_plugins

# Load plugins from environment
plugin_paths = os.environ.get('AWS_CLI_PLUGINS', '').split(',')
plugin_mapping = {}

for plugin_path in plugin_paths:
    if plugin_path.strip():
        name = plugin_path.split('.')[-1]
        plugin_mapping[name] = plugin_path.strip()

load_plugins(plugin_mapping)

Conditional Plugin Loading

def conditional_load(cli):
    """Load plugins based on conditions."""
    
    # Only load in development
    if os.environ.get('AWS_CLI_ENV') == 'development':
        cli.register('building-command-table.main', add_dev_commands)
    
    # Load based on AWS profile
    current_profile = cli.session.get_config_variable('profile')
    if current_profile == 'production':
        cli.register('before-call', add_production_safeguards)

Plugin Distribution

Package Structure

mypackage/
├── __init__.py
├── aws_plugin.py          # Main plugin module
├── commands/
│   ├── __init__.py
│   └── custom_commands.py # Custom command implementations
├── handlers/
│   ├── __init__.py
│   └── event_handlers.py  # Event handler implementations
└── setup.py               # Package configuration

Setup Configuration

# setup.py
from setuptools import setup, find_packages

setup(
    name='aws-cli-my-plugin',
    version='1.0.0',
    packages=find_packages(),
    install_requires=[
        'awscli>=1.40.0',
        'botocore>=1.30.0'
    ],
    entry_points={
        'console_scripts': [
            'aws-my-plugin=mypackage.cli:main'
        ]
    }
)

Plugin Testing

import unittest
from awscli.testutils import BaseCLIDriverTest

class TestMyPlugin(BaseCLIDriverTest):
    def setUp(self):
        super().setUp()
        # Load plugin for testing
        from mypackage.aws_plugin import awscli_initialize
        awscli_initialize(self.driver)
    
    def test_custom_command(self):
        """Test custom command functionality."""
        result = self.run_cmd(['custom', '--help'])
        self.assertEqual(result.rc, 0)
        self.assertIn('Custom command', result.stdout)
    
    def test_event_handler(self):
        """Test event handler integration."""
        result = self.run_cmd(['s3', 'ls'])
        # Verify plugin modifications
        self.assertIn('plugin_processed', result.stdout)

Install with Tessl CLI

npx tessl i tessl/pypi-awscli

docs

argument-processing.md

command-system.md

core-driver.md

custom-commands.md

error-handling.md

help-system.md

index.md

output-formatting.md

plugin-system.md

testing-framework.md

utilities.md

tile.json