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.
- duplocloud-client-0.0.4/.coveragerc +6 -0
- duplocloud-client-0.0.4/.github/workflows/publish.yaml +38 -0
- duplocloud-client-0.0.4/.github/workflows/test.yml +41 -0
- duplocloud-client-0.0.4/.gitignore +8 -0
- duplocloud-client-0.0.4/.gitmodules +3 -0
- duplocloud-client-0.0.4/CONTRIBUTING.md +35 -0
- duplocloud-client-0.0.4/PKG-INFO +30 -0
- duplocloud-client-0.0.4/README.md +16 -0
- duplocloud-client-0.0.4/dev-requirements.txt +9 -0
- duplocloud-client-0.0.4/pyproject.toml +20 -0
- duplocloud-client-0.0.4/setup.cfg +40 -0
- duplocloud-client-0.0.4/setup.py +6 -0
- duplocloud-client-0.0.4/src/duplo_resource/__init__.py +0 -0
- duplocloud-client-0.0.4/src/duplo_resource/service.py +32 -0
- duplocloud-client-0.0.4/src/duplo_resource/tenant.py +18 -0
- duplocloud-client-0.0.4/src/duplo_resource/user.py +33 -0
- duplocloud-client-0.0.4/src/duplocloud/__init__.py +0 -0
- duplocloud-client-0.0.4/src/duplocloud/cli.py +34 -0
- duplocloud-client-0.0.4/src/duplocloud/cli_test.py +4 -0
- duplocloud-client-0.0.4/src/duplocloud/client.py +56 -0
- duplocloud-client-0.0.4/src/duplocloud/errors.py +9 -0
- duplocloud-client-0.0.4/src/duplocloud/resource.py +22 -0
- duplocloud-client-0.0.4/src/duplocloud_client.egg-info/PKG-INFO +30 -0
- duplocloud-client-0.0.4/src/duplocloud_client.egg-info/SOURCES.txt +27 -0
- duplocloud-client-0.0.4/src/duplocloud_client.egg-info/dependency_links.txt +1 -0
- duplocloud-client-0.0.4/src/duplocloud_client.egg-info/entry_points.txt +7 -0
- duplocloud-client-0.0.4/src/duplocloud_client.egg-info/requires.txt +2 -0
- duplocloud-client-0.0.4/src/duplocloud_client.egg-info/top_level.txt +2 -0
|
@@ -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,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,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
|
+
|
|
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,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,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 @@
|
|
|
1
|
+
|