blob: 08637ed5a18d1cd422da0d7b978b4021cd979cbf [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
63 # map_sync_outputs can return this value to cause a step to be marked
64 # successful without running ansible. Used for sync_network_controllers
65 # on nat networks.
66 SYNC_WITHOUT_RUNNING = "sync_without_running"
67
68 slow = False
69
70 def get_prop(self, prop):
71 # NOTE config_dir is never define, is this used?
72 sync_config_dir = Config.get("config_dir")
73 prop_config_path = "/".join(sync_config_dir, self.name, prop)
74 return open(prop_config_path).read().rstrip()
75
76 def __init__(self, **args):
77 """Initialize a sync step
78 Keyword arguments:
Scott Bakerc2fddaa2019-01-30 15:45:03 -080079 model_accessor: class used to access models
80 driver: used by openstack synchronizer (DEPRECATED)
81 error_map: used by openstack synchronizer (DEPRECATED)
Scott Bakerbba67b62019-01-28 17:38:21 -080082 """
Scott Bakerc2fddaa2019-01-30 15:45:03 -080083 self.model_accessor = args.get("model_accessor")
Scott Bakerbba67b62019-01-28 17:38:21 -080084 self.driver = args.get("driver")
85 self.error_map = args.get("error_map")
86
Scott Bakerc2fddaa2019-01-30 15:45:03 -080087 assert self.model_accessor is not None
88
Scott Bakerbba67b62019-01-28 17:38:21 -080089 try:
90 self.soft_deadline = int(self.get_prop("soft_deadline_seconds"))
91 except BaseException:
92 self.soft_deadline = 5 # 5 seconds
93
94 if "log" in args:
95 self.log = args.get("log")
96
97 return
98
Scott Bakerc2fddaa2019-01-30 15:45:03 -080099 @property
100 def observes_classes(self):
101 """ Return a list of classes that this syncstep observes. The "observes" class member can be either a list of
102 items or a single item. Those items may be either classes or names of classes. This function always returns
103 a list of classes.
104 """
105 if not self.observes:
106 return []
107 if isinstance(self.observes, list):
108 observes = self.observes
109 else:
110 observes = [self.observes]
111 result = []
112 for class_or_name in observes:
113 if isinstance(class_or_name, str):
114 result.append(self.model_accessor.get_model_class(class_or_name))
115 else:
116 result.append(class_or_name)
117 return result
118
Scott Bakerbba67b62019-01-28 17:38:21 -0800119 def fetch_pending(self, deletion=False):
120 # This is the most common implementation of fetch_pending
121 # Steps should override it if they have their own logic
122 # for figuring out what objects are outstanding.
123
Scott Bakerc2fddaa2019-01-30 15:45:03 -0800124 return self.model_accessor.fetch_pending(self.observes_classes, deletion)
125
Scott Bakerbba67b62019-01-28 17:38:21 -0800126 def sync_record(self, o):
Scott Bakerc2fddaa2019-01-30 15:45:03 -0800127 self.log.debug("In abstract sync record", **o.tologdict())
128 # This method should be overridden by the service
Scott Bakerbba67b62019-01-28 17:38:21 -0800129
Scott Bakerbba67b62019-01-28 17:38:21 -0800130 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