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

custom-commands.mddocs/

Custom Commands Framework

Extensible framework for creating custom CLI commands with built-in support for argument handling, help generation, and integration with the AWS CLI command hierarchy. This framework enables developers to extend AWS CLI with domain-specific commands and workflows.

Capabilities

Basic Command Class

The foundational class for creating custom AWS CLI commands with automatic integration into the command system.

class BasicCommand(CLICommand):
    NAME: str  # Command name (required)
    DESCRIPTION: str  # Command description for help (required)
    SYNOPSIS: str  # Command synopsis for help
    EXAMPLES: str  # Usage examples for help
    ARG_TABLE: dict  # Argument definitions
    SUBCOMMANDS: dict  # Subcommand definitions
    
    FROM_FILE: type  # Helper for loading content from files

Usage Example:

from awscli.customizations.commands import BasicCommand
from awscli.arguments import CustomArgument

class DeployCommand(BasicCommand):
    NAME = 'deploy'
    DESCRIPTION = 'Deploy application to AWS infrastructure'
    SYNOPSIS = 'aws deploy [--environment ENV] [--dry-run] APPLICATION'
    EXAMPLES = '''
    Deploy to staging environment:
      aws deploy --environment staging my-app
      
    Perform dry run deployment:
      aws deploy --dry-run --environment prod my-app
    '''
    
    ARG_TABLE = [
        CustomArgument(
            'application',
            help_text='Application name to deploy',
            positional_arg=True,
            required=True
        ),
        CustomArgument(
            'environment',
            help_text='Target environment (dev, staging, prod)',
            choices=['dev', 'staging', 'prod'],
            default='dev'
        ),
        CustomArgument(
            'dry-run',
            help_text='Perform deployment validation without making changes',
            action='store_true'
        )
    ]
    
    def _run_main(self, parsed_args, parsed_globals):
        app_name = parsed_args.application
        environment = parsed_args.environment
        dry_run = parsed_args.dry_run
        
        if dry_run:
            print(f"Would deploy {app_name} to {environment}")
            return 0
        
        print(f"Deploying {app_name} to {environment}...")
        # Deployment logic here
        return 0

File Content Loading

Helper class for loading documentation and configuration from external files.

class _FromFile:
    def __init__(self, *paths, **kwargs):
        """
        Initialize file loader for documentation content.
        
        Parameters:
            *paths: str, file paths to load content from
            **kwargs: additional options for content loading
        """

Usage Example:

class DocumentedCommand(BasicCommand):
    NAME = 'documented-command'
    DESCRIPTION = FROM_FILE('docs/command-description.txt')
    EXAMPLES = FROM_FILE('docs/command-examples.txt', 'docs/additional-examples.txt')
    
    def _run_main(self, parsed_args, parsed_globals):
        # Command implementation
        return 0

Command Development Patterns

Simple Command Structure

For straightforward commands with minimal arguments:

from awscli.customizations.commands import BasicCommand

class StatusCommand(BasicCommand):
    NAME = 'status'
    DESCRIPTION = 'Check AWS resource status'
    
    def _run_main(self, parsed_args, parsed_globals):
        print("Checking AWS resource status...")
        # Status checking logic
        return 0

Command with Arguments

For commands requiring user input and configuration:

class ConfigureCommand(BasicCommand):
    NAME = 'configure-app'
    DESCRIPTION = 'Configure application settings'
    
    ARG_TABLE = [
        CustomArgument(
            'config-file',
            help_text='Configuration file path',
            required=True,
            cli_type_name='string'
        ),
        CustomArgument(
            'region',
            help_text='AWS region',
            default='us-east-1'
        ),
        CustomArgument(
            'validate',
            help_text='Validate configuration before applying',
            action='store_true'
        )
    ]
    
    def _run_main(self, parsed_args, parsed_globals):
        config_file = parsed_args.config_file
        region = parsed_args.region
        validate = parsed_args.validate
        
        if validate:
            if not self._validate_config(config_file):
                return 1
        
        self._apply_config(config_file, region)
        return 0
    
    def _validate_config(self, config_file):
        # Validation logic
        return True
    
    def _apply_config(self, config_file, region):
        # Configuration application logic
        pass

Command with Subcommands

For complex commands with multiple operations:

class ManageCommand(BasicCommand):
    NAME = 'manage'
    DESCRIPTION = 'Manage AWS resources'
    
    SUBCOMMANDS = [
        {
            'name': 'create',
            'command_class': CreateResourceCommand
        },
        {
            'name': 'delete', 
            'command_class': DeleteResourceCommand
        },
        {
            'name': 'list',
            'command_class': ListResourcesCommand
        }
    ]

class CreateResourceCommand(BasicCommand):
    NAME = 'create'
    DESCRIPTION = 'Create new AWS resource'
    
    ARG_TABLE = [
        CustomArgument(
            'resource-type',
            help_text='Type of resource to create',
            choices=['instance', 'bucket', 'function'],
            required=True
        ),
        CustomArgument(
            'name',
            help_text='Resource name',
            required=True
        )
    ]
    
    def _run_main(self, parsed_args, parsed_globals):
        resource_type = parsed_args.resource_type
        name = parsed_args.name
        
        print(f"Creating {resource_type} named {name}")
        # Resource creation logic
        return 0

Advanced Command Features

Error Handling and Exit Codes

Commands should handle errors gracefully and return appropriate exit codes:

class RobustCommand(BasicCommand):
    NAME = 'robust-command'
    DESCRIPTION = 'Command with comprehensive error handling'
    
    def _run_main(self, parsed_args, parsed_globals):
        try:
            self._execute_operation()
            return 0  # Success
        except ValidationError as e:
            self._write_error(f"Validation failed: {e}")
            return 1  # Validation error
        except ServiceError as e:
            self._write_error(f"AWS service error: {e}")
            return 2  # Service error
        except FileNotFoundError as e:
            self._write_error(f"File not found: {e}")
            return 3  # File error
        except Exception as e:
            self._write_error(f"Unexpected error: {e}")
            return 255  # Unknown error
    
    def _write_error(self, message):
        import sys
        sys.stderr.write(f"ERROR: {message}\n")
    
    def _execute_operation(self):
        # Main operation logic
        pass

Integration with AWS Services

Commands can integrate with AWS services using the session:

class S3Command(BasicCommand):
    NAME = 's3-utility'
    DESCRIPTION = 'Custom S3 utility command'
    
    ARG_TABLE = [
        CustomArgument(
            'bucket',
            help_text='S3 bucket name',
            required=True
        ),
        CustomArgument(
            'operation',
            help_text='Operation to perform',
            choices=['list', 'sync', 'cleanup'],
            required=True
        )
    ]
    
    def _run_main(self, parsed_args, parsed_globals):
        # Get S3 client from session
        session = self._session
        s3_client = session.create_client('s3')
        
        bucket = parsed_args.bucket
        operation = parsed_args.operation
        
        if operation == 'list':
            return self._list_objects(s3_client, bucket)
        elif operation == 'sync':
            return self._sync_bucket(s3_client, bucket)
        elif operation == 'cleanup':
            return self._cleanup_bucket(s3_client, bucket)
    
    def _list_objects(self, s3_client, bucket):
        try:
            response = s3_client.list_objects_v2(Bucket=bucket)
            for obj in response.get('Contents', []):
                print(f"{obj['Key']} ({obj['Size']} bytes)")
            return 0
        except Exception as e:
            self._write_error(f"Failed to list objects: {e}")
            return 1

Output Formatting

Commands can use AWS CLI's output formatting:

class FormattedCommand(BasicCommand):
    NAME = 'formatted-output'
    DESCRIPTION = 'Command with formatted output'
    
    def _run_main(self, parsed_args, parsed_globals):
        # Generate data
        data = {
            'resources': [
                {'name': 'resource1', 'status': 'active'},
                {'name': 'resource2', 'status': 'inactive'}
            ],
            'total': 2
        }
        
        # Use CLI's output formatting
        from awscli.formatter import get_formatter
        formatter = get_formatter(
            parsed_globals.get('output', 'json'),
            parsed_args
        )
        
        formatter(data)
        return 0

Command Registration and Integration

Plugin-Based Registration

Commands are typically registered through the plugin system:

# In your plugin module
def register_commands(cli):
    """Register custom commands with AWS CLI."""
    cli.register('building-command-table.main', add_custom_commands)

def add_custom_commands(command_table, session, **kwargs):
    """Add custom commands to the command table."""
    command_table['deploy'] = DeployCommand(session)
    command_table['status'] = StatusCommand(session)
    command_table['manage'] = ManageCommand(session)

Direct Integration

For development and testing, commands can be integrated directly:

from awscli.clidriver import create_clidriver

# Create CLI driver
driver = create_clidriver()

# Add custom command to command table
driver.session.register(
    'building-command-table.main',
    lambda command_table, session, **kwargs: 
        command_table.update({'my-command': MyCommand(session)})
)

# Execute command
exit_code = driver.main(['my-command', '--help'])

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