#!/usr/bin/env python3 # -*- coding: utf-8 -*- # # 2020 Nico Schottelius (nico.schottelius at ungleich.ch) # # This file is part of uncloud. # # uncloud is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # uncloud is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with uncloud. If not, see . import json import uuid import logging import re from uncloud import UncloudException from uncloud.hack.db import DB, db_logentry log = logging.getLogger(__name__) class ProductOrder(object): def __init__(self, config, product_entry=None, db_entry=None): self.config = config self.db = DB(self.config, prefix="/orders") self.db_entry = {} self.db_entry["product"] = product_entry # Overwrite if we are loading an existing product order if 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=None): """List all orders with - filtering not yet implemented """ for k,v in self.db.get_prefix("", as_json=True): log.debug("{} {}".format(k,v)) if filter_key and filter_regexp: if filter_key in v: if re.match(filter_regexp, v[filter_key]): yield self.__class__(self.config, db_entry=v) else: yield self.__class__(self.config, db_entry=v) def set_required_values(self): """Set values that are required to make the db entry valid""" if not "uuid" in self.db_entry: self.db_entry["uuid"] = str(uuid.uuid4()) if not "status" in self.db_entry: self.db_entry["status"] = "NEW" if not "owner" in self.db_entry: self.db_entry["owner"] = "UNKNOWN" if not "log" in self.db_entry: self.db_entry["log"] = [] if not "db_version" in self.db_entry: self.db_entry["db_version"] = 1 def validate_status(self): if "status" in self.db_entry: if self.db_entry["status"] in [ "NEW", "SCHEDULED", "CREATED_ACTIVE", "CANCELLED", "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"])) def process_orders(self): for order in self.list_orders(): if order.db_entry["status"] == "NEW": log.info("Handling new order: {}".format(order)) # FIXME: these all should be a transactions! -> fix concurrent access! ! if not "log" in order.db_entry: order.db_entry['log'] = [] for must_attribute in [ "owner", "product" ]: if not must_attribute in order.db_entry: order.db_entry['log'].append(db_logentry("Missing {} entry, rejecting order".format(must_attribute))) order.db_entry['status'] = "REJECTED" self.db.set(order.db_entry['uuid'], order.db_entry, as_json=True) def __str__(self): return str(self.db_entry) 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["log"] = [] 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): """ Schedule creating the product in etcd """ order = ProductOrder(self.config, product_entry=self.db_entry) order.set_required_values() order.order() def __str__(self): return json.dumps(self.db_entry)