201 lines
6.6 KiB
Python
201 lines
6.6 KiB
Python
# Copyright 2013 Mirantis, Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
import sys
|
|
import json
|
|
import Queue
|
|
import os.path
|
|
import itertools
|
|
from datetime import datetime
|
|
import jinja2
|
|
import StringIO
|
|
|
|
import sqlalchemy.types
|
|
from nailgun.settings import settings
|
|
from nailgun.api import models
|
|
from sqlalchemy import orm
|
|
from nailgun.db import orm as ormgen
|
|
from nailgun.logger import logger
|
|
from nailgun.network.manager import NetworkManager
|
|
|
|
db = ormgen()
|
|
|
|
|
|
def capitalize_model_name(model_name):
|
|
return ''.join(map(lambda s: s.capitalize(), model_name.split('_')))
|
|
|
|
|
|
def template_fixture(fileobj, config=None):
|
|
if not config:
|
|
config = settings
|
|
t = jinja2.Template(fileobj.read())
|
|
return StringIO.StringIO(t.render(settings=config))
|
|
|
|
|
|
def upload_fixture(fileobj):
|
|
db.expunge_all()
|
|
fixture = json.load(template_fixture(fileobj))
|
|
|
|
queue = Queue.Queue()
|
|
keys = {}
|
|
|
|
for obj in fixture:
|
|
pk = obj["pk"]
|
|
model_name = obj["model"].split(".")[1]
|
|
|
|
try:
|
|
model = itertools.dropwhile(
|
|
lambda m: not hasattr(models, m),
|
|
[model_name.capitalize(),
|
|
"".join(map(lambda n: n.capitalize(), model_name.split("_")))]
|
|
).next()
|
|
except StopIteration:
|
|
raise Exception("Couldn't find model {0}".format(model_name))
|
|
|
|
obj['model'] = getattr(models, capitalize_model_name(model_name))
|
|
keys[obj['model'].__tablename__] = {}
|
|
|
|
# Check if it's already uploaded
|
|
obj_from_db = db.query(obj['model']).get(pk)
|
|
if obj_from_db:
|
|
logger.info("Fixture model '%s' with pk='%s' already"
|
|
" uploaded. Skipping", model_name, pk)
|
|
continue
|
|
queue.put(obj)
|
|
|
|
pending_objects = []
|
|
|
|
while True:
|
|
try:
|
|
obj = queue.get_nowait()
|
|
except:
|
|
break
|
|
|
|
new_obj = obj['model']()
|
|
|
|
fk_fields = {}
|
|
for field, value in obj["fields"].iteritems():
|
|
f = getattr(obj['model'], field)
|
|
impl = f.impl
|
|
fk_model = None
|
|
if hasattr(f.comparator.prop, "argument"):
|
|
if hasattr(f.comparator.prop.argument, "__call__"):
|
|
fk_model = f.comparator.prop.argument()
|
|
else:
|
|
fk_model = f.comparator.prop.argument.class_
|
|
|
|
if fk_model:
|
|
if value not in keys[fk_model.__tablename__]:
|
|
if obj not in pending_objects:
|
|
queue.put(obj)
|
|
pending_objects.append(obj)
|
|
continue
|
|
else:
|
|
logger.error(
|
|
u"Can't resolve foreign key "
|
|
"'{0}' for object '{1}'".format(
|
|
field,
|
|
obj["model"]
|
|
)
|
|
)
|
|
break
|
|
else:
|
|
value = keys[fk_model.__tablename__][value].id
|
|
|
|
if isinstance(impl, orm.attributes.ScalarObjectAttributeImpl):
|
|
if value:
|
|
fk_fields[field] = (value, fk_model)
|
|
elif isinstance(impl, orm.attributes.CollectionAttributeImpl):
|
|
if value:
|
|
fk_fields[field] = (value, fk_model)
|
|
elif isinstance(
|
|
f.property.columns[0].type, sqlalchemy.types.DateTime
|
|
):
|
|
if value:
|
|
setattr(
|
|
new_obj,
|
|
field,
|
|
datetime.strptime(value, "%d-%m-%Y %H:%M:%S")
|
|
)
|
|
else:
|
|
setattr(
|
|
new_obj,
|
|
field,
|
|
datetime.now()
|
|
)
|
|
else:
|
|
setattr(new_obj, field, value)
|
|
|
|
for field, data in fk_fields.iteritems():
|
|
if isinstance(data[0], int):
|
|
setattr(new_obj, field, db.query(data[1]).get(data[0]))
|
|
elif isinstance(data[0], list):
|
|
for v in data[0]:
|
|
getattr(new_obj, field).append(
|
|
db.query(data[1]).get(v)
|
|
)
|
|
db.add(new_obj)
|
|
db.commit()
|
|
keys[obj['model'].__tablename__][obj["pk"]] = new_obj
|
|
|
|
# UGLY HACK for testing
|
|
if new_obj.__class__.__name__ == 'Node':
|
|
new_obj.attributes = models.NodeAttributes()
|
|
db.commit()
|
|
new_obj.attributes.volumes = \
|
|
new_obj.volume_manager.gen_default_volumes_info()
|
|
network_manager = NetworkManager(db)
|
|
network_manager.update_interfaces_info(new_obj)
|
|
db.commit()
|
|
|
|
|
|
def upload_fixtures():
|
|
fns = []
|
|
for path in settings.FIXTURES_TO_UPLOAD:
|
|
if not os.path.isabs(path):
|
|
path = os.path.abspath(os.path.join(os.path.dirname(__file__),
|
|
path))
|
|
fns.append(path)
|
|
|
|
for fn in fns:
|
|
with open(fn, "r") as fileobj:
|
|
upload_fixture(fileobj)
|
|
logger.info("Fixture has been uploaded from file: %s" % fn)
|
|
|
|
|
|
def dump_fixture(model_name):
|
|
dump = []
|
|
app_name = 'nailgun'
|
|
model = getattr(models, capitalize_model_name(model_name))
|
|
for obj in db.query(model).all():
|
|
obj_dump = {}
|
|
obj_dump['pk'] = getattr(obj, model.__mapper__.primary_key[0].name)
|
|
obj_dump['model'] = "%s.%s" % (app_name, model_name)
|
|
obj_dump['fields'] = {}
|
|
dump.append(obj_dump)
|
|
for prop in model.__mapper__.iterate_properties:
|
|
if isinstance(prop, sqlalchemy.orm.ColumnProperty):
|
|
field = str(prop.key)
|
|
value = getattr(obj, field)
|
|
if value is None:
|
|
continue
|
|
if not isinstance(value, (
|
|
list, dict, str, unicode, int, float, bool)):
|
|
value = ""
|
|
obj_dump['fields'][field] = value
|
|
sys.stdout.write(json.dumps(dump, indent=4))
|