blob: 77d62b4ae94a44be2e4efc7d6ae8fbca9b1bae44 [file] [log] [blame]
Rizwan Haider51fdb3f2016-11-09 18:29:32 -05001import os
2import sys
3
Andrea Campanellaf6e2ed12017-04-03 19:14:25 +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 Haider51fdb3f2016-11-09 18:29:32 -05007import requests, json
8from requests.auth import HTTPBasicAuth
9
10from xos.logger import Logger, logging
11
12# vnod local will be in steps/..
13parentdir = os.path.join(os.path.dirname(__file__), "..")
14sys.path.insert(0, parentdir)
15
16logger = Logger(level=logging.INFO)
17
18
19class SyncVnodLocalSystem(SyncStep):
20 provides = [VnodLocalService]
21 observes = VnodLocalService
22 requested_interval = 0
23 initialized = False
24
25 def __init__(self, **args):
26 SyncStep.__init__(self, **args)
27
28 def fetch_pending(self, deletion=False):
29 logger.info("VnodLocal fetch pending called")
30
31 # Some comments to replace as we write the code
32
33 # The AdministrativeState state machine:
34 #
35 # Diasabled (initial)
36 # |
37 # ConfigurationRequested
38 # / / \
39 # / / \
40 # ConfigurationFailed Configured---------DeactivationRequested
41 # \ |
42 # ActivationRequested |
43 # / / \ |
44 # / / \ |
45 # ActivationFailed Enabled -----------
46 #
47 #
48
49 # The OperationalState state machine
50 #
51 # active-----------------|
52 # | |
53 # inactivereported |
54 # | |
55 # inactive----------activereported
56
57 objs = []
58
59
60 # The whole thing needs to be conditional on the VnodLocalSystem existing and being 'enabled'
61 # This is the 'kill switch' in the system that is the first thing to check
62 vnodlocalsystem = self.get_vnodlocal_system()
63
64 if not vnodlocalsystem:
65 logger.debug("No VnodLocal System Configured, skipping sync")
66 return objs
67
68 # Check to make sure the Metro Network System is enabled
69 if vnodlocalsystem.administrativeState == 'disabled':
70 # Nothing to do
71 logger.debug("VnodLocal System configured - state is Disabled, skipping sync")
72 return objs
73
74
75
76 # Handle call when deletion is False
77 if deletion is False:
78
79 # First Part of Auto-attachement: What we need to do is ask the ECORD if there are any Spokes for our site
80 # that are set to 'auto-attached' but are not currently actually attached
81 # it will send back a list of servicehandles that meet that criteria. We will simply
82 # check if we have already created a VnodLocal for that service handle, if we have do
83 # nothing it should be still in progress. If we haven't create it, mark it as 'autoattached', set the
84 # servicehandle and mark it as 'ConfigurationRequested'
85 rest_url = vnodlocalsystem.restUrl
86 sitename = vnodlocalsystem.name
87 username = vnodlocalsystem.username
88 password = vnodlocalsystem.password
89
90 autoattachhandles = self.get_autoattachhandles(vnodlocalsystem)
91 for autoattachhandle in autoattachhandles:
92 # Check to see if it already exists - if not add it
93 if not VnodLocalService.objects.filter(servicehandle=autoattachhandle).exists():
94 vnodlocal = VnodLocalService()
95 vnodlocal.servicehandle = autoattachhandle
96 vnodlocal.autoattached = True
97 vnodlocal.administrativeState = 'configurationrequested'
98 logger.debug("Adding Auto-attached VnodLocalService servicehandle: %s" % vnodlocal.servicehandle)
99 objs.append(vnodlocal)
100
101 # Second Part of Auto-attachment
102 # Look for auto-attachmed Services that are Configured, move them automaticaly to activationrequested
103 autoattachconfigures = self.get_autoattachconfigured()
104 for autoattachconfigure in autoattachconfigures:
105 # Just bounce these forward to activationrequested to get them activated
106 autoattachconfigure.administrativeState = 'activationrequested'
107 objs.append(autoattachconfigure)
108
109
110 # Check for admin status 'ConfigurationRequested'
111 configreqs = VnodLocalService.objects.filter(administrativeState='configurationrequested')
112 for configreq in configreqs:
113 # Call the XOS Interface to configure the service
114 logger.debug("Attempting to configure VnodLocalService servicehandle: %s" % configreq.servicehandle)
115 # Add code to call REST api on the ECORD - For this state - we call VnodGlobal
116 # with the servciehandle and sitename it
117 # it gives us back the NNI port and Vlan Config
118 # we then set our state to 'Configured' or 'ConfigurationFailed'
119 servicehandle = configreq.servicehandle
120 query = {"sitename": sitename, "servicehandle" : servicehandle}
121
122 resp = requests.get("{}/vnodglobal_api_configuration/".format(rest_url), params=query,
123 auth=HTTPBasicAuth(username, password))
124
125 if resp.status_code == 200:
126 resp = resp.json()
127 # Success-path transitions to 'configured'
128 configreq.vlanid = resp['vlanid']
129 configreq.portid = resp['port']['name']
130 configreq.administrativeState = 'configured'
131
132 #update proxy adminstate in ecord
133 data = {"sitename": sitename, "servicehandle": servicehandle, "adminstate": 'configured',
134 "vlanid": configreq.vlanid, "portid": configreq.portid}
135 resp = requests.post("{}/vnodglobal_api_status/".format(rest_url), data=json.dumps(data),
136 auth=HTTPBasicAuth(username, password))
137
138 else:
139 configreq.administrativeState = 'configurationfailed'
140
141 objs.append(configreq)
142
143
144 # Check for admin status 'ActivationRequested'
145 activationreqs = VnodLocalService.objects.filter(administrativeState='activationrequested')
146 for acivationreq in activationreqs:
147 # Call the XOS Interface to activate the service
148 logger.debug("Attempting to activate VnodLocalService servicehandle: %s" % acivationreq.servicehandle)
149 # Add code to call REST api on the ECORD - For this state we send the VnodGlobal
150 # service our service handle, subscriber,
151 # VnodLocalId (this id)
152 # Once this is accepted we transition to the
153 # Final state of 'Enabled' or 'ActivationFailed'
154 servicehandle = acivationreq.servicehandle
155 vnodlocalid = acivationreq.id
156 vlanid = acivationreq.vlanid
157 portid = acivationreq.portid
158
159 data = {"sitename": sitename, "servicehandle": servicehandle, "vnodlocalid": vnodlocalid,
160 "vlanid": vlanid, "portid": portid, "activate": "true"}
161
162 resp = requests.post("{}/vnodglobal_api_activation/".format(rest_url), data=json.dumps(data),
163 auth=HTTPBasicAuth(username, password))
164
165 if resp.status_code == 200:
166 # Success-path transitions to 'enabled'
167 acivationreq.administrativeState = 'enabled'
168
169 # update proxy adminstate in ecord
170 data = {"sitename": sitename, "servicehandle": servicehandle, "adminstate": 'enabled',
171 "vlanid": vlanid, "portid": portid, "operstate": "active"}
172 resp = requests.post("{}/vnodglobal_api_status/".format(rest_url), data=json.dumps(data),
173 auth=HTTPBasicAuth(username, password))
174 else:
175 acivationreq.administrativeState = 'activationfailed'
176
177 # update proxy adminstate in ecord
178 data = {"sitename": sitename, "servicehandle": servicehandle, "adminstate": 'impaired',
179 "operstate": "inactive", "vlanid": vlanid, "portid": portid}
180 resp = requests.post("{}/vnodglobal_api_status/".format(rest_url), data=json.dumps(data),
181 auth=HTTPBasicAuth(username, password))
182
183 objs.append(acivationreq)
184
185
186 # Check for admin status 'DeactivationRequested'
187 deactivationreqs = VnodLocalService.objects.filter(administrativeState='deactivationrequested')
188 for deacivationreq in deactivationreqs:
189 # Call the XOS Interface to de-actiavte the spoke
190 logger.debug("Attempting to de-activate VnodLocalService servicehandle: %s" % deacivationreq.servicehandle)
191 # Add code to call REST api on the ECORD - Report change to VnodGlobal
192 servicehandle = deacivationreq.servicehandle
193 vnodlocalid = deacivationreq.id
194 vlanid = deacivationreq.vlanid
195 portid = deacivationreq.portid
196
197
198 data = {"sitename": sitename, "servicehandle": servicehandle, "vnodlocalid": vnodlocalid,
199 "vlanid": vlanid, "portid": portid, "activate": "false"}
200
201 resp = requests.post("{}/vnodglobal_api_activation/".format(rest_url), data=json.dumps(data),
202 auth=HTTPBasicAuth(username, password))
203
204 if resp.status_code == 200:
205 # Success-path transitions to 'enabled'
206 deacivationreq.administrativeState = 'configured'
207 else:
208 deacivationreq.administrativeState = 'deactivationfailed'
209
210 # update proxy adminstate in ecord
211 data = {"sitename": sitename, "servicehandle": servicehandle, "adminstate": 'impaired',
212 "vlanid": vlanid, "portid": portid}
213 resp = requests.post("{}/vnodglobal_api_status/".format(rest_url), data=json.dumps(data),
214 auth=HTTPBasicAuth(username, password))
215
216 objs.append(deacivationreq)
217
218
219 # Check for oper status inactive reported
220 inactivereports = VnodLocalService.objects.filter(operstate='inactivereported')
221 for inactivereport in inactivereports:
222 # Call the XOS Interface to report operstate issue
223 logger.debug("Attempting to report inactive VnodLocalService servicehandle: %s" % inactivereport.servicehandle)
224 # Add code to call REST api on the ECORD - Report change to VnodGlobal
225
226 servicehandle = inactivereport.servicehandle
227 vlanid = inactivereport.vlanid
228 portid = inactivereport.portid
229
230 # update proxy operstate in ecord
231 data = {"sitename": sitename, "servicehandle": servicehandle, "operstate": "inactive",
232 "adminstate":"impaired", "vlanid": vlanid, "portid": portid}
233 resp = requests.post("{}/vnodglobal_api_status/".format(rest_url), data=json.dumps(data),
234 auth=HTTPBasicAuth(username, password))
235
236 # transition to 'inactive' state regardless of whether call to ECORD was successful?!?
237 inactivereport.operstate = 'inactive'
238 objs.append(inactivereport)
239
240
241 # Check for oper status active reported
242 activereports = VnodLocalService.objects.filter(operstate='activereported')
243 for activereport in activereports:
244 # Call the XOS Interface to report operstate issue
245 logger.debug(
246 "Attempting to report active VnodLocalService servicehandle: %s" % activereport.servicehandle)
247
248 servicehandle = activereport.servicehandle
249 vlanid = activereport.vlanid
250 portid = activereport.portid
251 # Add code to call REST api on the ECORD - Report change to VnodGlobal.
252 # update proxy operstate in ecord
253 data = {"sitename": sitename, "servicehandle": servicehandle, "operstate": "active",
254 "vlanid": vlanid, "portid": portid}
255 resp = requests.post("{}/vnodglobal_api_status/".format(rest_url), data=json.dumps(data),
256 auth=HTTPBasicAuth(username, password))
257
258 activereport.operstate = 'active'
259 objs.append(activereport)
260 elif deletion:
261 # Apply Deletion Semantics:
262 logger.debug("Applying Deletion Semanctics")
263 # TODO: Figure out the odd scenario of Service deletion
264 deletedobjs = VnodLocalService.deleted_objects.all()
265 objs.extend(deletedobjs)
266
267 # Finally just return the set of changed objects
268 return objs
269
270 def get_vnodlocal_system(self):
271 # We only expect to have one of these objects in the system in the curent design
272 # So get the first element from the query
273 vnodlocalsystems = VnodLocalSystem.objects.all()
274 if not vnodlocalsystems:
275 return None
276
277 return vnodlocalsystems[0]
278
279 def get_autoattachhandles(self, vnodlocalsystem):
280 # Figure out API call to actually get this to work
281 rest_url = vnodlocalsystem.restUrl
282 sitename = vnodlocalsystem.name
283 username=vnodlocalsystem.username
284 password=vnodlocalsystem.password
285 query = {"sitename":sitename}
286
287
288 resp = requests.get("{}/vnodglobal_api_autoattach/".format(rest_url), params=query,
289 auth=HTTPBasicAuth(username, password))
290
291 handles = []
292 if resp.status_code == 200:
293 resp = resp.json()
294 handles = resp['servicehandles']
295 else:
296 logger.debug("Request for autoattach servicehandles failed.")
297
298 return handles
299
300 def get_autoattachconfigured(self):
301 # Query for the set of auto-attached handles that are in the 'Configured' state
302 autoattachedconfigured = VnodLocalService.objects.filter(autoattached=True, administrativeState='configured')
303
304 if not autoattachedconfigured:
305 return []
306
307 return autoattachedconfigured
308
309
310 def sync_record(self, o):
311
312 # Simply save the record to the DB - both updates and adds are handled the same way
313 o.save()
314
315
316 def delete_record(self, o):
317 # Overriden to customize our behaviour - the core sync step for will remove the record directly
318 # We just log and return
319 logger.debug("deleting Object %s" % str(o), extra=o.tologdict())
320