digital-ocean-cluster


Namedigital-ocean-cluster JSON
Version 1.1.22 PyPI version JSON
download
home_pageNone
Summarydigital ocean cluster management through droplets
upload_time2025-02-10 23:07:32
maintainerNone
docs_urlNone
authorNone
requires_python>=3.10
licenseBSD 3-Clause License
keywords template-python-cmd
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # digital-ocean-cluster

A well tested library for managing a fleet of droplets.

[![Linting](../../actions/workflows/lint.yml/badge.svg)](../../actions/workflows/lint.yml)

[![MacOS_Tests](../../actions/workflows/push_macos.yml/badge.svg)](../../actions/workflows/push_macos.yml)
[![Ubuntu_Tests](../../actions/workflows/push_ubuntu.yml/badge.svg)](../../actions/workflows/push_ubuntu.yml)
[![Win_Tests](../../actions/workflows/push_win.yml/badge.svg)](../../actions/workflows/push_win.yml)


# About

This library concurrent creates and runs digital ocean droplets through the doctl command line interface. This api allows massive concurrency running each action on a seperate thread.

The amount of implemented features for doctl is very few, but just enough to bring up a Droplet cloud, install dependencies, and execute commands on the cluster.

To develop software, run `. ./activate`

# Windows

This environment requires you to use `git-bash`.

# Linting

Run `./lint.sh` to find linting errors using `pylint`, `flake8` and `mypy`.

# Pre-requesits

  * You will need to have an ssh key registered with digital ocean. This key must also be in your ~/.ssh folder.
  * You will need to have the doctl binary installed in your path.

TODO: Make a more minimal example

# Example

```python
"""
Unit test file.
"""

import os
import subprocess
import unittest
from pathlib import Path

from digital_ocean_cluster import (
    DigitalOceanCluster,
    Droplet,
    DropletCluster,
    DropletCreationArgs,
)

# os.environ["home"] = "/home/niteris"

IS_GITHUB = os.environ.get("GITHUB_ACTIONS", False)

TAGS = ["test", "cluster"]

CLUSTER_SIZE = 4


def install(droplet: Droplet) -> None:
    """Install a package."""
    # droplet.run_cmd("apt-get update")
    #droplet.run_cmd("apt-get install -y vim")
    droplet.copy_text_to("echo 'Install Done!'", Path("/root/test.sh"))

class DigitalOceanClusterTester(unittest.TestCase):
    """Main tester class."""

    @unittest.skipIf(IS_GITHUB, "Skipping test for GitHub Actions")
    def test_create_droplets(self) -> None:
        """Test command line interface (CLI)."""
        # first delete the previous cluster
        # create a cluster of 4 machines
        # Deleting the cluster
        deleted: list[Droplet] = DigitalOceanCluster.delete_cluster(TAGS)
        print(f"Deleted: {[d.name for d in deleted]}")

        creation_args: list[DropletCreationArgs] = [
            DropletCreationArgs(name=f"test-droplet-creation-{i}", tags=TAGS, install=install)
            for i in range(CLUSTER_SIZE)
        ]

        print(f"Creating droplets: {creation_args}")
        cluster: DropletCluster = DigitalOceanCluster.create_droplets(creation_args)
        self.assertEqual(len(cluster.droplets), CLUSTER_SIZE)
        self.assertEqual(len(cluster.failed_droplets), 0)

        # now run ls on all of them
        cmd = "pwd"
        result: dict[Droplet, CompletedProcess] = cluster.run_cmd(cmd)
        for _, cp in result.items():
            self.assertIn(
                "/root",
                cp.stdout,
                f"Error: {cp.returncode}\n\nstderr:\n{cp.stderr}\n\nstdout:\n{cp.stdout}",
            )

        content: str = "the quick brown fox jumps over the lazy dog"
        remote_path = Path("/root/test.txt")

        # now copy a file to all of them
        cluster.copy_text_to(content, remote_path)

        # now get the text back
        results: dict[Droplet, str | Exception] = cluster.copy_text_from(remote_path)
        for droplet, text in results.items():
            if isinstance(text, Exception):
                print(f"Error: {text}")
                self.fail(f"Droplet {droplet.name} failed\nError: {text}")
            else:
                print(f"Text: {text}")

        print("Deleting cluster")
        # now delete the cluster
        DigitalOceanCluster.delete_cluster(cluster)
        print("Deleted cluster")


if __name__ == "__main__":
    unittest.main()

```

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "digital-ocean-cluster",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": "template-python-cmd",
    "author": null,
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/72/07/9e68fb76c0e8a8fa9d87a67445b61f5a25cde082492071c7c10fe31d250b/digital_ocean_cluster-1.1.22.tar.gz",
    "platform": null,
    "description": "# digital-ocean-cluster\r\n\r\nA well tested library for managing a fleet of droplets.\r\n\r\n[![Linting](../../actions/workflows/lint.yml/badge.svg)](../../actions/workflows/lint.yml)\r\n\r\n[![MacOS_Tests](../../actions/workflows/push_macos.yml/badge.svg)](../../actions/workflows/push_macos.yml)\r\n[![Ubuntu_Tests](../../actions/workflows/push_ubuntu.yml/badge.svg)](../../actions/workflows/push_ubuntu.yml)\r\n[![Win_Tests](../../actions/workflows/push_win.yml/badge.svg)](../../actions/workflows/push_win.yml)\r\n\r\n\r\n# About\r\n\r\nThis library concurrent creates and runs digital ocean droplets through the doctl command line interface. This api allows massive concurrency running each action on a seperate thread.\r\n\r\nThe amount of implemented features for doctl is very few, but just enough to bring up a Droplet cloud, install dependencies, and execute commands on the cluster.\r\n\r\nTo develop software, run `. ./activate`\r\n\r\n# Windows\r\n\r\nThis environment requires you to use `git-bash`.\r\n\r\n# Linting\r\n\r\nRun `./lint.sh` to find linting errors using `pylint`, `flake8` and `mypy`.\r\n\r\n# Pre-requesits\r\n\r\n  * You will need to have an ssh key registered with digital ocean. This key must also be in your ~/.ssh folder.\r\n  * You will need to have the doctl binary installed in your path.\r\n\r\nTODO: Make a more minimal example\r\n\r\n# Example\r\n\r\n```python\r\n\"\"\"\r\nUnit test file.\r\n\"\"\"\r\n\r\nimport os\r\nimport subprocess\r\nimport unittest\r\nfrom pathlib import Path\r\n\r\nfrom digital_ocean_cluster import (\r\n    DigitalOceanCluster,\r\n    Droplet,\r\n    DropletCluster,\r\n    DropletCreationArgs,\r\n)\r\n\r\n# os.environ[\"home\"] = \"/home/niteris\"\r\n\r\nIS_GITHUB = os.environ.get(\"GITHUB_ACTIONS\", False)\r\n\r\nTAGS = [\"test\", \"cluster\"]\r\n\r\nCLUSTER_SIZE = 4\r\n\r\n\r\ndef install(droplet: Droplet) -> None:\r\n    \"\"\"Install a package.\"\"\"\r\n    # droplet.run_cmd(\"apt-get update\")\r\n    #droplet.run_cmd(\"apt-get install -y vim\")\r\n    droplet.copy_text_to(\"echo 'Install Done!'\", Path(\"/root/test.sh\"))\r\n\r\nclass DigitalOceanClusterTester(unittest.TestCase):\r\n    \"\"\"Main tester class.\"\"\"\r\n\r\n    @unittest.skipIf(IS_GITHUB, \"Skipping test for GitHub Actions\")\r\n    def test_create_droplets(self) -> None:\r\n        \"\"\"Test command line interface (CLI).\"\"\"\r\n        # first delete the previous cluster\r\n        # create a cluster of 4 machines\r\n        # Deleting the cluster\r\n        deleted: list[Droplet] = DigitalOceanCluster.delete_cluster(TAGS)\r\n        print(f\"Deleted: {[d.name for d in deleted]}\")\r\n\r\n        creation_args: list[DropletCreationArgs] = [\r\n            DropletCreationArgs(name=f\"test-droplet-creation-{i}\", tags=TAGS, install=install)\r\n            for i in range(CLUSTER_SIZE)\r\n        ]\r\n\r\n        print(f\"Creating droplets: {creation_args}\")\r\n        cluster: DropletCluster = DigitalOceanCluster.create_droplets(creation_args)\r\n        self.assertEqual(len(cluster.droplets), CLUSTER_SIZE)\r\n        self.assertEqual(len(cluster.failed_droplets), 0)\r\n\r\n        # now run ls on all of them\r\n        cmd = \"pwd\"\r\n        result: dict[Droplet, CompletedProcess] = cluster.run_cmd(cmd)\r\n        for _, cp in result.items():\r\n            self.assertIn(\r\n                \"/root\",\r\n                cp.stdout,\r\n                f\"Error: {cp.returncode}\\n\\nstderr:\\n{cp.stderr}\\n\\nstdout:\\n{cp.stdout}\",\r\n            )\r\n\r\n        content: str = \"the quick brown fox jumps over the lazy dog\"\r\n        remote_path = Path(\"/root/test.txt\")\r\n\r\n        # now copy a file to all of them\r\n        cluster.copy_text_to(content, remote_path)\r\n\r\n        # now get the text back\r\n        results: dict[Droplet, str | Exception] = cluster.copy_text_from(remote_path)\r\n        for droplet, text in results.items():\r\n            if isinstance(text, Exception):\r\n                print(f\"Error: {text}\")\r\n                self.fail(f\"Droplet {droplet.name} failed\\nError: {text}\")\r\n            else:\r\n                print(f\"Text: {text}\")\r\n\r\n        print(\"Deleting cluster\")\r\n        # now delete the cluster\r\n        DigitalOceanCluster.delete_cluster(cluster)\r\n        print(\"Deleted cluster\")\r\n\r\n\r\nif __name__ == \"__main__\":\r\n    unittest.main()\r\n\r\n```\r\n",
    "bugtrack_url": null,
    "license": "BSD 3-Clause License",
    "summary": "digital ocean cluster management through droplets",
    "version": "1.1.22",
    "project_urls": null,
    "split_keywords": [
        "template-python-cmd"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "72079e68fb76c0e8a8fa9d87a67445b61f5a25cde082492071c7c10fe31d250b",
                "md5": "01ea26255f22070f5cfd8543f01dafa1",
                "sha256": "877611de8314419a93ba731050e4d5f0be2268743c7be05b5a8ca95a8bd3f050"
            },
            "downloads": -1,
            "filename": "digital_ocean_cluster-1.1.22.tar.gz",
            "has_sig": false,
            "md5_digest": "01ea26255f22070f5cfd8543f01dafa1",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 22362,
            "upload_time": "2025-02-10T23:07:32",
            "upload_time_iso_8601": "2025-02-10T23:07:32.541737Z",
            "url": "https://files.pythonhosted.org/packages/72/07/9e68fb76c0e8a8fa9d87a67445b61f5a25cde082492071c7c10fe31d250b/digital_ocean_cluster-1.1.22.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-02-10 23:07:32",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "digital-ocean-cluster"
}
        
Elapsed time: 0.67469s