Metadata-Version: 2.4
Name: infrahouse-core
Version: 0.25.0
Summary: Lightweight Python library with AWS and other general purpose classes.
Author-email: "InfraHouse Inc." <aleks@infrahouse.com>
Maintainer-email: Oleksandr Kuzminskyi <aleks@infrahouse.com>
License: Apache Software License 2.0
Project-URL: bugs, https://github.com/infrahouse/infrahouse-core/issues
Project-URL: changelog, https://github.com/infrahouse/infrahouse-core/commits/main/
Project-URL: homepage, https://github.com/infrahouse/infrahouse-core
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Testing
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: MacOS
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: License :: OSI Approved :: Apache Software License
Requires-Python: >=3.10
Description-Content-Type: text/x-rst
License-File: LICENSE
License-File: AUTHORS.rst
Requires-Dist: boto3~=1.36
Requires-Dist: cached-property~=2.0
Requires-Dist: diskcache~=5.6
Requires-Dist: ec2-metadata~=2.13
Requires-Dist: PyGithub~=2.4
Provides-Extra: dev
Requires-Dist: black~=26.1; extra == "dev"
Requires-Dist: build~=1.2; extra == "dev"
Requires-Dist: bump2version~=1.0; extra == "dev"
Requires-Dist: mdformat~=1.0; extra == "dev"
Requires-Dist: pytest~=9.0; extra == "dev"
Requires-Dist: pytest-cov~=7.0; extra == "dev"
Requires-Dist: pylint~=4.0; extra == "dev"
Requires-Dist: yamllint~=1.37; extra == "dev"
Provides-Extra: doc
Requires-Dist: Sphinx~=8.1; extra == "doc"
Dynamic: license-file

===============
InfraHouse Core
===============

.. image:: https://img.shields.io/badge/Need%20Help%3F-Contact%20Us-0066CC
   :target: https://infrahouse.com/contact
   :alt: Need Help? Contact Us

.. image:: https://img.shields.io/pypi/v/infrahouse_core.svg
   :target: https://pypi.python.org/pypi/infrahouse_core
   :alt: PyPI Version

.. image:: https://readthedocs.org/projects/infrahouse-core/badge/?version=latest
   :target: https://infrahouse-core.readthedocs.io/en/latest/?version=latest
   :alt: Documentation Status

.. image:: https://img.shields.io/github/release/infrahouse/infrahouse-core.svg
   :target: https://github.com/infrahouse/infrahouse-core/releases/latest
   :alt: Latest Release

.. image:: https://img.shields.io/badge/AWS-EC2%20%7C%20DynamoDB%20%7C%20Route53%20%7C%20SSM-orange?logo=amazonaws
   :target: https://aws.amazon.com/
   :alt: AWS Services

.. image:: https://img.shields.io/pypi/pyversions/infrahouse-core
   :target: https://pypi.python.org/pypi/infrahouse_core
   :alt: Python Versions

.. image:: https://img.shields.io/badge/License-Apache_2.0-blue.svg
   :target: https://github.com/infrahouse/infrahouse-core/blob/main/LICENSE
   :alt: License

Lightweight Python library with AWS and other general purpose classes.


* Free software: Apache Software License 2.0
* Documentation: https://infrahouse-core.readthedocs.io.


Requirements
------------

* Python 3.10+
* Linux or macOS (Windows is not supported)

Installation
------------

.. code-block:: bash

    pip install infrahouse-core


Features
--------

AWS Classes
~~~~~~~~~~~

* **EC2Instance** - Manage EC2 instances with SSM command execution support
* **ASGInstance** - EC2 instance within an AutoScaling Group (lifecycle state, protection, health)
* **ASG** - AutoScaling Group lifecycle management (instance refresh, lifecycle hooks)
* **DynamoDBTable** - DynamoDB operations with distributed locking support
* **Route53 Zone** - DNS record management (add/delete A records)
* **Secret** - AWS Secrets Manager operations (create, read, update, delete)
* **AWS Session Management** - SSO login, role assumption, credential handling via
  ``get_session()``, ``get_client()``, ``get_resource()`` helpers

GitHub Integration
~~~~~~~~~~~~~~~~~~

* **GitHubActions** - Manage self-hosted GitHub Actions runners
* **GitHubActionsRunner** - Query runner status, labels, and metadata
* Token generation from GitHub App credentials stored in AWS Secrets Manager

Orchestrator
~~~~~~~~~~~~~

* **OrchestratorRaftCluster** - Reconcile MySQL Orchestrator Raft membership against an ASG
* **OrchestratorRaftNode** - Interact with a single Orchestrator node's Raft API via SSM

Utilities
~~~~~~~~~

* **Input Validation** - Validators for AWS resource identifiers (instance IDs, ARNs, regions, DNS names)
* **Timeout** - Context manager for enforcing execution time limits (POSIX only)
* **Filesystem** - Secure permission management (``ensure_permissions()``)
* **Logging** - Configurable logging setup with stdout/stderr separation


Usage Examples
--------------

EC2 Instance with SSM Command Execution
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: python

    from infrahouse_core.aws.ec2_instance import EC2Instance

    # Connect to an instance (optionally assume a role for cross-account access)
    instance = EC2Instance(
        instance_id="i-0123456789abcdef0",
        region="us-east-1",
        role_arn="arn:aws:iam::123456789012:role/MyRole"  # optional
    )

    # Execute a command via SSM
    exit_code, stdout, stderr = instance.execute_command("hostname")

    # Access instance properties
    print(instance.private_ip)
    print(instance.hostname)
    print(instance.tags)

DynamoDB Distributed Lock
~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: python

    from infrahouse_core.aws.dynamodb import DynamoDBTable

    table = DynamoDBTable("my-lock-table", region="us-east-1")

    with table.lock("my-resource", timeout=30):
        # Critical section - only one process can hold this lock
        do_exclusive_work()

Route53 DNS Management
~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: python

    from infrahouse_core.aws.route53.zone import Zone

    zone = Zone(zone_name="example.com")

    # Add an A record
    zone.add_record("myhost", "10.0.0.1", ttl=300)

    # Delete an A record
    zone.delete_record("myhost", "10.0.0.1")

Secrets Manager
~~~~~~~~~~~~~~~

.. code-block:: python

    from infrahouse_core.aws.secretsmanager import Secret

    # Read a secret
    secret = Secret("my-app/api-key", region="us-east-1")
    print(secret.value)  # Returns dict if JSON, else string

    # Create or update a secret
    secret.ensure_present({"username": "admin", "password": "secret123"})

    # Cross-account access
    secret = Secret(
        "prod/database-creds",
        role_arn="arn:aws:iam::123456789012:role/SecretsReader"
    )

Cross-Account AWS Access
~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: python

    from infrahouse_core.aws import get_client, get_session

    # Get a client with assumed role
    ec2 = get_client(
        "ec2",
        role_arn="arn:aws:iam::123456789012:role/CrossAccountRole",
        region="us-west-2"
    )

    # Or get a session for multiple clients
    session = get_session(role_arn="arn:aws:iam::123456789012:role/MyRole")
    ec2 = session.client("ec2")
    s3 = session.client("s3")

Orchestrator Raft Reconciliation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: python

    from infrahouse_core.orchestrator import OrchestratorRaftCluster

    cluster = OrchestratorRaftCluster(
        "my-orchestrator-asg",
        region="us-east-1",
        role_arn="arn:aws:iam::123456789012:role/OrchestratorRole",  # optional
    )

    # Reconcile Raft peers with live ASG instances
    # (removes stale peers, adds missing ones)
    cluster.reconcile()

    # Inspect current state
    for node in cluster.nodes:
        print(f"{node.hostname}: leader={node.is_leader}")

GitHub Actions Runner Management
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: python

    from infrahouse_core.github import GitHubActions, GitHubAuth

    github = GitHubAuth(token="ghp_...", org="my-org")
    actions = GitHubActions(github)

    # List all runners
    for runner in actions.runners:
        print(f"{runner.name}: {runner.status}")

    # Find runners by label
    runners = actions.find_runners_by_label("self-hosted")


Contributing
------------

Contributions are welcome! Please see `CONTRIBUTING.rst`_ for guidelines.

.. _CONTRIBUTING.rst: https://github.com/infrahouse/infrahouse-core/blob/main/CONTRIBUTING.rst


License
-------

Apache Software License 2.0. See `LICENSE`_ for details.

.. _LICENSE: https://github.com/infrahouse/infrahouse-core/blob/main/LICENSE


Credits
-------

This package was created with Cookiecutter_ and the `audreyr/cookiecutter-pypackage`_ project template.

.. _Cookiecutter: https://github.com/audreyr/cookiecutter
.. _`audreyr/cookiecutter-pypackage`: https://github.com/audreyr/cookiecutter-pypackage
