Begin to phase in features and processing orders

This commit is contained in:
Nico Schottelius 2020-02-09 12:12:15 +01:00
parent 5da6dbb32e
commit 5ef009cc9b
4 changed files with 108 additions and 38 deletions

View file

@ -81,9 +81,13 @@ class DB(object):
@readable_errors @readable_errors
def get_prefix(self, key, as_json=False, **kwargs): def get_prefix(self, key, as_json=False, **kwargs):
key_range = self._db_clients[0].get_prefix(self.realkey(key), **kwargs) for value, meta in self._db_clients[0].get_prefix(self.realkey(key), **kwargs):
k = meta.key.decode("utf-8")
value = value.decode("utf-8")
if as_json:
value = json.loads(value)
return key_range yield (k, value)
@readable_errors @readable_errors

View file

@ -43,6 +43,8 @@ arg_parser.add_argument('--hackprefix', help="hackprefix, if you need it you kno
# order based commands => later to be shifted below "order" # order based commands => later to be shifted below "order"
arg_parser.add_argument('--order', action='store_true') arg_parser.add_argument('--order', action='store_true')
arg_parser.add_argument('--list-orders', help="List all orders", action='store_true') arg_parser.add_argument('--list-orders', help="List all orders", action='store_true')
arg_parser.add_argument('--process-orders', help="Process all (pending) orders", action='store_true')
arg_parser.add_argument('--product', choices=["dualstack-vm"]) arg_parser.add_argument('--product', choices=["dualstack-vm"])
arg_parser.add_argument('--os-image-name', help="Name of OS image (successor to --image)") arg_parser.add_argument('--os-image-name', help="Name of OS image (successor to --image)")
arg_parser.add_argument('--os-image-size', help="Size of OS image in GB", type=int, default=10) arg_parser.add_argument('--os-image-size', help="Size of OS image in GB", type=int, default=10)
@ -51,6 +53,10 @@ arg_parser.add_argument('--username')
arg_parser.add_argument('--password') arg_parser.add_argument('--password')
arg_parser.add_argument('--api', help="Run the API") arg_parser.add_argument('--api', help="Run the API")
arg_parser.add_argument('--mode',
choices=["direct", "api", "client"],
default="client",
help="Directly manipulate etcd, spawn the API server or behave as a client")
@ -101,7 +107,12 @@ def main(arguments):
if arguments['list_orders']: if arguments['list_orders']:
p = ProductOrder(config) p = ProductOrder(config)
p.list_orders() for product_order in p.list_orders():
print("Order {}: {}".format(product_order.db_entry['uuid'], product_order.db_entry))
if arguments['process_orders']:
p = ProductOrder(config)
p.process_orders()
if arguments['create_vm']: if arguments['create_vm']:
vm = VM(config) vm = VM(config)

View file

@ -20,52 +20,40 @@
import json import json
import uuid import uuid
import logging
from uncloud import UncloudException from uncloud import UncloudException
from uncloud.hack.db import DB from uncloud.hack.db import DB
log = logging.getLogger(__name__)
class ProductOrder(object): class ProductOrder(object):
def __init__(self, config): def __init__(self, config, product_entry=None, db_entry=None):
self.config = config self.config = config
self.db = DB(self.config, prefix="/orders") self.db = DB(self.config, prefix="/orders")
def list_orders(self, filter_key=None, filter_regexp_value=None):
for k,m in self.db.get_prefix(""):
print("{} {}".format(k,m))
class Product(object):
def __init__(self, config, product_name, db_entry=None):
self.config = config
self.db = DB(self.config, prefix="/orders")
self.db_entry = {} self.db_entry = {}
self.db_entry["product_name"] = product_name
self.db_entry["db_version"] = 1 self.db_entry["db_version"] = 1
self.db_entry["product"] = product_entry
# Existing product? Read in db_entry
# Overwrite if we are loading an existing product order
if db_entry: if db_entry:
self.db_entry = db_entry self.db_entry = db_entry
# FIXME: this should return a list of our class!
def list_orders(self, filter_key=None, filter_regexp_value=None):
"""List all orders with - filtering not yet implemented """
@staticmethod for k,v in self.db.get_prefix("", as_json=True):
def define_feature(self, log.debug("{} {}".format(k,v))
name,
feature,
one_time_price,
recurring_price,
recurring_period,
minimum_period):
feature = {}
feature[name] = {}
def valid_status(self): yield self.__class__(self.config, db_entry=v)
if "status" in self.db_entry:
if self.db_entry["status"] in [ "NEW", "SCHEDULED", "CREATED", "DELETED" ]:
return False
return True
def validate_product(self): def process_orders(self):
for orders in self.list_orders():
pass
def set_required_values(self):
if not "uuid" in self.db_entry: if not "uuid" in self.db_entry:
self.db_entry["uuid"] = str(uuid.uuid4()) self.db_entry["uuid"] = str(uuid.uuid4())
if not "status" in self.db_entry: if not "status" in self.db_entry:
@ -73,14 +61,75 @@ class Product(object):
if not "owner" in self.db_entry: if not "owner" in self.db_entry:
self.db_entry["owner"] = "UNKNOWN" self.db_entry["owner"] = "UNKNOWN"
def validate_status(self):
if "status" in self.db_entry:
if self.db_entry["status"] in [ "NEW", "SCHEDULED", "CREATED", "DELETED", "REJECTED" ]:
return False
return True
def order(self):
if not self.db_entry["status"] == "NEW":
raise UncloudException("Cannot re-order same order. Status: {}".format(self.db_entry["status"]))
class Product(object):
def __init__(self,
config,
product_name,
db_entry=None):
self.config = config
self.db = DB(self.config, prefix="/orders")
self.db_entry = {}
self.db_entry["product_name"] = product_name
self.db_entry["db_version"] = 1
self.db_entry["features"] = {}
# Existing product? Read in db_entry
if db_entry:
self.db_entry = db_entry
self.valid_periods = [ "per_year", "per_month", "per_week",
"per_day", "per_hour",
"per_minute", "per_second" ]
def define_feature(self,
name,
one_time_price,
recurring_price,
recurring_period,
minimum_period):
self.db_entry['features'][name] = {}
self.db_entry['features'][name]['one_time_price'] = one_time_price
self.db_entry['features'][name]['recurring_price'] = recurring_price
if not recurring_period in self.valid_periods:
raise UncloudException("Invalid recurring period: {}".format(recurring_period))
self.db_entry['features'][name]['recurring_period'] = recurring_period
if not minimum_period in self.valid_periods:
raise UncloudException("Invalid recurring period: {}".format(recurring_period))
recurring_index = self.valid_periods.index(recurring_period)
minimum_index = self.valid_periods.index(minimum_period)
if minimum_index < recurring_index:
raise UncloudException("Minimum period for product '{}' feature '{}' must be shorter or equal than/as recurring period: {} > {}".format(self.db_entry['product_name'], name, minimum_period, recurring_period))
self.db_entry['features'][name]['minimum_period'] = minimum_period
def validate_product(self):
for feature in self.db_entry['features']:
pass
def place_order(self): def place_order(self):
""" Schedule creating the product in etcd """ """ Schedule creating the product in etcd """
self.validate_product() order = ProductOrder(self.config, self.db_entry)
order.set_required_values()
# FIXME: very status order.order()
if not self.db_entry["status"] == "NEW":
raise UncloudException("Cannot re-order product")
self.db.set(self.db_entry["uuid"], str(self)) self.db.set(self.db_entry["uuid"], str(self))

View file

@ -90,6 +90,12 @@ class VM(object):
self.vm = {} self.vm = {}
self.product = Product(config, product_name="dualstack-vm") self.product = Product(config, product_name="dualstack-vm")
self.product.define_feature(name="base",
one_time_price=0,
recurring_price=9,
recurring_period="per_month",
minimum_period="per_hour")
self.features = [] self.features = []
# self.features.append(self.define_feature( # self.features.append(self.define_feature(