blob: 4afd2348fc45660ce165bb724ec4b2ed386ea0a4 [file] [log] [blame]
Chip Boling32aab302019-01-23 10:50:18 -06001#
2# Copyright 2017 the original author or authors.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16from task import Task
17from twisted.internet.defer import inlineCallbacks, TimeoutError, failure, AlreadyCalledError
18from twisted.internet import reactor
19from voltha.extensions.omci.omci_defs import ReasonCodes
20
21
22class MibUploadFailure(Exception):
23 """
24 This error is raised by default when the upload fails
25 """
26
27
28class MibUploadTask(Task):
29 """
30 OpenOMCI MIB upload task
31
32 On successful completion, this task will call the 'callback' method of the
33 deferred returned by the start method. Only a textual message is provided as
34 the successful results and it lists the number of ME entities successfully
35 retrieved.
36
37 Note that the MIB Synchronization State Machine will get event subscription
38 information for the MIB Reset and MIB Upload Next requests and it is the
39 MIB Synchronization State Machine that actually populates the MIB Database.
40 """
41 task_priority = 250
42 name = "MIB Upload Task"
43
44 def __init__(self, omci_agent, device_id):
45 """
46 Class initialization
47
48 :param omci_agent: (OmciAdapterAgent) OMCI Adapter agent
49 :param device_id: (str) ONU Device ID
50 """
51 super(MibUploadTask, self).__init__(MibUploadTask.name,
52 omci_agent,
53 device_id,
54 priority=MibUploadTask.task_priority)
55 self._local_deferred = None
56
57 def cancel_deferred(self):
58 super(MibUploadTask, self).cancel_deferred()
59
60 d, self._local_deferred = self._local_deferred, None
61 try:
62 if d is not None and not d.called:
63 d.cancel()
64 except:
65 pass
66
67 def start(self):
68 """
69 Start MIB Synchronization tasks
70 """
71 super(MibUploadTask, self).start()
72 self._local_deferred = reactor.callLater(0, self.perform_mib_upload)
73
74 def stop(self):
75 """
76 Shutdown MIB Synchronization tasks
77 """
78 self.log.debug('stopping')
79
80 self.cancel_deferred()
81 super(MibUploadTask, self).stop()
82
83 @inlineCallbacks
84 def perform_mib_upload(self):
85 """
86 Perform the MIB Upload sequence
87 """
88 self.log.debug('perform-mib-upload')
89
90 seq_no = 0
91 number_of_commands = 0
92
93 try:
94 device = self.omci_agent.get_device(self.device_id)
95
96 #########################################
97 # MIB Reset
98 self.strobe_watchdog()
99 results = yield device.omci_cc.send_mib_reset()
100
101 status = results.fields['omci_message'].fields['success_code']
102 if status != ReasonCodes.Success.value:
103 raise MibUploadFailure('MIB Reset request failed with status code: {}'.
104 format(status))
105
106 ########################################
107 # Begin MIB Upload
108 self.strobe_watchdog()
109 results = yield device.omci_cc.send_mib_upload()
110
111 number_of_commands = results.fields['omci_message'].fields['number_of_commands']
112
113 for seq_no in xrange(number_of_commands):
114 if not device.active or not device.omci_cc.enabled:
115 raise MibUploadFailure('OMCI and/or ONU is not active')
116
117 for retry in range(0, 3):
118 try:
119 self.log.debug('mib-upload-next-request', seq_no=seq_no,
120 retry=retry,
121 number_of_commands=number_of_commands)
122 self.strobe_watchdog()
123 yield device.omci_cc.send_mib_upload_next(seq_no)
124
125 self.log.debug('mib-upload-next-success', seq_no=seq_no,
126 number_of_commands=number_of_commands)
127 break
128
129 except TimeoutError as e:
130 from common.utils.asleep import asleep
131 self.log.warn('mib-upload-timeout', e=e, seq_no=seq_no,
132 number_of_commands=number_of_commands)
133 if retry >= 2:
134 raise MibUploadFailure('Upload timeout failure on req {} of {}'.
135 format(seq_no + 1, number_of_commands))
136 self.strobe_watchdog()
137 yield asleep(0.3)
138
139 # Successful if here
140 self.log.info('mib-synchronized')
141 self.deferred.callback('success, loaded {} ME Instances'.
142 format(number_of_commands))
143
144 except TimeoutError as e:
145 self.log.warn('mib-upload-timeout-on-reset', e=e, seq_no=seq_no,
146 number_of_commands=number_of_commands)
147 self.deferred.errback(failure.Failure(e))
148
149 except AlreadyCalledError:
150 # Can occur if task canceled due to MIB Sync state change
151 self.log.debug('already-called-exception', seq_no=seq_no,
152 number_of_commands=number_of_commands)
153 assert self.deferred.called, \
154 'Unexpected AlreadyCalledError exception: seq: {} of {}'.format(seq_no,
155 number_of_commands)
156 except Exception as e:
157 self.log.exception('mib-upload', e=e)
158 self.deferred.errback(failure.Failure(e))