Releases: code-lab-org/nost-tools
Releases · code-lab-org/nost-tools
NOS-T Tools v3.0.8
Fixed:
- Manager Stop Command Timing During Freezes (
manager.py): Fixed bug where Manager sent Stop command at the originally expected time instead of accounting for freeze duration:- Added pause mode check in
_execute_test_plan_impl()waiting loop to skip stop time calculations while simulator is inPAUSEDorPAUSINGmode - Prevents race condition where stale
_wallclock_epochand_simulation_epochvalues caused incorrect stop time calculations during freezes - Stop command now correctly sent at
original_expected_time + freeze_duration(e.g., 10 minutes total wallclock time for 5-minute execution + 5-minute freeze) - Ensures proper synchronization between Manager's waiting logic and Simulator's freeze/resume cycle
- Added pause mode check in
Full Changelog: v3.0.7...v3.0.8
NOS-T Tools v3.0.7
Changed:
- Python-Keycloak Version Constraint: Pinned
python-keycloakdependency to>=5, <7inpyproject.toml:- Version 7.0.0+ uses PEP 604 union type syntax (
str | Role) which requires Python 3.10+ - This constraint maintains compatibility with Python 3.9 (
requires-python = ">=3.9") - Can be relaxed when
nost_toolsdrops Python 3.9 support or upstream addsfrom __future__ import annotations
- Version 7.0.0+ uses PEP 604 union type syntax (
Full Changelog: v3.0.6...v3.0.7
NOS-T Tools v3.0.6
Changed:
-
Consumer Cleanup on Shutdown (
application.py): Removed redundantstop_consuming()call instop_application():- Queue deletion already implicitly cancels all consumers attached to those queues via RabbitMQ's standard behavior
- Eliminates "pika.channel: basic_cancel - consumer not found" warning during application shutdown
- Reduces unnecessary RPC calls during cleanup sequence
-
Reconnection Logic (
application.py): Fixed network reconnection failing when applications are in frozen/paused state:- Removed duplicate
_io_threadcreation inreconnect()method that caused two threads to compete for the same ioloop - Now stops the old ioloop explicitly after creating the new connection, allowing
_start_io_loop's while loop to pick up the new
connection naturally - Changed error handler to use
threading.Timerinstead ofioloop.call_later()for retry scheduling, since ioloop state may be
inconsistent during failures - Reconnection now works reliably regardless of simulator mode (executing, paused, etc.)
- Removed duplicate
Full Changelog: v3.0.5...v3.0.6
NOS-T Tools v3.0.5
Added:
- Application Configuration Support: Added
configuration_parameterssupport for unmanagedApplicationclass:- Updated
ExecConfiginschemas.pyto includeapplicationsdictionary (similar tomanaged_applications) - Updated
ApplicationConfiginschemas.pyto includeconfiguration_parametersfield - Updated
get_app_specific_config()inconfiguration.pyto acceptapp_typeparameter ("applications" or "managed_applications") - Updated
Application._get_parameters_from_config()to retrieve app-specific config fromapplicationssection - Updated
ConnectionConfigto populateapplication_configurationfrom bothapplicationsandmanaged_applicationssections - Enables custom per-application configuration parameters in YAML
- Updated
- Resume Tolerance Configuration: Added global
resume_toleranceparameter toGeneralConfig:- Added
request_resume()method toApplicationclass that sendsResumeRequestmessages with optionalsim_resume_timeandtoleranceparameters - Removed duplicate
request_resume()fromManagedApplication- now inherits enhanced version fromApplication - Default tolerance of 12 hours can be configured globally in
execution.general.resume_tolerance - Can be overridden per-request by passing
toleranceparameter torequest_resume() - Example YAML structure:
execution: general: prefix: nost resume_tolerance: "12:00:00" # Global default for all applications
- Added
Full Changelog: v3.0.4...v3.0.5
NOS-T Tools v3.0.4
Added:
- Basic Authentication Mode: Added support for localhost/development connections without Keycloak authentication
- Allows
USERNAME+PASSWORDonly (no client credentials required) - Ideal for local RabbitMQ development without Keycloak infrastructure
- System now supports three distinct authentication modes instead of two
- Allows
- Enhanced Credentials Validation: Updated
validate_authentication_mode()inCredentialsschema to support three authentication modes:- Basic Auth (localhost):
USERNAME+PASSWORDonly - Keycloak Service Account:
CLIENT_ID+CLIENT_SECRET_KEYonly - Keycloak User Account:
USERNAME+PASSWORD+CLIENT_ID+CLIENT_SECRET_KEY
- Basic Auth (localhost):
- 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
ResumeRequestParametersinschemas.py:sim_resume_time: Allows managed applications to specify target scenario time for resumetolerance: Time tolerance (timedelta) for matching scenario time to requested time- Both fields are optional and maintain backward compatibility (default to
None) - Uses
simResumeTimeandtolerancealiases for JSON serialization consistency
- Tolerance-Based Resume Command Logic: Added
_handle_resume_request()method inmanager.pyto 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()totest_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
- Renamed
- Error Messages: Updated validation error messages to include all three authentication modes for better troubleshooting
- Resume Request Handling (
manager.py): Modifiedon_resume_request()to delegate to_handle_resume_request()for tolerance-based handling:- If
toleranceis NOT provided:ResumeCommandis sent immediately (regardless ofsim_resume_time) - If
toleranceIS provided:- Both
toleranceandsim_resume_timeprovided: Checks if current scenario time is within tolerance of requested time- Within tolerance:
ResumeCommandis sent immediately - Outside tolerance: Request is ignored with informative log message showing time difference
- Within tolerance:
- Only
toleranceprovided (nosim_resume_time):ResumeCommandis sent immediately
- Both
- This tolerance-based approach allows managed applications to send multiple
ResumeRequestmessages with the Manager only acting when scenario time is within the specified tolerance window
- If
- Exchange Declaration (
application.py): Movedestablish_exchange()method fromManagerclass to baseApplicationclass:- 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 outNonevalues before creatingpika.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)
- Added
Full Changelog: v3.0.3...v3.0.4
NOS-T Tools v3.0.3
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, andCLIENT_SECRET_KEY - Service Account: Requires only
CLIENT_IDandCLIENT_SECRET_KEY
- User Account: Requires
- 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
- Analyzes Keycloak error responses for OTP-related keywords (
- Programmatic OTP Support: Added optional
otpparameter tonew_access_token()method to support automation with OTP-enabled accounts - Credentials Validation: Added
validate_authentication_mode()validator inCredentialsschema that enforces valid credential combinations and provides clear error messages for invalid configurations - Comprehensive Test Suite: Added
tests/test_credentials.pywith 7 tests covering both authentication modes and validation scenarios - Documentation:
- Created
KEYCLOAK_AUTH_MODES.mdwith detailed guide on both authentication modes, setup instructions, and error handling - Created
OTP_IMPROVEMENTS.mddocumenting intelligent OTP handling improvements - Created
.env.exampletemplate showing both authentication modes - Created
.env.sos.examplespecific template for sos.yaml configuration
- Created
Changed:
- Credentials Schema (
schemas.py): Changed default values forusernameandpasswordfrom"admin"toNoneto make them optional for service account authentication - Environment Variable Loading (
configuration.py): Updatedload_environment_variables()method to support optional username/password when Keycloak authentication is enabled, allowing service account mode - Authentication Method (
application.py): Updatednew_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
Updated:
- Removed
self._next_time = self._timefromresume()insimulator.py, which was causing a drift of approximately 1 second per simulated day. - Changed a log statement in
freeze()withinmanager.pyfrom 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
Updated:
- Removed the calculation of
target_resume_timefrom thefreeze()method inmanager.py.
A freeze event now persists until the resume time specified in theFreezeCommandmessage payload is reached. Previously, the resume time was calculated from the scenario time at which theFreezeRequestmessage 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 insimulator.pyre-anchors epochs and waits until the next tick before advancing. - Updated the
on_manager_freeze()method inmanaged_application.pyto honorsimFreezeTimefrom aFreezeCommand, aligning to the requested scenario time (via wallclock mapping) before callingpause()so all apps freeze at the same scenario time.
Full Changelog: v3.0.0...v3.0.1
NOS-T Tools v3.0.0
Added:
- Added comprehensive freeze time tracking system and callbacks in
Managerclass inmanager.pyto 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 intostart_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 intostart_up()method - Added
on_update_request()callback which updates the time scale factor based on messages containing requests from managed applications, integrated this callback intostart_up()method - Added
update()that issues update command, integrated this into theon_update_request()method
- Added
- Added new methods to
ManagedApplicationclass inmanaged_application.pyto allow requests for a freeze in scenario time from theManagerclass inmanager.py- Added
request_freeze()method that sends a FreezeRequest message which is received by theManagerapplication, added an associatedon_manager_freeze()callback that responds to FreezeCommand messages fromManger - Added
request_resume()method that sends a ResumeRequest message which is received by theManagerapplication, added an associatedon_manager_resume()callback that responds to ResumeCommand messages fromManager - Added
request_update()method that sends a UpdateRequest message which is received by theManagerapplication, added an associatedon_manager_update()callback that responds to UpdateCommand messages fromManager
- Added
- Added new freeze-tracking capabilities to
Simulatorclass insimulator.py- Added reset of wallclock and simulation epochs when mode switches to Mode.EXECUTING in
_wait_for_tock()method
- Added reset of wallclock and simulation epochs when mode switches to Mode.EXECUTING in
- 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()ofManagerapplication. Scheduled time scale factor updates, defined in the YAML configuration file, are no longer supported. They must now be requested by aManagedApplicationand processed by theManagerwho maintains control of sending theFreezeCommandas defined inschemas.py - Removed
TimeScaleUpdateclass inmanager.py - Removed
TimeScaleUpdateSchemaandFreezeSchemaclasses inschemas.py - Removed
time_scale_updatesandfreezesfields fromManagerConfigclass inschemas.py - Prevent re-entrant execution in
Simulator.execute()by adding an explicit mode guard; now raises a clearRuntimeErrorwhen called outsideUNDEFINED,INITIALIZED, orTERMINATEDmodes:Cannot execute: simulator is {self._mode}. Wait for TERMINATED or terminate the current run. - Removed
WallclockOffsetPropertiesclass andwallclock_offset_propertiessection fromRuntimeConfiginschemas.pyandconfiguration.py. - Added
wallclock_offset_refresh_intervalandntp_hosttoGeneralConfigclass inschemas.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
Added:
- Introduced the
configure_file_logging()method in the baseApplicationclass, automatically invoked during thestart_up()process. - Added a
LoggingConfigPydantic model to encapsulate configuration parameters for theconfigure_file_logging()method.
Updated:
- Changed the default value of
token_refresh_intervalin theKeycloakConfigPydantic class from 60 seconds (1 minute) to 240 seconds (4 minutes).
Full Changelog: v2.3.0...v2.4.0