blob: 715046a3854fd9959014098392ed7381b0ef5bd6 [file] [log] [blame]
# Copyright 2017-present Open Networking Foundation
#
# 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.
from __future__ import absolute_import
from functools import reduce
from xosconfig import Config
def f7(seq):
seen = set()
seen_add = seen.add
return [x for x in seq if not (x in seen or seen_add(x))]
def elim_dups(backend_str):
strs = backend_str.split(" // ")
strs2 = f7(strs)
return " // ".join(strs2)
def deepgetattr(obj, attr):
return reduce(getattr, attr.split("."), obj)
def obj_class_name(obj):
return getattr(obj, "model_name", obj.__class__.__name__)
class InnocuousException(Exception):
pass
class DeferredException(Exception):
pass
class FailedDependency(Exception):
pass
class SyncStep(object):
""" An XOS Sync step.
Attributes:
psmodel Model name the step synchronizes
dependencies list of names of models that must be synchronized first if the current model depends on them
"""
slow = False
def get_prop(self, prop):
# NOTE config_dir is never define, is this used?
sync_config_dir = Config.get("config_dir")
prop_config_path = "/".join(sync_config_dir, self.name, prop)
return open(prop_config_path).read().rstrip()
def __init__(self, **args):
"""Initialize a sync step
Keyword arguments:
model_accessor: class used to access models
driver: used by openstack synchronizer (DEPRECATED)
error_map: used by openstack synchronizer (DEPRECATED)
"""
self.model_accessor = args.get("model_accessor")
self.driver = args.get("driver")
self.error_map = args.get("error_map")
assert self.model_accessor is not None
try:
self.soft_deadline = int(self.get_prop("soft_deadline_seconds"))
except BaseException:
self.soft_deadline = 5 # 5 seconds
if "log" in args:
self.log = args.get("log")
return
@property
def observes_classes(self):
""" Return a list of classes that this syncstep observes. The "observes" class member can be either a list of
items or a single item. Those items may be either classes or names of classes. This function always returns
a list of classes.
"""
if not self.observes:
return []
if isinstance(self.observes, list):
observes = self.observes
else:
observes = [self.observes]
result = []
for class_or_name in observes:
if isinstance(class_or_name, str):
result.append(self.model_accessor.get_model_class(class_or_name))
else:
result.append(class_or_name)
return result
def fetch_pending(self, deletion=False):
# This is the most common implementation of fetch_pending
# Steps should override it if they have their own logic
# for figuring out what objects are outstanding.
return self.model_accessor.fetch_pending(self.observes_classes, deletion)
def sync_record(self, o):
self.log.debug("In abstract sync record", **o.tologdict())
# This method should be overridden by the service
def delete_record(self, o):
self.log.debug("In abstract delete record", **o.tologdict())
# This method should be overridden by the service