Compare commits

...

13 Commits

Author SHA1 Message Date
PCoder 7698db24ce Also print total vm count + make result clearer 2019-08-20 15:12:36 +05:30
PCoder fc9dbe9e57 Fix multiple packages error + add tabulate
Traceback (most recent call last):
  File "/usr/lib/python3.7/site-packages/pipenv/project.py", line 527, in _parse_pipfile
    return tomlkit.parse(contents)
  File "/usr/lib/python3.7/site-packages/pipenv/vendor/tomlkit/api.py", line 49, in parse
    return Parser(string).parse()
  File "/usr/lib/python3.7/site-packages/pipenv/vendor/tomlkit/parser.py", line 152, in parse
    body.append(key, value)
  File "/usr/lib/python3.7/site-packages/pipenv/vendor/tomlkit/container.py", line 129, in append
    raise KeyAlreadyPresent(key)
tomlkit.exceptions.KeyAlreadyPresent: Key "packages" already exists.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/bin/pipenv", line 11, in <module>
    load_entry_point('pipenv==2018.11.15.dev0', 'console_scripts', 'pipenv')()
  File "/usr/lib/python3.7/site-packages/pipenv/vendor/click/core.py", line 764, in __call__
    return self.main(*args, **kwargs)
  File "/usr/lib/python3.7/site-packages/pipenv/vendor/click/core.py", line 717, in main
    rv = self.invoke(ctx)
  File "/usr/lib/python3.7/site-packages/pipenv/vendor/click/core.py", line 1137, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/usr/lib/python3.7/site-packages/pipenv/vendor/click/core.py", line 956, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/lib/python3.7/site-packages/pipenv/vendor/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "/usr/lib/python3.7/site-packages/pipenv/vendor/click/decorators.py", line 64, in new_func
    return ctx.invoke(f, obj, *args, **kwargs)
  File "/usr/lib/python3.7/site-packages/pipenv/vendor/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "/usr/lib/python3.7/site-packages/pipenv/vendor/click/decorators.py", line 17, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "/usr/lib/python3.7/site-packages/pipenv/cli/command.py", line 254, in install
    editable_packages=state.installstate.editables,
  File "/usr/lib/python3.7/site-packages/pipenv/core.py", line 1741, in do_install
    pypi_mirror=pypi_mirror,
  File "/usr/lib/python3.7/site-packages/pipenv/core.py", line 578, in ensure_project
    if project.required_python_version:
  File "/usr/lib/python3.7/site-packages/pipenv/project.py", line 243, in required_python_version
    required = self.parsed_pipfile.get("requires", {}).get(
  File "/usr/lib/python3.7/site-packages/pipenv/project.py", line 509, in parsed_pipfile
    parsed = self._parse_pipfile(contents)
  File "/usr/lib/python3.7/site-packages/pipenv/project.py", line 531, in _parse_pipfile
    return toml.loads(contents)
  File "/usr/lib/python3.7/site-packages/pipenv/vendor/toml/decoder.py", line 425, in loads
    original, pos)
toml.decoder.TomlDecodeError: What? packages already exists?{'source': [{'url': 'https://pypi.python.org/simple', 'verify_ssl': True, 'name': 'pypi'}], 'packages': {'requests': '*', 'pyotp': '*'}, 'dev-packages': {}, 'requires': {'python_version': '3.7'}} (line 15 column 1 char 173)
2019-08-20 13:52:12 +05:30
PCoder 0b838b0172 #6430: display response nicely in tabular format 2019-08-20 11:50:27 +05:30
PCoder c3c9ba4a72 Show error message elegantly 2019-08-13 14:59:12 +05:30
PCoder 3e6d535a74 Replace token with seed and obtain token from seed + fix bug
Bug = getting data from dict
2019-08-13 14:48:53 +05:30
PCoder 1b8c8793f0 Update .gitignore: ignroe .idea folder 2019-08-13 14:47:32 +05:30
PCoder 5b3bb10677 Fix arguments for issue and fix missing endpoint trailing slash 2019-08-13 13:26:55 +05:30
PCoder 66a27d435f Allow ungleich_pay_server parameter to be passed by the user 2019-08-13 13:03:59 +05:30
PCoder 3af7d04a9a #6430: add customers-list feature 2019-08-13 12:00:19 +05:30
wcolmenares 992bd6d11b add response print 2019-06-12 21:02:04 -04:00
wcolmenares f84ab49365 include pyotp 2019-06-12 06:29:38 -04:00
wcolmenares cdd370f9c2 updated readme 2019-06-11 21:11:27 -04:00
wcolmenares ba6e83f925 config to read/store user data in json file 2019-06-11 20:57:55 -04:00
8 changed files with 216 additions and 22 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
.idea/
__pycache__/ __pycache__/

View File

@ -5,12 +5,11 @@ name = "pypi"
[packages] [packages]
requests = "*" requests = "*"
pyotp = "*"
apixu = {git = "https://github.com/apixu/apixu-python.git",ref = "master"}
tabulate = "*"
[dev-packages] [dev-packages]
[requires] [requires]
python_version = "3.7" python_version = "3.7"
[packages.apixu]
git = "https://github.com/apixu/apixu-python.git"
ref = "master"

25
Pipfile.lock generated
View File

@ -1,7 +1,7 @@
{ {
"_meta": { "_meta": {
"hash": { "hash": {
"sha256": "ca9c2522bf07f03d1588afe76e9f6fc73bc1efec20d4f155d82b709efaf14a56" "sha256": "b6d5bcc7b985514e125b8217b8d9f9467b2fc357f4760cd5e83bf0c115b37ea2"
}, },
"pipfile-spec": 6, "pipfile-spec": 6,
"requires": { "requires": {
@ -18,14 +18,14 @@
"default": { "default": {
"apixu": { "apixu": {
"git": "https://github.com/apixu/apixu-python.git", "git": "https://github.com/apixu/apixu-python.git",
"ref": "master" "ref": "370216999346d5caf7f8dc6724b5766dcc6da25d"
}, },
"certifi": { "certifi": {
"hashes": [ "hashes": [
"sha256:59b7658e26ca9c7339e00f8f4636cdfe59d34fa37b9b04f6f9e9926b3cece1a5", "sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939",
"sha256:b26104d6835d1f5e49452a26eb2ff87fe7090b89dfcaee5ea2212697e1e1d7ae" "sha256:945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695"
], ],
"version": "==2019.3.9" "version": "==2019.6.16"
}, },
"chardet": { "chardet": {
"hashes": [ "hashes": [
@ -41,6 +41,14 @@
], ],
"version": "==2.8" "version": "==2.8"
}, },
"pyotp": {
"hashes": [
"sha256:c88f37fd47541a580b744b42136f387cdad481b560ef410c0d85c957eb2a2bc0",
"sha256:fc537e8acd985c5cbf51e11b7d53c42276fee017a73aec7c07380695671ca1a1"
],
"index": "pypi",
"version": "==2.3.0"
},
"requests": { "requests": {
"hashes": [ "hashes": [
"sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4",
@ -49,6 +57,13 @@
"index": "pypi", "index": "pypi",
"version": "==2.22.0" "version": "==2.22.0"
}, },
"tabulate": {
"hashes": [
"sha256:8af07a39377cee1103a5c8b3330a421c2d99b9141e9cc5ddd2e3263fea416943"
],
"index": "pypi",
"version": "==0.8.3"
},
"urllib3": { "urllib3": {
"hashes": [ "hashes": [
"sha256:b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1", "sha256:b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1",

View File

@ -25,10 +25,23 @@ ungleich --help
ungleich weather ungleich weather
``` ```
## Usage: Config
```
ungleich config-add \
--name <otp username>
--realm <otp realm>
--seed <otp seed>
```
## Usage: DNS ## Usage: DNS
``` ```
ungleich dns --set-reverse <ip> --user <username> --token <token> --realm <realm> --email <email> --name mirror.example.com ungleich dns \
--set-reverse <ip>
--user <user_id>
--email <email>
--name mirror.example.com
``` ```
### Usage: RIPE ### Usage: RIPE
@ -47,8 +60,11 @@ ungleich ripe-add-route6 \
Creating a new account object: Creating a new account object:
``` ```
ungleich account --create-user <username> --name <firstname> --lastname <lastname> --email <email> ungleich account \
--create-user <username>
--name <firstname>
--lastname <lastname>
--email <email>
``` ```
### Usage: SSH Key ### Usage: SSH Key

View File

@ -7,6 +7,8 @@ from ungleich_ripe import ungleichRIPE
from ungleich_account import Account_Create from ungleich_account import Account_Create
from ungleich_weather import ungleichWeather from ungleich_weather import ungleichWeather
from ungleich_ssh_key import SSHKey from ungleich_ssh_key import SSHKey
from ungleich_config import Ungleich_Config
from ungleich_pay import ungleichPay
VERSION = "0.0.4" VERSION = "0.0.4"
@ -17,9 +19,11 @@ class ungleichCLI(object):
# FIXME: make it generic # FIXME: make it generic
dns = ungleichDNS(self.parser, self.parser_parents) dns = ungleichDNS(self.parser, self.parser_parents)
ripe = ungleichRIPE(self.parser, self.parser_parents) ripe = ungleichRIPE(self.parser, self.parser_parents)
ripe = Account_Create(self.parser, self.parser_parents) account = Account_Create(self.parser, self.parser_parents)
config = Ungleich_Config(self.parser, self.parser_parents)
SSHKey(self.parser, self.parser_parents) SSHKey(self.parser, self.parser_parents)
ungleichWeather(self.parser, self.parser_parents) ungleichWeather(self.parser, self.parser_parents)
ungleichPay(self.parser, self.parser_parents)
def _init_parser(self): def _init_parser(self):
self.parser = {} self.parser = {}

82
ungleich_config.py Normal file
View File

@ -0,0 +1,82 @@
import argparse
import json
import urllib.request
class Ungleich_Config(object):
def __init__(self, parser, parents):
self.parser = parser
self.parser['add'] = self.parser['sub'].add_parser(
'config-add',
help="Add user to configuration file",
parents=[parents])
self.parser['list'] = self.parser['sub'].add_parser(
'config-list',
help="list users in configuration file",
parents=[parents])
self.parser['delete'] = self.parser['sub'].add_parser(
'config-delete',
help="remove a user in configuration file",
parents=[parents])
self.parser['add'].add_argument('--name', help='otp name', required=True)
self.parser['add'].add_argument('--realm', help='otp realm', required=True)
self.parser['add'].add_argument('--seed', help='otp seed', required=True)
self.parser['delete'].add_argument('--id', help='user ID to remove', required=True)
self.parser['list'].set_defaults(func=self._list_users)
self.parser['add'].set_defaults(func=self._add_user)
self.parser['delete'].set_defaults(func=self._delete_user)
def _add_user(self, args):
try:
f = open('users.json', 'r')
json_info = json.loads(f.read())
if len(json_info) > 0:
with open('users.json', 'w') as fp:
last_id = int(list(json_info.keys())[-1]) + 1
json_info[last_id] = {"name": args.name, "realm": args.realm, "seed": args.seed}
json.dump(json_info, fp)
print('User added.')
else:
with open('users.json', 'w') as fp:
d = {"name": args.name, "realm": args.realm, "seed": args.seed}
json.dump({"1": d}, fp)
print('User added.')
except FileNotFoundError:
with open('users.json', 'w') as fp:
d = {"name": args.name, "realm": args.realm, "seed": args.seed}
json.dump({"1": d}, fp)
print('User added.')
def _list_users(self, args):
try:
f = open('users.json', 'r')
json_info = json.loads(f.read())
for key, value in json_info.items():
print('{}: {}'.format(key, value['name']))
except FileNotFoundError:
print('No users loaded.')
def _delete_user(self, args):
try:
f = open('users.json', 'r')
json_info = json.loads(f.read())
try:
del json_info[args.id]
f = open('users.json', 'w')
x = 1
for i in list(json_info.keys()):
json_info[str(x)] = json_info.pop(i)
x+=1
f.write(json.dumps(json_info))
f.close()
except KeyError:
print("No user with such id.")
except FileNotFoundError:
print('No users loaded.')

View File

@ -1,7 +1,7 @@
import urllib.request import urllib.request
import argparse import argparse
import json import json
from pyotp import TOTP
class ungleichDNS(object): class ungleichDNS(object):
def __init__(self, parser, parents): def __init__(self, parser, parents):
@ -13,15 +13,16 @@ class ungleichDNS(object):
parents=[parents]) parents=[parents])
self.parser['dns'].add_argument('--set-reverse', help='REQUIRED: IPv6 Address of your VM', required=True) self.parser['dns'].add_argument('--set-reverse', help='REQUIRED: IPv6 Address of your VM', required=True)
self.parser['dns'].add_argument('--user', help='Your ungleich username', required=True) self.parser['dns'].add_argument('--user', help='Your stored user ID', required=True)
self.parser['dns'].add_argument('--token', help='Your ungleich 6 digit OTP generated token', type=int, required=True)
self.parser['dns'].add_argument('--name', help='Hostname', required=True) self.parser['dns'].add_argument('--name', help='Hostname', required=True)
self.parser['dns'].add_argument('--email', help='registered email', required=True) self.parser['dns'].add_argument('--email', help='registered email', required=True)
self.parser['dns'].add_argument('--realm', help='Otp realm', required=True)
self.parser['dns'].set_defaults(func=self._handle_dns) self.parser['dns'].set_defaults(func=self._handle_dns)
def _handle_dns(self, args): def _handle_dns(self, args):
"""Reverse dns endpoint.""" """Reverse dns endpoint."""
f = open('users.json', 'r')
data = json.loads(f.read())[args.user]
url = 'https://dns.service.ungleich.ch' url = 'https://dns.service.ungleich.ch'
req = urllib.request.Request( req = urllib.request.Request(
url=url, url=url,
@ -30,13 +31,17 @@ class ungleichDNS(object):
"Content-Type": "application/json" "Content-Type": "application/json"
}, },
data=json.dumps({ data=json.dumps({
'username': args.user, 'username': data['name'],
'token': args.token, 'token': TOTP(data['seed']).now(),
'ipaddress': args.set_reverse, 'ipaddress': args.set_reverse,
'name': args.name, 'name': args.name,
'email': args.email, 'email': args.email,
'realm': args.realm 'realm': data['realm']
}).encode('utf-8') }).encode('utf-8')
) )
response = urllib.request.urlopen(req).read() try:
print(json.loads(response)) response = urllib.request.urlopen(req).read()
print(response)
except urllib.error.HTTPError as e:
error_message = e.read()
print(json.loads(error_message))

72
ungleich_pay.py Normal file
View File

@ -0,0 +1,72 @@
import urllib.request
import json
import sys
from pyotp import TOTP
from tabulate import tabulate
UNGLEICH_PAY_SERVER_URL = "https://pay.ungleich.ch"
class ungleichPay(object):
def __init__(self, parser, parents):
self.parser = parser
self.parser['customers-list'] = self.parser['sub'].add_parser(
'customers-list',
help="List customers who have an active VM at ungleich",
parents=[parents])
self.parser['customers-list'].add_argument('--username', required=True)
self.parser['customers-list'].add_argument('--realm', required=True)
self.parser['customers-list'].add_argument(
'--seed', required=True,
help="A valid seed obtained from ungleich"
)
self.parser['customers-list'].add_argument(
'--email', required=True,
help="Email associated with the username"
)
self.parser['customers-list'].add_argument(
'--ungleich-pay-server', required=False,
help="A valid ungleich pay server url"
)
self.parser['customers-list'].set_defaults(func=self.customers_list)
def customers_list(self, args):
customers_list_endpoint = "/customers-list/"
if args.ungleich_pay_server:
request_url = args.ungleich_pay_server + customers_list_endpoint
else:
request_url = UNGLEICH_PAY_SERVER_URL + customers_list_endpoint
print(f"request_url={request_url}")
req = urllib.request.Request(url=request_url,
method='GET',
headers={
"email": args.email,
"username": args.username,
"realm": args.realm,
"token": TOTP(args.seed).now(),
"Accept": "application/json"
})
try:
response = urllib.request.urlopen(req)
except urllib.error.HTTPError as err:
print(str(err))
sys.exit(1)
except urllib.error.URLError as uerr:
print(str(uerr))
sys.exit(2)
response_json = json.loads(response.read().decode('utf-8'))
if (response_json['response'] == 'success'):
data = response_json["data"]
rows = [(x['email'], x['vm_count']) for x in data]
headers = ["customer", "vm_count"]
print("---")
print(tabulate(rows, headers))
print("---")
vm_count = 0
for x in data:
vm_count += x['vm_count']
print("Total vm_count = {}".format(vm_count))
else:
print("An error occurred.")
print(response_json["message"])