howler-api 4.0.0.dev1308__tar.gz → 4.0.0.dev1337__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/PKG-INFO +2 -2
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/datastore/README.md +3 -4
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/datastore/collection.py +92 -22
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/external/reindex_data.py +1 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/README.md +5 -2
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/case.py +4 -4
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/random_data.py +5 -1
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/remote/datatypes/README.md +26 -19
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/pyproject.toml +5 -5
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/README.md +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/__init__.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/actions/__init__.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/actions/add_label.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/actions/add_to_bundle.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/actions/add_to_case.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/actions/change_field.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/actions/demote.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/actions/example_plugin.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/actions/prioritization.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/actions/promote.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/actions/remove_from_bundle.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/actions/remove_label.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/actions/transition.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/api/__init__.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/api/base.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/api/socket.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/api/v1/__init__.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/api/v1/action.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/api/v1/analytic.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/api/v1/auth.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/api/v1/clue.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/api/v1/configs.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/api/v1/dossier.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/api/v1/help.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/api/v1/hit.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/api/v1/notebook.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/api/v1/overview.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/api/v1/search.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/api/v1/template.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/api/v1/tool.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/api/v1/user.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/api/v1/utils/__init__.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/api/v1/utils/etag.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/api/v1/utils/params.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/api/v1/view.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/api/v2/__init__.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/api/v2/case.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/api/v2/fuzzy.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/api/v2/ingest.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/api/v2/search.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/app.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/common/README.md +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/common/__init__.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/common/classification.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/common/classification.yml +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/common/exceptions.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/common/loader.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/common/logging/__init__.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/common/logging/audit.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/common/logging/format.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/common/net.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/common/net_static.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/common/random_user.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/common/swagger.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/config.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/cronjobs/__init__.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/cronjobs/action_queue_worker.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/cronjobs/correlation.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/cronjobs/retention.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/cronjobs/view_cleanup.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/datastore/__init__.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/datastore/bulk.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/datastore/constants.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/datastore/exceptions.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/datastore/howler_store.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/datastore/migrations/fix_process.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/datastore/operations.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/datastore/schemas.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/datastore/store.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/datastore/support/__init__.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/datastore/support/build.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/datastore/support/schemas.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/datastore/types.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/error.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/external/README.md +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/external/__init__.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/external/generate_mitre.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/external/generate_sigma_rules.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/external/generate_tlds.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/external/wipe_databases.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/gunicorn_config.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/healthz.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/helper/__init__.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/helper/azure.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/helper/discover.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/helper/hit.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/helper/oauth.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/helper/search.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/helper/workflow.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/helper/ws.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/__init__.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/base.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/charter.txt +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/constants.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/helper.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/howler_enum.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/mixins.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/__init__.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/action.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/analytic.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/assemblyline.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/aws.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/azure.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/cbs.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/clue.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/config.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/dossier.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/__init__.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/agent.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/autonomous_system.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/client.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/cloud.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/code_signature.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/container.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/dns.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/egress.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/elf.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/email.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/error.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/event.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/faas.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/file.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/geo.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/group.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/hash.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/host.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/http.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/ingress.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/interface.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/network.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/observer.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/organization.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/os.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/pe.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/process.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/registry.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/related.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/rule.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/server.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/threat.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/tls.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/url.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/user.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/user_agent.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/ecs/vulnerability.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/event.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/gcp.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/hit.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/howler_data.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/lead.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/localized_label.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/overview.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/pivot.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/record.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/template.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/user.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/models/view.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/odm/randomizer.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/patched.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/plugins/__init__.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/plugins/config.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/remote/__init__.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/remote/datatypes/__init__.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/remote/datatypes/counters.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/remote/datatypes/events.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/remote/datatypes/hash.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/remote/datatypes/lock.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/remote/datatypes/queues/__init__.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/remote/datatypes/queues/comms.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/remote/datatypes/queues/multi.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/remote/datatypes/queues/named.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/remote/datatypes/queues/priority.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/remote/datatypes/set.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/remote/datatypes/user_quota_tracker.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/security/__init__.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/security/socket.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/security/utils.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/services/__init__.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/services/action_service.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/services/analytic_service.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/services/auth_service.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/services/bundle_compat_service.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/services/case_service.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/services/comms_service.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/services/config_service.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/services/correlation_service.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/services/docs_service.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/services/dossier_service.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/services/event_service.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/services/fuzzy_service.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/services/hit_service.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/services/jwt_service.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/services/lucene_service.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/services/notebook_service.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/services/overview_service.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/services/search_service.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/services/template_service.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/services/user_service.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/services/viewer_service.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/telemetry.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/utils/__init__.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/utils/annotations.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/utils/chunk.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/utils/compat.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/utils/constants.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/utils/dict_utils.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/utils/indexes.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/utils/isotime.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/utils/list_utils.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/utils/lucene.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/utils/net_utils.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/utils/path.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/utils/socket_utils.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/utils/str_utils.py +0 -0
- {howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/utils/uid.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: howler-api
|
|
3
|
-
Version: 4.0.0.
|
|
3
|
+
Version: 4.0.0.dev1337
|
|
4
4
|
Summary: Howler - API server
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: howler,alerting,gc,canada,cse-cst,cse,cst,cyber,cccs
|
|
@@ -38,7 +38,7 @@ Requires-Dist: opentelemetry-instrumentation-flask (==0.61b0)
|
|
|
38
38
|
Requires-Dist: opentelemetry-sdk (==1.40.0)
|
|
39
39
|
Requires-Dist: packaging (<25.0)
|
|
40
40
|
Requires-Dist: passlib (==1.7.4)
|
|
41
|
-
Requires-Dist: prometheus-client (==0.
|
|
41
|
+
Requires-Dist: prometheus-client (==0.26.0)
|
|
42
42
|
Requires-Dist: pydantic (>=2.11.4,<3.0.0)
|
|
43
43
|
Requires-Dist: pydantic-settings[yaml] (>=2.9.1,<3.0.0)
|
|
44
44
|
Requires-Dist: pydash (>=8.0.5,<9.0.0)
|
|
@@ -37,10 +37,9 @@ from howler.common import loader
|
|
|
37
37
|
from myapp.models.mymodel import MyModel
|
|
38
38
|
|
|
39
39
|
ds = loader.get_esstore()
|
|
40
|
-
ds.register(
|
|
40
|
+
ds.register("mymodel", MyModel)
|
|
41
41
|
|
|
42
42
|
my_document = ds.mymodel.get(document_id)
|
|
43
|
-
|
|
44
43
|
```
|
|
45
44
|
|
|
46
45
|
### Creating your own datastore
|
|
@@ -59,10 +58,10 @@ from myapp.models.mycollection import MyCollection
|
|
|
59
58
|
|
|
60
59
|
|
|
61
60
|
class MyDatastore(object):
|
|
62
|
-
def __init__(self, esstore_object: ESStore = None
|
|
61
|
+
def __init__(self, esstore_object: ESStore = None):
|
|
63
62
|
|
|
64
63
|
self.ds = esstore_object or loader.get_esstore()
|
|
65
|
-
self.ds.register(
|
|
64
|
+
self.ds.register("mycollection", MyCollection)
|
|
66
65
|
# ... + all other collections
|
|
67
66
|
|
|
68
67
|
def __enter__(self):
|
|
@@ -252,19 +252,50 @@ class ESCollection(Generic[ModelType]):
|
|
|
252
252
|
|
|
253
253
|
@property
|
|
254
254
|
def index_list_full(self):
|
|
255
|
+
"""Return every physical index for this collection, newest ILM index first.
|
|
256
|
+
|
|
257
|
+
Maintenance operations that must visit historical rollover indexes should use this
|
|
258
|
+
property. The active index is included even when no ILM rollover index exists.
|
|
259
|
+
"""
|
|
255
260
|
if not self._index_list:
|
|
256
|
-
self._index_list =
|
|
261
|
+
self._index_list = self._get_ilm_index_names()
|
|
257
262
|
|
|
258
|
-
return [self.index_name
|
|
263
|
+
return list(dict.fromkeys([self.index_name, *sorted(self._index_list, reverse=True)]))
|
|
259
264
|
|
|
260
265
|
@property
|
|
261
266
|
def index_list(self):
|
|
262
|
-
"""
|
|
267
|
+
"""Return the active physical write index for this collection.
|
|
263
268
|
|
|
264
|
-
|
|
269
|
+
Historical ILM rollover indexes are intentionally excluded. Bulk plans use this
|
|
270
|
+
list for default write, update, and delete targets, and widening it would fan those
|
|
271
|
+
operations out across historical indexes.
|
|
265
272
|
"""
|
|
266
273
|
return [self.index_name]
|
|
267
274
|
|
|
275
|
+
def _get_ilm_index_names(self) -> list[str]:
|
|
276
|
+
"""Return physical ILM rollover indexes, excluding temporary maintenance indexes."""
|
|
277
|
+
try:
|
|
278
|
+
indices = self.datastore.client.indices.get(
|
|
279
|
+
index=f"{self.name}-0*",
|
|
280
|
+
ignore_unavailable=True,
|
|
281
|
+
)
|
|
282
|
+
except elasticsearch.exceptions.NotFoundError:
|
|
283
|
+
return []
|
|
284
|
+
|
|
285
|
+
index_pattern = re.compile(rf"^{re.escape(self.name)}-\d{{6}}$")
|
|
286
|
+
return sorted(index for index in indices if index_pattern.fullmatch(index))
|
|
287
|
+
|
|
288
|
+
def _refresh_ilm_index_name(self):
|
|
289
|
+
"""Set ``index_name`` to the latest existing ILM index, when one exists."""
|
|
290
|
+
if not self.ilm_config:
|
|
291
|
+
return
|
|
292
|
+
|
|
293
|
+
ilm_indices = self._get_ilm_index_names()
|
|
294
|
+
|
|
295
|
+
if ilm_indices:
|
|
296
|
+
self._index_list = ilm_indices
|
|
297
|
+
self.index_name = ilm_indices[-1]
|
|
298
|
+
|
|
268
299
|
def scan_with_retry(
|
|
269
300
|
self,
|
|
270
301
|
query,
|
|
@@ -730,7 +761,7 @@ class ESCollection(Generic[ModelType]):
|
|
|
730
761
|
def reindex(self, allow_failures: bool = False, request_timeout: int = 60):
|
|
731
762
|
"""Reindex all the data of the collection into a freshly mapped index.
|
|
732
763
|
|
|
733
|
-
For every index in ``self.
|
|
764
|
+
For every physical index in ``self.index_list_full`` the data is copied into a temporary
|
|
734
765
|
``__reindex`` index that uses the current mappings/settings. Writes to the source
|
|
735
766
|
index are blocked while the copy runs so the reindex result and document counts can
|
|
736
767
|
be validated before the original index is deleted. The temporary index is only
|
|
@@ -750,7 +781,8 @@ class ESCollection(Generic[ModelType]):
|
|
|
750
781
|
operation can be recovered with :meth:`reindex_cleanup`.
|
|
751
782
|
"""
|
|
752
783
|
logger.warning("Beginning Reindex")
|
|
753
|
-
|
|
784
|
+
self._refresh_ilm_index_name()
|
|
785
|
+
for index in self.index_list_full:
|
|
754
786
|
new_name = f"{index}__reindex"
|
|
755
787
|
index_data = None
|
|
756
788
|
source_count = None
|
|
@@ -798,7 +830,7 @@ class ESCollection(Generic[ModelType]):
|
|
|
798
830
|
self.datastore.client.indices.create,
|
|
799
831
|
index=new_name,
|
|
800
832
|
mappings=self._get_index_mappings(),
|
|
801
|
-
settings=self.
|
|
833
|
+
settings=self._get_reindex_settings(index_data),
|
|
802
834
|
)
|
|
803
835
|
|
|
804
836
|
# Reindex data into target
|
|
@@ -847,12 +879,10 @@ class ESCollection(Generic[ModelType]):
|
|
|
847
879
|
)
|
|
848
880
|
|
|
849
881
|
alias_actions = []
|
|
850
|
-
aliases = index_data.get("aliases", {})
|
|
882
|
+
aliases = index_data.get("aliases", {})
|
|
851
883
|
for alias, alias_data in aliases.items():
|
|
852
884
|
alias_action = {"index": index, "alias": alias}
|
|
853
885
|
alias_action.update(alias_data)
|
|
854
|
-
if alias == self.name or alias_data.get("is_write_index", False):
|
|
855
|
-
alias_action["is_write_index"] = True
|
|
856
886
|
alias_actions.append({"add": alias_action})
|
|
857
887
|
alias_actions.append({"remove_index": {"index": new_name}})
|
|
858
888
|
self.with_retries(self.datastore.client.indices.update_aliases, actions=alias_actions)
|
|
@@ -880,6 +910,14 @@ class ESCollection(Generic[ModelType]):
|
|
|
880
910
|
|
|
881
911
|
return True
|
|
882
912
|
|
|
913
|
+
def _get_reindex_settings(self, index_data: dict) -> dict:
|
|
914
|
+
"""Build settings for a reindex target without dropping ILM lifecycle metadata."""
|
|
915
|
+
settings = self._get_index_settings()
|
|
916
|
+
lifecycle = index_data.get("settings", {}).get("index", {}).get("lifecycle")
|
|
917
|
+
if lifecycle:
|
|
918
|
+
settings["index"]["lifecycle"] = deepcopy(lifecycle)
|
|
919
|
+
return settings
|
|
920
|
+
|
|
883
921
|
def _validate_reindex_result(self, index, new_name, reindex_result, allow_failures):
|
|
884
922
|
"""Validate the result of an Elasticsearch reindex task.
|
|
885
923
|
|
|
@@ -956,17 +994,18 @@ class ESCollection(Generic[ModelType]):
|
|
|
956
994
|
def reindex_cleanup(self):
|
|
957
995
|
"""Recover from a failed or interrupted :meth:`reindex` run.
|
|
958
996
|
|
|
959
|
-
For every index that still has a leftover ``__reindex`` index, restore the source
|
|
960
|
-
index
|
|
961
|
-
|
|
962
|
-
|
|
997
|
+
For every physical index that still has a leftover ``__reindex`` index, restore the source
|
|
998
|
+
index's original aliases and delete the orphaned ``__reindex`` index. If the source
|
|
999
|
+
index is missing, raise an error instead of deleting ``__reindex`` because it may
|
|
1000
|
+
be the only remaining copy of the data.
|
|
963
1001
|
|
|
964
1002
|
Write blocks set during reindexing are cleared so the collection is usable again.
|
|
965
1003
|
|
|
966
1004
|
:return: ``True`` when cleanup completed on all indexes
|
|
967
1005
|
"""
|
|
968
1006
|
logger.warning("Beginning reindex cleanup")
|
|
969
|
-
|
|
1007
|
+
self._refresh_ilm_index_name()
|
|
1008
|
+
for index in self.index_list_full:
|
|
970
1009
|
new_name = f"{index}__reindex"
|
|
971
1010
|
|
|
972
1011
|
if not self.with_retries(self.datastore.client.indices.exists, index=new_name):
|
|
@@ -987,17 +1026,13 @@ class ESCollection(Generic[ModelType]):
|
|
|
987
1026
|
reindex_aliases = new_index_data.get("aliases", {})
|
|
988
1027
|
|
|
989
1028
|
alias_actions = []
|
|
990
|
-
for alias in sorted(set(source_aliases) | set(reindex_aliases)
|
|
1029
|
+
for alias in sorted(set(source_aliases) | set(reindex_aliases)):
|
|
991
1030
|
source_alias_data = source_aliases.get(alias, {})
|
|
992
1031
|
reindex_alias_data = reindex_aliases.get(alias, {})
|
|
993
1032
|
|
|
994
1033
|
add_alias_data = {"index": index, "alias": alias}
|
|
995
1034
|
add_alias_data.update(source_alias_data)
|
|
996
|
-
if (
|
|
997
|
-
alias == self.name
|
|
998
|
-
or source_alias_data.get("is_write_index", False)
|
|
999
|
-
or reindex_alias_data.get("is_write_index", False)
|
|
1000
|
-
):
|
|
1035
|
+
if source_alias_data.get("is_write_index", False) or reindex_alias_data.get("is_write_index", False):
|
|
1001
1036
|
add_alias_data["is_write_index"] = True
|
|
1002
1037
|
|
|
1003
1038
|
alias_actions.append({"add": add_alias_data})
|
|
@@ -2905,7 +2940,42 @@ class ESCollection(Generic[ModelType]):
|
|
|
2905
2940
|
if existing_ilm_indices:
|
|
2906
2941
|
# ILM already bootstrapped — ensure the alias exists
|
|
2907
2942
|
latest = sorted(existing_ilm_indices)[-1]
|
|
2908
|
-
|
|
2943
|
+
legacy_hot_index = f"{self.name}_hot"
|
|
2944
|
+
if self.with_retries(self.datastore.client.indices.exists_alias, name=self.name):
|
|
2945
|
+
alias_indices = self.with_retries(self.datastore.client.indices.get_alias, name=self.name)
|
|
2946
|
+
alias_actions = []
|
|
2947
|
+
for alias_index, alias_index_data in alias_indices.items():
|
|
2948
|
+
alias_data = alias_index_data.get("aliases", {}).get(self.name, {})
|
|
2949
|
+
if alias_index == legacy_hot_index:
|
|
2950
|
+
alias_actions.append({"remove": {"index": alias_index, "alias": self.name}})
|
|
2951
|
+
elif alias_index != latest and alias_data.get("is_write_index", False):
|
|
2952
|
+
alias_actions.append(
|
|
2953
|
+
{
|
|
2954
|
+
"add": {
|
|
2955
|
+
"index": alias_index,
|
|
2956
|
+
"alias": self.name,
|
|
2957
|
+
**alias_data,
|
|
2958
|
+
"is_write_index": False,
|
|
2959
|
+
}
|
|
2960
|
+
}
|
|
2961
|
+
)
|
|
2962
|
+
|
|
2963
|
+
latest_alias_data = alias_indices.get(latest, {}).get("aliases", {}).get(self.name, {})
|
|
2964
|
+
if not latest_alias_data.get("is_write_index", False):
|
|
2965
|
+
alias_actions.append(
|
|
2966
|
+
{
|
|
2967
|
+
"add": {
|
|
2968
|
+
"index": latest,
|
|
2969
|
+
"alias": self.name,
|
|
2970
|
+
**latest_alias_data,
|
|
2971
|
+
"is_write_index": True,
|
|
2972
|
+
}
|
|
2973
|
+
}
|
|
2974
|
+
)
|
|
2975
|
+
|
|
2976
|
+
if alias_actions:
|
|
2977
|
+
self.with_retries(self.datastore.client.indices.update_aliases, actions=alias_actions)
|
|
2978
|
+
else:
|
|
2909
2979
|
# Find the latest index to set as write index
|
|
2910
2980
|
self.with_retries(
|
|
2911
2981
|
self.datastore.client.indices.put_alias,
|
|
@@ -11,15 +11,18 @@ Here's example of a user model with settings and stats:
|
|
|
11
11
|
```python
|
|
12
12
|
from howler import odm
|
|
13
13
|
|
|
14
|
+
|
|
14
15
|
@odm.model(index=True, store=False, description="Settings of user")
|
|
15
16
|
class Settings(odm.Model):
|
|
16
|
-
default_view: str = odm.Enum(value=[
|
|
17
|
+
default_view: str = odm.Enum(value=["detail", "simple"], default="simple", description="Some random setting")
|
|
18
|
+
|
|
17
19
|
|
|
18
20
|
@odm.model(index=True, store=False, description="Settings of user")
|
|
19
21
|
class Stats(odm.Model):
|
|
20
|
-
last_login: str = odm.Date(default=
|
|
22
|
+
last_login: str = odm.Date(default="NOW", description="Last time user logged in")
|
|
21
23
|
login_count: str = odm.Integer(default=0, description="Number of time the user logged in")
|
|
22
24
|
|
|
25
|
+
|
|
23
26
|
@odm.model(index=True, store=True, description="User example")
|
|
24
27
|
class User(odm.Model):
|
|
25
28
|
username: str = odm.Keyword(description="Username of the user")
|
|
@@ -153,17 +153,17 @@ class CaseTask(odm.Model):
|
|
|
153
153
|
item: str = odm.Keyword(description="Associated case item id.", optional=True)
|
|
154
154
|
|
|
155
155
|
|
|
156
|
-
@odm.model(index=True, store=True, description="Enrichment annotations associated with a case
|
|
156
|
+
@odm.model(index=True, store=True, description="Enrichment annotations associated with a case item id.")
|
|
157
157
|
class CaseEnrichment(odm.Model):
|
|
158
|
-
|
|
158
|
+
item: str = odm.Keyword(description="Case item id associated with these annotations.")
|
|
159
159
|
annotations: list[str] = odm.List(
|
|
160
160
|
odm.Keyword(),
|
|
161
161
|
default=[],
|
|
162
|
-
description="Annotation IDs associated with the
|
|
162
|
+
description="Annotation IDs associated with the case item id.",
|
|
163
163
|
)
|
|
164
164
|
|
|
165
165
|
|
|
166
|
-
@odm.model(index=True, store=True, description="Case model with
|
|
166
|
+
@odm.model(index=True, store=True, description="Case model with items, enrichments, rules, and tasks.")
|
|
167
167
|
class Case(DatastoreMixin["Case"], odm.Model):
|
|
168
168
|
case_id: str = odm.UUID(description="A unique identifier for this case.")
|
|
169
169
|
classification: str = odm.Classification(
|
|
@@ -867,8 +867,12 @@ def wipe_actions(ds: HowlerDatastore):
|
|
|
867
867
|
def create_dossiers(ds: HowlerDatastore, num_dossiers: int = 5):
|
|
868
868
|
"Create random dossiers"
|
|
869
869
|
users = ds.user.search("*:*")["items"]
|
|
870
|
-
for
|
|
870
|
+
for index in range(num_dossiers):
|
|
871
871
|
dossier = generate_useful_dossier(users)
|
|
872
|
+
if index == 0:
|
|
873
|
+
dossier.type = "personal"
|
|
874
|
+
elif index == 1:
|
|
875
|
+
dossier.type = "global"
|
|
872
876
|
ds.dossier.save(dossier.dossier_id, dossier)
|
|
873
877
|
|
|
874
878
|
ds.dossier.commit()
|
|
@@ -25,9 +25,10 @@ Example:
|
|
|
25
25
|
|
|
26
26
|
```python
|
|
27
27
|
from howler.remote.datatypes.counters import Counters
|
|
28
|
-
|
|
28
|
+
|
|
29
|
+
with Counters("test-counter") as ct:
|
|
29
30
|
# Increment counter by 4
|
|
30
|
-
ct.inc(
|
|
31
|
+
ct.inc("value_1", 4)
|
|
31
32
|
|
|
32
33
|
# Get Counter values
|
|
33
34
|
ct.get_queues_sizes()
|
|
@@ -60,19 +61,20 @@ Example, A container register a watcher for a specific event:
|
|
|
60
61
|
import time
|
|
61
62
|
from howler.remote.datatypes.events import EventWatcher
|
|
62
63
|
|
|
64
|
+
|
|
63
65
|
def callback_func(data: dict[str, Any]):
|
|
64
66
|
print(data)
|
|
65
67
|
|
|
68
|
+
|
|
66
69
|
watcher = EventWatcher()
|
|
67
70
|
try:
|
|
68
71
|
# register for the test event in the event group
|
|
69
|
-
watcher.register(
|
|
72
|
+
watcher.register("event.test", callback_func)
|
|
70
73
|
watcher.start()
|
|
71
74
|
while True:
|
|
72
75
|
time.sleep(1)
|
|
73
76
|
finally:
|
|
74
77
|
watcher.stop()
|
|
75
|
-
|
|
76
78
|
```
|
|
77
79
|
|
|
78
80
|
Another container creates an event to wake up the first container:
|
|
@@ -82,10 +84,10 @@ import time
|
|
|
82
84
|
from howler.remote.datatypes.events import EventSender
|
|
83
85
|
|
|
84
86
|
# create a sender for the event group
|
|
85
|
-
sender = EventSender(
|
|
87
|
+
sender = EventSender("event.", redis_connection)
|
|
86
88
|
|
|
87
89
|
# send a test even
|
|
88
|
-
sender.send(
|
|
90
|
+
sender.send("test", {"payload": 100})
|
|
89
91
|
# After this call, the first container will have woken up and executed its callback function
|
|
90
92
|
# that would print: {'payload': 100}
|
|
91
93
|
```
|
|
@@ -114,7 +116,8 @@ Example:
|
|
|
114
116
|
|
|
115
117
|
```python
|
|
116
118
|
from howler.remote.datatypes.hash import Hash
|
|
117
|
-
|
|
119
|
+
|
|
120
|
+
with Hash("test-hashmap") as h:
|
|
118
121
|
h.add("key", "value")
|
|
119
122
|
print(h.exists("key"))
|
|
120
123
|
print(h.get("key"))
|
|
@@ -172,10 +175,11 @@ Example:
|
|
|
172
175
|
|
|
173
176
|
```python
|
|
174
177
|
from howler.remote.datatypes.set import Set
|
|
175
|
-
|
|
176
|
-
|
|
178
|
+
|
|
179
|
+
with Set("test-set") as s:
|
|
180
|
+
values = ["a", "b", 1, 2]
|
|
177
181
|
s.add(*values)
|
|
178
|
-
print(s.exist(
|
|
182
|
+
print(s.exist("b"))
|
|
179
183
|
print(s.pop())
|
|
180
184
|
print(s.length())
|
|
181
185
|
```
|
|
@@ -184,7 +188,7 @@ Output:
|
|
|
184
188
|
|
|
185
189
|
```python
|
|
186
190
|
True
|
|
187
|
-
|
|
191
|
+
"a" or "b" or 1 or 2
|
|
188
192
|
3
|
|
189
193
|
```
|
|
190
194
|
|
|
@@ -234,7 +238,7 @@ Example of message receiver:
|
|
|
234
238
|
```python
|
|
235
239
|
from howler.remote.datatypes.queues.comms import CommsQueue
|
|
236
240
|
|
|
237
|
-
with CommsQueue(
|
|
241
|
+
with CommsQueue("test-comms-queue") as cq:
|
|
238
242
|
for msg in cq.listen(blocking=True):
|
|
239
243
|
if msg == "stop":
|
|
240
244
|
break
|
|
@@ -247,7 +251,7 @@ Example of message sender:
|
|
|
247
251
|
```python
|
|
248
252
|
from howler.remote.datatypes.queues.comms import CommsQueue
|
|
249
253
|
|
|
250
|
-
with CommsQueue(
|
|
254
|
+
with CommsQueue("test-comms-queue") as cq:
|
|
251
255
|
# send a message to the receiver
|
|
252
256
|
cq.publish("This is my message!")
|
|
253
257
|
|
|
@@ -273,7 +277,8 @@ Example:
|
|
|
273
277
|
|
|
274
278
|
```python
|
|
275
279
|
from howler.remote.datatypes.queues.named import NamedQueue, select
|
|
276
|
-
|
|
280
|
+
|
|
281
|
+
with NamedQueue("test-named-queue") as nq:
|
|
277
282
|
for x in range(5):
|
|
278
283
|
nq.push(x)
|
|
279
284
|
|
|
@@ -307,12 +312,13 @@ Example:
|
|
|
307
312
|
|
|
308
313
|
```python
|
|
309
314
|
from howler.remote.datatypes.queues.priority import PriorityQueue, length, select
|
|
310
|
-
|
|
315
|
+
|
|
316
|
+
with PriorityQueue("test-priority-queue") as pq:
|
|
311
317
|
for x in range(10):
|
|
312
318
|
pq.push(100, x)
|
|
313
319
|
|
|
314
|
-
a_key = pq.push(101,
|
|
315
|
-
z_key = pq.push(99,
|
|
320
|
+
a_key = pq.push(101, "a")
|
|
321
|
+
z_key = pq.push(99, "z")
|
|
316
322
|
print(pq.rank(a_key))
|
|
317
323
|
print(pq.rank(z_key))
|
|
318
324
|
print(pq.pop())
|
|
@@ -323,7 +329,7 @@ Output:
|
|
|
323
329
|
```python
|
|
324
330
|
0
|
|
325
331
|
11
|
|
326
|
-
|
|
332
|
+
"a"
|
|
327
333
|
```
|
|
328
334
|
|
|
329
335
|
#### Unique Priority queues
|
|
@@ -334,7 +340,8 @@ Example:
|
|
|
334
340
|
|
|
335
341
|
```python
|
|
336
342
|
from howler.remote.datatypes.queues.priority import PriorityQueue, length, select
|
|
337
|
-
|
|
343
|
+
|
|
344
|
+
with PriorityQueue("test-priority-queue") as pq:
|
|
338
345
|
for x in range(10):
|
|
339
346
|
pq.push(100, x)
|
|
340
347
|
|
|
@@ -152,7 +152,7 @@ suppress-none-returning = true
|
|
|
152
152
|
[tool.poetry]
|
|
153
153
|
package-mode = true
|
|
154
154
|
name = "howler-api"
|
|
155
|
-
version = "4.0.0.
|
|
155
|
+
version = "4.0.0.dev1337"
|
|
156
156
|
description = "Howler - API server"
|
|
157
157
|
authors = [
|
|
158
158
|
"Canadian Centre for Cyber Security <howler@cyber.gc.ca>",
|
|
@@ -206,7 +206,7 @@ gevent = "^25.9.1"
|
|
|
206
206
|
flask-caching = "2.4.1"
|
|
207
207
|
packaging = "<25.0"
|
|
208
208
|
passlib = "1.7.4"
|
|
209
|
-
prometheus-client = "0.
|
|
209
|
+
prometheus-client = "0.26.0"
|
|
210
210
|
pyjwt = "2.13.0"
|
|
211
211
|
python-baseconv = "1.2.2"
|
|
212
212
|
python-datemath = "3.0.3"
|
|
@@ -235,7 +235,7 @@ azure-monitor-opentelemetry = "^1.8.7"
|
|
|
235
235
|
|
|
236
236
|
[tool.poetry.group.dev.dependencies]
|
|
237
237
|
pre-commit = "^3.7.0"
|
|
238
|
-
ruff = ">=0.8,<0.
|
|
238
|
+
ruff = ">=0.8,<0.17"
|
|
239
239
|
pyright = { extras = ["nodejs"], version = "^1.1.408" }
|
|
240
240
|
mypy = "^1.6.1"
|
|
241
241
|
|
|
@@ -252,10 +252,10 @@ coverage = { extras = ["toml"], version = "^7.4.4" }
|
|
|
252
252
|
|
|
253
253
|
[tool.poetry.group.types.dependencies]
|
|
254
254
|
typing-extensions = "^4.12.2"
|
|
255
|
-
types-PyYAML = "6.0.12.
|
|
255
|
+
types-PyYAML = "6.0.12.20260724"
|
|
256
256
|
types-paramiko = "3.5.0.20250801"
|
|
257
257
|
types-pyOpenSSL = "23.3.0.20240106"
|
|
258
|
-
types-six = "1.17.0.
|
|
258
|
+
types-six = "1.17.0.20260724"
|
|
259
259
|
types-requests = "<2.33.0.20260713"
|
|
260
260
|
websocket-client = "1.9.0"
|
|
261
261
|
types-pytz = "^2024.1.0.20240417"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{howler_api-4.0.0.dev1308 → howler_api-4.0.0.dev1337}/howler/cronjobs/action_queue_worker.py
RENAMED
|
File without changes
|
|
File without changes
|