blob: 10667b182f42aaf6c9e850e6fb459387e44ab52c [file] [log] [blame]
Matteo Scandoload0c1752018-08-09 15:47:16 -07001
2# Copyright 2017-present Open Networking Foundation
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
16
Scott Bakerc2a633d2019-04-01 19:27:41 -070017from helpers import AttHelpers
Scott Baker71d20472019-02-01 12:05:35 -080018from xossynchronizer.model_policies.policy import Policy
Matteo Scandoload0c1752018-08-09 15:47:16 -070019
Matteo Scandoloea529092018-09-11 16:36:39 -070020import os
21import sys
22
23sync_path = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), ".."))
24sys.path.append(sync_path)
25
Matteo Scandoloea529092018-09-11 16:36:39 -070026
Matteo Scandoloe8c33d62018-08-16 14:37:24 -070027class DeferredException(Exception):
28 pass
29
Scott Bakerc2a633d2019-04-01 19:27:41 -070030
Matteo Scandoload0c1752018-08-09 15:47:16 -070031class AttWorkflowDriverServiceInstancePolicy(Policy):
32 model_name = "AttWorkflowDriverServiceInstance"
33
34 def handle_create(self, si):
35 self.logger.debug("MODEL_POLICY: handle_create for AttWorkflowDriverServiceInstance %s " % si.id)
36 self.handle_update(si)
37
Matteo Scandoload0c1752018-08-09 15:47:16 -070038 def handle_update(self, si):
Scott Bakerc2a633d2019-04-01 19:27:41 -070039 self.logger.debug("MODEL_POLICY: handle_update for AttWorkflowDriverServiceInstance %s " %
Matteo Scandolo2d9f40d2019-04-19 08:38:10 -070040 (si.id), onu_state=si.admin_onu_state, authentication_state=si.authentication_state)
Matteo Scandoloe8c33d62018-08-16 14:37:24 -070041
Andy Bavierafaf1762019-01-16 09:41:43 -070042 # Changing ONU state can change auth state
43 # Changing auth state can change DHCP state
44 # So need to process in this order
45 self.process_onu_state(si)
46 self.process_auth_state(si)
47 self.process_dhcp_state(si)
48
49 self.validate_states(si)
Matteo Scandoloe8c33d62018-08-16 14:37:24 -070050
Matteo Scandoloea529092018-09-11 16:36:39 -070051 # handling the subscriber status
Andy Bavierafaf1762019-01-16 09:41:43 -070052 # It's a combination of all the other states
Matteo Scandoloea529092018-09-11 16:36:39 -070053 subscriber = self.get_subscriber(si.serial_number)
Matteo Scandoloea529092018-09-11 16:36:39 -070054 if subscriber:
55 self.update_subscriber(subscriber, si)
Matteo Scandoload0c1752018-08-09 15:47:16 -070056
Andy Bavierafaf1762019-01-16 09:41:43 -070057 si.save_changed_fields()
58
Matteo Scandolo2d9f40d2019-04-19 08:38:10 -070059 # Check the whitelist to see if the ONU is valid. If it is, make sure that it's enabled.
Andy Bavierafaf1762019-01-16 09:41:43 -070060 def process_onu_state(self, si):
Scott Baker71d20472019-02-01 12:05:35 -080061 [valid, message] = AttHelpers.validate_onu(self.model_accessor, self.logger, si)
Matteo Scandolo2d9f40d2019-04-19 08:38:10 -070062 si.status_message = message
63 if valid:
64 si.admin_onu_state = "ENABLED"
65 self.update_onu(si.serial_number, "ENABLED")
66 else:
67 si.admin_onu_state = "DISABLED"
Andy Bavierafaf1762019-01-16 09:41:43 -070068 self.update_onu(si.serial_number, "DISABLED")
69
Andy Bavier11ffbf52019-02-08 11:53:21 -070070 # If the ONU has been disabled then we force re-authentication when it
71 # is re-enabled.
72 # Setting si.authentication_state = AWAITING:
73 # -> subscriber status = "awaiting_auth"
74 # -> service chain deleted
75 # -> need authentication to restore connectivity after ONU enabled
Andy Bavierafaf1762019-01-16 09:41:43 -070076 def process_auth_state(self, si):
77 auth_msgs = {
78 "AWAITING": " - Awaiting Authentication",
79 "REQUESTED": " - Authentication requested",
80 "STARTED": " - Authentication started",
81 "APPROVED": " - Authentication succeeded",
82 "DENIED": " - Authentication denied"
83 }
Matteo Scandolo2d9f40d2019-04-19 08:38:10 -070084 if si.admin_onu_state == "DISABLED" or si.oper_onu_status == "DISABLED":
Andy Bavierafaf1762019-01-16 09:41:43 -070085 si.authentication_state = "AWAITING"
86 else:
87 si.status_message += auth_msgs[si.authentication_state]
88
Andy Bavier11ffbf52019-02-08 11:53:21 -070089 # The DhcpL2Relay ONOS app generates events that update the fields below.
90 # It only sends events when it processes DHCP packets. It keeps no internal state.
91 # We reset dhcp_state when:
92 # si.authentication_state in ["AWAITING", "REQUESTED", "STARTED"]
93 # -> subscriber status = "awaiting_auth"
94 # -> service chain not present
95 # -> subscriber's OLT flow rules, xconnect not present
96 # -> DHCP packets won't go through
97 # Note, however, that the DHCP state at the endpoints is not changed.
98 # A previously issued DHCP lease may still be valid.
Andy Bavierafaf1762019-01-16 09:41:43 -070099 def process_dhcp_state(self, si):
Andy Bavier8ed30c92018-12-11 13:46:25 -0700100 if si.authentication_state in ["AWAITING", "REQUESTED", "STARTED"]:
101 si.ip_address = ""
102 si.mac_address = ""
Andy Bavier15310cf2018-12-13 14:16:49 -0700103 si.dhcp_state = "AWAITING"
Andy Bavier8ed30c92018-12-11 13:46:25 -0700104
Andy Bavierafaf1762019-01-16 09:41:43 -0700105 # Make sure the object is in a legitimate state
106 # It should be after the above processing steps
107 # However this might still fail if an event has fired in the meantime
108 # Valid states:
109 # ONU | Auth | DHCP
110 # ===============================
111 # AWAITING | AWAITING | AWAITING
112 # ENABLED | * | AWAITING
113 # ENABLED | APPROVED | *
114 # DISABLED | AWAITING | AWAITING
115 def validate_states(self, si):
Matteo Scandolo2d9f40d2019-04-19 08:38:10 -0700116 if (si.admin_onu_state == "AWAITING" or si.admin_onu_state ==
Scott Bakerc2a633d2019-04-01 19:27:41 -0700117 "DISABLED") and si.authentication_state == "AWAITING" and si.dhcp_state == "AWAITING":
Andy Bavierafaf1762019-01-16 09:41:43 -0700118 return
Matteo Scandolo2d9f40d2019-04-19 08:38:10 -0700119 if si.admin_onu_state == "ENABLED" and (si.authentication_state == "APPROVED" or si.dhcp_state == "AWAITING"):
Andy Bavierafaf1762019-01-16 09:41:43 -0700120 return
Scott Bakerc2a633d2019-04-01 19:27:41 -0700121 self.logger.warning(
122 "MODEL_POLICY (validate_states): invalid state combination",
Matteo Scandolo2d9f40d2019-04-19 08:38:10 -0700123 onu_state=si.admin_onu_state,
Scott Bakerc2a633d2019-04-01 19:27:41 -0700124 auth_state=si.authentication_state,
125 dhcp_state=si.dhcp_state)
Matteo Scandoload0c1752018-08-09 15:47:16 -0700126
Matteo Scandoloea529092018-09-11 16:36:39 -0700127 def update_onu(self, serial_number, admin_state):
Scott Bakerc2a633d2019-04-01 19:27:41 -0700128 onu = [onu for onu in self.model_accessor.ONUDevice.objects.all() if onu.serial_number.lower()
129 == serial_number.lower()][0]
Andy Baviere02c07f2019-05-15 12:56:34 -0700130 if onu.admin_state == "ADMIN_DISABLED":
131 self.logger.debug(
132 "MODEL_POLICY: ONUDevice [%s] has been manually disabled, not changing state to %s" %
133 (serial_number, admin_state))
134 return
Matteo Scandoloc6ac74a2018-09-14 08:14:51 -0700135 if onu.admin_state == admin_state:
Scott Bakerc2a633d2019-04-01 19:27:41 -0700136 self.logger.debug(
137 "MODEL_POLICY: ONUDevice [%s] already has admin_state to %s" %
138 (serial_number, admin_state))
Matteo Scandoloc6ac74a2018-09-14 08:14:51 -0700139 else:
140 self.logger.debug("MODEL_POLICY: setting ONUDevice [%s] admin_state to %s" % (serial_number, admin_state))
141 onu.admin_state = admin_state
Andy Bavier0d631eb2018-10-17 18:05:04 -0700142 onu.save_changed_fields(always_update_timestamp=True)
Matteo Scandoload0c1752018-08-09 15:47:16 -0700143
Matteo Scandoloea529092018-09-11 16:36:39 -0700144 def get_subscriber(self, serial_number):
145 try:
Scott Bakerc2a633d2019-04-01 19:27:41 -0700146 return [s for s in self.model_accessor.RCORDSubscriber.objects.all() if s.onu_device.lower()
147 == serial_number.lower()][0]
Matteo Scandoloea529092018-09-11 16:36:39 -0700148 except IndexError:
149 # If the subscriber doesn't exist we don't do anything
Scott Bakerc2a633d2019-04-01 19:27:41 -0700150 self.logger.debug(
151 "MODEL_POLICY: subscriber does not exists for this SI, doing nothing",
152 onu_device=serial_number)
Matteo Scandoloea529092018-09-11 16:36:39 -0700153 return None
Matteo Scandoload0c1752018-08-09 15:47:16 -0700154
Matteo Scandolo74f63302018-11-01 14:05:01 -0700155 def update_subscriber_ip(self, subscriber, ip):
156 # TODO check if the subscriber has an IP and update it,
157 # or create a new one
158 try:
Scott Baker71d20472019-02-01 12:05:35 -0800159 ip = self.model_accessor.RCORDIpAddress.objects.filter(
Matteo Scandolo74f63302018-11-01 14:05:01 -0700160 subscriber_id=subscriber.id,
161 ip=ip
162 )[0]
Scott Bakerc2a633d2019-04-01 19:27:41 -0700163 self.logger.debug("MODEL_POLICY: found existing RCORDIpAddress for subscriber",
164 onu_device=subscriber.onu_device, subscriber_status=subscriber.status, ip=ip)
Matteo Scandolo74f63302018-11-01 14:05:01 -0700165 ip.save_changed_fields()
166 except IndexError:
Scott Bakerc2a633d2019-04-01 19:27:41 -0700167 self.logger.debug(
168 "MODEL_POLICY: Creating new RCORDIpAddress for subscriber",
169 onu_device=subscriber.onu_device,
170 subscriber_status=subscriber.status,
171 ip=ip)
Scott Baker71d20472019-02-01 12:05:35 -0800172 ip = self.model_accessor.RCORDIpAddress(
Matteo Scandolo74f63302018-11-01 14:05:01 -0700173 subscriber_id=subscriber.id,
174 ip=ip,
175 description="DHCP Assigned IP Address"
176 )
177 ip.save()
178
Andy Bavier8ed30c92018-12-11 13:46:25 -0700179 def delete_subscriber_ip(self, subscriber, ip):
180 try:
Scott Baker71d20472019-02-01 12:05:35 -0800181 ip = self.model_accessor.RCORDIpAddress.objects.filter(
Andy Bavier8ed30c92018-12-11 13:46:25 -0700182 subscriber_id=subscriber.id,
183 ip=ip
184 )[0]
Scott Bakerc2a633d2019-04-01 19:27:41 -0700185 self.logger.debug(
186 "MODEL_POLICY: delete RCORDIpAddress for subscriber",
187 onu_device=subscriber.onu_device,
188 subscriber_status=subscriber.status,
189 ip=ip)
Andy Bavier8ed30c92018-12-11 13:46:25 -0700190 ip.delete()
Scott Bakerc2a633d2019-04-01 19:27:41 -0700191 except BaseException:
Andy Bavier8ed30c92018-12-11 13:46:25 -0700192 self.logger.warning("MODEL_POLICY: no RCORDIpAddress object found, cannot delete", ip=ip)
193
Matteo Scandoloea529092018-09-11 16:36:39 -0700194 def update_subscriber(self, subscriber, si):
Matteo Scandoloc6ac74a2018-09-14 08:14:51 -0700195 cur_status = subscriber.status
Andy Bavierafaf1762019-01-16 09:41:43 -0700196 # Don't change state if someone has disabled the subscriber
197 if subscriber.status != "disabled":
198 if si.authentication_state in ["AWAITING", "REQUESTED", "STARTED"]:
199 subscriber.status = "awaiting-auth"
200 elif si.authentication_state == "APPROVED":
201 subscriber.status = "enabled"
202 elif si.authentication_state == "DENIED":
203 subscriber.status = "auth-failed"
Matteo Scandoload0c1752018-08-09 15:47:16 -0700204
Matteo Scandolode8cfa82018-10-16 13:49:05 -0700205 # NOTE we save the subscriber only if:
206 # - the status has changed
207 # - we get a DHCPACK event
208 if cur_status != subscriber.status or si.dhcp_state == "DHCPACK":
Scott Bakerc2a633d2019-04-01 19:27:41 -0700209 self.logger.debug(
210 "MODEL_POLICY: updating subscriber",
211 onu_device=subscriber.onu_device,
212 authentication_state=si.authentication_state,
213 subscriber_status=subscriber.status)
Andy Bavier8ed30c92018-12-11 13:46:25 -0700214 if subscriber.status == "awaiting-auth":
215 self.delete_subscriber_ip(subscriber, si.ip_address)
216 subscriber.mac_address = ""
217 elif si.ip_address and si.mac_address:
Matteo Scandolo74f63302018-11-01 14:05:01 -0700218 self.update_subscriber_ip(subscriber, si.ip_address)
Matteo Scandolode8cfa82018-10-16 13:49:05 -0700219 subscriber.mac_address = si.mac_address
Andy Bavier0d631eb2018-10-17 18:05:04 -0700220 subscriber.save_changed_fields(always_update_timestamp=True)
Matteo Scandolode8cfa82018-10-16 13:49:05 -0700221 else:
Matteo Scandoloc6ac74a2018-09-14 08:14:51 -0700222 self.logger.debug("MODEL_POLICY: subscriber status has not changed", onu_device=subscriber.onu_device,
223 authentication_state=si.authentication_state, subscriber_status=subscriber.status)
Matteo Scandoload0c1752018-08-09 15:47:16 -0700224
225 def handle_delete(self, si):
226 pass