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