2020-02-15 08:38:33 +00:00
|
|
|
from flask import Flask, request
|
|
|
|
from flask_restful import Resource, Api
|
|
|
|
import etcd3
|
|
|
|
import json
|
|
|
|
import logging
|
|
|
|
from functools import wraps
|
|
|
|
|
2020-02-20 15:55:01 +00:00
|
|
|
from ldaptest import is_valid_ldap_user
|
|
|
|
|
|
|
|
def authenticate(func):
|
|
|
|
@wraps(func)
|
|
|
|
def wrapper(*args, **kwargs):
|
|
|
|
if not getattr(func, 'authenticated', True):
|
|
|
|
return func(*args, **kwargs)
|
|
|
|
|
|
|
|
# pass in username/password !
|
|
|
|
acct = basic_authentication() # custom account lookup function
|
|
|
|
|
|
|
|
if acct:
|
|
|
|
return func(*args, **kwargs)
|
|
|
|
|
|
|
|
flask_restful.abort(401)
|
|
|
|
return wrapper
|
|
|
|
|
2020-02-15 08:38:33 +00:00
|
|
|
def readable_errors(func):
|
|
|
|
@wraps(func)
|
|
|
|
def wrapper(*args, **kwargs):
|
|
|
|
try:
|
|
|
|
return func(*args, **kwargs)
|
|
|
|
except etcd3.exceptions.ConnectionFailedError as e:
|
|
|
|
raise UncloudException('Cannot connect to etcd: is etcd running and reachable? {}'.format(e))
|
|
|
|
except etcd3.exceptions.ConnectionTimeoutError as e:
|
|
|
|
raise UncloudException('etcd connection timeout. {}'.format(e))
|
|
|
|
|
|
|
|
return wrapper
|
|
|
|
|
|
|
|
|
|
|
|
class DB(object):
|
|
|
|
def __init__(self, config, prefix="/"):
|
|
|
|
self.config = config
|
|
|
|
|
|
|
|
# Root for everything
|
|
|
|
self.base_prefix= '/nicohack'
|
|
|
|
|
|
|
|
# Can be set from outside
|
|
|
|
self.prefix = prefix
|
|
|
|
|
|
|
|
self.connect()
|
|
|
|
|
|
|
|
@readable_errors
|
|
|
|
def connect(self):
|
|
|
|
self._db_clients = []
|
|
|
|
for endpoint in self.config.etcd_hosts:
|
|
|
|
client = etcd3.client(host=endpoint, **self.config.etcd_args)
|
|
|
|
self._db_clients.append(client)
|
|
|
|
|
|
|
|
def realkey(self, key):
|
|
|
|
return "{}{}/{}".format(self.base_prefix,
|
|
|
|
self.prefix,
|
|
|
|
key)
|
|
|
|
|
|
|
|
@readable_errors
|
|
|
|
def get(self, key, as_json=False, **kwargs):
|
|
|
|
value, _ = self._db_clients[0].get(self.realkey(key), **kwargs)
|
|
|
|
|
|
|
|
if as_json:
|
|
|
|
value = json.loads(value)
|
|
|
|
|
|
|
|
return value
|
|
|
|
|
|
|
|
|
|
|
|
@readable_errors
|
|
|
|
def set(self, key, value, as_json=False, **kwargs):
|
|
|
|
if as_json:
|
|
|
|
value = json.dumps(value)
|
|
|
|
|
|
|
|
# FIXME: iterate over clients in case of failure ?
|
|
|
|
return self._db_clients[0].put(self.realkey(key), value, **kwargs)
|
|
|
|
|
|
|
|
|
|
|
|
class Membership(Resource):
|
|
|
|
def __init__(self, config):
|
|
|
|
self.config = config
|
|
|
|
|
|
|
|
def get(self):
|
|
|
|
data = request.get_json(silent=True) or {}
|
|
|
|
print("{} {}".format(data, config))
|
|
|
|
return {'message': 'Order successful' }, 200
|
|
|
|
|
2020-02-20 08:44:30 +00:00
|
|
|
def post(self):
|
|
|
|
data = request.get_json(silent=True) or {}
|
|
|
|
print("{} {}".format(data, config))
|
|
|
|
return {'message': 'Order 2x successful' }, 200
|
|
|
|
|
2020-02-15 08:38:33 +00:00
|
|
|
|
|
|
|
class Order(Resource):
|
|
|
|
def __init__(self, config):
|
|
|
|
self.config = config
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def post():
|
2020-02-20 15:05:58 +00:00
|
|
|
data = request.get_json(silent=True) or {}
|
2020-02-15 08:38:33 +00:00
|
|
|
print("{} {}".format(data, config))
|
2020-02-20 15:05:58 +00:00
|
|
|
|
|
|
|
|
|
|
|
class Product(Resource):
|
|
|
|
def __init__(self, config):
|
|
|
|
self.config = config
|
|
|
|
|
|
|
|
self.products = []
|
|
|
|
self.products.append(
|
|
|
|
{ "name": "membership-free",
|
|
|
|
"description": """
|
|
|
|
This membership gives you access to the API and includes a VPN
|
|
|
|
with 1 IPv6 address.
|
|
|
|
See https://redmine.ungleich.ch/issues/7747?
|
|
|
|
""",
|
|
|
|
"uuid": "a3883466-0012-4d01-80ff-cbf7469957af",
|
|
|
|
"recurring": True,
|
|
|
|
"recurring_time_frame": "per_year",
|
|
|
|
"features": [
|
|
|
|
{ "name": "membership",
|
|
|
|
"price_one_time": 0,
|
|
|
|
"price_recurring": 0
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
)
|
|
|
|
self.products.append(
|
|
|
|
{ "name": "membership-standard",
|
|
|
|
"description": """
|
|
|
|
This membership gives you access to the API and includes an IPv6-VPN with
|
|
|
|
one IPv6 address ("Road warrior")
|
|
|
|
See https://redmine.ungleich.ch/issues/7747?
|
|
|
|
""",
|
|
|
|
"uuid": "1d85296b-0863-4dd6-a543-a6d5a4fbe4a6",
|
|
|
|
"recurring": True,
|
|
|
|
"recurring_time_frame": "per_month",
|
|
|
|
"features": [
|
|
|
|
{ "name": "membership",
|
|
|
|
"price_one_time": 0,
|
|
|
|
"price_recurring": 5
|
|
|
|
}
|
|
|
|
|
|
|
|
]
|
|
|
|
}
|
|
|
|
)
|
|
|
|
self.products.append(
|
|
|
|
{ "name": "membership-premium",
|
|
|
|
"description": """
|
|
|
|
This membership gives you access to the API and includes an
|
|
|
|
IPv6-VPN with a /48 IPv6 network.
|
|
|
|
See https://redmine.ungleich.ch/issues/7747?
|
|
|
|
""",
|
|
|
|
"uuid": "bfd63fd2-d227-436f-a8b8-600de74dd6ce",
|
|
|
|
"recurring": True,
|
|
|
|
"recurring_time_frame": "per_month",
|
|
|
|
"features": [
|
|
|
|
{ "name": "membership",
|
|
|
|
"price_one_time": 0,
|
|
|
|
"price_recurring": 5
|
|
|
|
}
|
|
|
|
|
|
|
|
]
|
|
|
|
}
|
|
|
|
)
|
2020-02-20 15:55:01 +00:00
|
|
|
self.products.append(
|
|
|
|
{ "name": "ipv6-vpn-with-/48",
|
|
|
|
"description": """
|
|
|
|
An IPv6 VPN with a /48 network included.
|
|
|
|
""",
|
|
|
|
"uuid": "fe5753f8-6fe1-4dc4-9b73-7b803de4c597",
|
|
|
|
"recurring": True,
|
|
|
|
"recurring_time_frame": "per_year",
|
|
|
|
"features": [
|
|
|
|
{ "name": "vpn",
|
|
|
|
"price_one_time": 0,
|
|
|
|
"price_recurring": 120
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
)
|
2020-02-20 15:05:58 +00:00
|
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def post():
|
|
|
|
data = request.get_json(silent=True) or {}
|
|
|
|
print("{} {}".format(data, config))
|
|
|
|
|
|
|
|
def get(self):
|
2020-02-15 08:38:33 +00:00
|
|
|
data = request.get_json(silent=True) or {}
|
2020-02-20 15:05:58 +00:00
|
|
|
print("{} {}".format(data, config))
|
|
|
|
|
|
|
|
return self.products
|
|
|
|
|
2020-02-15 08:38:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
app = Flask(__name__)
|
|
|
|
|
|
|
|
config = {}
|
|
|
|
|
|
|
|
config['etcd_url']="https://etcd1.ungleich.ch"
|
|
|
|
config['ldap_url']="ldaps://ldap1.ungleich.ch"
|
|
|
|
|
|
|
|
api = Api(app)
|
2020-02-20 15:05:58 +00:00
|
|
|
api.add_resource(Order, '/orders', resource_class_args=( config, ))
|
|
|
|
api.add_resource(Product, '/products', resource_class_args=( config, ))
|
2020-02-15 08:38:33 +00:00
|
|
|
api.add_resource(Membership, '/membership', resource_class_args=( config, ))
|
|
|
|
|
|
|
|
app.run(host='::', port=5000, debug=True)
|