duplocloud-client 0.0.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. duplocloud-client-0.0.4/.coveragerc +6 -0
  2. duplocloud-client-0.0.4/.github/workflows/publish.yaml +38 -0
  3. duplocloud-client-0.0.4/.github/workflows/test.yml +41 -0
  4. duplocloud-client-0.0.4/.gitignore +8 -0
  5. duplocloud-client-0.0.4/.gitmodules +3 -0
  6. duplocloud-client-0.0.4/CONTRIBUTING.md +35 -0
  7. duplocloud-client-0.0.4/PKG-INFO +30 -0
  8. duplocloud-client-0.0.4/README.md +16 -0
  9. duplocloud-client-0.0.4/dev-requirements.txt +9 -0
  10. duplocloud-client-0.0.4/pyproject.toml +20 -0
  11. duplocloud-client-0.0.4/setup.cfg +40 -0
  12. duplocloud-client-0.0.4/setup.py +6 -0
  13. duplocloud-client-0.0.4/src/duplo_resource/__init__.py +0 -0
  14. duplocloud-client-0.0.4/src/duplo_resource/service.py +32 -0
  15. duplocloud-client-0.0.4/src/duplo_resource/tenant.py +18 -0
  16. duplocloud-client-0.0.4/src/duplo_resource/user.py +33 -0
  17. duplocloud-client-0.0.4/src/duplocloud/__init__.py +0 -0
  18. duplocloud-client-0.0.4/src/duplocloud/cli.py +34 -0
  19. duplocloud-client-0.0.4/src/duplocloud/cli_test.py +4 -0
  20. duplocloud-client-0.0.4/src/duplocloud/client.py +56 -0
  21. duplocloud-client-0.0.4/src/duplocloud/errors.py +9 -0
  22. duplocloud-client-0.0.4/src/duplocloud/resource.py +22 -0
  23. duplocloud-client-0.0.4/src/duplocloud_client.egg-info/PKG-INFO +30 -0
  24. duplocloud-client-0.0.4/src/duplocloud_client.egg-info/SOURCES.txt +27 -0
  25. duplocloud-client-0.0.4/src/duplocloud_client.egg-info/dependency_links.txt +1 -0
  26. duplocloud-client-0.0.4/src/duplocloud_client.egg-info/entry_points.txt +7 -0
  27. duplocloud-client-0.0.4/src/duplocloud_client.egg-info/requires.txt +2 -0
  28. duplocloud-client-0.0.4/src/duplocloud_client.egg-info/top_level.txt +2 -0
@@ -0,0 +1,6 @@
1
+ [run]
2
+ omit =
3
+ *_test.py
4
+ foo.py
5
+ src/conftest.py
6
+ **/__*__.py
@@ -0,0 +1,38 @@
1
+ name: Python Publish
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - '*'
7
+
8
+ jobs:
9
+ publish:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+
13
+ # checkout code
14
+ - name: Checkout Code
15
+ uses: actions/checkout@v3
16
+
17
+ # install python
18
+ - name: Set up Python 3.11
19
+ uses: actions/setup-python@v4
20
+ with:
21
+ python-version: "3.11"
22
+
23
+ # install the project
24
+ - name: Install Dependencies
25
+ run: |
26
+ pip install -r dev-requirements.txt
27
+ pip install .
28
+
29
+ - name: Run the Build
30
+ run: |
31
+ version=$(python -m setuptools_scm)
32
+ echo "Building Version: $version"
33
+ python -m build
34
+
35
+ - name: Publish Package to PyPI
36
+ uses: pypa/gh-action-pypi-publish@release/v1
37
+ with:
38
+ password: ${{ secrets.PYPI_API_TOKEN }}
@@ -0,0 +1,41 @@
1
+ name: Python Test
2
+
3
+ on: [push]
4
+
5
+ jobs:
6
+ test:
7
+
8
+ runs-on: ubuntu-latest
9
+ strategy:
10
+ matrix:
11
+ python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
12
+
13
+ steps:
14
+
15
+ # checkout code
16
+ - name: Checkout Code
17
+ uses: actions/checkout@v3
18
+
19
+ # install python
20
+ - name: Set up Python ${{ matrix.python-version }}
21
+ uses: actions/setup-python@v4
22
+ with:
23
+ python-version: ${{ matrix.python-version }}
24
+
25
+ # install the project
26
+ - name: Install dependencies
27
+ run: |
28
+ pip install -r dev-requirements.txt
29
+ pip install .
30
+
31
+ # do linting
32
+ - name: Lint with ruff
33
+ run: |
34
+ # stop the build if there are Python syntax errors or undefined names
35
+ ruff --format=github --select=E9,F63,F7,F82 --target-version=py37 .
36
+
37
+ # run the tests
38
+ - name: Test with pytest
39
+ run: |
40
+
41
+ pytest src
@@ -0,0 +1,8 @@
1
+ build
2
+ dist
3
+ *.egg-info
4
+ .ruff_cache
5
+ .pytest_cache
6
+ .coverage
7
+ __pycache__
8
+ .direnv
@@ -0,0 +1,3 @@
1
+ [submodule "wiki"]
2
+ path = wiki
3
+ url = https://github.com/duplocloud/py-client.wiki.git
@@ -0,0 +1,35 @@
1
+ # Contributing
2
+
3
+ Follow these steps to be proper.
4
+
5
+ ## Version Bump
6
+
7
+ Make sure you have the duplo git-bump installed and then run
8
+
9
+ ```sh
10
+ git bump -v '[patch, major, minor]'
11
+ ```
12
+ e.g. a small patch do this:
13
+ ```sh
14
+ git bump -v patch
15
+ ```
16
+
17
+ Doing this creates a proper semver which will trigger a new publish pipeline.
18
+
19
+ ## Build
20
+
21
+ Build the package which creates the artifact in the dist folder.
22
+ ```
23
+ python -m build
24
+ ```
25
+
26
+ ## Semver with Setuptools SCM command
27
+
28
+ Get the current version
29
+ ```
30
+ python -m setuptools_scm
31
+ ```
32
+
33
+ When building the artifact the setuptools scm tool will use the a snazzy semver logic to determine version.
34
+
35
+ *ref:* [SetupTools SCM](https://pypi.org/project/setuptools-scm/)
@@ -0,0 +1,30 @@
1
+ Metadata-Version: 2.1
2
+ Name: duplocloud-client
3
+ Version: 0.0.4
4
+ Summary: Generic DuploClient for Python apps.
5
+ Home-page: https://github.com/duplocloud/py-client
6
+ Author: Kelly Ferrone
7
+ Author-email: kelly@duplocloud.net
8
+ Project-URL: Bug Tracker, https://github.com/duplocloud/py-client/issues
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.6
13
+ Description-Content-Type: text/markdown
14
+
15
+ # Duplocloud Py Client
16
+
17
+ A package to spawn service clients for working with Duplocloud.
18
+
19
+ ## Installation
20
+
21
+ From PyPi:
22
+ ```
23
+ pip install duplocloud-client
24
+ ```
25
+
26
+ From source:
27
+ ```
28
+ pip install .
29
+ ```
30
+
@@ -0,0 +1,16 @@
1
+ # Duplocloud Py Client
2
+
3
+ A package to spawn service clients for working with Duplocloud.
4
+
5
+ ## Installation
6
+
7
+ From PyPi:
8
+ ```
9
+ pip install duplocloud-client
10
+ ```
11
+
12
+ From source:
13
+ ```
14
+ pip install .
15
+ ```
16
+
@@ -0,0 +1,9 @@
1
+ pytest
2
+ ruff
3
+ pytest-black
4
+ pytest-isort
5
+ pytest-cov
6
+ invoke
7
+ setuptools_scm
8
+ build
9
+ twine
@@ -0,0 +1,20 @@
1
+ [project]
2
+ name = "duplocloud-client"
3
+ dynamic = ["version"]
4
+ [build-system]
5
+ requires = [
6
+ "setuptools>=42",
7
+ "setuptools_scm[toml]>=6.2",
8
+ "wheel",
9
+ "build",
10
+ "twine"
11
+ ]
12
+ build-backend = "setuptools.build_meta"
13
+ [tool.pytest.ini_options]
14
+ minversion = "6.0"
15
+ addopts = "--verbose --cov=src --cov-report term-missing"
16
+ testpaths = [
17
+ "tests",
18
+ "integration",
19
+ ]
20
+ [tool.setuptools_scm]
@@ -0,0 +1,40 @@
1
+ [metadata]
2
+ name = duplocloud-client
3
+ author = Kelly Ferrone
4
+ author_email = kelly@duplocloud.net
5
+ description = Generic DuploClient for Python apps.
6
+ long_description = file: README.md
7
+ long_description_content_type = text/markdown
8
+ url = https://github.com/duplocloud/py-client
9
+ project_urls =
10
+ Bug Tracker = https://github.com/duplocloud/py-client/issues
11
+ classifiers =
12
+ Programming Language :: Python :: 3
13
+ License :: OSI Approved :: MIT License
14
+ Operating System :: OS Independent
15
+
16
+ [options]
17
+ package_dir =
18
+ = src
19
+ packages = find:
20
+ include_package_data = True
21
+ python_requires = >=3.6
22
+ install_requires =
23
+ requests >= 2.22.0
24
+ cachetools >= 5.2.0
25
+
26
+ [options.packages.find]
27
+ where = src
28
+
29
+ [options.entry_points]
30
+ console_scripts =
31
+ duploctl = duplocloud.cli:main
32
+ duplocloud.net =
33
+ service = duplo_resource.service:DuploService
34
+ tenant = duplo_resource.tenant:DuploTenant
35
+ user = duplo_resource.user:DuploUser
36
+
37
+ [egg_info]
38
+ tag_build =
39
+ tag_date = 0
40
+
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env python3
2
+
3
+ from setuptools import setup
4
+
5
+ if __name__ == '__main__':
6
+ setup()
File without changes
@@ -0,0 +1,32 @@
1
+ from duplocloud.client import DuploClient
2
+ from duplocloud.resource import DuploResource
3
+ from duplocloud.errors import DuploError
4
+
5
+ class DuploService(DuploResource):
6
+
7
+ def __init__(self, duplo: DuploClient):
8
+ super().__init__(duplo)
9
+ self.tenent_svc = duplo.service('tenant')
10
+
11
+ def list(self):
12
+ """Retrieve a list of all services in a tenant."""
13
+ tenant_id = self.get_tenant()["TenantId"]
14
+ return self.duplo.get(f"subscriptions/{tenant_id}/GetReplicationControllers")
15
+
16
+ def find(self, service_name):
17
+ """Find a service by name."""
18
+ try:
19
+ return [s for s in self.list() if s["Name"] == service_name][0]
20
+ except IndexError:
21
+ raise DuploError(f"Service '{service_name}' not found", 404)
22
+
23
+ def update_image(self, service_name, image):
24
+ tenant_id = self.get_tenant()["TenantId"]
25
+ service = self.find(service_name)
26
+ allocation_tags = service["Template"]["AllocationTags"]
27
+ data = {
28
+ "Name": service_name,
29
+ "Image": image,
30
+ "AllocationTags": allocation_tags
31
+ }
32
+ return self.duplo.post(f"subscriptions/{tenant_id}/ReplicationControllerChange", data)
@@ -0,0 +1,18 @@
1
+ from duplocloud.client import DuploClient
2
+ from duplocloud.resource import DuploResource
3
+ from duplocloud.errors import DuploError
4
+
5
+ class DuploTenant(DuploResource):
6
+ def __init__(self, duplo: DuploClient):
7
+ super().__init__(duplo)
8
+
9
+ def list(self):
10
+ """Retrieve a list of all tenants in the Duplo system."""
11
+ return self.duplo.get("adminproxy/GetTenantNames")
12
+
13
+ def find(self, tenant_name):
14
+ """Find a tenant by name."""
15
+ try:
16
+ return [t for t in self.list() if t["AccountName"] == tenant_name][0]
17
+ except IndexError:
18
+ raise DuploError(f"Tenant '{tenant_name}' not found", 404)
@@ -0,0 +1,33 @@
1
+ from duplocloud.client import DuploClient
2
+ from duplocloud.resource import DuploResource
3
+ from duplocloud.errors import DuploError
4
+
5
+ class DuploUser(DuploResource):
6
+ def __init__(self, duplo: DuploClient):
7
+ super().__init__(duplo)
8
+ self.tenent_svc = duplo.service('tenant')
9
+
10
+ def add_tenant(self, username, tenant):
11
+ """Retrieve a list of all tenants in the Duplo system."""
12
+ tenant_id = self.tenent_svc.find(tenant)["TenantId"]
13
+ res = self.duplo.post("admin/UpdateUserAccess", {
14
+ "Policy": { "IsReadOnly": None },
15
+ "Username": username,
16
+ "TenantId": tenant_id
17
+ })
18
+ # check http response is 204
19
+ if res.status_code != 204:
20
+ raise DuploError(f"Failed to add user '{username}' to tenant '{tenant}'", res["status_code"])
21
+ else:
22
+ return f"User '{username}' added to tenant '{tenant}'"
23
+
24
+ def find(self, username):
25
+ """Find a User by their username."""
26
+ try:
27
+ return [u for u in self.list() if u["Username"] == username][0]
28
+ except IndexError:
29
+ raise DuploError(f"User '{username}' not found", 404)
30
+
31
+ def list(self):
32
+ """Retrieve a list of all users in the Duplo system."""
33
+ return self.duplo.get("admin/GetAllUserRoles")
File without changes
@@ -0,0 +1,34 @@
1
+ from .client import DuploClient
2
+ import argparse
3
+ import os
4
+
5
+ def main():
6
+ env, args = load_env()
7
+ client = DuploClient(
8
+ host=env.host,
9
+ token=env.token,
10
+ tenant=env.tenant
11
+ )
12
+ service = client.service(env.service)
13
+ service.exec(env.subcmd, args)
14
+
15
+ def load_env():
16
+ """Get the environment variables for the Duplo session."""
17
+ parser = argparse.ArgumentParser(
18
+ prog='duplocloud-cli',
19
+ description='Duplo Cloud CLI',
20
+ )
21
+ parser.add_argument('service', help='The service to run')
22
+ parser.add_argument('subcmd', help='The subcommand to run')
23
+ parser.add_argument('-t', '--tenant',
24
+ help='The tenant to be scope into',
25
+ default=os.getenv('DUPLO_TENANT', 'default'))
26
+ parser.add_argument('-H', '--host',
27
+ help='The tenant to be scope into',
28
+ default=os.getenv('DUPLO_HOST', None))
29
+ parser.add_argument('-p', '--token',
30
+ help='The token/password to authenticate with',
31
+ default=os.getenv('DUPLO_TOKEN', None))
32
+ return parser.parse_known_args()
33
+
34
+
@@ -0,0 +1,4 @@
1
+ import pytest
2
+
3
+ def test_app():
4
+ assert True
@@ -0,0 +1,56 @@
1
+
2
+ import requests
3
+ from cachetools import cached, TTLCache
4
+ from importlib.metadata import entry_points
5
+ import os
6
+
7
+ ENTRYPOINT="duplocloud.net"
8
+
9
+ class DuploClient():
10
+
11
+ def __init__(self, host, token, tenant="default", args=[]) -> None:
12
+ self.host = host
13
+ self.timeout = 10
14
+ self.args = args
15
+ self.tenant = tenant
16
+ self.headers = {
17
+ 'Content-Type': 'application/json',
18
+ 'Authorization': f"Bearer {token}"
19
+ }
20
+
21
+ def __str__(self) -> str:
22
+ return f"""
23
+ Client for Duplo at {self.host}
24
+ """
25
+
26
+ @cached(cache=TTLCache(maxsize=128, ttl=60))
27
+ def get(self, path):
28
+ response = requests.get(
29
+ url=f"{self.host}/{path}",
30
+ headers=self.headers,
31
+ timeout=self.timeout
32
+ )
33
+ return response.json()
34
+
35
+ def post(self, path, data={}):
36
+ return requests.post(
37
+ url=f"{self.host}/{path}",
38
+ headers=self.headers,
39
+ timeout=self.timeout,
40
+ json=data
41
+ )
42
+
43
+ def service(self, name):
44
+ """Load Service
45
+
46
+ Load a Service class from the entry points.
47
+ Args:
48
+ name: The name of the service.
49
+ Returns:
50
+ The callable krm function
51
+ """
52
+ eps = entry_points()[ENTRYPOINT]
53
+ # e = entry_points(group=group, name=kind)
54
+ e = [ep for ep in eps if ep.name == name][0]
55
+ svc = e.load()
56
+ return svc(self)
@@ -0,0 +1,9 @@
1
+
2
+ class DuploError(Exception):
3
+ """Base class for Duplo errors."""
4
+ def __init__(self, message, code=1, response=None):
5
+ super().__init__(message)
6
+ self.code = code
7
+ self.response = response
8
+ def __str__(self):
9
+ return f"{self.code}: {self.message}"
@@ -0,0 +1,22 @@
1
+ from .client import DuploClient
2
+ from .errors import DuploError
3
+
4
+ class DuploResource():
5
+
6
+ def __init__(self, duplo: DuploClient):
7
+ self.duplo = duplo
8
+ self.tenant = None
9
+
10
+ def get_tenant(self):
11
+ if not self.tenant:
12
+ self.tenant_svc = self.duplo.service("tenant")
13
+ self.tenant = self.tenant_svc.find(self.duplo.tenant_name)
14
+ return self.tenant
15
+
16
+ def exec(self, subcmd, args=[]):
17
+ if not (func := getattr(self, subcmd, None)):
18
+ raise ValueError(f"Invalid subcommand: {subcmd}")
19
+ try:
20
+ return print(func(*args))
21
+ except Exception as e:
22
+ raise DuploError(f"Error executing subcommand: {subcmd}") from e
@@ -0,0 +1,30 @@
1
+ Metadata-Version: 2.1
2
+ Name: duplocloud-client
3
+ Version: 0.0.4
4
+ Summary: Generic DuploClient for Python apps.
5
+ Home-page: https://github.com/duplocloud/py-client
6
+ Author: Kelly Ferrone
7
+ Author-email: kelly@duplocloud.net
8
+ Project-URL: Bug Tracker, https://github.com/duplocloud/py-client/issues
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.6
13
+ Description-Content-Type: text/markdown
14
+
15
+ # Duplocloud Py Client
16
+
17
+ A package to spawn service clients for working with Duplocloud.
18
+
19
+ ## Installation
20
+
21
+ From PyPi:
22
+ ```
23
+ pip install duplocloud-client
24
+ ```
25
+
26
+ From source:
27
+ ```
28
+ pip install .
29
+ ```
30
+
@@ -0,0 +1,27 @@
1
+ .coveragerc
2
+ .gitignore
3
+ .gitmodules
4
+ CONTRIBUTING.md
5
+ README.md
6
+ dev-requirements.txt
7
+ pyproject.toml
8
+ setup.cfg
9
+ setup.py
10
+ .github/workflows/publish.yaml
11
+ .github/workflows/test.yml
12
+ src/duplo_resource/__init__.py
13
+ src/duplo_resource/service.py
14
+ src/duplo_resource/tenant.py
15
+ src/duplo_resource/user.py
16
+ src/duplocloud/__init__.py
17
+ src/duplocloud/cli.py
18
+ src/duplocloud/cli_test.py
19
+ src/duplocloud/client.py
20
+ src/duplocloud/errors.py
21
+ src/duplocloud/resource.py
22
+ src/duplocloud_client.egg-info/PKG-INFO
23
+ src/duplocloud_client.egg-info/SOURCES.txt
24
+ src/duplocloud_client.egg-info/dependency_links.txt
25
+ src/duplocloud_client.egg-info/entry_points.txt
26
+ src/duplocloud_client.egg-info/requires.txt
27
+ src/duplocloud_client.egg-info/top_level.txt
@@ -0,0 +1,7 @@
1
+ [console_scripts]
2
+ duploctl = duplocloud.cli:main
3
+
4
+ [duplocloud.net]
5
+ service = duplo_resource.service:DuploService
6
+ tenant = duplo_resource.tenant:DuploTenant
7
+ user = duplo_resource.user:DuploUser
@@ -0,0 +1,2 @@
1
+ requests>=2.22.0
2
+ cachetools>=5.2.0
@@ -0,0 +1,2 @@
1
+ duplo_resource
2
+ duplocloud