tuca 0.1__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.
- tuca-0.1/.github/workflows/build.yml +105 -0
- tuca-0.1/.gitignore +11 -0
- tuca-0.1/.python-version +1 -0
- tuca-0.1/PKG-INFO +214 -0
- tuca-0.1/README.md +201 -0
- tuca-0.1/pyproject.toml +27 -0
- tuca-0.1/src/tuca/__init__.py +42 -0
- tuca-0.1/src/tuca/_version.py +34 -0
- tuca-0.1/src/tuca/auth.py +47 -0
- tuca-0.1/src/tuca/clouding.py +133 -0
- tuca-0.1/src/tuca/config.py +13 -0
- tuca-0.1/src/tuca/endpoints/__init__.py +9 -0
- tuca-0.1/src/tuca/endpoints/endpoint.py +140 -0
- tuca-0.1/src/tuca/endpoints/firewalls.py +18 -0
- tuca-0.1/src/tuca/endpoints/images.py +40 -0
- tuca-0.1/src/tuca/endpoints/keypairs.py +68 -0
- tuca-0.1/src/tuca/endpoints/servers.py +181 -0
- tuca-0.1/src/tuca/endpoints/sizes.py +62 -0
- tuca-0.1/src/tuca/endpoints/snapshots.py +37 -0
- tuca-0.1/src/tuca/resource.py +19 -0
- tuca-0.1/src/tuca/version.py +8 -0
- tuca-0.1/uv.lock +452 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2026 René de Hesselle <dehesselle@web.de>
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
4
|
+
|
|
5
|
+
name: Build
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
jobs:
|
|
9
|
+
#-----------------------------------------------------------------------------
|
|
10
|
+
|
|
11
|
+
Build:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- name: Checkout repository
|
|
15
|
+
uses: actions/checkout@v6
|
|
16
|
+
with:
|
|
17
|
+
fetch-depth: 0
|
|
18
|
+
|
|
19
|
+
- name: Run Black
|
|
20
|
+
uses: psf/black@stable
|
|
21
|
+
with:
|
|
22
|
+
options: "--check --verbose"
|
|
23
|
+
|
|
24
|
+
- name: Install uv
|
|
25
|
+
uses: astral-sh/setup-uv@v7
|
|
26
|
+
|
|
27
|
+
- name: Build project
|
|
28
|
+
run: uv build
|
|
29
|
+
|
|
30
|
+
- name: Upload artifacts
|
|
31
|
+
uses: actions/upload-artifact@v6
|
|
32
|
+
with:
|
|
33
|
+
name: dist
|
|
34
|
+
path: dist/tuca*.*
|
|
35
|
+
|
|
36
|
+
#-----------------------------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
Prerelease:
|
|
39
|
+
runs-on: ubuntu-latest
|
|
40
|
+
permissions:
|
|
41
|
+
contents: write
|
|
42
|
+
needs: Build
|
|
43
|
+
if: startsWith(github.ref, 'refs/heads/develop')
|
|
44
|
+
steps:
|
|
45
|
+
- name: Download artifacts
|
|
46
|
+
uses: actions/download-artifact@v7
|
|
47
|
+
with:
|
|
48
|
+
name: dist
|
|
49
|
+
|
|
50
|
+
- name: Update prerelease
|
|
51
|
+
uses: ncipollo/release-action@v1
|
|
52
|
+
with:
|
|
53
|
+
name: develop
|
|
54
|
+
artifacts: tuca*.*
|
|
55
|
+
prerelease: true
|
|
56
|
+
allowUpdates: true
|
|
57
|
+
removeArtifacts: true
|
|
58
|
+
tag: latest
|
|
59
|
+
body: |
|
|
60
|
+
This prerelease follows the develop branch.
|
|
61
|
+
For testing purposes only.
|
|
62
|
+
|
|
63
|
+
#-----------------------------------------------------------------------------
|
|
64
|
+
|
|
65
|
+
Release:
|
|
66
|
+
runs-on: ubuntu-latest
|
|
67
|
+
permissions:
|
|
68
|
+
contents: write
|
|
69
|
+
needs: Build
|
|
70
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
71
|
+
steps:
|
|
72
|
+
- name: Download artifacts
|
|
73
|
+
uses: actions/download-artifact@v7
|
|
74
|
+
with:
|
|
75
|
+
name: dist
|
|
76
|
+
|
|
77
|
+
- name: Create release
|
|
78
|
+
uses: ncipollo/release-action@v1
|
|
79
|
+
with:
|
|
80
|
+
artifacts: tuca*.*
|
|
81
|
+
draft: true
|
|
82
|
+
|
|
83
|
+
#-----------------------------------------------------------------------------
|
|
84
|
+
|
|
85
|
+
PyPI:
|
|
86
|
+
runs-on: ubuntu-latest
|
|
87
|
+
permissions:
|
|
88
|
+
id-token: write
|
|
89
|
+
needs:
|
|
90
|
+
- Build
|
|
91
|
+
- Release
|
|
92
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
93
|
+
environment:
|
|
94
|
+
name: pypi
|
|
95
|
+
url: https://pypi.org/p/tuca
|
|
96
|
+
|
|
97
|
+
steps:
|
|
98
|
+
- name: Download artifacts
|
|
99
|
+
uses: actions/download-artifact@v7
|
|
100
|
+
with:
|
|
101
|
+
name: dist
|
|
102
|
+
path: dist/
|
|
103
|
+
|
|
104
|
+
- name: Publish to PyPI
|
|
105
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
tuca-0.1/.gitignore
ADDED
tuca-0.1/.python-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
tuca-0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tuca
|
|
3
|
+
Version: 0.1
|
|
4
|
+
Summary: tool using clouding api
|
|
5
|
+
Author-email: René de Hesselle <dehesselle@web.de>
|
|
6
|
+
Requires-Python: >=3.12
|
|
7
|
+
Requires-Dist: keyring>=25.7.0
|
|
8
|
+
Requires-Dist: pydantic>=2.12.5
|
|
9
|
+
Requires-Dist: python-slugify>=8.0.4
|
|
10
|
+
Requires-Dist: requests>=2.32.5
|
|
11
|
+
Requires-Dist: urlpath>=2.0.0
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
# tool using Clouding.io API
|
|
15
|
+
|
|
16
|
+
This is an unofficial CLI tool that interacts with the Clouding.io's REST API. Its main goal is to provide a simple interface that I can use to create and destroy servers from shell scripts. Therefore it neither provides access to all available API endpoints nor to all available attributes and/or actions.
|
|
17
|
+
|
|
18
|
+
The project status is best described as "alpha" as things are still very much in motion and specifically tailored towards my usecase.
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
`tuca` is on [PyPi](https://pypi.org/project/tuca/), you can use the package manager of your choice to set yourself up. Here is an example using `uv`:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
uv tool install tuca
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
### the basics
|
|
31
|
+
|
|
32
|
+
The CLI interface follows this pattern:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
tuca <endpoint> <action> [options]
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
- `endpoint` is the same as in https://api.clouding.io/docs/
|
|
39
|
+
- `action` is one of `create`, `list` and `delete`
|
|
40
|
+
- `options` depend on `endpoint` and `action`, consult `--help` for details
|
|
41
|
+
|
|
42
|
+
`tuca` writes pretty-printed JSON (no colors) to `stdout`. It's both human-readable and intended to be piped into `jq` for non-interactive usage. The following example shows the available SSH keys (redacted values) in a freshly created account:
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"keypairs": [
|
|
47
|
+
{
|
|
48
|
+
"fingerprint": "00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00",
|
|
49
|
+
"id": "xxxxxxxxxxxxxxxx",
|
|
50
|
+
"name": "default"
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The output is
|
|
57
|
+
|
|
58
|
+
- always organized as list, even if the result count is 1 or 0
|
|
59
|
+
- usually named after the endpoint
|
|
60
|
+
- contains only a limited number attributes, but always `id` and `name`
|
|
61
|
+
- limited to 100 entries
|
|
62
|
+
|
|
63
|
+
### authentication
|
|
64
|
+
|
|
65
|
+
Before showing you examples, you need to setup an API token first. You can do that via environment variable:
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
export CLOUDINGIO_API_TOKEN=my_secret_token
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Or, more securely, have tuca write it into your desktop's keyring. The following command will give you an interactive prompt to do that.
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
tuca auth create
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
_And before you say anything, I'm aware that `auth` is not an endpoint._
|
|
78
|
+
|
|
79
|
+
If you provide both, the environment variable takes precendence.
|
|
80
|
+
|
|
81
|
+
### here we go
|
|
82
|
+
|
|
83
|
+
Time to create your first server. First, pick an image.
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
tuca images list
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
<details>
|
|
90
|
+
<summary>Output</summary>
|
|
91
|
+
|
|
92
|
+
_(modified/shortened for brevity)_
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"sizes/flavors": [
|
|
97
|
+
...
|
|
98
|
+
{
|
|
99
|
+
"accessMethods": {
|
|
100
|
+
"password": "required",
|
|
101
|
+
"sshKey": "not-supported"
|
|
102
|
+
},
|
|
103
|
+
"id": "jXEm7yK3MJ2VYkQ9",
|
|
104
|
+
"minimumSizeGb": 25,
|
|
105
|
+
"name": "Windows 11 (English 64Bit | Based on Windows Server 2025)"
|
|
106
|
+
},
|
|
107
|
+
...
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
</details>
|
|
112
|
+
|
|
113
|
+
Now pick a size.
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
tuca flavors list
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
<details>
|
|
120
|
+
<summary>Output</summary>
|
|
121
|
+
|
|
122
|
+
_(modified/shortened for brevity)_
|
|
123
|
+
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"sizes/flavors": [
|
|
127
|
+
...
|
|
128
|
+
{
|
|
129
|
+
"id": "8x16",
|
|
130
|
+
"pricePerHour": 0.05472,
|
|
131
|
+
"pricePerMonthApprox": 39.9456,
|
|
132
|
+
"ramGb": 16,
|
|
133
|
+
"vCores": 8.0
|
|
134
|
+
},
|
|
135
|
+
...
|
|
136
|
+
]
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
</details>
|
|
140
|
+
|
|
141
|
+
That's all to create a server with minimal configuration.
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
# Windows 11 compatible image
|
|
145
|
+
# 8 cores, 16 GB RAM
|
|
146
|
+
# default firewall
|
|
147
|
+
# default image size
|
|
148
|
+
tuca servers create --image jXEm7yK3MJ2VYkQ9 --name MyWinServer --flavorid 8x16 --password start123
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
<details>
|
|
152
|
+
<summary>Output</summary>
|
|
153
|
+
|
|
154
|
+
```json
|
|
155
|
+
{
|
|
156
|
+
"servers": [
|
|
157
|
+
{
|
|
158
|
+
"createdAt": "2026-02-04T23:42:16",
|
|
159
|
+
"id": "mJOZBKqGP702Xjax",
|
|
160
|
+
"name": "MyWinServer",
|
|
161
|
+
"publicIp": null,
|
|
162
|
+
"status": "Pending"
|
|
163
|
+
}
|
|
164
|
+
]
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
</details>
|
|
168
|
+
|
|
169
|
+
Spooling up the server can take some time and you can check how it's doing.
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
tuca servers list --name MyWinServer
|
|
173
|
+
```
|
|
174
|
+
<details>
|
|
175
|
+
<summary>Output</summary>
|
|
176
|
+
|
|
177
|
+
```json
|
|
178
|
+
{
|
|
179
|
+
"servers": [
|
|
180
|
+
{
|
|
181
|
+
"createdAt": "2026-02-04T23:42:16",
|
|
182
|
+
"id": "mJOZBKqGP702Xjax",
|
|
183
|
+
"name": "MyWinServer",
|
|
184
|
+
"publicIp": "103.23.60.115",
|
|
185
|
+
"status": "Creating"
|
|
186
|
+
}
|
|
187
|
+
]
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
</details>
|
|
191
|
+
|
|
192
|
+
The server will be ready eventually.
|
|
193
|
+
|
|
194
|
+
<details>
|
|
195
|
+
<summary>Output</summary>
|
|
196
|
+
|
|
197
|
+
```json
|
|
198
|
+
{
|
|
199
|
+
"servers": [
|
|
200
|
+
{
|
|
201
|
+
"createdAt": "2026-02-04T23:42:16",
|
|
202
|
+
"id": "mJOZBKqGP702Xjax",
|
|
203
|
+
"name": "MyWinServer",
|
|
204
|
+
"publicIp": "103.23.60.115",
|
|
205
|
+
"status": "Active"
|
|
206
|
+
}
|
|
207
|
+
]
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
</details>
|
|
211
|
+
|
|
212
|
+
## License
|
|
213
|
+
|
|
214
|
+
[GPL-2.0-or-later](https://github.com/dehesselle/tuca/blob/main/LICENSE)
|
tuca-0.1/README.md
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# tool using Clouding.io API
|
|
2
|
+
|
|
3
|
+
This is an unofficial CLI tool that interacts with the Clouding.io's REST API. Its main goal is to provide a simple interface that I can use to create and destroy servers from shell scripts. Therefore it neither provides access to all available API endpoints nor to all available attributes and/or actions.
|
|
4
|
+
|
|
5
|
+
The project status is best described as "alpha" as things are still very much in motion and specifically tailored towards my usecase.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
`tuca` is on [PyPi](https://pypi.org/project/tuca/), you can use the package manager of your choice to set yourself up. Here is an example using `uv`:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
uv tool install tuca
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
### the basics
|
|
18
|
+
|
|
19
|
+
The CLI interface follows this pattern:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
tuca <endpoint> <action> [options]
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
- `endpoint` is the same as in https://api.clouding.io/docs/
|
|
26
|
+
- `action` is one of `create`, `list` and `delete`
|
|
27
|
+
- `options` depend on `endpoint` and `action`, consult `--help` for details
|
|
28
|
+
|
|
29
|
+
`tuca` writes pretty-printed JSON (no colors) to `stdout`. It's both human-readable and intended to be piped into `jq` for non-interactive usage. The following example shows the available SSH keys (redacted values) in a freshly created account:
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"keypairs": [
|
|
34
|
+
{
|
|
35
|
+
"fingerprint": "00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00",
|
|
36
|
+
"id": "xxxxxxxxxxxxxxxx",
|
|
37
|
+
"name": "default"
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The output is
|
|
44
|
+
|
|
45
|
+
- always organized as list, even if the result count is 1 or 0
|
|
46
|
+
- usually named after the endpoint
|
|
47
|
+
- contains only a limited number attributes, but always `id` and `name`
|
|
48
|
+
- limited to 100 entries
|
|
49
|
+
|
|
50
|
+
### authentication
|
|
51
|
+
|
|
52
|
+
Before showing you examples, you need to setup an API token first. You can do that via environment variable:
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
export CLOUDINGIO_API_TOKEN=my_secret_token
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Or, more securely, have tuca write it into your desktop's keyring. The following command will give you an interactive prompt to do that.
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
tuca auth create
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
_And before you say anything, I'm aware that `auth` is not an endpoint._
|
|
65
|
+
|
|
66
|
+
If you provide both, the environment variable takes precendence.
|
|
67
|
+
|
|
68
|
+
### here we go
|
|
69
|
+
|
|
70
|
+
Time to create your first server. First, pick an image.
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
tuca images list
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
<details>
|
|
77
|
+
<summary>Output</summary>
|
|
78
|
+
|
|
79
|
+
_(modified/shortened for brevity)_
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"sizes/flavors": [
|
|
84
|
+
...
|
|
85
|
+
{
|
|
86
|
+
"accessMethods": {
|
|
87
|
+
"password": "required",
|
|
88
|
+
"sshKey": "not-supported"
|
|
89
|
+
},
|
|
90
|
+
"id": "jXEm7yK3MJ2VYkQ9",
|
|
91
|
+
"minimumSizeGb": 25,
|
|
92
|
+
"name": "Windows 11 (English 64Bit | Based on Windows Server 2025)"
|
|
93
|
+
},
|
|
94
|
+
...
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
</details>
|
|
99
|
+
|
|
100
|
+
Now pick a size.
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
tuca flavors list
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
<details>
|
|
107
|
+
<summary>Output</summary>
|
|
108
|
+
|
|
109
|
+
_(modified/shortened for brevity)_
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"sizes/flavors": [
|
|
114
|
+
...
|
|
115
|
+
{
|
|
116
|
+
"id": "8x16",
|
|
117
|
+
"pricePerHour": 0.05472,
|
|
118
|
+
"pricePerMonthApprox": 39.9456,
|
|
119
|
+
"ramGb": 16,
|
|
120
|
+
"vCores": 8.0
|
|
121
|
+
},
|
|
122
|
+
...
|
|
123
|
+
]
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
</details>
|
|
127
|
+
|
|
128
|
+
That's all to create a server with minimal configuration.
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
# Windows 11 compatible image
|
|
132
|
+
# 8 cores, 16 GB RAM
|
|
133
|
+
# default firewall
|
|
134
|
+
# default image size
|
|
135
|
+
tuca servers create --image jXEm7yK3MJ2VYkQ9 --name MyWinServer --flavorid 8x16 --password start123
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
<details>
|
|
139
|
+
<summary>Output</summary>
|
|
140
|
+
|
|
141
|
+
```json
|
|
142
|
+
{
|
|
143
|
+
"servers": [
|
|
144
|
+
{
|
|
145
|
+
"createdAt": "2026-02-04T23:42:16",
|
|
146
|
+
"id": "mJOZBKqGP702Xjax",
|
|
147
|
+
"name": "MyWinServer",
|
|
148
|
+
"publicIp": null,
|
|
149
|
+
"status": "Pending"
|
|
150
|
+
}
|
|
151
|
+
]
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
</details>
|
|
155
|
+
|
|
156
|
+
Spooling up the server can take some time and you can check how it's doing.
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
tuca servers list --name MyWinServer
|
|
160
|
+
```
|
|
161
|
+
<details>
|
|
162
|
+
<summary>Output</summary>
|
|
163
|
+
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"servers": [
|
|
167
|
+
{
|
|
168
|
+
"createdAt": "2026-02-04T23:42:16",
|
|
169
|
+
"id": "mJOZBKqGP702Xjax",
|
|
170
|
+
"name": "MyWinServer",
|
|
171
|
+
"publicIp": "103.23.60.115",
|
|
172
|
+
"status": "Creating"
|
|
173
|
+
}
|
|
174
|
+
]
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
</details>
|
|
178
|
+
|
|
179
|
+
The server will be ready eventually.
|
|
180
|
+
|
|
181
|
+
<details>
|
|
182
|
+
<summary>Output</summary>
|
|
183
|
+
|
|
184
|
+
```json
|
|
185
|
+
{
|
|
186
|
+
"servers": [
|
|
187
|
+
{
|
|
188
|
+
"createdAt": "2026-02-04T23:42:16",
|
|
189
|
+
"id": "mJOZBKqGP702Xjax",
|
|
190
|
+
"name": "MyWinServer",
|
|
191
|
+
"publicIp": "103.23.60.115",
|
|
192
|
+
"status": "Active"
|
|
193
|
+
}
|
|
194
|
+
]
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
</details>
|
|
198
|
+
|
|
199
|
+
## License
|
|
200
|
+
|
|
201
|
+
[GPL-2.0-or-later](https://github.com/dehesselle/tuca/blob/main/LICENSE)
|
tuca-0.1/pyproject.toml
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "tuca"
|
|
3
|
+
dynamic = ["version"]
|
|
4
|
+
description = "tool using clouding api"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [{ name = "René de Hesselle", email = "dehesselle@web.de" }]
|
|
7
|
+
requires-python = ">=3.12"
|
|
8
|
+
dependencies = [
|
|
9
|
+
"keyring>=25.7.0",
|
|
10
|
+
"pydantic>=2.12.5",
|
|
11
|
+
"python-slugify>=8.0.4",
|
|
12
|
+
"requests>=2.32.5",
|
|
13
|
+
"urlpath>=2.0.0",
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
[project.scripts]
|
|
17
|
+
tuca = "tuca:main"
|
|
18
|
+
|
|
19
|
+
[build-system]
|
|
20
|
+
requires = ["hatchling", "hatch-vcs"]
|
|
21
|
+
build-backend = "hatchling.build"
|
|
22
|
+
|
|
23
|
+
[tool.hatch.version]
|
|
24
|
+
source = "vcs"
|
|
25
|
+
|
|
26
|
+
[tool.hatch.build.hooks.vcs]
|
|
27
|
+
version-file = "src/tuca/_version.py"
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2026 René de Hesselle <dehesselle@web.de>
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
|
|
7
|
+
from tuca.auth import setup_auth_cli
|
|
8
|
+
from tuca.config import config
|
|
9
|
+
from tuca.endpoints import (
|
|
10
|
+
setup_images_endpoint,
|
|
11
|
+
setup_keypairs_endpoint,
|
|
12
|
+
setup_servers_endpoint,
|
|
13
|
+
setup_sizes_endpoint,
|
|
14
|
+
setup_snapshots_endpoint,
|
|
15
|
+
)
|
|
16
|
+
from tuca.version import VERSION
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def main() -> None:
|
|
20
|
+
parser = argparse.ArgumentParser(description="unofficial CLI for Clouding.io")
|
|
21
|
+
parser.add_argument(
|
|
22
|
+
"-v",
|
|
23
|
+
"--verbose",
|
|
24
|
+
action="store_true",
|
|
25
|
+
default=False,
|
|
26
|
+
help="make output verbose",
|
|
27
|
+
)
|
|
28
|
+
parser.add_argument("--version", action="version", version=f"tuca {VERSION}")
|
|
29
|
+
endpoints = parser.add_subparsers(help="manageable endpoints", dest="endpoint")
|
|
30
|
+
setup_auth_cli(endpoints)
|
|
31
|
+
setup_images_endpoint(endpoints)
|
|
32
|
+
setup_keypairs_endpoint(endpoints)
|
|
33
|
+
setup_servers_endpoint(endpoints)
|
|
34
|
+
setup_snapshots_endpoint(endpoints)
|
|
35
|
+
setup_sizes_endpoint(endpoints)
|
|
36
|
+
|
|
37
|
+
args = parser.parse_args()
|
|
38
|
+
config.be_verbose = args.verbose
|
|
39
|
+
try:
|
|
40
|
+
args.func(args)
|
|
41
|
+
except AttributeError:
|
|
42
|
+
parser.print_usage()
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# file generated by setuptools-scm
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
|
|
4
|
+
__all__ = [
|
|
5
|
+
"__version__",
|
|
6
|
+
"__version_tuple__",
|
|
7
|
+
"version",
|
|
8
|
+
"version_tuple",
|
|
9
|
+
"__commit_id__",
|
|
10
|
+
"commit_id",
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
TYPE_CHECKING = False
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from typing import Tuple
|
|
16
|
+
from typing import Union
|
|
17
|
+
|
|
18
|
+
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
19
|
+
COMMIT_ID = Union[str, None]
|
|
20
|
+
else:
|
|
21
|
+
VERSION_TUPLE = object
|
|
22
|
+
COMMIT_ID = object
|
|
23
|
+
|
|
24
|
+
version: str
|
|
25
|
+
__version__: str
|
|
26
|
+
__version_tuple__: VERSION_TUPLE
|
|
27
|
+
version_tuple: VERSION_TUPLE
|
|
28
|
+
commit_id: COMMIT_ID
|
|
29
|
+
__commit_id__: COMMIT_ID
|
|
30
|
+
|
|
31
|
+
__version__ = version = '0.1'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 1)
|
|
33
|
+
|
|
34
|
+
__commit_id__ = commit_id = None
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2026 René de Hesselle <dehesselle@web.de>
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from argparse import _SubParsersAction
|
|
7
|
+
from enum import StrEnum, auto
|
|
8
|
+
from getpass import getpass
|
|
9
|
+
|
|
10
|
+
import keyring
|
|
11
|
+
|
|
12
|
+
SERVICENAME = "Clouding.io API token"
|
|
13
|
+
USERNAME = "tuca"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Action(StrEnum):
|
|
17
|
+
CREATE = auto()
|
|
18
|
+
DELETE = auto()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def set_token(_) -> None:
|
|
22
|
+
token = getpass("API token:")
|
|
23
|
+
keyring.set_password(SERVICENAME, USERNAME, token)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def get_token(_) -> str:
|
|
27
|
+
if api_token := os.getenv("CLOUDINGIO_API_TOKEN"):
|
|
28
|
+
return api_token
|
|
29
|
+
else:
|
|
30
|
+
return keyring.get_password(SERVICENAME, USERNAME)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def delete_token(_) -> None:
|
|
34
|
+
keyring.delete_password(SERVICENAME, USERNAME)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def setup_auth_cli(subparser: _SubParsersAction):
|
|
38
|
+
auth = subparser.add_parser("auth", help="manage authentication token")
|
|
39
|
+
auth_actions = auth.add_subparsers()
|
|
40
|
+
auth_action_set = auth_actions.add_parser(
|
|
41
|
+
Action.CREATE, help="set authentication token"
|
|
42
|
+
)
|
|
43
|
+
auth_action_set.set_defaults(func=set_token)
|
|
44
|
+
auth_action_delete = auth_actions.add_parser(
|
|
45
|
+
Action.DELETE, help="delete authentication token"
|
|
46
|
+
)
|
|
47
|
+
auth_action_delete.set_defaults(func=delete_token)
|