robusta-cli 0.11.0__tar.gz → 0.12.0__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.
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/PKG-INFO +4 -1
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/pyproject.toml +6 -2
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/_version.py +1 -1
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/model/env_vars.py +5 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/model/runner_config.py +2 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/playbooks/pod_utils/imagepull_utils.py +1 -1
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/reporting/base.py +11 -2
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/reporting/blocks.py +2 -2
- robusta_cli-0.12.0/src/robusta/core/sinks/common/__init__.py +1 -0
- robusta_cli-0.12.0/src/robusta/core/sinks/common/channel_transformer.py +106 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/datadog/datadog_sink_params.py +4 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/discord/discord_sink_params.py +4 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/file/file_sink_params.py +4 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/google_chat/google_chat_params.py +4 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/jira/jira_sink_params.py +4 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/kafka/kafka_sink_params.py +4 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/mail/mail_sink_params.py +4 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/mattermost/mattermost_sink_params.py +4 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/msteams/msteams_sink_params.py +4 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/opsgenie/opsgenie_sink_params.py +4 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/pagerduty/pagerduty_sink_params.py +4 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/pushover/pushover_sink_params.py +5 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/robusta/robusta_sink_params.py +4 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/rocketchat/rocketchat_sink_params.py +4 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/servicenow/servicenow_sink_params.py +4 -0
- robusta_cli-0.12.0/src/robusta/core/sinks/sink_base.py +185 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/sink_base_params.py +62 -1
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/sink_factory.py +3 -1
- robusta_cli-0.12.0/src/robusta/core/sinks/slack/slack_sink.py +80 -0
- robusta_cli-0.12.0/src/robusta/core/sinks/slack/slack_sink_params.py +32 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/telegram/telegram_sink_params.py +4 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/victorops/victorops_sink_params.py +4 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/webex/webex_sink_params.py +4 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/webhook/webhook_sink_params.py +4 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/yamessenger/yamessenger_sink_params.py +4 -0
- robusta_cli-0.12.0/src/robusta/core/sinks/zulip/__init__.py +2 -0
- robusta_cli-0.12.0/src/robusta/core/sinks/zulip/zulip_sink.py +32 -0
- robusta_cli-0.12.0/src/robusta/core/sinks/zulip/zulip_sink_params.py +28 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/triggers/container_oom_killed_trigger.py +4 -1
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/triggers/error_event_trigger.py +9 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/triggers/job_failed_trigger.py +4 -1
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/triggers/multi_resources_trigger.py +2 -5
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/triggers/oom_killed_trigger_base.py +3 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/triggers/pod_crash_loop_trigger.py +4 -1
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/triggers/pod_image_pull_backoff.py +4 -1
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/triggers/pod_oom_killed_trigger.py +4 -1
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/kubernetes/api_client_utils.py +23 -1
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/kubernetes/autogenerated/triggers.py +32 -9
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/kubernetes/base_triggers.py +4 -8
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/kubernetes/custom_models.py +75 -30
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/slack/sender.py +153 -12
- robusta_cli-0.12.0/src/robusta/integrations/zulip/__init__.py +1 -0
- robusta_cli-0.12.0/src/robusta/integrations/zulip/sender.py +171 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/runner/web.py +30 -2
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/utils/scope.py +11 -8
- robusta_cli-0.11.0/src/robusta/core/sinks/sink_base.py +0 -63
- robusta_cli-0.11.0/src/robusta/core/sinks/slack/slack_sink.py +0 -15
- robusta_cli-0.11.0/src/robusta/core/sinks/slack/slack_sink_params.py +0 -116
- robusta_cli-0.11.0/src/robusta/utils/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/LICENSE +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/api/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/cli/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/cli/auth.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/cli/backend_profile.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/cli/eula.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/cli/integrations_cmd.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/cli/main.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/cli/playbooks_cmd.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/cli/self_host.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/cli/slack_feedback_message.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/cli/slack_verification.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/cli/utils.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/discovery/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/discovery/discovery.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/discovery/resource_names.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/discovery/top_service_resolver.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/discovery/utils.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/exceptions.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/model/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/model/base_params.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/model/cluster_status.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/model/events.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/model/helm_release.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/model/jobs.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/model/k8s_operation_type.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/model/namespaces.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/model/nodes.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/model/pods.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/model/services.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/persistency/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/persistency/in_memory.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/persistency/scheduled_jobs_states_dal.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/playbooks/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/playbooks/actions_registry.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/playbooks/base_trigger.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/playbooks/common.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/playbooks/container_playbook_utils.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/playbooks/crash_reporter.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/playbooks/generation.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/playbooks/internal/discovery_events.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/playbooks/job_utils.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/playbooks/node_playbook_utils.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/playbooks/oom_killer_utils.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/playbooks/playbook_utils.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/playbooks/playbooks_event_handler.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/playbooks/playbooks_event_handler_impl.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/playbooks/pod_utils/crashloop_utils.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/playbooks/pod_utils/pending_pod_utils.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/playbooks/prometheus_enrichment_utils.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/playbooks/trigger.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/pubsub/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/pubsub/event_emitter.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/pubsub/event_subscriber.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/pubsub/events_pubsub.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/reporting/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/reporting/action_requests.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/reporting/callbacks.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/reporting/consts.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/reporting/custom_rendering.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/reporting/finding_subjects.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/reporting/utils.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/schedule/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/schedule/model.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/schedule/scheduler.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/common/html_tools.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/datadog/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/datadog/datadog_sink.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/discord/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/discord/discord_sink.py +0 -0
- {robusta_cli-0.11.0/src/robusta/core/sinks/common → robusta_cli-0.12.0/src/robusta/core/sinks/file}/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/file/file_sink.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/file/object_traverser.py +0 -0
- {robusta_cli-0.11.0/src/robusta/core/sinks/file → robusta_cli-0.12.0/src/robusta/core/sinks/google_chat}/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/google_chat/google_chat.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/jira/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/jira/jira_sink.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/kafka/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/kafka/kafka_sink.py +0 -0
- {robusta_cli-0.11.0/src/robusta/core/sinks/google_chat → robusta_cli-0.12.0/src/robusta/core/sinks/mail}/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/mail/mail_sink.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/mattermost/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/mattermost/mattermost_sink.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/msteams/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/msteams/msteams_sink.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/opsgenie/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/opsgenie/opsgenie_sink.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/pagerduty/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/pagerduty/pagerduty_sink.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/pushover/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/pushover/pushover_client.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/pushover/pushover_sink.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/robusta/__init__.py +0 -0
- {robusta_cli-0.11.0/src/robusta/core/sinks/mail → robusta_cli-0.12.0/src/robusta/core/sinks/robusta/dal}/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/robusta/dal/model_conversion.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/robusta/dal/supabase_dal.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/robusta/discovery_metrics.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/robusta/prometheus_health_checker.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/robusta/robusta_sink.py +0 -0
- {robusta_cli-0.11.0/src/robusta/core/sinks/robusta/dal → robusta_cli-0.12.0/src/robusta/core/sinks/robusta/rrm}/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/robusta/rrm/account_resource_fetcher.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/robusta/rrm/base_resource_manager.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/robusta/rrm/prometheus_alert_resource_manager.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/robusta/rrm/rrm.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/robusta/rrm/types.py +0 -0
- {robusta_cli-0.11.0/src/robusta/core/sinks/robusta/rrm → robusta_cli-0.12.0/src/robusta/core/sinks/rocketchat}/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/rocketchat/rocketchat_sink.py +0 -0
- {robusta_cli-0.11.0/src/robusta/core/sinks/rocketchat → robusta_cli-0.12.0/src/robusta/core/sinks/servicenow}/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/servicenow/servicenow_sink.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/sink_config.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/slack/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/telegram/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/telegram/telegram_client.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/telegram/telegram_sink.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/timing.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/transformer.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/victorops/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/victorops/victorops_sink.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/webex/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/webex/webex_sink.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/webhook/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/webhook/webhook_sink.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/yamessenger/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/yamessenger/yamessenger_client.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/yamessenger/yamessenger_sink.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/triggers/custom_triggers.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/triggers/helm_releases_triggers.py +0 -0
- {robusta_cli-0.11.0/src/robusta/core/sinks/servicenow → robusta_cli-0.12.0/src/robusta/integrations}/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/argocd/argocd_client.py +0 -0
- {robusta_cli-0.11.0/src/robusta/integrations → robusta_cli-0.12.0/src/robusta/integrations/common}/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/common/requests.py +0 -0
- {robusta_cli-0.11.0/src/robusta/integrations/common → robusta_cli-0.12.0/src/robusta/integrations/discord}/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/discord/sender.py +0 -0
- {robusta_cli-0.11.0/src/robusta/integrations/discord → robusta_cli-0.12.0/src/robusta/integrations/git}/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/git/git_repo.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/git/well_known_hosts.py +0 -0
- {robusta_cli-0.11.0/src/robusta/integrations/git → robusta_cli-0.12.0/src/robusta/integrations/google_chat}/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/google_chat/sender.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/grafana.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/helper.py +0 -0
- {robusta_cli-0.11.0/src/robusta/integrations/google_chat → robusta_cli-0.12.0/src/robusta/integrations/jira}/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/jira/client.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/jira/sender.py +0 -0
- {robusta_cli-0.11.0/src/robusta/integrations/jira → robusta_cli-0.12.0/src/robusta/integrations/kubernetes}/__init__.py +0 -0
- {robusta_cli-0.11.0/src/robusta/integrations/kubernetes → robusta_cli-0.12.0/src/robusta/integrations/kubernetes/autogenerated}/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/kubernetes/autogenerated/events.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/kubernetes/autogenerated/models.py +0 -0
- {robusta_cli-0.11.0/src/robusta/integrations/kubernetes/autogenerated → robusta_cli-0.12.0/src/robusta/integrations/kubernetes/autogenerated/v1}/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/kubernetes/autogenerated/v1/models.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/kubernetes/base_event.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/kubernetes/model_not_found_exception.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/kubernetes/process_utils.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/kubernetes/templates.py +0 -0
- {robusta_cli-0.11.0/src/robusta/integrations/kubernetes/autogenerated/v1 → robusta_cli-0.12.0/src/robusta/integrations/mail}/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/mail/sender.py +0 -0
- {robusta_cli-0.11.0/src/robusta/integrations/mail → robusta_cli-0.12.0/src/robusta/integrations/mattermost}/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/mattermost/client.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/mattermost/sender.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/msteams/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/msteams/msteams_adaptive_card_files.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/msteams/msteams_adaptive_card_files_image.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/msteams/msteams_adaptive_card_files_text.py +0 -0
- {robusta_cli-0.11.0/src/robusta/integrations/mattermost → robusta_cli-0.12.0/src/robusta/integrations/msteams/msteams_elements}/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/msteams/msteams_elements/msteams_action.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/msteams/msteams_elements/msteams_base.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/msteams/msteams_elements/msteams_card.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/msteams/msteams_elements/msteams_column.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/msteams/msteams_elements/msteams_container.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/msteams/msteams_elements/msteams_images.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/msteams/msteams_elements/msteams_table.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/msteams/msteams_elements/msteams_text_block.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/msteams/msteams_mark_down_fix_url.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/msteams/msteams_msg.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/msteams/sender.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/openshift/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/openshift/token.py +0 -0
- {robusta_cli-0.11.0/src/robusta/integrations/msteams/msteams_elements → robusta_cli-0.12.0/src/robusta/integrations/prometheus}/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/prometheus/models.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/prometheus/trigger.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/prometheus/utils.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/receiver.py +0 -0
- {robusta_cli-0.11.0/src/robusta/integrations/prometheus → robusta_cli-0.12.0/src/robusta/integrations/resource_analysis}/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/resource_analysis/cpu_analyzer.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/resource_analysis/memory_analyzer.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/resource_analysis/node_cpu_analyzer.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/resource_analysis/prometheus_analyzer.py +0 -0
- {robusta_cli-0.11.0/src/robusta/integrations/resource_analysis → robusta_cli-0.12.0/src/robusta/integrations/rocketchat}/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/rocketchat/sender.py +0 -0
- {robusta_cli-0.11.0/src/robusta/integrations/rocketchat → robusta_cli-0.12.0/src/robusta/integrations/scheduled}/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/scheduled/event.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/scheduled/models.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/scheduled/playbook_scheduler.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/scheduled/playbook_scheduler_manager.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/scheduled/playbook_scheduler_manager_impl.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/scheduled/trigger.py +0 -0
- {robusta_cli-0.11.0/src/robusta/integrations/scheduled → robusta_cli-0.12.0/src/robusta/integrations/servicenow}/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/servicenow/sender.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/slack/__init__.py +0 -0
- {robusta_cli-0.11.0/src/robusta/integrations/servicenow → robusta_cli-0.12.0/src/robusta/integrations/webex}/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/integrations/webex/sender.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/model/alert_relabel_config.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/model/config.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/model/playbook_action.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/model/playbook_definition.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/patch/patch.py +0 -0
- {robusta_cli-0.11.0/src/robusta/integrations/webex → robusta_cli-0.12.0/src/robusta/runner}/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/runner/config_loader.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/runner/log_init.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/runner/main.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/runner/not_found_exception.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/runner/object_updater.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/runner/process_setup.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/runner/ssl_utils.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/runner/telemetry.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/runner/telemetry_service.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/runner/web_api.py +0 -0
- {robusta_cli-0.11.0/src/robusta/runner → robusta_cli-0.12.0/src/robusta/utils}/__init__.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/utils/auth_provider.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/utils/base64_utils.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/utils/cluster_provider_discovery.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/utils/common.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/utils/decorators.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/utils/docs.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/utils/documented_pydantic.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/utils/error_codes.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/utils/file_system_watcher.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/utils/function_hashes.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/utils/json_schema.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/utils/parsing.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/utils/rate_limiter.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/utils/server_start.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/utils/service_discovery.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/utils/silence_utils.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/utils/stack_tracer.py +0 -0
- {robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/utils/task_queue.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: robusta-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.0
|
|
4
4
|
Summary:
|
|
5
5
|
Author: Natan Yellin
|
|
6
6
|
Author-email: aantn@users.noreply.github.com
|
|
@@ -17,6 +17,8 @@ Requires-Dist: apprise (>=1.5.0,<2.0.0)
|
|
|
17
17
|
Requires-Dist: attrs (>=23.1.0,<24.0.0)
|
|
18
18
|
Requires-Dist: better-exceptions (>=0.3.3,<0.4.0) ; extra == "all"
|
|
19
19
|
Requires-Dist: bitmath (>=1.3.3.1,<2.0.0.0)
|
|
20
|
+
Requires-Dist: boto3 (==1.28.72)
|
|
21
|
+
Requires-Dist: botocore (==1.31.72)
|
|
20
22
|
Requires-Dist: click-spinner (>=0.1.10,<0.2.0)
|
|
21
23
|
Requires-Dist: colorlog (>=5.0.1,<6.0.0)
|
|
22
24
|
Requires-Dist: croniter (>=1.3.15,<2.0.0)
|
|
@@ -28,6 +30,7 @@ Requires-Dist: dulwich (==0.20.28) ; extra == "all"
|
|
|
28
30
|
Requires-Dist: fpdf2 (>=2.7.1,<3.0.0)
|
|
29
31
|
Requires-Dist: grafana-api (>=1.0.3,<2.0.0) ; extra == "all"
|
|
30
32
|
Requires-Dist: hikaru-model-26 (>=1.1.1,<2.0.0)
|
|
33
|
+
Requires-Dist: humanize (>=3.13.1,<4.0.0)
|
|
31
34
|
Requires-Dist: jinja2 (==3.1.3)
|
|
32
35
|
Requires-Dist: kafka-python (>=2.0.2,<3.0.0) ; extra == "all"
|
|
33
36
|
Requires-Dist: kubernetes (>=26.1.0,<27.0.0)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "robusta-cli"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.12.0"
|
|
4
4
|
description = ""
|
|
5
5
|
authors = ["Natan Yellin <aantn@users.noreply.github.com>"]
|
|
6
6
|
packages = [
|
|
@@ -58,6 +58,11 @@ watchgod = "^0.7"
|
|
|
58
58
|
webexteamssdk = "^1.6.1"
|
|
59
59
|
bitmath = "^1.3.3.1"
|
|
60
60
|
croniter = "^1.3.15"
|
|
61
|
+
humanize = "^3.13.1"
|
|
62
|
+
|
|
63
|
+
# The following are added to speed up poetry dependency resolution
|
|
64
|
+
botocore = "1.31.72"
|
|
65
|
+
boto3 = "1.28.72"
|
|
61
66
|
|
|
62
67
|
# we're freezing a specific version here because the latest version doesn't have prebuilt wheels on pypi
|
|
63
68
|
# and therefore requires gcc to install which we'd like to avoid
|
|
@@ -88,7 +93,6 @@ sphinxcontrib-images = "^0.9.4"
|
|
|
88
93
|
jsonref = "^0.2"
|
|
89
94
|
Pillow = "^10.3.0"
|
|
90
95
|
sphinxcontrib-mermaid = "^0.7.1"
|
|
91
|
-
humanize = "^3.13.1"
|
|
92
96
|
cssselect = "^1.1.0"
|
|
93
97
|
pygal = "^3.0.0"
|
|
94
98
|
tinycss = "^0.4"
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
# this is updated by .github/workflows/release.yaml
|
|
2
|
-
__version__ = "0.
|
|
2
|
+
__version__ = "0.12.0"
|
|
@@ -113,3 +113,8 @@ RUN_AS_SUBPROCESS = load_bool("RUN_AS_SUBPROCESS", True)
|
|
|
113
113
|
ARGO_ROLLOUTS = load_bool("ARGO_ROLLOUTS", False)
|
|
114
114
|
# lowered case k8s kinds in a json array string. "[\"configmap\", \"secret\"]"
|
|
115
115
|
RESOURCE_YAML_BLOCK_LIST = json.loads(os.environ.get("RESOURCE_YAML_BLOCK_LIST", "[]"))
|
|
116
|
+
|
|
117
|
+
NAMESPACE_DATA_TTL = int(os.environ.get("NAMESPACE_DATA_TTL", 30*60)) # in seconds
|
|
118
|
+
|
|
119
|
+
PROCESSED_ALERTS_CACHE_TTL = int(os.environ.get("PROCESSED_ALERT_CACHE_TTL", 2*3600))
|
|
120
|
+
PROCESSED_ALERTS_CACHE_MAX_SIZE = int(os.environ.get("PROCESSED_ALERTS_CACHE_MAX_SIZE", 100_000))
|
|
@@ -25,6 +25,7 @@ from robusta.core.sinks.webex.webex_sink_params import WebexSinkConfigWrapper
|
|
|
25
25
|
from robusta.core.sinks.webhook.webhook_sink_params import WebhookSinkConfigWrapper
|
|
26
26
|
from robusta.core.sinks.yamessenger.yamessenger_sink_params import YaMessengerSinkConfigWrapper
|
|
27
27
|
from robusta.core.sinks.pushover.pushover_sink_params import PushoverSinkConfigWrapper
|
|
28
|
+
from robusta.core.sinks.zulip.zulip_sink_params import ZulipSinkConfigWrapper
|
|
28
29
|
from robusta.model.alert_relabel_config import AlertRelabel
|
|
29
30
|
from robusta.model.playbook_definition import PlaybookDefinition
|
|
30
31
|
from robusta.utils.base64_utils import is_base64_encoded
|
|
@@ -63,6 +64,7 @@ class RunnerConfig(BaseModel):
|
|
|
63
64
|
PushoverSinkConfigWrapper,
|
|
64
65
|
GoogleChatSinkConfigWrapper,
|
|
65
66
|
ServiceNowSinkConfigWrapper,
|
|
67
|
+
ZulipSinkConfigWrapper
|
|
66
68
|
]
|
|
67
69
|
]
|
|
68
70
|
]
|
{robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/playbooks/pod_utils/imagepull_utils.py
RENAMED
|
@@ -101,7 +101,7 @@ def get_image_pull_backoff_enrichment(pod: Pod) -> Enrichment:
|
|
|
101
101
|
return Enrichment(
|
|
102
102
|
enrichment_type=EnrichmentType.image_pull_backoff_info,
|
|
103
103
|
blocks=image_pull_table_blocks,
|
|
104
|
-
title="Container
|
|
104
|
+
title="Container ImagePullBackoff Information")
|
|
105
105
|
|
|
106
106
|
|
|
107
107
|
def __imagepull_backoff_reason_to_fix(reason: ImagePullBackoffReason) -> Optional[Tuple[str, str]]:
|
|
@@ -14,6 +14,7 @@ from pydantic.main import BaseModel
|
|
|
14
14
|
from robusta.core.discovery.top_service_resolver import TopServiceResolver
|
|
15
15
|
from robusta.core.model.env_vars import ROBUSTA_UI_DOMAIN
|
|
16
16
|
from robusta.core.reporting.consts import FindingSource, FindingSubjectType, FindingType
|
|
17
|
+
from robusta.integrations.kubernetes.api_client_utils import get_namespace_labels
|
|
17
18
|
from robusta.utils.scope import BaseScopeMatcher
|
|
18
19
|
|
|
19
20
|
|
|
@@ -106,7 +107,7 @@ class EnrichmentType(Enum):
|
|
|
106
107
|
|
|
107
108
|
|
|
108
109
|
class Enrichment:
|
|
109
|
-
#
|
|
110
|
+
# This is the actual enrichment data
|
|
110
111
|
blocks: List[BaseBlock] = []
|
|
111
112
|
# General purpose rendering flags, that can be used by specific sinks
|
|
112
113
|
annotations: Dict[str, str] = {}
|
|
@@ -138,6 +139,9 @@ class FilterableScopeMatcher(BaseScopeMatcher):
|
|
|
138
139
|
def get_data(self) -> Dict:
|
|
139
140
|
return self.data
|
|
140
141
|
|
|
142
|
+
def scope_match_namespace_labels(self, attr_matcher, attr_value):
|
|
143
|
+
return self.match_labels_annotations(attr_matcher, attr_value)
|
|
144
|
+
|
|
141
145
|
|
|
142
146
|
class Filterable(ABC):
|
|
143
147
|
@property
|
|
@@ -169,7 +173,12 @@ class Filterable(ABC):
|
|
|
169
173
|
# 1. "scope" check
|
|
170
174
|
accept = True
|
|
171
175
|
if scope_requirements is not None:
|
|
172
|
-
|
|
176
|
+
data = self.attribute_map
|
|
177
|
+
try:
|
|
178
|
+
data["namespace_labels"] = get_namespace_labels(data["namespace"])
|
|
179
|
+
except KeyError:
|
|
180
|
+
data["namespace_labels"] = {}
|
|
181
|
+
matcher = FilterableScopeMatcher(data)
|
|
173
182
|
if scope_requirements.exclude:
|
|
174
183
|
if matcher.scope_inc_exc_matches(scope_requirements.exclude):
|
|
175
184
|
return False
|
|
@@ -427,13 +427,13 @@ class TableBlock(BaseBlock):
|
|
|
427
427
|
|
|
428
428
|
return MarkdownBlock(f"{prefix}{table_contents}{suffix}")
|
|
429
429
|
|
|
430
|
-
def to_table_string(self, table_max_width: int = PRINTED_TABLE_MAX_WIDTH) -> str:
|
|
430
|
+
def to_table_string(self, table_max_width: int = PRINTED_TABLE_MAX_WIDTH, table_fmt: str = "presto") -> str:
|
|
431
431
|
rendered_rows = self.__to_strings_rows(self.render_rows())
|
|
432
432
|
col_max_width = self.__calc_max_width(self.headers, rendered_rows, table_max_width)
|
|
433
433
|
return tabulate(
|
|
434
434
|
rendered_rows,
|
|
435
435
|
headers=self.headers,
|
|
436
|
-
tablefmt=
|
|
436
|
+
tablefmt=table_fmt,
|
|
437
437
|
maxcolwidths=col_max_width,
|
|
438
438
|
)
|
|
439
439
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from robusta.core.sinks.common.channel_transformer import ChannelTransformer
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
from collections import defaultdict
|
|
2
|
+
from string import Template
|
|
3
|
+
from typing import Dict, Optional, Union
|
|
4
|
+
|
|
5
|
+
import regex
|
|
6
|
+
|
|
7
|
+
CLUSTER_PREF = "cluster_name"
|
|
8
|
+
CLUSTER_PREF_PATTERN = regex.compile("(\$?\{?" + CLUSTER_PREF + "\}?)") # noqa: W605
|
|
9
|
+
LABELS_PREF = "labels."
|
|
10
|
+
ESCAPED_LABEL_PREF = regex.escape(LABELS_PREF)
|
|
11
|
+
LABEL_PREF_PATTERN = regex.compile("\$?" + ESCAPED_LABEL_PREF + "[\w.]+") # noqa: W605
|
|
12
|
+
ANNOTATIONS_PREF = "annotations."
|
|
13
|
+
ESCAPED_ANNOTATIONS_PREF = regex.escape(ANNOTATIONS_PREF)
|
|
14
|
+
ANNOTATIONS_PREF_PATTERN = regex.compile("\$?" + ESCAPED_ANNOTATIONS_PREF + "[\w.]+") # noqa: W605
|
|
15
|
+
BRACKETS_PATTERN = regex.compile(r"\$\{[^\}]+\}")
|
|
16
|
+
COMPOSITE_PATTERN = r".*\$({?labels.[^$]+|{?annotations.[^$]+|{?cluster_name).*"
|
|
17
|
+
ONLY_VALUE_PATTERN = r"^(labels.[^$]+|annotations.[^$]+|cluster_name)$"
|
|
18
|
+
MISSING = "<missing>"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ChannelTransformer:
|
|
22
|
+
@classmethod
|
|
23
|
+
def validate_channel_override(cls, v: Union[str, None]):
|
|
24
|
+
if v:
|
|
25
|
+
if regex.match(ONLY_VALUE_PATTERN, v):
|
|
26
|
+
return "$" + v
|
|
27
|
+
if not regex.match(COMPOSITE_PATTERN, v):
|
|
28
|
+
err_msg = (
|
|
29
|
+
f"channel_override must be '{CLUSTER_PREF}' or '{LABELS_PREF}foo' or '{ANNOTATIONS_PREF}foo' "
|
|
30
|
+
f"or contain patters like: '${CLUSTER_PREF}'/'${LABELS_PREF}foo'/"
|
|
31
|
+
f"'${ANNOTATIONS_PREF}foo'"
|
|
32
|
+
)
|
|
33
|
+
raise ValueError(err_msg)
|
|
34
|
+
return v
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def normalize_key_string(cls, s: str) -> str:
|
|
38
|
+
return s.replace("/", "_").replace(".", "_").replace("-", "_")
|
|
39
|
+
|
|
40
|
+
@classmethod
|
|
41
|
+
def normalize_dict_keys(cls, metadata: Dict) -> Dict:
|
|
42
|
+
result = defaultdict(lambda: MISSING)
|
|
43
|
+
result.update({cls.normalize_key_string(k): v for k, v in metadata.items()})
|
|
44
|
+
return result
|
|
45
|
+
|
|
46
|
+
# if prefix not present, return ""
|
|
47
|
+
# else, if found, return replacement else return MISSING
|
|
48
|
+
@classmethod
|
|
49
|
+
def get_replacement(cls, prefix: str, value: str, normalized_replacements: Dict) -> str:
|
|
50
|
+
if prefix in value: # value is in the format of "$prefix" or "prefix"
|
|
51
|
+
value = cls.normalize_key_string(value.replace(prefix, ""))
|
|
52
|
+
if "$" in value:
|
|
53
|
+
return Template(value).safe_substitute(normalized_replacements)
|
|
54
|
+
else:
|
|
55
|
+
return normalized_replacements[value]
|
|
56
|
+
return ""
|
|
57
|
+
|
|
58
|
+
@classmethod
|
|
59
|
+
def replace_token(
|
|
60
|
+
cls,
|
|
61
|
+
pattern: regex.Pattern,
|
|
62
|
+
prefix: str,
|
|
63
|
+
channel: str,
|
|
64
|
+
replacements: Dict[str, str],
|
|
65
|
+
) -> str:
|
|
66
|
+
tokens = pattern.findall(channel)
|
|
67
|
+
for token in tokens:
|
|
68
|
+
clean_token = token.replace("{", "").replace("}", "")
|
|
69
|
+
replacement = cls.get_replacement(prefix, clean_token, replacements)
|
|
70
|
+
if replacement:
|
|
71
|
+
channel = channel.replace(token, replacement)
|
|
72
|
+
return channel
|
|
73
|
+
|
|
74
|
+
@classmethod
|
|
75
|
+
def template(
|
|
76
|
+
cls,
|
|
77
|
+
channel_override: Optional[str],
|
|
78
|
+
default_channel: str,
|
|
79
|
+
cluster_name: str,
|
|
80
|
+
labels: Dict[str, str],
|
|
81
|
+
annotations: Dict[str, str],
|
|
82
|
+
) -> str:
|
|
83
|
+
if not channel_override:
|
|
84
|
+
return default_channel
|
|
85
|
+
|
|
86
|
+
channel = channel_override
|
|
87
|
+
if CLUSTER_PREF in channel:
|
|
88
|
+
# replace "cluster_name" or "$cluster_name" or ${cluster_name} with the value of the cluster name
|
|
89
|
+
channel = CLUSTER_PREF_PATTERN.sub(cluster_name, channel)
|
|
90
|
+
|
|
91
|
+
if LABELS_PREF in channel:
|
|
92
|
+
normalized_labels = cls.normalize_dict_keys(labels)
|
|
93
|
+
channel = cls.replace_token(BRACKETS_PATTERN, LABELS_PREF, channel, normalized_labels)
|
|
94
|
+
channel = cls.replace_token(LABEL_PREF_PATTERN, LABELS_PREF, channel, normalized_labels)
|
|
95
|
+
|
|
96
|
+
if ANNOTATIONS_PREF in channel:
|
|
97
|
+
normalized_annotations = cls.normalize_dict_keys(annotations)
|
|
98
|
+
channel = cls.replace_token(BRACKETS_PATTERN, ANNOTATIONS_PREF, channel, normalized_annotations)
|
|
99
|
+
channel = cls.replace_token(
|
|
100
|
+
ANNOTATIONS_PREF_PATTERN,
|
|
101
|
+
ANNOTATIONS_PREF,
|
|
102
|
+
channel,
|
|
103
|
+
normalized_annotations,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
return channel if MISSING not in channel else default_channel
|
{robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/datadog/datadog_sink_params.py
RENAMED
|
@@ -5,6 +5,10 @@ from robusta.core.sinks.sink_config import SinkConfigBase
|
|
|
5
5
|
class DataDogSinkParams(SinkBaseParams):
|
|
6
6
|
api_key: str
|
|
7
7
|
|
|
8
|
+
@classmethod
|
|
9
|
+
def _get_sink_type(cls):
|
|
10
|
+
return "datadog"
|
|
11
|
+
|
|
8
12
|
|
|
9
13
|
class DataDogSinkConfigWrapper(SinkConfigBase):
|
|
10
14
|
datadog_sink: DataDogSinkParams
|
{robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/discord/discord_sink_params.py
RENAMED
|
@@ -5,6 +5,10 @@ from robusta.core.sinks.sink_config import SinkConfigBase
|
|
|
5
5
|
class DiscordSinkParams(SinkBaseParams):
|
|
6
6
|
url: str
|
|
7
7
|
|
|
8
|
+
@classmethod
|
|
9
|
+
def _get_sink_type(cls):
|
|
10
|
+
return "discord"
|
|
11
|
+
|
|
8
12
|
|
|
9
13
|
class DiscordSinkConfigWrapper(SinkConfigBase):
|
|
10
14
|
discord_sink: DiscordSinkParams
|
|
@@ -7,6 +7,10 @@ from robusta.core.sinks.sink_config import SinkConfigBase
|
|
|
7
7
|
class FileSinkParms(SinkBaseParams):
|
|
8
8
|
file_name: str = None
|
|
9
9
|
|
|
10
|
+
@classmethod
|
|
11
|
+
def _get_sink_type(cls):
|
|
12
|
+
return "file"
|
|
13
|
+
|
|
10
14
|
|
|
11
15
|
class FileSinkConfigWrapper(SinkConfigBase):
|
|
12
16
|
file_sink: FileSinkParms
|
{robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/google_chat/google_chat_params.py
RENAMED
|
@@ -7,6 +7,10 @@ from robusta.core.sinks.sink_config import SinkConfigBase
|
|
|
7
7
|
class GoogleChatSinkParams(SinkBaseParams):
|
|
8
8
|
webhook_url: SecretStr
|
|
9
9
|
|
|
10
|
+
@classmethod
|
|
11
|
+
def _get_sink_type(cls):
|
|
12
|
+
return "google_chat"
|
|
13
|
+
|
|
10
14
|
|
|
11
15
|
class GoogleChatSinkConfigWrapper(SinkConfigBase):
|
|
12
16
|
google_chat_sink: GoogleChatSinkParams
|
|
@@ -19,6 +19,10 @@ class JiraSinkParams(SinkBaseParams):
|
|
|
19
19
|
reopenStatusName: Optional[str] = "To Do"
|
|
20
20
|
noReopenResolution: Optional[str] = ""
|
|
21
21
|
|
|
22
|
+
@classmethod
|
|
23
|
+
def _get_sink_type(cls):
|
|
24
|
+
return "jira"
|
|
25
|
+
|
|
22
26
|
|
|
23
27
|
class JiraSinkConfigWrapper(SinkConfigBase):
|
|
24
28
|
jira_sink: JiraSinkParams
|
|
@@ -7,6 +7,10 @@ from robusta.core.sinks.sink_config import SinkConfigBase
|
|
|
7
7
|
class MailSinkParams(SinkBaseParams):
|
|
8
8
|
mailto: str
|
|
9
9
|
|
|
10
|
+
@classmethod
|
|
11
|
+
def _get_sink_type(cls):
|
|
12
|
+
return "mail"
|
|
13
|
+
|
|
10
14
|
@validator("mailto")
|
|
11
15
|
def validate_mailto(cls, mailto):
|
|
12
16
|
# Make sure we only handle emails and exclude other schemes provided by apprise
|
{robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/msteams/msteams_sink_params.py
RENAMED
|
@@ -5,6 +5,10 @@ from robusta.core.sinks.sink_config import SinkConfigBase
|
|
|
5
5
|
class MsTeamsSinkParams(SinkBaseParams):
|
|
6
6
|
webhook_url: str
|
|
7
7
|
|
|
8
|
+
@classmethod
|
|
9
|
+
def _get_sink_type(cls):
|
|
10
|
+
return "msteams"
|
|
11
|
+
|
|
8
12
|
|
|
9
13
|
class MsTeamsSinkConfigWrapper(SinkConfigBase):
|
|
10
14
|
ms_teams_sink: MsTeamsSinkParams
|
{robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/opsgenie/opsgenie_sink_params.py
RENAMED
|
@@ -10,6 +10,10 @@ class OpsGenieSinkParams(SinkBaseParams):
|
|
|
10
10
|
tags: List[str] = []
|
|
11
11
|
host: Optional[str] = None # NOTE: If None, the default value will be used from opsgenie_sdk
|
|
12
12
|
|
|
13
|
+
@classmethod
|
|
14
|
+
def _get_sink_type(cls):
|
|
15
|
+
return "opsgenie"
|
|
16
|
+
|
|
13
17
|
|
|
14
18
|
class OpsGenieSinkConfigWrapper(SinkConfigBase):
|
|
15
19
|
opsgenie_sink: OpsGenieSinkParams
|
{robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/pagerduty/pagerduty_sink_params.py
RENAMED
|
@@ -5,6 +5,10 @@ from robusta.core.sinks.sink_config import SinkConfigBase
|
|
|
5
5
|
class PagerdutySinkParams(SinkBaseParams):
|
|
6
6
|
api_key: str
|
|
7
7
|
|
|
8
|
+
@classmethod
|
|
9
|
+
def _get_sink_type(cls):
|
|
10
|
+
return "pagerduty"
|
|
11
|
+
|
|
8
12
|
|
|
9
13
|
class PagerdutyConfigWrapper(SinkConfigBase):
|
|
10
14
|
pagerduty_sink: PagerdutySinkParams
|
{robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/pushover/pushover_sink_params.py
RENAMED
|
@@ -10,6 +10,11 @@ class PushoverSinkParams(SinkBaseParams):
|
|
|
10
10
|
device: str = None
|
|
11
11
|
pushover_url: str = "https://api.pushover.net/1/messages.json"
|
|
12
12
|
|
|
13
|
+
@classmethod
|
|
14
|
+
def _get_sink_type(cls):
|
|
15
|
+
return "pushover"
|
|
16
|
+
|
|
17
|
+
|
|
13
18
|
class PushoverSinkConfigWrapper(SinkConfigBase):
|
|
14
19
|
pushover_sink: PushoverSinkParams
|
|
15
20
|
|
{robusta_cli-0.11.0 → robusta_cli-0.12.0}/src/robusta/core/sinks/robusta/robusta_sink_params.py
RENAMED
|
@@ -17,6 +17,10 @@ class RobustaSinkParams(SinkBaseParams):
|
|
|
17
17
|
ttl_hours: int = 4380 # Time before unactive cluster data is deleted. 6 Months default.
|
|
18
18
|
persist_events: bool = False
|
|
19
19
|
|
|
20
|
+
@classmethod
|
|
21
|
+
def _get_sink_type(cls):
|
|
22
|
+
return "robusta"
|
|
23
|
+
|
|
20
24
|
|
|
21
25
|
class RobustaSinkConfigWrapper(SinkConfigBase):
|
|
22
26
|
robusta_sink: RobustaSinkParams
|
|
@@ -12,6 +12,10 @@ class ServiceNowSinkParams(SinkBaseParams):
|
|
|
12
12
|
password: SecretStr
|
|
13
13
|
caller_id: Optional[str]
|
|
14
14
|
|
|
15
|
+
@classmethod
|
|
16
|
+
def _get_sink_type(cls):
|
|
17
|
+
return "servicenow"
|
|
18
|
+
|
|
15
19
|
|
|
16
20
|
class ServiceNowSinkConfigWrapper(SinkConfigBase):
|
|
17
21
|
service_now_sink: ServiceNowSinkParams
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import threading
|
|
2
|
+
import time
|
|
3
|
+
from abc import abstractmethod, ABC
|
|
4
|
+
from collections import defaultdict
|
|
5
|
+
from typing import Any, List, Dict, Tuple, DefaultDict, Optional
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, Field
|
|
8
|
+
|
|
9
|
+
from robusta.core.model.k8s_operation_type import K8sOperationType
|
|
10
|
+
from robusta.core.reporting.base import Finding
|
|
11
|
+
from robusta.core.sinks.sink_base_params import ActivityInterval, ActivityParams, SinkBaseParams
|
|
12
|
+
from robusta.core.sinks.timing import TimeSlice, TimeSliceAlways
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
KeyT = Tuple[str, ...]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class NotificationGroup(BaseModel):
|
|
19
|
+
timestamps: List[float] = []
|
|
20
|
+
|
|
21
|
+
def register_notification(self, interval: int, threshold: int) -> bool:
|
|
22
|
+
"""Record information about an incoming notification. Returns True if this
|
|
23
|
+
notification should be emitted by a sink, False otherwise."""
|
|
24
|
+
now_ts = time.time()
|
|
25
|
+
|
|
26
|
+
# Prune any events older than the interval
|
|
27
|
+
while self.timestamps and now_ts - self.timestamps[0] > interval:
|
|
28
|
+
self.timestamps.pop(0)
|
|
29
|
+
|
|
30
|
+
self.timestamps.append(now_ts)
|
|
31
|
+
return len(self.timestamps) >= threshold
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class NotificationSummary(BaseModel):
|
|
35
|
+
message_id: Optional[str] = None # identifier of the summary message
|
|
36
|
+
start_ts: float = Field(default_factory=lambda: time.time()) # Timestamp of the first notification
|
|
37
|
+
# Keys for the table are determined by grouping.notification_mode.summary.by
|
|
38
|
+
summary_table: DefaultDict[KeyT, List[int]] = None
|
|
39
|
+
|
|
40
|
+
def register_notification(self, summary_key: KeyT, resolved: bool, interval: int):
|
|
41
|
+
now_ts = time.time()
|
|
42
|
+
idx = 1 if resolved else 0
|
|
43
|
+
if now_ts - self.start_ts > interval or not self.summary_table:
|
|
44
|
+
# Expired or the first summary ever for this group_key, reset the data
|
|
45
|
+
self.summary_table = defaultdict(lambda: [0, 0])
|
|
46
|
+
self.start_ts = now_ts
|
|
47
|
+
self.message_id = None
|
|
48
|
+
self.summary_table[summary_key][idx] += 1
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class SinkBase(ABC):
|
|
52
|
+
grouping_enabled: bool
|
|
53
|
+
grouping_summary_mode: bool
|
|
54
|
+
|
|
55
|
+
# Keys for groups and summaries are determined by grouping.group_by
|
|
56
|
+
groups: DefaultDict[KeyT, NotificationGroup]
|
|
57
|
+
summaries: DefaultDict[KeyT, NotificationSummary]
|
|
58
|
+
|
|
59
|
+
# Notification summaries
|
|
60
|
+
summary_header: List[str] # descriptive header for the summary table
|
|
61
|
+
|
|
62
|
+
def __init__(self, sink_params: SinkBaseParams, registry):
|
|
63
|
+
self.sink_name = sink_params.name
|
|
64
|
+
self.params = sink_params
|
|
65
|
+
self.default = sink_params.default
|
|
66
|
+
self.registry = registry
|
|
67
|
+
global_config = self.registry.get_global_config()
|
|
68
|
+
|
|
69
|
+
self.account_id: str = global_config.get("account_id", "")
|
|
70
|
+
self.cluster_name: str = global_config.get("cluster_name", "")
|
|
71
|
+
self.signing_key = global_config.get("signing_key", "")
|
|
72
|
+
|
|
73
|
+
self.time_slices = self._build_time_slices_from_params(self.params.activity)
|
|
74
|
+
|
|
75
|
+
self.grouping_summary_mode = False
|
|
76
|
+
self.grouping_enabled = False
|
|
77
|
+
|
|
78
|
+
if sink_params.grouping:
|
|
79
|
+
self.finding_group_lock = threading.RLock()
|
|
80
|
+
self.grouping_enabled = True
|
|
81
|
+
if sink_params.grouping.notification_mode.summary:
|
|
82
|
+
self.grouping_summary_mode = True
|
|
83
|
+
self.summaries = defaultdict(lambda: NotificationSummary())
|
|
84
|
+
self.summary_header = self.create_summary_header()
|
|
85
|
+
else:
|
|
86
|
+
self.grouping_summary_mode = False
|
|
87
|
+
self.groups = defaultdict(lambda: NotificationGroup())
|
|
88
|
+
|
|
89
|
+
def create_summary_header(self):
|
|
90
|
+
summary_header = []
|
|
91
|
+
for attr in self.params.grouping.notification_mode.summary.by:
|
|
92
|
+
if isinstance(attr, str):
|
|
93
|
+
summary_header.append("notification" if attr == "identifier" else attr)
|
|
94
|
+
elif isinstance(attr, dict):
|
|
95
|
+
keys = list(attr.keys())
|
|
96
|
+
if len(keys) > 1:
|
|
97
|
+
raise ValueError(
|
|
98
|
+
"Invalid sink configuration: multiple values for one of the elements in"
|
|
99
|
+
"grouping.notification_mode.summary.by"
|
|
100
|
+
)
|
|
101
|
+
key = keys[0]
|
|
102
|
+
if key not in ["labels", "annotations"]:
|
|
103
|
+
raise ValueError(
|
|
104
|
+
f"Sink configuration: grouping.notification_mode.summary.by.{key} is invalid "
|
|
105
|
+
"(only labels/annotations allowed)"
|
|
106
|
+
)
|
|
107
|
+
for label_or_attr_name in attr[key]:
|
|
108
|
+
summary_header.append(f"{key[:-1]}:{label_or_attr_name}")
|
|
109
|
+
return summary_header
|
|
110
|
+
|
|
111
|
+
def get_group_key_and_header(self, finding_data: Dict, attributes: List) -> Tuple[KeyT, List[str]]:
|
|
112
|
+
"""Generates group key and descriptive header from finding data.
|
|
113
|
+
|
|
114
|
+
For example, for finding_data = {"a":1, "b":2, "x": 3, "y": None} and attributes = ["x", "y"]
|
|
115
|
+
this method will return ((3, "(undefined)"), [])"""
|
|
116
|
+
values = ()
|
|
117
|
+
descriptions = []
|
|
118
|
+
for attr in attributes:
|
|
119
|
+
if isinstance(attr, str):
|
|
120
|
+
if attr not in finding_data:
|
|
121
|
+
continue
|
|
122
|
+
value = finding_data[attr]
|
|
123
|
+
values += (value, )
|
|
124
|
+
descriptions.append(
|
|
125
|
+
f"{'notification' if attr=='identifier' else attr}: {self.display_value(value)}"
|
|
126
|
+
)
|
|
127
|
+
elif isinstance(attr, dict):
|
|
128
|
+
# This is typically for labels and annotations
|
|
129
|
+
top_level_attr_name = list(attr.keys())[0]
|
|
130
|
+
values += tuple(
|
|
131
|
+
finding_data.get(top_level_attr_name, {}).get(element_name)
|
|
132
|
+
for element_name in sorted(attr[top_level_attr_name])
|
|
133
|
+
)
|
|
134
|
+
subvalues = []
|
|
135
|
+
for subattr_name in sorted(attr[top_level_attr_name]):
|
|
136
|
+
subvalues.append((subattr_name, finding_data.get(top_level_attr_name, {}).get(subattr_name)))
|
|
137
|
+
subvalues_str = ", ".join(f"{key}={self.display_value(value)}" for key, value in sorted(subvalues))
|
|
138
|
+
descriptions.append(f"{top_level_attr_name}: {subvalues_str}")
|
|
139
|
+
return values, descriptions
|
|
140
|
+
|
|
141
|
+
def display_value(self, value: Optional[str]) -> str:
|
|
142
|
+
return value if value is not None else "(undefined)"
|
|
143
|
+
|
|
144
|
+
def _build_time_slices_from_params(self, params: ActivityParams):
|
|
145
|
+
if params is None:
|
|
146
|
+
return [TimeSliceAlways()]
|
|
147
|
+
else:
|
|
148
|
+
timezone = params.timezone
|
|
149
|
+
return [self._interval_to_time_slice(timezone, interval) for interval in params.intervals]
|
|
150
|
+
|
|
151
|
+
def _interval_to_time_slice(self, timezone: str, interval: ActivityInterval):
|
|
152
|
+
return TimeSlice(interval.days, [(time.start, time.end) for time in interval.hours], timezone)
|
|
153
|
+
|
|
154
|
+
def is_global_config_changed(self):
|
|
155
|
+
# registry global config can be updated without these stored values being changed
|
|
156
|
+
global_config = self.registry.get_global_config()
|
|
157
|
+
account_id = global_config.get("account_id", "")
|
|
158
|
+
cluster_name = global_config.get("cluster_name", "")
|
|
159
|
+
signing_key = global_config.get("signing_key", "")
|
|
160
|
+
return self.account_id != account_id or self.cluster_name != cluster_name or self.signing_key != signing_key
|
|
161
|
+
|
|
162
|
+
def stop(self):
|
|
163
|
+
pass
|
|
164
|
+
|
|
165
|
+
def accepts(self, finding: Finding) -> bool:
|
|
166
|
+
return (
|
|
167
|
+
finding.matches(self.params.match, self.params.scope)
|
|
168
|
+
and any(time_slice.is_active_now for time_slice in self.time_slices)
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
@abstractmethod
|
|
172
|
+
def write_finding(self, finding: Finding, platform_enabled: bool):
|
|
173
|
+
raise NotImplementedError(f"write_finding not implemented for sink {self.sink_name}")
|
|
174
|
+
|
|
175
|
+
def is_healthy(self) -> bool:
|
|
176
|
+
"""
|
|
177
|
+
Sink health check. Concrete sinks can implement real health checks
|
|
178
|
+
"""
|
|
179
|
+
return True
|
|
180
|
+
|
|
181
|
+
def handle_service_diff(self, new_obj: Any, operation: K8sOperationType):
|
|
182
|
+
pass
|
|
183
|
+
|
|
184
|
+
def set_cluster_active(self, active: bool):
|
|
185
|
+
pass
|