blob: 3468d2be3839e3fc54d5ae542e7024de22350808 [file] [log] [blame]
Rizwan Haidere6ffdc02016-11-08 13:43:48 -05001import os, sys
2from itertools import chain
Rizwan Haider30b33792016-08-18 02:11:18 -04003
Andrea Campanellaade88482017-04-05 12:39:52 +02004from synchronizers.new_base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible #if needed
5from synchronizers.new_base.ansible_helper import run_template_ssh #if needed
6from synchronizers.new_base.modelaccessor import *
Rizwan Haider30b33792016-08-18 02:11:18 -04007from xos.logger import Logger, logging
8from synchronizers.metronetwork.providers.providerfactory import ProviderFactory
Rizwan Haider65baf552016-09-28 16:47:28 -04009from synchronizers.metronetwork.invokers.invokerfactory import InvokerFactory
Rizwan Haider30b33792016-08-18 02:11:18 -040010
11# metronetwork will be in steps/..
12parentdir = os.path.join(os.path.dirname(__file__), "..")
13sys.path.insert(0, parentdir)
14
15logger = Logger(level=logging.INFO)
16
17
Rizwan Haider65baf552016-09-28 16:47:28 -040018class SyncMetroNetworkSystem(SyncStep):
19 provides = [MetroNetworkSystem]
20 observes = MetroNetworkSystem
Rizwan Haider30b33792016-08-18 02:11:18 -040021 requested_interval = 0
22 initialized = False
23
24 def __init__(self, **args):
25 SyncStep.__init__(self, **args)
26
27 def fetch_pending(self, deletion=False):
28
29 # The general idea:
30 # We do one of two things in here:
31 # 1. Full Synchronization of the DBS (XOS <-> MetroONOS)
32 # 2. Look for updates between the two stores
33 # The first thing is potentially a much bigger
34 # operation and should not happen as often
35 #
36 # The Sync operation must take into account the 'deletion' flag
37
38 objs = []
39
Rizwan Haider65baf552016-09-28 16:47:28 -040040 # Get the NetworkSystem object - if it exists it will test us
Rizwan Haider30b33792016-08-18 02:11:18 -040041 # whether we should do a full sync or not - it all has our config
42 # information about the REST interface
43
Rizwan Haider65baf552016-09-28 16:47:28 -040044 metronetworksystem = self.get_metronetwork_system()
45 if not metronetworksystem:
Rizwan Haider30b33792016-08-18 02:11:18 -040046 logger.debug("No Service configured")
47 return objs
48
Rizwan Haider65baf552016-09-28 16:47:28 -040049 # Check to make sure the Metro Network System is enabled
50 metronetworksystem = self.get_metronetwork_system()
51 if metronetworksystem.administrativeState == 'disabled':
Rizwan Haider30b33792016-08-18 02:11:18 -040052 # Nothing to do
53 logger.debug("MetroService configured - state is Disabled")
54 return objs
55
56 # The Main Loop - retrieve all the NetworkDevice objects - for each of these
57 # Apply synchronization aspects
58 networkdevices = NetworkDevice.objects.all()
59
60 for dev in networkdevices:
61
62 # Set up the provider
63 provider = ProviderFactory.getprovider(dev)
64
65 # First check is for the AdminState of Disabled - do nothing
66 if dev.administrativeState == 'disabled':
67 # Nothing to do with this device
68 logger.debug("NetworkDevice %s: administrativeState set to Disabled - continuing" % dev.id)
69
70 # Now to the main options - are we syncing - deletion portion
71 elif dev.administrativeState == 'syncrequested' and deletion is True:
72
73 logger.info("NetworkDevice %s: administrativeState set to SyncRequested" % dev.id)
74
75 # Kill Links
76 networklinks = provider.get_network_links_for_deletion()
77 for link in networklinks:
78 objs.append(link)
79
80 # Kill Ports
81 allports = provider.get_network_ports_for_deletion()
82 for port in allports:
83 objs.append(port)
84
85 logger.info("NetworkDevice %s: Deletion part of Sync completed" % dev.id)
86 dev.administrativeState = 'syncinprogress'
87 dev.save(update_fields=['administrativeState'])
88
89 # Now to the main options - are we syncing - creation portion
90 elif dev.administrativeState == 'syncinprogress' and deletion is False:
91
92 logger.info("NetworkDevice %s: administrativeState set to SyncRequested" % dev.id)
93 # Reload objects in the reverse order of deletion
94
95 # Add Ports
96 networkports = provider.get_network_ports()
97 for port in networkports:
98 objs.append(port)
99
100 # Add Links
101 networklinks = provider.get_network_links()
102 for link in networklinks:
103 objs.append(link)
104
105 logger.info("NetworkDevice %s: Creation part of Sync completed" % dev.id)
106 dev.administrativeState = 'enabled'
107 dev.save(update_fields=['administrativeState'])
108
109 # If we are enabled - then check for events - in either direction and sync
110 elif dev.administrativeState == 'enabled' and deletion is False:
111 logger.debug("NetworkDevice: administrativeState set to Enabled - non deletion phase")
112
113 # This should be the 'normal running state' when we are not deleting - a few things to do in here
114
115 # Get the changed objects from the provider - deletions are handled separately
116 eventobjs = provider.get_updated_or_created_objects()
117 for eventobj in eventobjs:
118 # Simply put in the queue for update - this will handle both new and changed objects
119 objs.append(eventobj)
120
121 # Handle changes XOS -> ONOS
122 # Check for ConnectivityObjects that are in acticationequested state - creates to the backend
Rizwan Haidere6ffdc02016-11-08 13:43:48 -0500123 p2pactivatereqs = NetworkEdgeToEdgePointConnection.objects.filter(adminstate='activationrequested')
124 mp2mpactivatereqs = NetworkMultipointToMultipointConnection.objects.filter(adminstate='activationrequested')
125 r2mpactivatereqs = NetworkEdgeToMultipointConnection.objects.filter(adminstate='activationrequested')
126 activatereqs = list(chain(p2pactivatereqs, mp2mpactivatereqs, r2mpactivatereqs))
Rizwan Haider30b33792016-08-18 02:11:18 -0400127 for activatereq in activatereqs:
128
129 # Call the XOS Interface to create the service
130 logger.debug("Attempting to create EdgePointToEdgePointConnectivity: %s" % activatereq.id)
Rizwan Haidere6ffdc02016-11-08 13:43:48 -0500131 if (provider.create_network_connectivity(activatereq)):
Rizwan Haider30b33792016-08-18 02:11:18 -0400132 # Everyting is OK, lets let the system handle the persist
133 objs.append(activatereq)
134 else:
135 # In the case of an error we persist the state of the object directly to preserve
136 # the error code - and because that is how the base synchronizer is designed
137 activatereq.save()
138
139 # Check for ConnectivityObjects that are in deacticationequested state - deletes to the backend
Rizwan Haidere6ffdc02016-11-08 13:43:48 -0500140 p2pdeactivatereqs = NetworkEdgeToEdgePointConnection.objects.filter(adminstate='deactivationrequested')
141 mp2mpdeactivatereqs = NetworkMultipointToMultipointConnection.objects.filter(adminstate='deactivationrequested')
142 r2mpdeactivatereqs = NetworkEdgeToMultipointConnection.objects.filter(adminstate='deactivationrequested')
143 deactivatereqs = list(chain(p2pdeactivatereqs, mp2mpdeactivatereqs, r2mpdeactivatereqs))
Rizwan Haider30b33792016-08-18 02:11:18 -0400144 for deactivatereq in deactivatereqs:
145
146 # Call the XOS Interface to delete the service
147 logger.debug("Attempting to delete EdgePointToEdgePointConnectivity: %s" % deactivatereq.id)
Rizwan Haidere6ffdc02016-11-08 13:43:48 -0500148 if provider.delete_network_connectivity(deactivatereq):
Rizwan Haider30b33792016-08-18 02:11:18 -0400149 # Everyting is OK, lets let the system handle the persist
150 objs.append(deactivatereq)
151 else:
152 # In the case of an error we persist the state of the object directly to preserve
153 # the error code - and because that is how the base synchronizer is designed
154 deactivatereq.save()
155
156 # If we are enabled - and in our deletion pass then look for objects waiting for deletion
157 elif dev.administrativeState == 'enabled' and deletion is True:
158 logger.debug("NetworkDevice: administrativeState set to Enabled - deletion phase")
159
160 # Any object that is simply deleted in the model gets removed automatically - the synchronizer
161 # doesn't get involved - we just need to check for deleted objects in the domain and reflect that
162 # in the model
163 #
164 # Get the deleted objects from the provider
165 eventobjs = provider.get_deleted_objects()
166 for eventobj in eventobjs:
167 # Simply put in the queue for update - this will handle both new and changed objects
168 objs.append(eventobj)
169
Rizwan Haidere6ffdc02016-11-08 13:43:48 -0500170 # Handle the case where we have deleted Eline Services from our side - if the Service is in
171 # enabled state then we call the provider, otherwise just queue it for deletion
172 elinedeletedobjs = NetworkEdgeToEdgePointConnection.deleted_objects.all()
173 for elinedeletedobj in elinedeletedobjs:
174 if elinedeletedobj.adminstate == 'enabled':
175 provider.delete_network_connectivity(elinedeletedobj)
176 # Either way queue it for deletion
177 objs.append(elinedeletedobj)
178
179 # Handle the case where we have deleted Etree Services from our side - if the Service is in
180 # enabled state then we call the provider, otherwise just queue it for deletion
181 etreedeletedobjs = NetworkEdgeToMultipointConnection.deleted_objects.all()
182 for etreedeletedobj in etreedeletedobjs:
183 # TODO: Handle the case where its connected, we need to disconnect first
184 if etreedeletedobj.adminstate == 'enabled':
185 provider.delete_network_connectivity(etreedeletedobj)
186 # Either way queue it for deletion
187 objs.append(etreedeletedobj)
188
189 # Handle the case where we have deleted Elan Services from our side - if the Service is in
190 # enabled state then we call the provider, otherwise just queue it for deletion
191 elandeletedobjs = NetworkMultipointToMultipointConnection.deleted_objects.all()
192 for elandeletedobj in elandeletedobjs:
193 # TODO: Handle the case where its connected, we need to disconnect first
194 if elandeletedobj.adminstate == 'enabled':
195 provider.delete_network_connectivity(elandeletedobj)
196 # Either way queue it for deletion
197 objs.append(elandeletedobj)
198
199 # Handle the case where we have deleted VnodGlobal Services from our side - if there is
200 # an attached Eline/Etree/Elan we set that to deleted
201 vnodbloaldeletedobjs = VnodGlobalService.deleted_objects.all()
202 for vnodbloaldeletedobj in vnodbloaldeletedobjs:
203 # Check for dependent eline service
204 if vnodbloaldeletedobj.metronetworkpointtopoint is not None:
205 elineobj = vnodbloaldeletedobj.metronetworkpointtopoint
206 elineobj.deleted = True
207 objs.append(elineobj)
208 # Check for dependent elan service
209 if vnodbloaldeletedobj.metronetworkmultipoint is not None:
210 elanobj = vnodbloaldeletedobj.metronetworkmultipoint
211 elanobj.deleted = True
212 objs.append(elanobj)
213 # Check for dependent etree service
214 if vnodbloaldeletedobj.metronetworkroottomultipoint is not None:
215 etreeobj = vnodbloaldeletedobj.metronetworkroottomultipoint
216 etreeobj.deleted = True
217 objs.append(etreeobj)
218
219 objs.append(vnodbloaldeletedobj)
220
Rizwan Haider30b33792016-08-18 02:11:18 -0400221 # In add cases return the objects we are interested in
222 return objs
223
224 def sync_record(self, o):
Rizwan Haider65baf552016-09-28 16:47:28 -0400225
226 # First we call and see if there is an invoker for this object - the idea of the invoker
227 # is to wrap the save with a pre/post paradigm to handle special cases
228 # It will only exist for a subset of ojbects
229 invoker = InvokerFactory.getinvoker(o)
230
231 # Call Pre-save on the inovker (if it exists)
232 if invoker is not None:
233 invoker.presave(o)
234
Rizwan Haider30b33792016-08-18 02:11:18 -0400235 # Simply save the record to the DB - both updates and adds are handled the same way
236 o.save()
237
Rizwan Haider65baf552016-09-28 16:47:28 -0400238 # Call Post-save on the inovker (if it exists)
239 if invoker is not None:
240 invoker.postsave(o)
241
Rizwan Haider30b33792016-08-18 02:11:18 -0400242 def delete_record(self, o):
243 # Overriden to customize our behaviour - the core sync step for will remove the record directly
244 # We just log and return
245 logger.debug("deleting Object %s" % str(o), extra=o.tologdict())
246
Rizwan Haider65baf552016-09-28 16:47:28 -0400247 def get_metronetwork_system(self):
Rizwan Haider30b33792016-08-18 02:11:18 -0400248 # We only expect to have one of these objects in the system in the curent design
249 # So get the first element from the query
Rizwan Haider65baf552016-09-28 16:47:28 -0400250 metronetworksystem = MetroNetworkSystem.objects.all()
251 if not metronetworksystem:
Rizwan Haider30b33792016-08-18 02:11:18 -0400252 return None
253
Rizwan Haider65baf552016-09-28 16:47:28 -0400254 return metronetworksystem[0]