AETHER-2846 Support all parameters which lists in Aether Docs
AETHER-2847 Integrating with Prometheus and record eNB information
AETHER-2848 Move SAS configuration as enodeb base, not plugin in driver code
AETHER-2879 add gps information in prometheus
AETHER-2880 add ip and port as configurable parameter in enodebd
AETHER-2897 Firmware update feature over CWMP
AETHER-3022 Integrate firmware upgrade state into configuration workflow
AETHER-3120 Develop ACS state machine with firmware upgrade feature
Change-Id: I0bcbf2229ba3c1638f2a997f3c651f8d6240145d
diff --git a/state_machines/enb_acs_states.py b/state_machines/enb_acs_states.py
index a9b84a5..d9e2ed9 100644
--- a/state_machines/enb_acs_states.py
+++ b/state_machines/enb_acs_states.py
@@ -10,10 +10,15 @@
See the License for the specific language governing permissions and
limitations under the License.
"""
+
+import time
from abc import ABC, abstractmethod
from collections import namedtuple
from typing import Any, Optional
+import metrics
+
+from configuration.service_configs import load_service_config
from data_models.data_model import InvalidTrParamPath
from data_models.data_model_parameters import ParameterName
from device_config.configuration_init import build_desired_config
@@ -964,6 +969,14 @@
'Status=%d' % message.Status,
)
self._mark_as_configured()
+
+ metrics.STAT_ENODEB_LAST_CONFIGURED.labels(
+ serial_number=self.acs.device_cfg.get_parameter("Serial number"),
+ ip_address=self.acs.device_cfg.get_parameter("ip_address"),
+ gps_lat=self.acs.device_cfg.get_parameter("GPS lat"),
+ gps_lon=self.acs.device_cfg.get_parameter("GPS long")
+ ).set(int(time.time()))
+
if not self.acs.are_invasive_changes_applied:
return AcsReadMsgResult(True, self.apply_invasive_transition)
return AcsReadMsgResult(True, self.done_transition)
@@ -1257,6 +1270,115 @@
return 'Waiting after eNB reboot to prevent race conditions'
+class DownloadState(EnodebAcsState):
+ """
+ The eNB handler will enter this state when firmware version is older than desired version.
+ """
+
+ def __init__(self, acs: EnodebAcsStateMachine, when_done: str):
+ super().__init__()
+ self.acs = acs
+ self.done_transition = when_done
+
+ def get_msg(self, message: Any) -> AcsMsgAndTransition:
+
+ print("ACS Device CFG")
+ print(self.acs.device_cfg._param_to_value)
+
+ request = models.Download()
+ request.CommandKey = "20220206215200"
+ request.FileType = "1 Firmware Upgrade Image"
+ request.URL = "http://18.116.99.179/firmware/Qproject_TEST3918_2102241222.ffw"
+ request.Username = ""
+ request.Password = ""
+ request.FileSize = 57208579
+ request.TargetFileName = "Qproject_TEST3918_2102241222.ffw"
+ request.DelaySeconds = 0
+ request.SuccessURL = ""
+ request.FailureURL = ""
+ return AcsMsgAndTransition(request, self.done_transition)
+
+ def state_description(self) -> str:
+ return 'Upgrade the firmware the desired version'
+
+class WaitDownloadResponseState(EnodebAcsState):
+ """
+ The eNB handler will enter this state after the Download command sent.
+ """
+
+ def __init__(self, acs: EnodebAcsStateMachine, when_done: str):
+ super().__init__()
+ self.acs = acs
+ self.done_transition = when_done
+
+ def read_msg(self, message: Any) -> AcsReadMsgResult:
+ if not isinstance(message, models.DownloadResponse):
+ return AcsReadMsgResult(False, None)
+ return AcsReadMsgResult(True, None)
+
+ def get_msg(self, message: Any) -> AcsMsgAndTransition:
+ """ Reply with empty message """
+ logger.info("Received Download Response from eNodeB")
+ return AcsMsgAndTransition(models.DummyInput(), self.done_transition)
+
+ def state_description(self) -> str:
+ return "Wait DownloadResponse message"
+
+class WaitInformTransferCompleteState(EnodebAcsState):
+ """
+ The eNB handler will enter this state after firmware upgraded and rebooted
+ """
+
+ REBOOT_TIMEOUT = 300 # In seconds
+ INFORM_EVENT_CODE = "7 TRANSFER COMPLETE"
+ PREIODIC_EVENT_CODE = "2 PERIODIC"
+
+ def __init__(self, acs: EnodebAcsStateMachine, when_done: str, when_periodic: str, when_timeout: str):
+ super().__init__()
+ self.acs = acs
+ self.done_transition = when_done
+ self.periodic_update_transition = when_periodic
+ self.timeout_transition = when_timeout
+ self.timeout_timer = None
+ self.timer_handle = None
+
+ def enter(self):
+ print("Get into the TransferComplete State")
+ self.timeout_timer = StateMachineTimer(self.REBOOT_TIMEOUT)
+
+ def check_timer() -> None:
+ if self.timeout_timer.is_done():
+ self.acs.transition(self.timeout_transition)
+ raise Tr069Error("Didn't receive Inform response after rebooting")
+
+ self.timer_handle = self.acs.event_loop.call_later(
+ self.REBOOT_TIMEOUT,
+ check_timer,
+ )
+
+ def exit(self):
+ self.timer_handle.cancel()
+ self.timeout_timer = None
+
+ def get_msg(self, message: Any) -> AcsMsgAndTransition:
+ return AcsMsgAndTransition(models.DummyInput(), None)
+
+ def read_msg(self, message: Any) -> AcsReadMsgResult:
+ if not isinstance(message, models.Inform):
+ return AcsReadMsgResult(False, None)
+ if does_inform_have_event(message, self.PREIODIC_EVENT_CODE):
+ logger.info("Receive Periodic update from enodeb")
+ return AcsReadMsgResult(True, self.periodic_update_transition)
+ if does_inform_have_event(message, self.INFORM_EVENT_CODE):
+ logger.info("Receive Transfer complete")
+ return AcsReadMsgResult(True, self.done_transition)
+
+ # Unhandled situation
+ return AcsReadMsgResult(False, None)
+
+ def state_description(self) -> str:
+ return "Wait DownloadResponse message"
+
class ErrorState(EnodebAcsState):
"""
The eNB handler will enter this state when an unhandled Fault is received.
@@ -1290,4 +1412,4 @@
def state_description(self) -> str:
return 'Error state - awaiting manual restart of enodebd service or ' \
- 'an Inform to be received from the eNB'
+ 'an Inform to be received from the eNB'
\ No newline at end of file