Skip to content

Releases: code-lab-org/nost-tools

NOS-T Tools v3.0.5

03 Dec 08:28
9ecd128

Choose a tag to compare

Added:

  • Application Configuration Support: Added configuration_parameters support for unmanaged Application class:
    • Updated ExecConfig in schemas.py to include applications dictionary (similar to managed_applications)
    • Updated ApplicationConfig in schemas.py to include configuration_parameters field
    • Updated get_app_specific_config() in configuration.py to accept app_type parameter ("applications" or "managed_applications")
    • Updated Application._get_parameters_from_config() to retrieve app-specific config from applications section
    • Updated ConnectionConfig to populate application_configuration from both applications and managed_applications sections
    • Enables custom per-application configuration parameters in YAML
  • Resume Tolerance Configuration: Added global resume_tolerance parameter to GeneralConfig:
    • Added request_resume() method to Application class that sends ResumeRequest messages with optional sim_resume_time and tolerance parameters
    • Removed duplicate request_resume() from ManagedApplication - now inherits enhanced version from Application
    • Default tolerance of 12 hours can be configured globally in execution.general.resume_tolerance
    • Can be overridden per-request by passing tolerance parameter to request_resume()
    • Example YAML structure:
      execution:
        general:
          prefix: nost
          resume_tolerance: "12:00:00"  # Global default for all applications

Full Changelog: v3.0.4...v3.0.5

NOS-T Tools v3.0.4

26 Nov 21:50
d87c1e1

Choose a tag to compare

Added:

  • Basic Authentication Mode: Added support for localhost/development connections without Keycloak authentication
    • Allows USERNAME + PASSWORD only (no client credentials required)
    • Ideal for local RabbitMQ development without Keycloak infrastructure
    • System now supports three distinct authentication modes instead of two
  • Enhanced Credentials Validation: Updated validate_authentication_mode() in Credentials schema to support three authentication modes:
    • Basic Auth (localhost): USERNAME + PASSWORD only
    • Keycloak Service Account: CLIENT_ID + CLIENT_SECRET_KEY only
    • Keycloak User Account: USERNAME + PASSWORD + CLIENT_ID + CLIENT_SECRET_KEY
  • Comprehensive Three-Mode Testing: Added test_basic_auth_mode_valid() test to verify localhost authentication works correctly
  • Optional Scenario Time and Tolerance for ResumeRequest: Added optional fields to ResumeRequestParameters in schemas.py:
    • sim_resume_time: Allows managed applications to specify target scenario time for resume
    • tolerance: Time tolerance (timedelta) for matching scenario time to requested time
    • Both fields are optional and maintain backward compatibility (default to None)
    • Uses simResumeTime and tolerance aliases for JSON serialization consistency
  • Tolerance-Based Resume Command Logic: Added _handle_resume_request() method in manager.py to handle tolerance-based resume requests:
    • Runs in a separate thread to avoid blocking message callbacks
    • Default tolerance of 12 hours can be specified by managed applications

Changed:

  • Credentials Validator (schemas.py): Enhanced validation logic to recognize basic authentication as a valid mode alongside Keycloak authentication modes
  • Test Suite (tests/test_credentials.py):
    • Renamed test_user_account_mode_valid() to test_keycloak_user_account_mode_valid() for clarity
    • Updated test assertions to match new error messages
    • Now testing 8 scenarios (was 7) including basic auth mode
  • Error Messages: Updated validation error messages to include all three authentication modes for better troubleshooting
  • Resume Request Handling (manager.py): Modified on_resume_request() to delegate to _handle_resume_request() for tolerance-based handling:
    • If tolerance is NOT provided: ResumeCommand is sent immediately (regardless of sim_resume_time)
    • If tolerance IS provided:
      • Both tolerance and sim_resume_time provided: Checks if current scenario time is within tolerance of requested time
        • Within tolerance: ResumeCommand is sent immediately
        • Outside tolerance: Request is ignored with informative log message showing time difference
      • Only tolerance provided (no sim_resume_time): ResumeCommand is sent immediately
    • This tolerance-based approach allows managed applications to send multiple ResumeRequest messages with the Manager only acting when scenario time is within the specified tolerance window
  • Exchange Declaration (application.py): Moved establish_exchange() method from Manager class to base Application class:
    • All applications (unmanaged Application, ManagedApplication, and Manager) now automatically declare the exchange when channel opens
    • Fixes "NOT_FOUND - no exchange" errors when unmanaged applications try to publish messages
    • Exchange is declared in on_channel_open() callback, ensuring it exists before any message operations
    • Eliminates requirement for Manager to run first before other applications can send messages
  • Freeze Request Logging (manager.py): Fixed misleading log message in _handle_freeze_request():
    • "Indefinite freeze requested - manual resume required" now logs before freeze starts (not after)
    • Added "Indefinite freeze has ended" log message after freeze completes
  • BasicProperties Handling (application.py): Fixed RabbitMQ protocol error "UNEXPECTED_FRAME - expected content header for class 60":
    • Added _build_basic_properties() helper method that filters out None values before creating pika.BasicProperties
    • Updated send_message() and _process_message_queue() to use the new helper
    • Prevents protocol errors when YAML configuration has undefined/None BasicProperties fields
    • Resolves random connection drops with error code 505 (UNEXPECTED_FRAME)

Full Changelog: v3.0.3...v3.0.4

NOS-T Tools v3.0.3

20 Nov 08:14
8db56f2

Choose a tag to compare

Added:

  • Service Account Authentication Support: Applications can now authenticate with Keycloak using service accounts (client credentials only) without requiring username and password. This is ideal for automated systems, scripts, and long-running processes.
  • Dual Authentication Modes: The system now supports two Keycloak authentication modes:
    • User Account: Requires USERNAME, PASSWORD, CLIENT_ID, and CLIENT_SECRET_KEY
    • Service Account: Requires only CLIENT_ID and CLIENT_SECRET_KEY
  • Intelligent OTP Detection: Added smart OTP/TOTP requirement detection in new_access_token() method that:
    • Analyzes Keycloak error responses for OTP-related keywords (otp, totp, two-factor, 2fa, mfa)
    • Only prompts for OTP when Keycloak explicitly indicates it's required
    • Prevents false OTP prompts when username/password are incorrect
    • Provides clear, context-specific error messages for different failure scenarios
  • Programmatic OTP Support: Added optional otp parameter to new_access_token() method to support automation with OTP-enabled accounts
  • Credentials Validation: Added validate_authentication_mode() validator in Credentials schema that enforces valid credential combinations and provides clear error messages for invalid configurations
  • Comprehensive Test Suite: Added tests/test_credentials.py with 7 tests covering both authentication modes and validation scenarios
  • Documentation:
    • Created KEYCLOAK_AUTH_MODES.md with detailed guide on both authentication modes, setup instructions, and error handling
    • Created OTP_IMPROVEMENTS.md documenting intelligent OTP handling improvements
    • Created .env.example template showing both authentication modes
    • Created .env.sos.example specific template for sos.yaml configuration

Changed:

  • Credentials Schema (schemas.py): Changed default values for username and password from "admin" to None to make them optional for service account authentication
  • Environment Variable Loading (configuration.py): Updated load_environment_variables() method to support optional username/password when Keycloak authentication is enabled, allowing service account mode
  • Authentication Method (application.py): Updated new_access_token() method to:
    • Automatically detect authentication mode based on presence of username/password
    • Use grant_type="password" for user authentication
    • Use grant_type=["client_credentials"] for service account authentication
    • Intelligently handle OTP requirements with proper error detection
    • Log which authentication mode is being used for debugging
  • Error Messages: Improved authentication error messages to clearly indicate:
    • "Authentication failed. Please check your username and password" for wrong credentials
    • "OTP/TOTP is required for this account" when OTP is needed
    • "The provided OTP may be incorrect or expired" for wrong OTP

Full Changelog: v3.0.2...v3.0.3

NOS-T Tools v3.0.2

02 Sep 06:26
114c86e

Choose a tag to compare

Updated:

  • Removed self._next_time = self._time from resume() in simulator.py, which was causing a drift of approximately 1 second per simulated day.
  • Changed a log statement in freeze() within manager.py from log.info to log.debug to reduce verbosity. The affected line reports the remaining time during a freeze.

Full Changelog: v3.0.1...v3.0.2

NOS-T Tools v3.0.1

25 Aug 05:27
aaa56c5

Choose a tag to compare

Updated:

  • Removed the calculation of target_resume_time from the freeze() method in manager.py.
    A freeze event now persists until the resume time specified in the FreezeCommand message payload is reached. Previously, the resume time was calculated from the scenario time at which the FreezeRequest message was received by the manager (scenario time at message receipt + freeze duration), which could cause time drift.
  • Prevented a one-step early advance after RESUMING by ensuring the _wait_for_tock() method in simulator.py re-anchors epochs and waits until the next tick before advancing.
  • Updated the on_manager_freeze() method in managed_application.py to honor simFreezeTime from a FreezeCommand, aligning to the requested scenario time (via wallclock mapping) before calling pause() so all apps freeze at the same scenario time.

Full Changelog: v3.0.0...v3.0.1

NOS-T Tools v3.0.0

19 Aug 03:19
b371477

Choose a tag to compare

Added:

  • Added comprehensive freeze time tracking system and callbacks in Manager class in manager.py to properly account for dynamic, distributed freezes, resumes, and updates to scenario time:
    • Added on_freeze_request() callback which freezes scenario time based on messages containing requests from managed applications, integrated this callback into start_up() method
    • Added _handle_freeze_request() that handles dynamic, distributed freeze requests
    • Added freeze() that issues freeze command, integrated this into the _handle_freeze_request()
    • Added on_resume_request() callback which resumes scenario time based on messages containing requests from managed applications, integrated this callback into start_up() method
    • Added on_update_request() callback which updates the time scale factor based on messages containing requests from managed applications, integrated this callback into start_up() method
    • Added update() that issues update command, integrated this into the on_update_request() method
  • Added new methods to ManagedApplication class in managed_application.py to allow requests for a freeze in scenario time from the Manager class in manager.py
    • Added request_freeze() method that sends a FreezeRequest message which is received by the Manager application, added an associated on_manager_freeze() callback that responds to FreezeCommand messages from Manger
    • Added request_resume() method that sends a ResumeRequest message which is received by the Manager application, added an associated on_manager_resume() callback that responds to ResumeCommand messages from Manager
    • Added request_update() method that sends a UpdateRequest message which is received by the Manager application, added an associated on_manager_update() callback that responds to UpdateCommand messages from Manager
  • Added new freeze-tracking capabilities to Simulator class in simulator.py
    • Added reset of wallclock and simulation epochs when mode switches to Mode.EXECUTING in _wait_for_tock() method
  • Added the following classes to schemas.py:
    • FreezeTaskingParameters, FreezeCommand, ResumeTaskingParameters, ResumeCommand, FreezeRequestParameters, FreezeRequest, ResumeRequestParameters, ResumeRequest, UpdateRequestParameters, UpdateRequest

Updated:

  • Removed code related to scheduled time scale updates in _execute_test_plan_impl() of Manager application. Scheduled time scale factor updates, defined in the YAML configuration file, are no longer supported. They must now be requested by a ManagedApplication and processed by the Manager who maintains control of sending the FreezeCommand as defined in schemas.py
  • Removed TimeScaleUpdate class in manager.py
  • Removed TimeScaleUpdateSchema and FreezeSchema classes in schemas.py
  • Removed time_scale_updates and freezes fields from ManagerConfig class in schemas.py
  • Prevent re-entrant execution in Simulator.execute() by adding an explicit mode guard; now raises a clear RuntimeError when called outside UNDEFINED, INITIALIZED, or TERMINATED modes: Cannot execute: simulator is {self._mode}. Wait for TERMINATED or terminate the current run.
  • Removed WallclockOffsetProperties class and wallclock_offset_properties section from RuntimeConfig in schemas.py and configuration.py.
  • Added wallclock_offset_refresh_interval and ntp_host to GeneralConfig class in schemas.py
  • Updated FireSat test suite to show examples of time scale updates and scenario time freezes.

Full Changelog: v2.4.0...v3.0.0

NOS-T Tools v2.4.0

02 Jul 20:34
4952de3

Choose a tag to compare

Added:

  • Introduced the configure_file_logging() method in the base Application class, automatically invoked during the start_up() process.
  • Added a LoggingConfig Pydantic model to encapsulate configuration parameters for the configure_file_logging() method.

Updated:

  • Changed the default value of token_refresh_interval in the KeycloakConfig Pydantic class from 60 seconds (1 minute) to 240 seconds (4 minutes).

Full Changelog: v2.3.0...v2.4.0

NOS-T Tools v2.3.0

06 Jun 06:04
4bc9054

Choose a tag to compare

Added:

  • Introduced a boolean setup_signal_handlers (default=True) parameter for Application() class, which makes self._setup_signal_handlers() conditional. This prevents errors in nost-manager-backend.
    • Added setup_signal_handlers argument (default=True) to __init__ of Manager and ManagedApplication classes.
  • Added yaml_file section to RuntimeConfig in both schemas.py and configuration.py. This attribute holds the path to YAML configuration file if provided; otherwise, it defaults to None.
  • Introduced _get_parameters_from_config() in Application, Manager, and ManagedApplication to facilitate getting the application parameters from the YAML configuration or user-provided arguments based on self.config.rc.yaml_file being None or not.
  • Added keycloak_authentication argument to __init__() of ConnectionConfig class (default=False).
  • Implemented start_wallclock_refresh_thread() which periodically updates the wallclock offset.
  • Added WallclockOffsetProperties to schemas.py that contains wallclock_offset_refresh_interval and ntp_host fields used in start_wallclock_refresh_thread()
  • Implemented is_scenario_time_step in ManagerConfig class, similar to that of ManagedApplicationConfig

Updated:

  • Made general section of ExecConfig optional in schemas.pyfor situations where YAML configuration file is not provided.
  • Made client_id and client_secret_key in Credentials default to None.
  • Changed parameters.time_scale_updates reference to self.time_scale_updates in manager.py.
  • Updated code in start_up() related to the definition of parameters to use _get_parameters_from_config() subclasses to customize parameter retrieval in:
    • Application class of application.py
    • Manager class of manager.py
    • ManagedApplication class of managed_application.py
  • Updated self.simulator.set_end_time(sim_stop_time) from stop() in manager.py to run only if self.simulator.get_mode() == Mode.EXECUTING
  • Removed time_step and manager_app_name arguments from start_up() in Manager class
  • Modified set_wallclock_offset() in simulator.py to allow setting wallclock offset when in Mode.EXECUTING
  • Update default value of time_status_init to datetime.now() in ApplicationConfig class

Full Changelog: v2.2.0...v2.3.0

NOS-T Tools v2.2.0

04 Jun 09:12
ce2e22f

Choose a tag to compare

Added:

  • Introduced TimeScaleUpdateSchema in schemas.py, which allows users to define time scale updates in the YAML configuration file at execution.manager.time_scale_updates, each update can be defined by time_scale_factor and sim_update_time. For example:
    time_scale_updates:
      - time_scale_factor: 120.0
        sim_update_time: "2020-01-01T08:20:00+00:00"

    NOTE: An example is provided in FireSat+ YAML configuration file.

  • Introduced get_app_specific_config() in configuration.py that retrieves application-specific configuration from the execution.managed_applications section based on the application name.
  • Added application_configuration to config.rc (runtime configuration) at configuration.py, which contains user-provided, application-specific configurations. These application-specific configurations can be defined for each application within the YAML configuration file at the field execution.managed_applications.<application name>.configuration_parameters. This replaces config.py for each application in the NOS-T Tools examples.

Changed:

  • Moved self.establish_exchange() from self._execute_test_plan_impl() to self.start_up() to prevent execution from starting before RabbitMQ exchanges have been declared and resulting in an error.
  • Removed conditional check for self.app.channel.is_open and self.app.connection.is_open in application_utils.py before sending status messages; now assumes connection is always valid or managed externally.
  • Refactored the FireSat+, Downlink, Scalability, and scienceDash test suites to:
    • Use a unified YAML configuration file per example
    • Define application-specific settings under the execution.managed_applications.<application name>.configuration_parameters field instead of the previous config.py
    • Improve general code structure for enhanced efficiency, readability, and user experience
  • Updated documentation for the FireSat+, Downlink, Scalability, and scienceDash test suites.

Full Changelog: v2.1.1...v2.2.0

NOS-T Tools v2.1.1

20 May 23:14
614c326

Choose a tag to compare

Added

  • Introduces a new boolean flags to explicitly define the time domain for time_step and time_status_step. These flags will determine whether the associated values are interpreted in scenario time (unscaled) or wall clock time (scaled by the time scale factor).

Full Changelog: v2.1.0...v2.1.1