knotctl 0.1.0__tar.gz → 0.1.2__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.
- knotctl-0.1.2/.gitignore +162 -0
- knotctl-0.1.2/CHANGELOG +0 -0
- knotctl-0.1.2/Makefile +13 -0
- {knotctl-0.1.0 → knotctl-0.1.2}/PKG-INFO +34 -5
- {knotctl-0.1.0 → knotctl-0.1.2}/README.md +30 -3
- knotctl-0.1.2/publiccode.yml +41 -0
- {knotctl-0.1.0 → knotctl-0.1.2}/pyproject.toml +27 -2
- knotctl-0.1.2/requirements.txt +5 -0
- knotctl-0.1.2/src/knotctl/__init__.py +204 -0
- knotctl-0.1.2/src/knotctl/__main__.py +4 -0
- knotctl-0.1.2/src/knotctl/config/__init__.py +84 -0
- knotctl-0.1.2/src/knotctl/openstack/__init__.py +17 -0
- knotctl-0.1.2/src/knotctl/runners/__init__.py +219 -0
- knotctl-0.1.2/src/knotctl/utils/__init__.py +282 -0
- knotctl-0.1.2/stdeb.cfg +4 -0
- knotctl-0.1.0/knotctl/__init__.py +0 -532
- {knotctl-0.1.0 → knotctl-0.1.2}/LICENSE +0 -0
knotctl-0.1.2/.gitignore
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# ---> Python
|
|
2
|
+
# Byte-compiled / optimized / DLL files
|
|
3
|
+
__pycache__/
|
|
4
|
+
*.py[cod]
|
|
5
|
+
*$py.class
|
|
6
|
+
|
|
7
|
+
# C extensions
|
|
8
|
+
*.so
|
|
9
|
+
|
|
10
|
+
# Distribution / packaging
|
|
11
|
+
.Python
|
|
12
|
+
build/
|
|
13
|
+
develop-eggs/
|
|
14
|
+
dist/
|
|
15
|
+
downloads/
|
|
16
|
+
eggs/
|
|
17
|
+
.eggs/
|
|
18
|
+
lib/
|
|
19
|
+
lib64/
|
|
20
|
+
parts/
|
|
21
|
+
sdist/
|
|
22
|
+
var/
|
|
23
|
+
wheels/
|
|
24
|
+
share/python-wheels/
|
|
25
|
+
*.egg-info/
|
|
26
|
+
.installed.cfg
|
|
27
|
+
*.egg
|
|
28
|
+
MANIFEST
|
|
29
|
+
|
|
30
|
+
# PyInstaller
|
|
31
|
+
# Usually these files are written by a python script from a template
|
|
32
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
33
|
+
*.manifest
|
|
34
|
+
*.spec
|
|
35
|
+
|
|
36
|
+
# Installer logs
|
|
37
|
+
pip-log.txt
|
|
38
|
+
pip-delete-this-directory.txt
|
|
39
|
+
|
|
40
|
+
# Unit test / coverage reports
|
|
41
|
+
htmlcov/
|
|
42
|
+
.tox/
|
|
43
|
+
.nox/
|
|
44
|
+
.coverage
|
|
45
|
+
.coverage.*
|
|
46
|
+
.cache
|
|
47
|
+
nosetests.xml
|
|
48
|
+
coverage.xml
|
|
49
|
+
*.cover
|
|
50
|
+
*.py,cover
|
|
51
|
+
.hypothesis/
|
|
52
|
+
.pytest_cache/
|
|
53
|
+
cover/
|
|
54
|
+
|
|
55
|
+
# Translations
|
|
56
|
+
*.mo
|
|
57
|
+
*.pot
|
|
58
|
+
|
|
59
|
+
# Django stuff:
|
|
60
|
+
*.log
|
|
61
|
+
local_settings.py
|
|
62
|
+
db.sqlite3
|
|
63
|
+
db.sqlite3-journal
|
|
64
|
+
|
|
65
|
+
# Flask stuff:
|
|
66
|
+
instance/
|
|
67
|
+
.webassets-cache
|
|
68
|
+
|
|
69
|
+
# Scrapy stuff:
|
|
70
|
+
.scrapy
|
|
71
|
+
|
|
72
|
+
# Sphinx documentation
|
|
73
|
+
docs/_build/
|
|
74
|
+
|
|
75
|
+
# PyBuilder
|
|
76
|
+
.pybuilder/
|
|
77
|
+
target/
|
|
78
|
+
|
|
79
|
+
# Jupyter Notebook
|
|
80
|
+
.ipynb_checkpoints
|
|
81
|
+
|
|
82
|
+
# IPython
|
|
83
|
+
profile_default/
|
|
84
|
+
ipython_config.py
|
|
85
|
+
|
|
86
|
+
# pyenv
|
|
87
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
88
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
89
|
+
# .python-version
|
|
90
|
+
|
|
91
|
+
# pipenv
|
|
92
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
93
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
94
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
95
|
+
# install all needed dependencies.
|
|
96
|
+
#Pipfile.lock
|
|
97
|
+
|
|
98
|
+
# poetry
|
|
99
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
100
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
101
|
+
# commonly ignored for libraries.
|
|
102
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
103
|
+
#poetry.lock
|
|
104
|
+
|
|
105
|
+
# pdm
|
|
106
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
107
|
+
#pdm.lock
|
|
108
|
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
109
|
+
# in version control.
|
|
110
|
+
# https://pdm.fming.dev/#use-with-ide
|
|
111
|
+
.pdm.toml
|
|
112
|
+
|
|
113
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
114
|
+
__pypackages__/
|
|
115
|
+
|
|
116
|
+
# Celery stuff
|
|
117
|
+
celerybeat-schedule
|
|
118
|
+
celerybeat.pid
|
|
119
|
+
|
|
120
|
+
# SageMath parsed files
|
|
121
|
+
*.sage.py
|
|
122
|
+
|
|
123
|
+
# Environments
|
|
124
|
+
.env
|
|
125
|
+
.venv
|
|
126
|
+
env/
|
|
127
|
+
venv/
|
|
128
|
+
ENV/
|
|
129
|
+
env.bak/
|
|
130
|
+
venv.bak/
|
|
131
|
+
|
|
132
|
+
# Spyder project settings
|
|
133
|
+
.spyderproject
|
|
134
|
+
.spyproject
|
|
135
|
+
|
|
136
|
+
# Rope project settings
|
|
137
|
+
.ropeproject
|
|
138
|
+
|
|
139
|
+
# mkdocs documentation
|
|
140
|
+
/site
|
|
141
|
+
|
|
142
|
+
# mypy
|
|
143
|
+
.mypy_cache/
|
|
144
|
+
.dmypy.json
|
|
145
|
+
dmypy.json
|
|
146
|
+
|
|
147
|
+
# Pyre type checker
|
|
148
|
+
.pyre/
|
|
149
|
+
|
|
150
|
+
# pytype static type analyzer
|
|
151
|
+
.pytype/
|
|
152
|
+
|
|
153
|
+
# Cython debug symbols
|
|
154
|
+
cython_debug/
|
|
155
|
+
|
|
156
|
+
# PyCharm
|
|
157
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
158
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
159
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
160
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
161
|
+
#.idea/
|
|
162
|
+
|
knotctl-0.1.2/CHANGELOG
ADDED
|
File without changes
|
knotctl-0.1.2/Makefile
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
.PHONY: publish
|
|
2
|
+
publish:
|
|
3
|
+
flit publish
|
|
4
|
+
|
|
5
|
+
.PHONY: deb
|
|
6
|
+
deb:
|
|
7
|
+
briefcase update linux system --target debian:testing
|
|
8
|
+
briefcase build linux system --target debian:testing
|
|
9
|
+
briefcase package linux system --target debian:testing
|
|
10
|
+
|
|
11
|
+
.PHONY: clean
|
|
12
|
+
clean:
|
|
13
|
+
rm -rf build dist
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: knotctl
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: A CLI for knotapi.
|
|
5
5
|
Author-email: Micke Nordin <hej@mic.ke>
|
|
6
6
|
Requires-Python: >=3.9
|
|
@@ -8,10 +8,12 @@ Description-Content-Type: text/markdown
|
|
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
|
9
9
|
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
10
10
|
Classifier: Operating System :: OS Independent
|
|
11
|
+
License-File: LICENSE
|
|
11
12
|
Requires-Dist: argcomplete==2.0.0
|
|
12
13
|
Requires-Dist: pyyaml==6.0.1
|
|
13
14
|
Requires-Dist: requests==2.27.1
|
|
14
15
|
Requires-Dist: simplejson==3.17.6
|
|
16
|
+
Requires-Dist: openstacksdk==4.2.0
|
|
15
17
|
Project-URL: Documentation, https://code.smolnet.org/micke/knotctl
|
|
16
18
|
Project-URL: Source, https://code.smolnet.org/micke/knotctl
|
|
17
19
|
|
|
@@ -20,11 +22,15 @@ Project-URL: Source, https://code.smolnet.org/micke/knotctl
|
|
|
20
22
|
This is a commandline tool for knotapi: https://gitlab.nic.cz/knot/knot-dns-rest
|
|
21
23
|
|
|
22
24
|
## Build and install
|
|
25
|
+
The preffered method of installation is via pipx:
|
|
26
|
+
```
|
|
27
|
+
pipx install knotctl
|
|
28
|
+
```
|
|
23
29
|
|
|
24
30
|
To install using pip, run the following command in a virtual envrionment.
|
|
25
31
|
|
|
26
32
|
```
|
|
27
|
-
python -m pip install
|
|
33
|
+
python -m pip install knotctl
|
|
28
34
|
```
|
|
29
35
|
|
|
30
36
|
To build and install as a deb-package
|
|
@@ -208,9 +214,9 @@ options:
|
|
|
208
214
|
### LIST
|
|
209
215
|
|
|
210
216
|
```
|
|
211
|
-
usage: knotctl list [-h] [-d DATA] [-n NAME] [-r RTYPE] -z ZONE
|
|
217
|
+
usage: knotctl list [-h] [-d DATA] [-n NAME] [-r RTYPE] [-z ZONE]
|
|
212
218
|
|
|
213
|
-
List records
|
|
219
|
+
List records.
|
|
214
220
|
|
|
215
221
|
options:
|
|
216
222
|
-h, --help show this help message and exit
|
|
@@ -249,3 +255,26 @@ Available arguments are:
|
|
|
249
255
|
ttl: New record time to live (TTL).
|
|
250
256
|
```
|
|
251
257
|
|
|
258
|
+
### USER
|
|
259
|
+
```
|
|
260
|
+
usage: knotctl user [-h] [-u USERNAME]
|
|
261
|
+
|
|
262
|
+
View user information.
|
|
263
|
+
|
|
264
|
+
options:
|
|
265
|
+
-h, --help show this help message and exit
|
|
266
|
+
-u USERNAME, --username USERNAME
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### ZONE
|
|
270
|
+
|
|
271
|
+
```
|
|
272
|
+
usage: knotctl zone
|
|
273
|
+
|
|
274
|
+
List zones.
|
|
275
|
+
|
|
276
|
+
options:
|
|
277
|
+
-h, --help show this help message and exit
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
|
|
@@ -3,11 +3,15 @@
|
|
|
3
3
|
This is a commandline tool for knotapi: https://gitlab.nic.cz/knot/knot-dns-rest
|
|
4
4
|
|
|
5
5
|
## Build and install
|
|
6
|
+
The preffered method of installation is via pipx:
|
|
7
|
+
```
|
|
8
|
+
pipx install knotctl
|
|
9
|
+
```
|
|
6
10
|
|
|
7
11
|
To install using pip, run the following command in a virtual envrionment.
|
|
8
12
|
|
|
9
13
|
```
|
|
10
|
-
python -m pip install
|
|
14
|
+
python -m pip install knotctl
|
|
11
15
|
```
|
|
12
16
|
|
|
13
17
|
To build and install as a deb-package
|
|
@@ -191,9 +195,9 @@ options:
|
|
|
191
195
|
### LIST
|
|
192
196
|
|
|
193
197
|
```
|
|
194
|
-
usage: knotctl list [-h] [-d DATA] [-n NAME] [-r RTYPE] -z ZONE
|
|
198
|
+
usage: knotctl list [-h] [-d DATA] [-n NAME] [-r RTYPE] [-z ZONE]
|
|
195
199
|
|
|
196
|
-
List records
|
|
200
|
+
List records.
|
|
197
201
|
|
|
198
202
|
options:
|
|
199
203
|
-h, --help show this help message and exit
|
|
@@ -231,3 +235,26 @@ Available arguments are:
|
|
|
231
235
|
rtype: New record type.
|
|
232
236
|
ttl: New record time to live (TTL).
|
|
233
237
|
```
|
|
238
|
+
|
|
239
|
+
### USER
|
|
240
|
+
```
|
|
241
|
+
usage: knotctl user [-h] [-u USERNAME]
|
|
242
|
+
|
|
243
|
+
View user information.
|
|
244
|
+
|
|
245
|
+
options:
|
|
246
|
+
-h, --help show this help message and exit
|
|
247
|
+
-u USERNAME, --username USERNAME
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### ZONE
|
|
251
|
+
|
|
252
|
+
```
|
|
253
|
+
usage: knotctl zone
|
|
254
|
+
|
|
255
|
+
List zones.
|
|
256
|
+
|
|
257
|
+
options:
|
|
258
|
+
-h, --help show this help message and exit
|
|
259
|
+
```
|
|
260
|
+
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
publiccodeYmlVersion: "0.4"
|
|
2
|
+
|
|
3
|
+
name: knotctl
|
|
4
|
+
url: "https://platform.sunet.se/SUNET/knotctl"
|
|
5
|
+
platforms:
|
|
6
|
+
- linux
|
|
7
|
+
- mac
|
|
8
|
+
|
|
9
|
+
categories:
|
|
10
|
+
- it-service-management
|
|
11
|
+
|
|
12
|
+
developmentStatus: development
|
|
13
|
+
|
|
14
|
+
softwareType: "standalone/desktop"
|
|
15
|
+
|
|
16
|
+
description:
|
|
17
|
+
en:
|
|
18
|
+
shortDescription: >
|
|
19
|
+
This is a commandline tool for knotapirestapi
|
|
20
|
+
https://gitlab.nic.cz/knot/knot-dns-rest
|
|
21
|
+
|
|
22
|
+
longDescription: >
|
|
23
|
+
This is a commandline tool for knotapirestapi
|
|
24
|
+
https://gitlab.nic.cz/knot/knot-dns-rest
|
|
25
|
+
|
|
26
|
+
features:
|
|
27
|
+
- DNS management
|
|
28
|
+
|
|
29
|
+
legal:
|
|
30
|
+
license: GPL-3.0
|
|
31
|
+
|
|
32
|
+
maintenance:
|
|
33
|
+
type: "community"
|
|
34
|
+
|
|
35
|
+
contacts:
|
|
36
|
+
- name: Micke Nordin <kano@sunet.se>
|
|
37
|
+
|
|
38
|
+
localisation:
|
|
39
|
+
localisationReady: false
|
|
40
|
+
availableLanguages:
|
|
41
|
+
- en
|
|
@@ -16,13 +16,14 @@ classifiers=[
|
|
|
16
16
|
"Operating System :: OS Independent",
|
|
17
17
|
]
|
|
18
18
|
requires-python= ">=3.9"
|
|
19
|
-
version = "0.1.
|
|
19
|
+
version = "0.1.2"
|
|
20
20
|
|
|
21
21
|
dependencies = [
|
|
22
22
|
"argcomplete==2.0.0",
|
|
23
23
|
"pyyaml==6.0.1",
|
|
24
24
|
"requests==2.27.1",
|
|
25
25
|
"simplejson==3.17.6",
|
|
26
|
+
"openstacksdk==4.2.0",
|
|
26
27
|
]
|
|
27
28
|
|
|
28
29
|
[project.urls]
|
|
@@ -34,4 +35,28 @@ knotctl="knotctl:main"
|
|
|
34
35
|
|
|
35
36
|
|
|
36
37
|
[tool.flit.sdist]
|
|
37
|
-
include = ["LICENSE",]
|
|
38
|
+
include = ["LICENSE", "README.md"]
|
|
39
|
+
|
|
40
|
+
[tool.briefcase]
|
|
41
|
+
project_name = "knotctl"
|
|
42
|
+
bundle = "org.smolnet"
|
|
43
|
+
version = "0.1.2"
|
|
44
|
+
|
|
45
|
+
[tool.briefcase.app.knotctl]
|
|
46
|
+
formal_name = "knotctl"
|
|
47
|
+
description = "A CLI for knotapi."
|
|
48
|
+
long_description = "A CLI for knotapi."
|
|
49
|
+
sources = ['src/knotctl']
|
|
50
|
+
console_app = "True"
|
|
51
|
+
requires = [
|
|
52
|
+
"argcomplete==2.0.0",
|
|
53
|
+
"pyyaml==6.0.1",
|
|
54
|
+
"requests==2.27.1",
|
|
55
|
+
"simplejson==3.17.6",
|
|
56
|
+
"openstacksdk==4.2.0",
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
[tool.briefcase.app.knotctl.linux.system.debian]
|
|
60
|
+
system_runtime_requires = [
|
|
61
|
+
"libpython3.13",
|
|
62
|
+
]
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
import getpass
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
from typing import Union
|
|
7
|
+
from urllib.parse import quote
|
|
8
|
+
|
|
9
|
+
import requests
|
|
10
|
+
from simplejson.errors import JSONDecodeError as SimplejsonJSONDecodeError
|
|
11
|
+
|
|
12
|
+
from .config import Config
|
|
13
|
+
from .runners import Run
|
|
14
|
+
from .utils import error, get_parser, output, setup_url
|
|
15
|
+
|
|
16
|
+
try:
|
|
17
|
+
from requests.exceptions import JSONDecodeError as RequestsJSONDecodeError
|
|
18
|
+
except ImportError:
|
|
19
|
+
from requests.exceptions import InvalidJSONError as RequestsJSONDecodeError
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Knotctl:
|
|
23
|
+
|
|
24
|
+
def __init__(self):
|
|
25
|
+
self.conf = Config()
|
|
26
|
+
self.config = self.get_config()
|
|
27
|
+
self.config_filename = self.conf.config_filename
|
|
28
|
+
self.runner = Run()
|
|
29
|
+
|
|
30
|
+
def get_config(self):
|
|
31
|
+
config = self.conf.get_config()
|
|
32
|
+
if not config:
|
|
33
|
+
print("You need to configure knotctl before proceeding")
|
|
34
|
+
run_config()
|
|
35
|
+
|
|
36
|
+
return config
|
|
37
|
+
|
|
38
|
+
def run(self, url: str, args: dict, baseurl: str, parser: dict,
|
|
39
|
+
username: str):
|
|
40
|
+
try:
|
|
41
|
+
if args.command == "add":
|
|
42
|
+
self.runner.add(url, args.json)
|
|
43
|
+
elif args.command == "delete":
|
|
44
|
+
self.runner.delete(url, args.json)
|
|
45
|
+
elif args.command == "list":
|
|
46
|
+
self.runner.lister(url, args.json)
|
|
47
|
+
elif args.command == "update":
|
|
48
|
+
self.runner.update(url, args.json)
|
|
49
|
+
elif args.command == "user":
|
|
50
|
+
url = baseurl + f"/user/info/{username}"
|
|
51
|
+
self.runner.lister(url, args.json)
|
|
52
|
+
elif args.command == "auditlog":
|
|
53
|
+
url = baseurl + "/user/auditlog"
|
|
54
|
+
self.runner.log(url, args.json)
|
|
55
|
+
elif args.command == "changelog":
|
|
56
|
+
url = baseurl + f"/zones/changelog/{args.zone.rstrip('.')}"
|
|
57
|
+
self.runner.log(url, args.json)
|
|
58
|
+
elif args.command == "zone":
|
|
59
|
+
url = baseurl + "/zones"
|
|
60
|
+
self.runner.zone(url, args.json)
|
|
61
|
+
elif args.command == "openstack-sync":
|
|
62
|
+
self.runner.openstack_sync(args.cloud, args.name, args.zone,
|
|
63
|
+
baseurl, args.json)
|
|
64
|
+
else:
|
|
65
|
+
parser.print_help(sys.stderr)
|
|
66
|
+
return 2
|
|
67
|
+
except requests.exceptions.RequestException as e:
|
|
68
|
+
output(error(e, "Could not connect to server"))
|
|
69
|
+
except (RequestsJSONDecodeError, SimplejsonJSONDecodeError):
|
|
70
|
+
output(
|
|
71
|
+
error("Could not decode api response as JSON",
|
|
72
|
+
"Could not decode"))
|
|
73
|
+
return 0
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def run_complete(shell: Union[None, str]):
|
|
77
|
+
if not shell or shell in ["bash", "zsh"]:
|
|
78
|
+
os.system("register-python-argcomplete knotctl")
|
|
79
|
+
elif shell == "fish":
|
|
80
|
+
os.system("register-python-argcomplete --shell fish knotctl")
|
|
81
|
+
elif shell == "tcsh":
|
|
82
|
+
os.system("register-python-argcomplete --shell tcsh knotctl")
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def run_config(
|
|
86
|
+
context: Union[None, str] = None,
|
|
87
|
+
baseurl: Union[None, str] = None,
|
|
88
|
+
list_config: bool = False,
|
|
89
|
+
username: Union[None, str] = None,
|
|
90
|
+
password: Union[None, str] = None,
|
|
91
|
+
current: Union[None, str] = None,
|
|
92
|
+
):
|
|
93
|
+
conf = Config()
|
|
94
|
+
if current:
|
|
95
|
+
print(conf.get_current())
|
|
96
|
+
return
|
|
97
|
+
config = {"baseurl": baseurl, "username": username, "password": password}
|
|
98
|
+
needed = []
|
|
99
|
+
if context:
|
|
100
|
+
found = conf.set_context(context)
|
|
101
|
+
if found:
|
|
102
|
+
return
|
|
103
|
+
if list_config:
|
|
104
|
+
config_data = conf.get_config_data()
|
|
105
|
+
output(config_data)
|
|
106
|
+
return
|
|
107
|
+
if not baseurl:
|
|
108
|
+
needed.append("baseurl")
|
|
109
|
+
if not username:
|
|
110
|
+
needed.append("username")
|
|
111
|
+
for need in needed:
|
|
112
|
+
if need == "":
|
|
113
|
+
output(
|
|
114
|
+
error(
|
|
115
|
+
"Can not configure without {}".format(need),
|
|
116
|
+
"No {}".format(need),
|
|
117
|
+
))
|
|
118
|
+
sys.exit(1)
|
|
119
|
+
config[need] = input("Enter {}: ".format(need))
|
|
120
|
+
|
|
121
|
+
if not password:
|
|
122
|
+
try:
|
|
123
|
+
config["password"] = getpass.getpass()
|
|
124
|
+
except EOFError:
|
|
125
|
+
output(error("Can not configure without password", "No password"))
|
|
126
|
+
sys.exit(1)
|
|
127
|
+
|
|
128
|
+
conf.set_config(config)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
# Entry point to program
|
|
132
|
+
def main() -> int:
|
|
133
|
+
parser = get_parser()
|
|
134
|
+
args = parser.parse_args()
|
|
135
|
+
if args.command == "completion":
|
|
136
|
+
run_complete(args.shell)
|
|
137
|
+
return 0
|
|
138
|
+
|
|
139
|
+
knotctl = Knotctl()
|
|
140
|
+
|
|
141
|
+
if args.command == "config":
|
|
142
|
+
run_config(
|
|
143
|
+
args.context,
|
|
144
|
+
args.baseurl,
|
|
145
|
+
args.list_config,
|
|
146
|
+
args.username,
|
|
147
|
+
args.password,
|
|
148
|
+
args.current,
|
|
149
|
+
)
|
|
150
|
+
return 0
|
|
151
|
+
|
|
152
|
+
config = knotctl.get_config()
|
|
153
|
+
baseurl = config["baseurl"]
|
|
154
|
+
token = knotctl.conf.get_token()
|
|
155
|
+
if token == "":
|
|
156
|
+
print("Could not get token, exiting")
|
|
157
|
+
return 1
|
|
158
|
+
|
|
159
|
+
# Route based on command
|
|
160
|
+
url = ""
|
|
161
|
+
ttl = None
|
|
162
|
+
quotedata = None
|
|
163
|
+
user = config["username"]
|
|
164
|
+
if "ttl" in args:
|
|
165
|
+
ttl = args.ttl
|
|
166
|
+
if "data" in args:
|
|
167
|
+
quotedata = quote(args.data, safe="")
|
|
168
|
+
if args.command != "update":
|
|
169
|
+
args.argument = None
|
|
170
|
+
if args.command == "add" and not ttl:
|
|
171
|
+
if args.zone.endswith("."):
|
|
172
|
+
zname = args.zone
|
|
173
|
+
else:
|
|
174
|
+
zname = args.zone + "."
|
|
175
|
+
soa_url = setup_url(baseurl, None, None, zname, "SOA", None, args.zone)
|
|
176
|
+
soa_json = knotctl.runner.lister(soa_url, True, ret=True)
|
|
177
|
+
ttl = soa_json[0]["ttl"]
|
|
178
|
+
if args.command == "user":
|
|
179
|
+
if args.username:
|
|
180
|
+
user = args.username
|
|
181
|
+
if args.command in [
|
|
182
|
+
"auditlog", "changelog", "openstack-sync", "user", "zone"
|
|
183
|
+
]:
|
|
184
|
+
pass
|
|
185
|
+
else:
|
|
186
|
+
try:
|
|
187
|
+
url = setup_url(
|
|
188
|
+
baseurl,
|
|
189
|
+
args.argument,
|
|
190
|
+
quotedata,
|
|
191
|
+
args.name,
|
|
192
|
+
args.rtype,
|
|
193
|
+
ttl,
|
|
194
|
+
args.zone,
|
|
195
|
+
)
|
|
196
|
+
except AttributeError:
|
|
197
|
+
parser.print_help(sys.stderr)
|
|
198
|
+
return 1
|
|
199
|
+
|
|
200
|
+
return knotctl.run(url, args, baseurl, parser, user)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
if __name__ == "__main__":
|
|
204
|
+
sys.exit(main())
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
import os
|
|
3
|
+
from os import mkdir
|
|
4
|
+
from os.path import isdir, isfile, join
|
|
5
|
+
from typing import Union
|
|
6
|
+
|
|
7
|
+
import requests
|
|
8
|
+
import yaml
|
|
9
|
+
from requests.models import HTTPBasicAuth
|
|
10
|
+
|
|
11
|
+
from ..utils import error, output
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Config:
|
|
15
|
+
|
|
16
|
+
def __init__(self):
|
|
17
|
+
# Make sure we have config
|
|
18
|
+
self.config_basepath = join(os.environ["HOME"], ".knot")
|
|
19
|
+
self.config_filename = join(self.config_basepath, "config")
|
|
20
|
+
if not isdir(self.config_basepath):
|
|
21
|
+
mkdir(self.config_basepath)
|
|
22
|
+
|
|
23
|
+
def get_config(self) -> Union[None, dict]:
|
|
24
|
+
if not isfile(self.config_filename):
|
|
25
|
+
return None
|
|
26
|
+
with open(self.config_filename, "r") as fh:
|
|
27
|
+
return yaml.safe_load(fh.read())
|
|
28
|
+
|
|
29
|
+
def get_config_data(self) -> dict:
|
|
30
|
+
config_data = self.get_config()
|
|
31
|
+
config_data.pop("password", None)
|
|
32
|
+
return config_data
|
|
33
|
+
|
|
34
|
+
def get_current(self) -> str:
|
|
35
|
+
if os.path.islink(self.config_filename):
|
|
36
|
+
actual_path = os.readlink(self.config_filename)
|
|
37
|
+
return actual_path.split("-")[-1]
|
|
38
|
+
else:
|
|
39
|
+
return "none"
|
|
40
|
+
|
|
41
|
+
def get_token(self) -> str:
|
|
42
|
+
# Authenticate
|
|
43
|
+
config = self.get_config()
|
|
44
|
+
baseurl = config["baseurl"]
|
|
45
|
+
username = config["username"]
|
|
46
|
+
password = config["password"]
|
|
47
|
+
basic = HTTPBasicAuth(username, password)
|
|
48
|
+
response = requests.get(baseurl + "/user/login", auth=basic)
|
|
49
|
+
token = ""
|
|
50
|
+
try:
|
|
51
|
+
token = response.json()["token"]
|
|
52
|
+
except KeyError:
|
|
53
|
+
output(response.json())
|
|
54
|
+
except requests.exceptions.JSONDecodeError:
|
|
55
|
+
output(
|
|
56
|
+
error("Could not decode api response as JSON",
|
|
57
|
+
"Could not decode"))
|
|
58
|
+
return token
|
|
59
|
+
|
|
60
|
+
def set_context(self, context) -> bool:
|
|
61
|
+
symlink = f"{self.config_filename}-{context}"
|
|
62
|
+
found = os.path.isfile(symlink)
|
|
63
|
+
if os.path.islink(self.config_filename):
|
|
64
|
+
os.remove(self.config_filename)
|
|
65
|
+
elif os.path.isfile(self.config_filename):
|
|
66
|
+
os.rename(self.config_filename, symlink)
|
|
67
|
+
os.symlink(symlink, self.config_filename)
|
|
68
|
+
self.config_filename = symlink
|
|
69
|
+
return found
|
|
70
|
+
|
|
71
|
+
def set_config(
|
|
72
|
+
self,
|
|
73
|
+
baseurl: str,
|
|
74
|
+
username: str,
|
|
75
|
+
password: str,
|
|
76
|
+
):
|
|
77
|
+
config = {
|
|
78
|
+
"baseurl": baseurl,
|
|
79
|
+
"username": username,
|
|
80
|
+
"password": password
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
with open(self.config_filename, "w") as fh:
|
|
84
|
+
fh.write(yaml.dump(config))
|