Add filtering support:

(venv) [12:54] diamond:uncloud% ./bin/uncloud-run-reinstall hack --product 'dualstack-vm' --os-image-name alpine311 --username nicocustomer --password '...' --hackprefix ~/vcs/uncloud/uncloud/hack/hackcloud/ --etcd-host etcd1.ungleich.ch --etcd-ca-cert ~/vcs/ungleich-dot-cdist/files/etcd/ca.pem --etcd-cert-cert ~/vcs/ungleich-dot-cdist/files/etcd/nico.pem --etcd-cert-key ~/vcs/ungleich-dot-cdist/files/etcd/nico-key.pem --list-orders --filter-order-key "status" --filter-order-regexp NEW
This commit is contained in:
Nico Schottelius 2020-02-09 12:54:52 +01:00
parent 5ef009cc9b
commit a80a279ba5
5 changed files with 59 additions and 16 deletions

View file

@ -0,0 +1 @@

View file

@ -23,12 +23,20 @@
import etcd3
import json
import logging
import datetime
from functools import wraps
from uncloud import UncloudException
log = logging.getLogger(__name__)
def db_logentry(message):
timestamp = datetime.datetime.now()
return {
"timestamp": str(timestamp),
"message": message
}
def readable_errors(func):
@wraps(func)
@ -99,6 +107,8 @@ class DB(object):
# FIXME: iterate over clients in case of failure ?
return self._db_clients[0].put(self.realkey(key), value, **kwargs)
@readable_errors
def increment(self, key, **kwargs):
print(self.realkey(key))

View file

@ -1,8 +1,10 @@
import argparse
import logging
import re
import ldap3
from uncloud.hack.vm import VM
from uncloud.hack.config import Config
from uncloud.hack.mac import MAC
@ -43,6 +45,9 @@ arg_parser.add_argument('--hackprefix', help="hackprefix, if you need it you kno
# order based commands => later to be shifted below "order"
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('--filter-order-key', help="Which key to filter on")
arg_parser.add_argument('--filter-order-regexp', help="Which regexp the value should match")
arg_parser.add_argument('--process-orders', help="Process all (pending) orders", action='store_true')
arg_parser.add_argument('--product', choices=["dualstack-vm"])
@ -107,7 +112,8 @@ def main(arguments):
if arguments['list_orders']:
p = ProductOrder(config)
for product_order in p.list_orders():
for product_order in p.list_orders(filter_key=arguments['filter_order_key'],
filter_regexp=arguments['filter_order_regexp']):
print("Order {}: {}".format(product_order.db_entry['uuid'], product_order.db_entry))
if arguments['process_orders']:

View file

@ -21,9 +21,10 @@
import json
import uuid
import logging
import re
from uncloud import UncloudException
from uncloud.hack.db import DB
from uncloud.hack.db import DB, db_logentry
log = logging.getLogger(__name__)
@ -32,38 +33,45 @@ class ProductOrder(object):
self.config = config
self.db = DB(self.config, prefix="/orders")
self.db_entry = {}
self.db_entry["db_version"] = 1
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_value=None):
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 process_orders(self):
for orders in self.list_orders():
pass
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", "DELETED", "REJECTED" ]:
if self.db_entry["status"] in [ "NEW",
"SCHEDULED",
"CREATED_ACTIVE",
"CANCELLED",
"REJECTED" ]:
return False
return True
@ -71,6 +79,25 @@ class ProductOrder(object):
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,
@ -83,6 +110,7 @@ class Product(object):
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
@ -127,12 +155,9 @@ class Product(object):
def place_order(self):
""" Schedule creating the product in etcd """
order = ProductOrder(self.config, self.db_entry)
order = ProductOrder(self.config, product_entry=self.db_entry)
order.set_required_values()
order.order()
self.db.set(self.db_entry["uuid"], str(self))
def __str__(self):
return json.dumps(self.db_entry)

View file

@ -101,6 +101,7 @@ class VM(object):
# self.features.append(self.define_feature(
# self.super().__init__(
def get_qemu_args(self):
command = (
"-name {owner}-{name}"