cli: initial import for import/export
This commit is contained in:
parent
dc59921498
commit
0c349091e7
3 changed files with 143 additions and 13 deletions
29
app/cli/__main__.py
Normal file
29
app/cli/__main__.py
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import argparse
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
from os.path import basename
|
||||||
|
|
||||||
|
from app.cli.db import DbCliHandler
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args(argv):
|
||||||
|
if basename(argv[0]) == "__main__.py":
|
||||||
|
argv[0] = "bypass"
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("-v", "--verbose", help="increase logging verbosity", action="store_true")
|
||||||
|
subparsers = parser.add_subparsers(title="command", help="command to run")
|
||||||
|
DbCliHandler.add_subparser_to(subparsers)
|
||||||
|
args = parser.parse_args(argv[1:])
|
||||||
|
if "cls" in args:
|
||||||
|
command = args.cls(args)
|
||||||
|
command.run()
|
||||||
|
else:
|
||||||
|
parser.print_help()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
verbose = "-v" in sys.argv or "--verbose" in sys.argv
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.DEBUG if verbose else logging.INFO)
|
||||||
|
logging.debug("Arguments: %s", sys.argv)
|
||||||
|
parse_args(sys.argv)
|
74
app/cli/db.py
Normal file
74
app/cli/db.py
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
import argparse
|
||||||
|
import csv
|
||||||
|
import datetime
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from app import app
|
||||||
|
from app.extensions import db
|
||||||
|
from app.models import Group, Origin, Proxy, BridgeConf, Alarm
|
||||||
|
|
||||||
|
models = {
|
||||||
|
"group": Group,
|
||||||
|
"origin": Origin,
|
||||||
|
"proxy": Proxy,
|
||||||
|
"bridge": BridgeConf,
|
||||||
|
"alarm": Alarm
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def export(model: db.Model):
|
||||||
|
out = csv.writer(sys.stdout)
|
||||||
|
out.writerow(model.csv_header())
|
||||||
|
for r in model.query.all():
|
||||||
|
out.writerow(r.csv_row())
|
||||||
|
|
||||||
|
|
||||||
|
def impot(model: db.Model):
|
||||||
|
first = True
|
||||||
|
header = model.csv_header()
|
||||||
|
try:
|
||||||
|
for line in csv.reader(sys.stdin):
|
||||||
|
if first:
|
||||||
|
if line != header:
|
||||||
|
logging.error("CSV header mismatch")
|
||||||
|
sys.exit(1)
|
||||||
|
first = False
|
||||||
|
continue
|
||||||
|
x = model()
|
||||||
|
for i in range(len(header)):
|
||||||
|
if header[i] in ["added", "updated", "destroyed", "deprecated", "last_updated", "terraform_updated"]:
|
||||||
|
if line[i] == "":
|
||||||
|
line[i] = None
|
||||||
|
else:
|
||||||
|
line[i] = datetime.datetime.strptime(line[i], "%Y-%m-%d %H:%M:%S.%f")
|
||||||
|
setattr(x, header[i], line[i])
|
||||||
|
db.session.add(x)
|
||||||
|
db.session.commit()
|
||||||
|
logging.info("Import completed successfully")
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception(e)
|
||||||
|
db.session.rollback()
|
||||||
|
|
||||||
|
|
||||||
|
class DbCliHandler:
|
||||||
|
@classmethod
|
||||||
|
def add_subparser_to(cls, subparsers: argparse._SubParsersAction) -> None:
|
||||||
|
parser = subparsers.add_parser("db", help="database operations")
|
||||||
|
parser.add_argument("--export", choices=["group", "origin", "proxy", "bridge"],
|
||||||
|
help="export data to CSV format")
|
||||||
|
parser.add_argument("--import", choices=["group", "origin", "proxy", "bridge"],
|
||||||
|
help="import data from CSV format", dest="impot")
|
||||||
|
parser.set_defaults(cls=cls)
|
||||||
|
|
||||||
|
def __init__(self, args):
|
||||||
|
self.args = args
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
with app.app_context():
|
||||||
|
if self.args.export:
|
||||||
|
export(models[self.args.export])
|
||||||
|
elif self.args.impot:
|
||||||
|
impot(models[self.args.impot])
|
||||||
|
else:
|
||||||
|
logging.error("No action requested")
|
|
@ -18,6 +18,17 @@ class AbstractConfiguration(db.Model):
|
||||||
self.updated = datetime.utcnow()
|
self.updated = datetime.utcnow()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def csv_header(self):
|
||||||
|
return [
|
||||||
|
"id", "description", "added", "updated", "destroyed"
|
||||||
|
]
|
||||||
|
|
||||||
|
def csv_row(self):
|
||||||
|
return [
|
||||||
|
getattr(self, x) for x in self.csv_header()
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class AbstractResource(db.Model):
|
class AbstractResource(db.Model):
|
||||||
__abstract__ = True
|
__abstract__ = True
|
||||||
|
@ -40,30 +51,28 @@ class AbstractResource(db.Model):
|
||||||
self.updated = datetime.utcnow()
|
self.updated = datetime.utcnow()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
def csv_row(self):
|
||||||
|
return [
|
||||||
|
self[x] for x in self.csv_header()
|
||||||
|
]
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<{self.__class__.__name__} #{self.id}>"
|
return f"<{self.__class__.__name__} #{self.id}>"
|
||||||
|
|
||||||
|
|
||||||
class Group(db.Model):
|
class Group(AbstractConfiguration):
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
|
||||||
group_name = db.Column(db.String(80), unique=True, nullable=False)
|
group_name = db.Column(db.String(80), unique=True, nullable=False)
|
||||||
description = db.Column(db.String(255), nullable=False)
|
|
||||||
eotk = db.Column(db.Boolean())
|
eotk = db.Column(db.Boolean())
|
||||||
added = db.Column(db.DateTime(), default=datetime.utcnow, nullable=False)
|
|
||||||
updated = db.Column(db.DateTime(), default=datetime.utcnow, nullable=False)
|
|
||||||
|
|
||||||
origins = db.relationship("Origin", back_populates="group")
|
origins = db.relationship("Origin", back_populates="group")
|
||||||
bridgeconfs = db.relationship("BridgeConf", back_populates="group")
|
bridgeconfs = db.relationship("BridgeConf", back_populates="group")
|
||||||
alarms = db.relationship("Alarm", back_populates="group")
|
alarms = db.relationship("Alarm", back_populates="group")
|
||||||
|
|
||||||
def as_dict(self):
|
@classmethod
|
||||||
return {
|
def csv_header(self):
|
||||||
"id": self.id,
|
return super().csv_header() + [
|
||||||
"name": self.group_name,
|
"group_name", "eotk"
|
||||||
"description": self.description,
|
]
|
||||||
"added": self.added,
|
|
||||||
"updated": self.updated
|
|
||||||
}
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<Group %r>' % self.group_name
|
return '<Group %r>' % self.group_name
|
||||||
|
@ -78,6 +87,12 @@ class Origin(AbstractConfiguration):
|
||||||
proxies = db.relationship("Proxy", back_populates="origin")
|
proxies = db.relationship("Proxy", back_populates="origin")
|
||||||
alarms = db.relationship("Alarm", back_populates="origin")
|
alarms = db.relationship("Alarm", back_populates="origin")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def csv_header(cls):
|
||||||
|
return [
|
||||||
|
"id", "description", "added", "updated", "destroyed", "group_id", "domain_name"
|
||||||
|
]
|
||||||
|
|
||||||
def as_dict(self):
|
def as_dict(self):
|
||||||
return {
|
return {
|
||||||
"id": self.id,
|
"id": self.id,
|
||||||
|
@ -171,6 +186,18 @@ class Alarm(db.Model):
|
||||||
proxy = db.relationship("Proxy", back_populates="alarms")
|
proxy = db.relationship("Proxy", back_populates="alarms")
|
||||||
bridge = db.relationship("Bridge", back_populates="alarms")
|
bridge = db.relationship("Bridge", back_populates="alarms")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def csv_header(cls):
|
||||||
|
return [
|
||||||
|
"id", "target", "group_id", "origin_id", "proxy_id", "bridge_id", "alarm_type",
|
||||||
|
"alarm_state", "state_changed", "last_updated", "text"
|
||||||
|
]
|
||||||
|
|
||||||
|
def csv_row(self):
|
||||||
|
return [
|
||||||
|
self[x] for x in self.csv_header()
|
||||||
|
]
|
||||||
|
|
||||||
def update_state(self, state: AlarmState, text: str):
|
def update_state(self, state: AlarmState, text: str):
|
||||||
if self.alarm_state != state or self.state_changed is None:
|
if self.alarm_state != state or self.state_changed is None:
|
||||||
self.state_changed = datetime.utcnow()
|
self.state_changed = datetime.utcnow()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue