blob: 7644822c81b689b2e9a5d0c30401630f4f6f055d [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
Scott Bakerbba67b62019-01-28 17:38:21 -080016from xosconfig import Config
17from functools import reduce
18
19
20def f7(seq):
21 seen = set()
22 seen_add = seen.add
23 return [x for x in seq if not (x in seen or seen_add(x))]
24
25
26def elim_dups(backend_str):
27 strs = backend_str.split(" // ")
28 strs2 = f7(strs)
29 return " // ".join(strs2)
30
31
32def deepgetattr(obj, attr):
33 return reduce(getattr, attr.split("."), obj)
34
35
36def obj_class_name(obj):
37 return getattr(obj, "model_name", obj.__class__.__name__)
38
39
40class InnocuousException(Exception):
41 pass
42
43
44class DeferredException(Exception):
45 pass
46
47
48class FailedDependency(Exception):
49 pass
50
51
52class SyncStep(object):
53 """ An XOS Sync step.
54
55 Attributes:
56 psmodel Model name the step synchronizes
57 dependencies list of names of models that must be synchronized first if the current model depends on them
58 """
59
60 # map_sync_outputs can return this value to cause a step to be marked
61 # successful without running ansible. Used for sync_network_controllers
62 # on nat networks.
63 SYNC_WITHOUT_RUNNING = "sync_without_running"
64
65 slow = False
66
67 def get_prop(self, prop):
68 # NOTE config_dir is never define, is this used?
69 sync_config_dir = Config.get("config_dir")
70 prop_config_path = "/".join(sync_config_dir, self.name, prop)
71 return open(prop_config_path).read().rstrip()
72
73 def __init__(self, **args):
74 """Initialize a sync step
75 Keyword arguments:
Scott Bakerc2fddaa2019-01-30 15:45:03 -080076 model_accessor: class used to access models
77 driver: used by openstack synchronizer (DEPRECATED)
78 error_map: used by openstack synchronizer (DEPRECATED)
Scott Bakerbba67b62019-01-28 17:38:21 -080079 """
Scott Bakerc2fddaa2019-01-30 15:45:03 -080080 self.model_accessor = args.get("model_accessor")
Scott Bakerbba67b62019-01-28 17:38:21 -080081 self.driver = args.get("driver")
82 self.error_map = args.get("error_map")
83
Scott Bakerc2fddaa2019-01-30 15:45:03 -080084 assert self.model_accessor is not None
85
Scott Bakerbba67b62019-01-28 17:38:21 -080086 try:
87 self.soft_deadline = int(self.get_prop("soft_deadline_seconds"))
88 except BaseException:
89 self.soft_deadline = 5 # 5 seconds
90
91 if "log" in args:
92 self.log = args.get("log")
93
94 return
95
Scott Bakerc2fddaa2019-01-30 15:45:03 -080096 @property
97 def observes_classes(self):
98 """ Return a list of classes that this syncstep observes. The "observes" class member can be either a list of
99 items or a single item. Those items may be either classes or names of classes. This function always returns
100 a list of classes.
101 """
102 if not self.observes:
103 return []
104 if isinstance(self.observes, list):
105 observes = self.observes
106 else:
107 observes = [self.observes]
108 result = []
109 for class_or_name in observes:
110 if isinstance(class_or_name, str):
111 result.append(self.model_accessor.get_model_class(class_or_name))
112 else:
113 result.append(class_or_name)
114 return result
115
116
Scott Bakerbba67b62019-01-28 17:38:21 -0800117 def fetch_pending(self, deletion=False):
118 # This is the most common implementation of fetch_pending
119 # Steps should override it if they have their own logic
120 # for figuring out what objects are outstanding.
121
Scott Bakerc2fddaa2019-01-30 15:45:03 -0800122 return self.model_accessor.fetch_pending(self.observes_classes, deletion)
123
Scott Bakerbba67b62019-01-28 17:38:21 -0800124
125 def sync_record(self, o):
Scott Bakerc2fddaa2019-01-30 15:45:03 -0800126 self.log.debug("In abstract sync record", **o.tologdict())
127 # This method should be overridden by the service
Scott Bakerbba67b62019-01-28 17:38:21 -0800128
Scott Bakerbba67b62019-01-28 17:38:21 -0800129
130 def delete_record(self, o):
Scott Bakerc2fddaa2019-01-30 15:45:03 -0800131 self.log.debug("In abstract delete record", **o.tologdict())
132 # This method should be overridden by the service