blob: 715046a3854fd9959014098392ed7381b0ef5bd6 [file] [log] [blame]
Scott Bakerbba67b62019-01-28 17:38:21 -08001# Copyright 2017-present Open Networking Foundation
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15
Zack Williams5c2ea232019-01-30 15:23:01 -070016from __future__ import absolute_import
17
Scott Bakerbba67b62019-01-28 17:38:21 -080018from functools import reduce
19
Zack Williams5c2ea232019-01-30 15:23:01 -070020from xosconfig import Config
21
Scott Bakerbba67b62019-01-28 17:38:21 -080022
23def f7(seq):
24 seen = set()
25 seen_add = seen.add
26 return [x for x in seq if not (x in seen or seen_add(x))]
27
28
29def elim_dups(backend_str):
30 strs = backend_str.split(" // ")
31 strs2 = f7(strs)
32 return " // ".join(strs2)
33
34
35def deepgetattr(obj, attr):
36 return reduce(getattr, attr.split("."), obj)
37
38
39def obj_class_name(obj):
40 return getattr(obj, "model_name", obj.__class__.__name__)
41
42
43class InnocuousException(Exception):
44 pass
45
46
47class DeferredException(Exception):
48 pass
49
50
51class FailedDependency(Exception):
52 pass
53
54
55class SyncStep(object):
56 """ An XOS Sync step.
57
58 Attributes:
59 psmodel Model name the step synchronizes
60 dependencies list of names of models that must be synchronized first if the current model depends on them
61 """
62
Scott Bakerbba67b62019-01-28 17:38:21 -080063 slow = False
64
65 def get_prop(self, prop):
66 # NOTE config_dir is never define, is this used?
67 sync_config_dir = Config.get("config_dir")
68 prop_config_path = "/".join(sync_config_dir, self.name, prop)
69 return open(prop_config_path).read().rstrip()
70
71 def __init__(self, **args):
72 """Initialize a sync step
73 Keyword arguments:
Scott Bakerc2fddaa2019-01-30 15:45:03 -080074 model_accessor: class used to access models
75 driver: used by openstack synchronizer (DEPRECATED)
76 error_map: used by openstack synchronizer (DEPRECATED)
Scott Bakerbba67b62019-01-28 17:38:21 -080077 """
Scott Bakerc2fddaa2019-01-30 15:45:03 -080078 self.model_accessor = args.get("model_accessor")
Scott Bakerbba67b62019-01-28 17:38:21 -080079 self.driver = args.get("driver")
80 self.error_map = args.get("error_map")
81
Scott Bakerc2fddaa2019-01-30 15:45:03 -080082 assert self.model_accessor is not None
83
Scott Bakerbba67b62019-01-28 17:38:21 -080084 try:
85 self.soft_deadline = int(self.get_prop("soft_deadline_seconds"))
86 except BaseException:
87 self.soft_deadline = 5 # 5 seconds
88
89 if "log" in args:
90 self.log = args.get("log")
91
92 return
93
Scott Bakerc2fddaa2019-01-30 15:45:03 -080094 @property
95 def observes_classes(self):
96 """ Return a list of classes that this syncstep observes. The "observes" class member can be either a list of
97 items or a single item. Those items may be either classes or names of classes. This function always returns
98 a list of classes.
99 """
100 if not self.observes:
101 return []
102 if isinstance(self.observes, list):
103 observes = self.observes
104 else:
105 observes = [self.observes]
106 result = []
107 for class_or_name in observes:
108 if isinstance(class_or_name, str):
109 result.append(self.model_accessor.get_model_class(class_or_name))
110 else:
111 result.append(class_or_name)
112 return result
113
Scott Bakerbba67b62019-01-28 17:38:21 -0800114 def fetch_pending(self, deletion=False):
115 # This is the most common implementation of fetch_pending
116 # Steps should override it if they have their own logic
117 # for figuring out what objects are outstanding.
118
Scott Bakerc2fddaa2019-01-30 15:45:03 -0800119 return self.model_accessor.fetch_pending(self.observes_classes, deletion)
120
Scott Bakerbba67b62019-01-28 17:38:21 -0800121 def sync_record(self, o):
Scott Bakerc2fddaa2019-01-30 15:45:03 -0800122 self.log.debug("In abstract sync record", **o.tologdict())
123 # This method should be overridden by the service
Scott Bakerbba67b62019-01-28 17:38:21 -0800124
Scott Bakerbba67b62019-01-28 17:38:21 -0800125 def delete_record(self, o):
Scott Bakerc2fddaa2019-01-30 15:45:03 -0800126 self.log.debug("In abstract delete record", **o.tologdict())
127 # This method should be overridden by the service