Grafana

Grafana alerting service.

Analytics & SIEM · Grafana

Details

IDGrafana
ProviderGrafana Labs
CategoryAnalytics & SIEM
From Version6.0.0
Docker Imagedemisto/python3:3.12.13.10116658
Supported ModulesAgentix XSIAM

README

Grafana alerting service.
This integration was integrated and tested with version 8.0.0 of Grafana

Configure Grafana in Cortex

Parameter Description Required
Server URL   True
Username   True
Password   True
Use system proxy settings   False
Trust any certificate (not secure)   False
Maximum number of incidents to fetch Maximum is limited to 200. False
Fetch incidents   False
First fetch time interval   False
Dashboard IDs to fetch A comma-separated list of dashboard IDs. Can be found by running the “grafana-dashboards-search” command. False
Panel ID to fetch See “help”. False
Alert name to fetch   False
States to fetch   False
Incident type   False

Commands

You can execute these commands from the CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.

grafana-alerts-list


Gets alerts.

Base Command

grafana-alerts-list

Input

Argument Name Description Required
dashboard_id A comma-separated list of dashboard IDs by which to filter the results. Optional
panel_id The ID of the panel by which to filter the results. Optional
name Value that is contained in the alert’s name by which to filter the results. Optional
state A comma-separated list of states by which to filter the results. The options are: all, no_data, paused, alerting, ok, pending, unknown. Optional
limit The maximum number of alerts to return. Optional
folder_id A comma-separated list of folder IDs by which to filter the results. Optional
dashboard_name Value that is contained in the dashboard’s name by which to filter the results. Optional
dashboard_tag A comma-separated list of dashboard tags by which to filter the results. Optional

Context Output

Path Type Description
Grafana.Alert.id Number Alert ID.
Grafana.Alert.dashboardId Number Alert dashboard ID.
Grafana.Alert.dashboardUid String Alert dashboard UID.
Grafana.Alert.dashboardName String Alert dashboard name.
Grafana.Alert.panelId Number Alert panel ID.
Grafana.Alert.name String Alert name.
Grafana.Alert.state String Alert state.
Grafana.Alert.newStateDate Date The date on which the new alert state appeared.
Grafana.Alert.evalDate Date The date the alert was evaluated.
Grafana.Alert.evalData Unknown The metric that triggered the alert and made it change to the alerting state.
Grafana.Alert.executionError String Alert execution error.
Grafana.Alert.url String Alert URL.

Command Example


#### Context Example

```json
{
    "Grafana": {
        "Alert": [
            {
                "dashboardId": 2,
                "dashboardName": "streaming2",
                "dashboardUid": "yzDQUOR7z",
                "evalData": {
                    "noData": true
                },
                "evalDate": "0001-01-01T00:00:00Z",
                "executionError": "",
                "id": 2,
                "name": "Adi's Alert",
                "newStateDate": "2021-09-30T15:43:20Z",
                "panelId": 5,
                "state": "unknown",
                "url": "https://base_url/d/yzDQUOR7z/streaming2"
            },
            {
                "dashboardId": 1,
                "dashboardName": "streaming",
                "dashboardUid": "TXSTREZ",
                "evalData": {
                    "noData": true
                },
                "evalDate": "0001-01-01T00:00:00Z",
                "executionError": "",
                "id": 1,
                "name": "Arseny's Alert",
                "newStateDate": "2021-06-09T15:20:01Z",
                "panelId": 4,
                "state": "no_data",
                "url": "https://base_url/d/TXSTREZ/streaming"
            },
            {
                "dashboardId": 2,
                "dashboardName": "streaming2",
                "dashboardUid": "yzDQUOR7z",
                "evalData": {
                    "noData": true
                },
                "evalDate": "0001-01-01T00:00:00Z",
                "executionError": "",
                "id": 3,
                "name": "TryAlert",
                "newStateDate": "2021-08-11T13:30:40Z",
                "panelId": 6,
                "state": "alerting",
                "url": "https://base_url/d/yzDQUOR7z/streaming2"
            }
        ]
    }
}

Human Readable Output

Existing Alerts

Id Name State New State Date Panel Id Dashboard Id Dashboard Uid Dashboard Name Url
2 Adi’s Alert no_data 2021-09-30T15:43:20Z 5 2 yzDQUOR7z streaming2 https://base_url/d/yzDQUOR7z/streaming2
1 Arseny’s Alert no_data 2021-06-09T15:20:01Z 4 1 TXSTREZ streaming https://base_url/d/TXSTREZ/streaming
3 TryAlert alerting 2021-08-11T13:30:40Z 6 2 yzDQUOR7z streaming2 https://base_url/d/yzDQUOR7z/streaming2

grafana-alert-pause


Pauses an alert by ID.

Base Command

grafana-alert-pause

Input

Argument Name Description Required
alert_id ID of the alert to pause. Required

Context Output

Path Type Description
Grafana.Alert.id Number The ID of the alert that was paused.
Grafana.Alert.state String The new state of the alert.

Command Example

!grafana-alert-pause alert_id=2

Context Example

{
    "Grafana": {
        "Alert": {
            "id": 2,
            "message": "Alert paused",
            "state": "paused"
        }
    }
}

Human Readable Output

Paused Alert 2

Id Message State
2 Alert paused paused

grafana-alert-unpause


Unpauses an alert by ID.

Base Command

grafana-alert-unpause

Input

Argument Name Description Required
alert_id ID of the alert to unpause. Required

Context Output

Path Type Description
Grafana.Alert.id Number The ID of the alert that was unpaused.
Grafana.Alert.state String The new state of the alert.

Command Example

!grafana-alert-unpause alert_id=2

Context Example

{
    "Grafana": {
        "Alert": {
            "id": 2,
            "message": "Alert un-paused",
            "state": "unknown"
        }
    }
}

Human Readable Output

Un-paused Alert 2

Id Message State
2 Alert un-paused unknown

grafana-users-search


Gets users.

Base Command

grafana-users-search

Input

Argument Name Description Required
perpage Number of results to return per page. Optional
page Index of the page of results to retrieve. Optional
query The value contained in either the name, login, or email fields by which to filter the results. Optional

Context Output

Path Type Description
Grafana.User.id Number User ID.
Grafana.User.name String User name.
Grafana.User.login String User login.
Grafana.User.email String User email.
Grafana.User.avatarUrl String User avatar URL.
Grafana.User.isAdmin Boolean Is user an admin?
Grafana.User.isDisabled Boolean Is user disabled?
Grafana.User.lastSeenAt Date The date the user was last seen.
Grafana.User.lastSeenAtAge String When the user was last seen in minutes (m), years (Y), month (M), days (d), etc.
Grafana.User.authLabels Unknown User authentication labels

Command Example


#### Context Example

```json
{
    "Grafana": {
        "User": [
            {
                "authLabels": [],
                "avatarUrl": "https://base_url/avatar/5d9c68c6c50ed3d02a2fcf54f63993b",
                "email": "User@mail",
                "id": 1,
                "isAdmin": true,
                "isDisabled": false,
                "lastSeenAt": "2021-10-04T15:25:40Z",
                "lastSeenAtAge": "4m",
                "login": "admin",
                "name": "admin"
            },
            {
                "authLabels": [],
                "avatarUrl": "https://base_url/avatar/04501192ea3453723d1336c6520ce2c",
                "email": "xadmin",
                "id": 2,
                "isAdmin": false,
                "isDisabled": false,
                "lastSeenAt": "2021-09-29T12:47:23Z",
                "lastSeenAtAge": "5d",
                "login": "xadmin",
                "name": "xadmin"
            }
        ]
    }
}

Human Readable Output

Existing Users

Id Email Name Login Is Admin Is Disabled Avatar Url Last Seen At Last Seen At Age
1 User@mail admin admin true false https://base_url/avatar/5d9c68c6c50ed3d02a2fcf54f63993b 2021-10-04T15:25:40Z 4m
2 xadmin xadmin xadmin false false https://base_url/avatar/04501192ea3453723d1336c6520ce2c 2021-09-29T12:47:23Z 5d
3 test@test User3 User false false https://base_url/avatar/46d229b033af06a191ff2267bca9ae5 2011-07-27T15:10:37Z 10y

grafana-user-teams-get


Gets the user’s teams by user ID.

Base Command

grafana-user-teams-get

Input

Argument Name Description Required
user_id ID of user for whom to get teams. Required

Context Output

Path Type Description
Grafana.User.id Number User ID.
Grafana.User.teams.id Number Team ID.
Grafana.User.teams.orgId Number Team organization ID.
Grafana.User.teams.name String Team name.
Grafana.User.teams.email String Team email.
Grafana.User.teams.avatarUrl String Team avatar URL.
Grafana.User.teams.memberCount Number Team member count.
Grafana.User.teams.permission Number Number of team permissions.

Command Example

!grafana-user-teams-get user_id=1

Context Example

{
    "Grafana": {
        "User": {
            "id": "1",
            "teams": [
                {
                    "avatarUrl": "https://base_url/avatar/f1f97cfa3c828a7352da671a",
                    "email": "team@test.com",
                    "id": 15,
                    "memberCount": 1,
                    "name": "Test Team",
                    "orgId": 1,
                    "permission": 0
                },
                {
                    "avatarUrl": "https://base_url/avatar/1d3226029e424011bffde2f",
                    "email": "test2@test.com",
                    "id": 16,
                    "memberCount": 2,
                    "name": "TestTeam2",
                    "orgId": 1,
                    "permission": 0
                }
            ]
        }
    }
}

Human Readable Output

Teams For User 1

Id Org Id Name Email Avatar Url Member Count Permission
15 1 Test Team team@test.com https://base_url/avatar/f1f97cfa3c828a7352da671a 1 0
16 1 TestTeam2 test2@test.com https://base_url/avatar/1d3226029e424011bffde2f 2 0

grafana-user-orgs-get


Gets user’s organizations by user ID.

Base Command

grafana-user-orgs-get

Input

Argument Name Description Required
user_id ID of user for whom to get the organizations. Required

Context Output

Path Type Description
Grafana.User.id Number User ID.
Grafana.User.orgs.orgId Number Organization ID.
Grafana.User.orgs.name String Organization name.
Grafana.User.orgs.role String Organization role.

Command Example

!grafana-user-orgs-get user_id=1

Context Example

{
    "Grafana": {
        "User": {
            "id": "1",
            "orgs": [
                {
                    "name": "Main Org.",
                    "orgId": 1,
                    "role": "Admin"
                },
                {
                    "name": "New Org.",
                    "orgId": 2,
                    "role": "Admin"
                }
            ]
        }
    }
}

Human Readable Output

Organizations For User 1

Name Org Id Role
Main Org. 1 Admin
New Org. 2 Admin

grafana-user-update


Updates a user by user ID. Login or email is mandatory. If you change your own login information, you won’t be able to continue querying as your username (login) will change. Login and email should be unique.

Base Command

grafana-user-update

Input

Argument Name Description Required
email User email. If email is not specified, login must be specified. Optional
name User’s name. Optional
login User login (username). If login is not specified, email must be specified. Optional
theme User theme when using Grafana’s interface. Possilble values: “light” or “dark”. Possible values are: light, dark. Optional
user_id User ID. Required

Context Output

There is no context output for this command.

Command Example

!grafana-user-update user_id=3 email=TestUser login=TestUser name=TestUser

Human Readable Output

Successfully Updated User 3

Message
User updated

grafana-annotation-create


Creates an annotation in the Grafana database. The dashboard_id and panel_id fields are optional. If they are not specified, a global annotation is created and can be queried in any dashboard that adds the Grafana annotations data source. When creating a region annotation include the time_end property.

Base Command

grafana-annotation-create

Input

Argument Name Description Required
dashboard_id Dashboard ID. Optional
panel_id Panel ID. Optional
time Start time. Optional
time_end End time. Optional
tags A comma-separated list of tags by which to filter the dashboards to add the annotation to. Optional
text Text of the annotation. Required

Context Output

Path Type Description
Grafana.Annotation.id Number Annotation ID.

Command Example

!grafana-annotation-create text="annotate"

Context Example

{
    "Grafana": {
        "Annotation": {
            "id": 266,
            "message": "Annotation added"
        }
    }
}

Human Readable Output

Successfully Created Annotation 266

Id Message
266 Annotation added

grafana-teams-search


Gets teams.

Base Command

grafana-teams-search

Input

Argument Name Description Required
perpage Number of results to return on a page. Optional
page Index of the page of results to retrieve. Optional
query The value contained in the name of a team. Optional
name The exact name of the team. Optional

Context Output

Path Type Description
Grafana.Team.id Number Team ID.
Grafana.Team.orgId Number Team organization ID.
Grafana.Team.name String Team name.
Grafana.Team.email String Team email.
Grafana.Team.avatarUrl String Team avatar URL.
Grafana.Team.memberCount Number The number of team members.
Grafana.Team.permission Number Number of team permissions.

Command Example


#### Context Example

```json
{
    "Grafana": {
        "Team": [
            {
                "avatarUrl": "https://base_url/avatar/f1f97cfa3c828a7352da671a",
                "email": "team@test.com",
                "id": 15,
                "memberCount": 1,
                "name": "Test Team",
                "orgId": 1,
                "permission": 0
            },
            {
                "avatarUrl": "https://base_url/avatar/1d3226029e424011bffde2f",
                "email": "test2@test.com",
                "id": 16,
                "memberCount": 2,
                "name": "TestTeam2",
                "orgId": 1,
                "permission": 0
            },
            {
                "avatarUrl": "https://base_url/avatar/71cc610bc4841e3444235f09d9c",
                "email": "email@test.com",
                "id": 144,
                "memberCount": 0,
                "name": "Elia",
                "orgId": 1,
                "permission": 0
            }
        ]
    }
}

Human Readable Output

Teams Search Results

Id Org Id Name Email Avatar Url Member Count Permission
15 1 Test Team team@test.com https://base_url/avatar/f1f97cfa3c828a7352da671a 1 0
16 1 TestTeam2 test2@test.com https://base_url/avatar/1d3226029e424011bffde2f 2 0
144 1 Elia email@test.com https://base_url/avatar/71cc610bc4841e3444235f09d9c 0 0

grafana-team-members-list


Gets a list of all team members by team ID.

Base Command

grafana-team-members-list

Input

Argument Name Description Required
team_id Team ID. Required

Context Output

Path Type Description
Grafana.Team.id Number Team ID.
Grafana.Team.members.orgId Number Member organization ID.
Grafana.Team.members.teamId Number Member team ID.
Grafana.Team.members.userId Number Member user ID.
Grafana.Team.members.auth_module String Member authentication module.
Grafana.Team.members.email String Member email.
Grafana.Team.members.name String Member name.
Grafana.Team.members.login String Member login.
Grafana.Team.members.avatarUrl String Member avatar URL.
Grafana.Team.members.labels Unknown Member labels.
Grafana.Team.members.permission Number Member permission.

Command Example

!grafana-team-members-list team_id=15

Context Example

{
    "Grafana": {
        "Team": {
            "id": "15",
            "members": [
                {
                    "auth_module": "",
                    "avatarUrl": "https://base_url/avatar/5d9c68c6c50ed3d02a2fcf54f63993b",
                    "email": "User@mail",
                    "labels": [],
                    "login": "admin",
                    "name": "admin",
                    "orgId": 1,
                    "permission": 0,
                    "teamId": 15,
                    "userId": 1
                }
            ]
        }
    }
}

Human Readable Output

Team 15 Members

Org Id Team Id User Id Email Name Login Avatar Url Permission
1 15 1 User@mail admin admin https://base_url/avatar/5d9c68c6c50ed3d02a2fcf54f63993b 0

grafana-user-add-to-team


Adds a user to a team.

Base Command

grafana-user-add-to-team

Input

Argument Name Description Required
user_id User ID. Required
team_id Team ID. Required

Context Output

There is no context output for this command.

Command Example

!grafana-user-add-to-team team_id=15 user_id=3

Human Readable Output

Successfully Added User 3 to Team 15

Message
Member added to Team

grafana-user-remove-from-team


Removes a user from a team.

Base Command

grafana-user-remove-from-team

Input

Argument Name Description Required
team_id Team ID. Required
user_id User ID. Required

Context Output

There is no context output for this command.

Command Example

!grafana-user-remove-from-team team_id=15 user_id=3

Human Readable Output

Successfully Removed User 3 from Team 15

Message
Team Member removed

grafana-team-add


Creates a new team.

Base Command

grafana-team-add

Input

Argument Name Description Required
name The team name. Must be unique. Required
email Email address of the team. Optional
org_id Organization ID. Optional

Context Output

Path Type Description
Grafana.Team.id Number Team ID.

Command Example

!grafana-team-add name="TestTeam4"

Context Example

{
    "Grafana": {
        "Team": {
            "id": 153,
            "message": "Team created"
        }
    }
}

Human Readable Output

Successfully Created Team 153

Message Team Id
Team created 153

grafana-team-delete


Deletes a team.

Base Command

grafana-team-delete

Input

Argument Name Description Required
team_id Team ID. Required

Context Output

There is no context output for this command.

Command Example

!grafana-team-delete team_id=152

Human Readable Output

Successfully Deleted Team 152

Message
Team deleted

grafana-org-create


Creates an organization.

Base Command

grafana-org-create

Input

Argument Name Description Required
name Name of the organization. Required

Context Output

Path Type Description
Grafana.Organization.id Number Organization ID.

Command Example

!grafana-org-create name="Organization"

Context Example

{
    "Grafana": {
        "Organization": {
            "id": 12,
            "message": "Organization created"
        }
    }
}

Human Readable Output

Successfully Created Organization 12

Message Org Id
Organization created 12

grafana-dashboards-search


Searches dashboards.

Base Command

grafana-dashboards-search

Input

Argument Name Description Required
query Value is contained in the name of the dashboard. Optional
tag A comma-separated list of tags by which to filter the results. Optional
type Type of the dashboard. Possible values: “dash-folder” and “dash-db”. Possible values are: dash-folder, dash-db. Optional
dashboard_ids A comma-separated list of dashboard IDs by which to filter the results. Optional
folder_ids A comma-separated list of folder IDs by which to filter the results. Optional
starred Whether to only return starred dashboards. Possible values: “true” and “false”. Possible values are: true, false. Optional
limit The maximum number of dashboards to return. Optional
page Page. Optional

Context Output

Path Type Description
Grafana.Dashboard.id Number Dashboard ID.
Grafana.Dashboard.uid String Dashboard UID.
Grafana.Dashboard.title String Dashboard title.
Grafana.Dashboard.uri String Dashboard URI.
Grafana.Dashboard.url String Dashboard URL
Grafana.Dashboard.slug String Dashboard slug.
Grafana.Dashboard.type String Dashboard type.
Grafana.Dashboard.tags Unknown Dashboard tags.
Grafana.Dashboard.isStarred Boolean Is dashboard starred?

Command Example


#### Context Example

```json
{
    "Grafana": {
        "Dashboard": [
            {
                "id": 1,
                "isStarred": true,
                "slug": "",
                "tags": [],
                "title": "Streaming",
                "type": "dash-db",
                "uid": "TXSTREZ",
                "uri": "db/streaming",
                "url": "https://base_url/d/TXSTREZ/streaming"
            },
            {
                "id": 2,
                "isStarred": false,
                "slug": "",
                "tags": [
                    "tag1"
                ],
                "title": "Streaming Simple",
                "type": "dash-db",
                "uid": "yzDQUOR7z",
                "uri": "db/streaming2",
                "url": "https://base_url/d/yzDQUOR7z/streaming2"
            }
        ]
    }
}

Human Readable Output

Existing Dashboards

Id Uid Title Is Starred Tags Uri Url Type Sort Meta
1 TXSTREZ Streaming true   db/streaming https://base_url/d/TXSTREZ/streaming dash-db 0
2 yzDQUOR7z Streaming Simple false tag1 db/streaming2 https://base_url/d/yzDQUOR7z/streaming2 dash-db 0

grafana-user-get-by-id


Gets a user by ID.

Base Command

grafana-user-get-by-id

Input

Argument Name Description Required
user_id User ID. Required

Context Output

Path Type Description
Grafana.User.id Number User ID.
Grafana.User.email String User email.
Grafana.User.name String User name.
Grafana.User.login String User login.
Grafana.User.theme String User theme.
Grafana.User.orgId Number Organization ID.
Grafana.User.isGrafanaAdmin Boolean Is user a Grafana admin?
Grafana.User.isDisabled Boolean Is user disabled?
Grafana.User.isExternal Boolean Is user external?
Grafana.User.updatedAt Date Date when user was updated.
Grafana.User.createdAt Date Date when user was created.
Grafana.User.avatarUrl String User avatar URL.
Grafana.User.authLabels Unknown User authentication labels.

Command Example

!grafana-user-get-by-id user_id=1

Context Example

{
    "Grafana": {
        "User": {
            "authLabels": [],
            "avatarUrl": "/avatar/46d229b033af06a191ff2267bca9ae5",
            "createdAt": "2021-06-08T10:57:39Z",
            "email": "User@mail",
            "id": 1,
            "isDisabled": false,
            "isExternal": false,
            "isGrafanaAdmin": true,
            "login": "admin",
            "name": "admin",
            "orgId": 1,
            "theme": "light",
            "updatedAt": "2021-09-30T14:46:22Z"
        }
    }
}

Human Readable Output

User 1 Results

Id Email Name Login Theme Org Id Is Grafana Admin Is D Is abled Is External Updated At Created At Avatar Url
1 User@mail admin admin light 1 true false false 2021-09-30T14:46:22Z 2021-06-08T10:57:39Z https://base_url/avatar/46d229b033af06a191ff2267bca9ae5

grafana-team-get-by-id


Gets a team by ID.

Base Command

grafana-team-get-by-id

Input

Argument Name Description Required
team_id Team ID. Required

Context Output

Path Type Description
Grafana.Team.id Number Team ID.
Grafana.Team.orgId Number Team organization ID.
Grafana.Team.name String Team name.
Grafana.Team.email String Team email.
Grafana.Team.avatarUrl String Team avatar URL.
Grafana.Team.memberCount Number The number of team members.
Grafana.Team.permission Number Number of team permissions.

Command Example

!grafana-team-get-by-id team_id=15

Context Example

{
    "Grafana": {
        "Team": {
            "avatarUrl": "https://base_url/avatar/f1f97cfa3c828a7352da671a",
            "email": "team@test.com",
            "id": 15,
            "memberCount": 1,
            "name": "Test Team",
            "orgId": 1,
            "permission": 0
        }
    }
}

Human Readable Output

Team 15 Results

Id Org Id Name Email Avatar Url Member Count Permission
15 1 Test Team team@test.com https://base_url/avatar/f1f97cfa3c828a7352da671a 1 0

grafana-alert-get-by-id


Gets an alert by id.

Base Command

grafana-alert-get-by-id

Input

Argument Name Description Required
alert_id Alert ID. Required

Context Output

Path Type Description
Grafana.Alert.id Number Alert ID.
Grafana.Alert.version Number Alert version.
Grafana.Alert.orgId Number Alert organization ID.
Grafana.Alert.dashboardId Number Alert dashboard ID.
Grafana.Alert.panelId Number Alert panel ID.
Grafana.Alert.name String Alert name.
Grafana.Alert.message String Alert message.
Grafana.Alert.severity String Alert severity.
Grafana.Alert.state String Alert state.
Grafana.Alert.handler Number Alert handler.
Grafana.Alert.silenced Boolean Whether the alert was silenced.
Grafana.Alert.executionError String Alert execution error.
Grafana.Alert.frequency Number Alert frequency in seconds.
Grafana.Alert.for Number Once the alert rule has been firing for more than this duration in nanoseconds, then the alert changes to “Alerting”. Otherwise it goes from “OK” to “Pending”.
Grafana.Alert.evalData Unknown The metric that triggered the alert and made it change to the “Alerting” state.
Grafana.Alert.newStateDate Date The date of the alert’s new state.
Grafana.Alert.stateChanges Number The number of time the alert state changes.
Grafana.Alert.created Date Date the alert was created.
Grafana.Alert.updated Date Date the alert was updated.
Grafana.Alert.settings Unknown Alert settings.

Command Example

!grafana-alert-get-by-id alert_id=1

Context Example

{
    "Grafana": {
        "Alert": {
            "created": "2021-06-09T15:13:45Z",
            "dashboardId": 1,
            "evalData": {
                "noData": true
            },
            "executionError": " ",
            "for": 60000000000,
            "frequency": 600,
            "handler": 1,
            "id": 1,
            "message": "man down!",
            "name": "Arseny's Alert",
            "newStateDate": "2021-06-09T15:20:01Z",
            "orgId": 1,
            "panelId": 4,
            "settings": {
                "alertRuleTags": {
                    "moshe": "2"
                },
                "conditions": [
                    {
                        "evaluator": {
                            "params": [
                                10
                            ],
                            "type": "gt"
                        },
                        "operator": {
                            "type": "and"
                        },
                        "query": {
                            "datasourceId": 1,
                            "model": {
                                "refId": "A",
                                "scenarioId": "streaming_client",
                                "stream": {
                                    "noise": 2.2,
                                    "speed": 100,
                                    "spread": 3.5,
                                    "type": "signal"
                                },
                                "stringInput": ""
                            },
                            "params": [
                                "A",
                                "5m",
                                "now"
                            ]
                        },
                        "reducer": {
                            "params": [],
                            "type": "avg"
                        },
                        "type": "query"
                    }
                ],
                "executionErrorState": "alerting",
                "for": "1m",
                "frequency": "10m",
                "handler": 1,
                "message": "man down!",
                "name": "Arseny's Alert",
                "noDataState": "no_data",
                "notifications": []
            },
            "severity": "",
            "silenced": false,
            "state": "no_data",
            "stateChanges": 1,
            "updated": "2021-06-09T15:14:51Z",
            "version": 0
        }
    }
}

Human Readable Output

Alert 1 Results

Id Version Org Id Dashboard Id Panel Id Name Message State New State Date State Changes Handler Silenced Frequency For Created Updated
1 0 1 1 4 Arseny’s Alert man down! no_data 2021-06-09T15:20:01Z 1 1 false 600 60000000000 2021-06-09T15:13:45Z 2021-06-09T15:14:51Z

grafana-org-list


Gets organizations.

Base Command

grafana-org-list

Input

Argument Name Description Required
perpage Number of results to return on a page. Optional
page Index of the page of results to retrieve. Optional

Context Output

Path Type Description
Grafana.Organization.id Number Organization ID.
Grafana.Organization.name String Organization name.

Command Example


#### Context Example

```json
{
    "Grafana": {
        "Organization": [
            {
                "id": 1,
                "name": "Main Org."
            },
            {
                "id": 2,
                "name": "New Org."
            },
            {
                "id": 12,
                "name": "Organization"
            }
        ]
    }
}

Human Readable Output

Existing Organizations

Id Name
1 Main Org.
2 New Org.
12 Organization

grafana-org-get-by-name


Gets an organization by name.

Base Command

grafana-org-get-by-name

Input

Argument Name Description Required
name The exact name of the organization to get. Required

Context Output

Path Type Description
Grafana.Organization.id Number Organization ID.
Grafana.Organization.name String Organization name.
Grafana.Organization.address Unknown Organization address.

Command Example

!grafana-org-get-by-name name="Main Org."

Context Example

{
    "Grafana": {
        "Organization": {
            "address": {
                "address1": "",
                "address2": "",
                "city": "",
                "country": "",
                "state": "",
                "zipCode": ""
            },
            "id": 1,
            "name": "Main Org."
        }
    }
}

Human Readable Output

Organization “Main Org.” Results

Name Id Address
Main Org. 1 address1:
address2:
city:
zipCode:
state:
country:

grafana-org-get-by-id


Gets an organization by ID.

Base Command

grafana-org-get-by-id

Input

Argument Name Description Required
org_id Organization ID. Required

Context Output

Path Type Description
Grafana.Organization.id Number Organization ID.
Grafana.Organization.name String Organization name.
Grafana.Organization.address Unknown Organization address.

Command Example

!grafana-org-get-by-id org_id=1

Context Example

{
    "Grafana": {
        "Organization": {
            "address": {
                "address1": "",
                "address2": "",
                "city": "",
                "country": "",
                "state": "",
                "zipCode": ""
            },
            "id": 1,
            "name": "Main Org."
        }
    }
}

Human Readable Output

Organization 1 Results

Id Name Address
1 Main Org. address1:
address2:
city:
zipCode:
state:
country:

Configuration parameters

  • url — Server URL (required)
  • credentials — Username (required)
  • proxy — Use system proxy settings
  • insecure — Trust any certificate (not secure)
  • max_fetch — Maximum number of incidents to fetch
  • isFetch — Fetch incidents
  • first_fetch — First fetch time interval
  • dashboard_id — Dashboard IDs to fetch
  • panel_id — Panel ID to fetch
  • alert_name — Alert name to fetch
  • state — States to fetch
  • incidentType — Incident type
  • incidentFetchInterval — Incidents Fetch Interval

Commands (22)

  • grafana-alert-get-by-id

    Gets an alert by id.

  • grafana-alert-pause

    Pauses an alert by ID.

  • grafana-alert-unpause

    Unpauses an alert by ID.

  • grafana-alerts-list

    Gets alerts.

  • grafana-annotation-create

    Creates an annotation in the Grafana database. The dashboard_id and panel_id fields are optional. If they are not specified, a global annotation is created and can be queried in any dashboard that adds the Grafana annotations data source. When creating a region annotation include the time_end property.

  • grafana-dashboards-search

    Searches dashboards.

  • grafana-org-create

    Creates an organization.

  • grafana-org-get-by-id

    Gets an organization by ID.

  • grafana-org-get-by-name

    Gets an organization by name.

  • grafana-org-list

    Gets organizations.

  • grafana-team-add

    Creates a new team.

  • grafana-team-delete

    Deletes a team.

  • grafana-team-get-by-id

    Gets a team by ID.

  • grafana-team-members-list

    Gets a list of all team members by team ID.

  • grafana-teams-search

    Gets teams.

  • grafana-user-add-to-team

    Adds a user to a team.

  • grafana-user-get-by-id

    Gets a user by ID.

  • grafana-user-orgs-get

    Gets user's organizations by user ID.

  • grafana-user-remove-from-team

    Removes a user from a team.

  • grafana-user-teams-get

    Gets the user's teams by user ID.

  • grafana-user-update

    Updates a user by user ID. Login or email is mandatory. If you change your own login information, you won't be able to continue querying as your username (login) will change. Login and email should be unique.

  • grafana-users-search

    Gets users.

import json

import dateparser
import pytest
from freezegun import freeze_time
from Grafana import (
    Client,
    alert_get_by_id_command,
    alert_pause_command,
    alert_to_incident,
    alert_unpause_command,
    alerts_list_command,
    annotation_create_command,
    calculate_fetch_start_time,
    change_key,
    dashboards_search_command,
    decapitalize,
    filter_alerts_by_id,
    filter_alerts_by_time,
    keys_to_lowercase,
    org_create_command,
    org_get_by_id_command,
    org_get_by_name_command,
    org_list_command,
    paging_heading,
    parse_alerts,
    reduce_incidents_to_limit,
    set_state,
    set_time_to_epoch_millisecond,
    team_add_command,
    team_delete_command,
    team_get_by_id_command,
    team_members_command,
    teams_search_command,
    user_add_to_team_command,
    user_get_by_id_command,
    user_remove_from_team_command,
    user_update_command,
    users_organization_command,
    users_search_command,
    users_teams_command,
)
from pytz import utc


def create_client(url: str = "url", verify_certificate: bool = True, proxy: bool = False):
    return Client(url, verify_certificate, proxy)


""" HELPER FUNCTIONS TESTS """

with open("TestData/change_key_values.json") as change_key_values_file:
    change_key_values_data = json.load(change_key_values_file)

alertId_to_id = change_key_values_data["alertId_to_id"]
teamID_to_id = change_key_values_data["teamID_to_id"]
orgID_to_id = change_key_values_data["orgID_to_id"]
CHANGE_KEY_VALUES = [alertId_to_id, teamID_to_id, orgID_to_id]


@pytest.mark.parametrize("dict_input, prev_key, new_key, expected_result", CHANGE_KEY_VALUES)
def test_change_key(dict_input, prev_key, new_key, expected_result):
    """

    Given:
        - Dictionary we want to change one of it's keys

    When:
        - Getting response from Grafana API, which has a different key than desired

    Then:
        - Returns the dictionary with the wanted key changed

    """
    assert change_key(dict_input, prev_key, new_key) == expected_result


def test_keys_to_lowercase():
    """

    Given:
        - Dictionary we want to change it's keys to decapitalized

    When:
        - Getting response about an alert, that has it's keys capitalized

    Then:
        - Returns the dictionary with it's keys decapitalized

    """
    with open("TestData/keys_to_lowercase.json") as keys_to_lowercase_file:
        keys_to_lowercase_data = json.load(keys_to_lowercase_file)
    dict_input = keys_to_lowercase_data["dict_input"]
    expected_result = keys_to_lowercase_data["expected_result"]
    assert keys_to_lowercase(dict_input) == expected_result


first_capitalized = ("Id", "id")
decapitalize_only_first = ("NewStateDate", "newStateDate")
empty_string = ("", "")
DECAPITALIZE_VALUES = [first_capitalized, decapitalize_only_first, empty_string]


@pytest.mark.parametrize("str_input, expected_output", DECAPITALIZE_VALUES)
def test_decapitalize(str_input, expected_output):
    """

    Given:
        - A string we want to decapitalize

    When:
        - Getting response about an alert, that has it's keys capitalized, this is executed to lower the keys in the dictionary

    Then:
        - Returns the string decapitalized

    """
    assert decapitalize(str_input) == expected_output


first_fetch_hour_ago = (
    None,
    "1 hour",  # equals to 2020-07-29 10:00:00 UTC
    dateparser.parse("2020-07-29 10:00:00 UTC").replace(tzinfo=utc, microsecond=0),
)
first_fetch_day_ago = (
    None,
    "3 days",  # equals to 2020-07-26 11:00:00 UTC
    dateparser.parse("2020-07-26 11:00:00 UTC").replace(tzinfo=utc, microsecond=0),
)
fetch_from_closer_time_last_fetched = (
    "1595847600",  # epoch time for 2020-07-27 11:00:00 UTC
    "3 days",  # equals to 2020-07-26 11:00:00 UTC
    dateparser.parse("2020-07-27 11:00:00 UTC").replace(tzinfo=utc, microsecond=0),
)
fetch_from_closer_time_given_human = (
    "1595847600",  # epoch time for 2020-07-27 11:00:00 UTC
    "2 hours",  # equals to 2020-07-29 09:00:00 UTC
    dateparser.parse("2020-07-29 9:00:00 UTC").replace(tzinfo=utc, microsecond=0),
)
fetch_from_closer_time_given_epoch = (
    "1595847600",  # epoch time for 2020-07-27 11:00:00 UTC
    "1596013200",  # epoch time for 2020-07-29 9:00:00 UTC
    dateparser.parse("2020-07-29 9:00:00 UTC").replace(tzinfo=utc, microsecond=0),
)
FETCH_START_TIME_VALUES = [
    first_fetch_hour_ago,
    first_fetch_day_ago,
    fetch_from_closer_time_last_fetched,
    fetch_from_closer_time_given_human,
    fetch_from_closer_time_given_epoch,
]


@pytest.mark.parametrize("last_fetch, first_fetch, expected_output", FETCH_START_TIME_VALUES)
@freeze_time("2020-07-29 11:00:00 UTC")
def test_calculate_fetch_start_time(last_fetch, first_fetch, expected_output):
    """

    Given:
        - Fetch incidents runs

    When:
        - Needs to calculate the time to start fetching from

    Then:
        - Returns the time to fetch from - the latter of the 2 given

    """
    # works only with lint due to freeze_time
    assert calculate_fetch_start_time(last_fetch, first_fetch) == expected_output


with open("TestData/parse_alerts_values.json") as parse_alerts_values_file:
    parse_alerts_values_data = json.load(parse_alerts_values_file)

no_alerts_to_fetch = (
    [],
    5,
    dateparser.parse("2021-06-09 15:20:01 UTC").replace(tzinfo=utc, microsecond=0),
    2,
    dateparser.parse("2021-06-09 15:20:01 UTC").replace(tzinfo=utc, microsecond=0),
    2,
    [],
)
after_one_alert_was_fetched_high_limit = (
    parse_alerts_values_data["after_one_alert_was_fetched_high_limit"],
    10,
    dateparser.parse("2021-06-09 15:20:01 UTC").replace(tzinfo=utc, microsecond=0),
    1,
    dateparser.parse("2021-07-29 14:03:20 UTC").replace(tzinfo=utc, microsecond=0),
    2,
    ["TryAlert", "Adi's Alert"],
)
after_one_alert_was_fetched_low_limit = (
    parse_alerts_values_data["after_one_alert_was_fetched_low_limit"],
    1,
    dateparser.parse("2021-06-09 15:20:01 UTC").replace(tzinfo=utc, microsecond=0),
    1,
    dateparser.parse("2021-07-08 12:08:40 UTC").replace(tzinfo=utc, microsecond=0),
    3,
    ["TryAlert"],
)
first_fetch_high_limit = (
    parse_alerts_values_data["first_fetch_high_limit"],
    100,
    dateparser.parse("2020-06-08 10:00:00 UTC").replace(tzinfo=utc, microsecond=0),
    -1,
    dateparser.parse("2021-07-29 14:03:20 UTC").replace(tzinfo=utc, microsecond=0),
    2,
    ["Arseny's Alert", "TryAlert", "Adi's Alert"],
)
first_fetch_low_limit = (
    parse_alerts_values_data["first_fetch_low_limit"],
    2,
    dateparser.parse("2020-06-08 10:00:00 UTC").replace(tzinfo=utc, microsecond=0),
    -1,
    dateparser.parse("2021-07-08 12:08:40 UTC").replace(tzinfo=utc, microsecond=0),
    3,
    ["Arseny's Alert", "TryAlert"],
)
limit_to_one_first_fetch = (
    parse_alerts_values_data["limit_to_one_first_fetch"],
    1,
    dateparser.parse("2020-06-08 10:00:00 UTC").replace(tzinfo=utc, microsecond=0),
    -1,
    dateparser.parse("2021-06-09 15:20:01 UTC").replace(tzinfo=utc, microsecond=0),
    1,
    ["Arseny's Alert"],
)
limit_to_one_second_fetch = (
    parse_alerts_values_data["limit_to_one_second_fetch"],
    1,
    dateparser.parse("2021-06-09 15:20:01 UTC").replace(tzinfo=utc, microsecond=0),
    1,
    dateparser.parse("2021-07-08 12:08:40 UTC").replace(tzinfo=utc, microsecond=0),
    3,
    ["TryAlert"],
)
same_time_at_fetch_bigger_id = (
    parse_alerts_values_data["same_time_at_fetch_bigger_id"],
    100,
    dateparser.parse("2021-07-08 12:08:40 UTC").replace(tzinfo=utc, microsecond=0),
    2,
    dateparser.parse("2021-07-08 12:08:40 UTC").replace(tzinfo=utc, microsecond=0),
    3,
    ["TryAlert"],
)
PARSE_ALERTS_VALUES = [
    limit_to_one_first_fetch,
    first_fetch_high_limit,
    after_one_alert_was_fetched_low_limit,
    after_one_alert_was_fetched_high_limit,
    no_alerts_to_fetch,
    same_time_at_fetch_bigger_id,
    first_fetch_low_limit,
    no_alerts_to_fetch,
    limit_to_one_second_fetch,
]


@pytest.mark.parametrize(
    "alerts, max_fetch, last_fetch, last_id_fetched, expected_output_time, expected_output_id, expected_incidents_names",
    PARSE_ALERTS_VALUES,
)
def test_parse_alerts(
    alerts, max_fetch, last_fetch, last_id_fetched, expected_output_time, expected_output_id, expected_incidents_names
):
    """

    Given:
        - Fetch incidents runs and got all alerts, that some of them will become fetched incidents

    When:
        - Needs to choose only the relevant incidents to fetch

    Then:
        - Returns the incidents fetched, the new time to fetch from next time and the last id fetched

    """
    output_time, output_id, output_incidents = parse_alerts(alerts, max_fetch, last_fetch, last_id_fetched)
    assert output_time == expected_output_time
    assert output_id == expected_output_id
    for i in range(len(expected_incidents_names)):
        assert output_incidents[i]["name"] == expected_incidents_names[i]


def test_alert_to_incident():
    """

    Given:
        - An alert fetched in fetch incidents

    When:
        - Fetch incidents runs and needs to turn the alert given into an incident to return

    Then:
        - Returns the incident created

    """
    alert = {
        "id": 2,
        "dashboardId": 2,
        "dashboardUid": "yzDQUOR7z",
        "dashboardSlug": "simple-streaming-example-adis-copy",
        "panelId": 5,
        "name": "Adi's Alert",
        "state": "no_data",
        "newStateDate": "2021-07-29T14:03:20Z",
        "evalDate": "0001-01-01T00:00:00Z",
        "evalData": {"noData": True},
    }
    expected_incident = {"name": "Adi's Alert", "occurred": "2021-07-29T14:03:20Z", "type": "Grafana Alert"}
    incident = alert_to_incident(alert)
    if incident:
        incident.pop("rawJSON")
    assert incident == expected_incident


with open("TestData/concatenate_url_values.json") as concatenate_url_values_file:
    concatenate_url_values_data = json.load(concatenate_url_values_file)

url_with_nothing_at_the_end = (
    "https://base_url",
    concatenate_url_values_data["url_with_nothing_at_the_end"][0],
    concatenate_url_values_data["url_with_nothing_at_the_end"][1],
)
url_with_end_character = (
    "https://00.000.000.000:0000/",
    concatenate_url_values_data["url_with_end_character"][0],
    concatenate_url_values_data["url_with_end_character"][1],
)
no_url_field_at_given_list = (
    "https://base_url",
    concatenate_url_values_data["no_url_field_at_given_list"][0],
    concatenate_url_values_data["no_url_field_at_given_list"][1],
)
CONCATENATE_URL_VALUES = [url_with_nothing_at_the_end, url_with_end_character, no_url_field_at_given_list]


@pytest.mark.parametrize("base_url, dict_input, expected_result", CONCATENATE_URL_VALUES)
def test_concatenate_url(base_url, dict_input, expected_result):
    """

    Given:
        - A url entry in a dictionary, with the value of the suffix only

    When:
        - The url is about to be shown to the user

    Then:
        - Returns the dictionary with the url value as base and suffix

    """
    client = create_client(url=base_url)
    assert client._concatenate_urls(dict_input) == expected_result


with open("TestData/alerts_to_filter_by_time.json") as alerts_to_filter_by_time_file:
    alerts_to_filter_by_time_data = json.load(alerts_to_filter_by_time_file)

first_fetch_high_limit = (
    alerts_to_filter_by_time_data["keep_all_alerts"][0],
    dateparser.parse("2020-06-08 10:00:00 UTC").replace(tzinfo=utc, microsecond=0),
    alerts_to_filter_by_time_data["keep_all_alerts"][1],
)
keep_two_alerts = (
    alerts_to_filter_by_time_data["keep_two_alerts"][0],
    dateparser.parse("2021-06-10 10:00:00 UTC").replace(tzinfo=utc, microsecond=0),
    alerts_to_filter_by_time_data["keep_two_alerts"][1],
)
keep_one_alert_same_time = (
    alerts_to_filter_by_time_data["keep_one_alert_same_time"][0],
    dateparser.parse("2021-07-29 14:03:20 UTC").replace(tzinfo=utc, microsecond=0),
    alerts_to_filter_by_time_data["keep_one_alert_same_time"][1],
)

ALERTS_TO_FILTER_BY_TIME = [first_fetch_high_limit, keep_two_alerts, keep_one_alert_same_time]


@pytest.mark.parametrize("alerts, last_fetch, expected_alerts", ALERTS_TO_FILTER_BY_TIME)
def test_filter_alerts_by_time(alerts, last_fetch, expected_alerts):
    """

    Given:
        - All alerts got from Grafana

    When:
        - Fetch incidents runs needs to filter alerts so only recent ones will be returned

    Then:
        - Returns the alerts that happened after the last fetch

    """
    assert filter_alerts_by_time(alerts, last_fetch) == expected_alerts


with open("TestData/alerts_to_filter_by_date.json") as alerts_to_filter_by_date_file:
    alerts_to_filter_by_date_data = json.load(alerts_to_filter_by_date_file)

keep_all_alerts_first_fetch = (
    alerts_to_filter_by_date_data["keep_all_alerts_first_fetch"][0],
    dateparser.parse("2020-06-08 10:00:00 UTC").replace(tzinfo=utc, microsecond=0),
    0,
    alerts_to_filter_by_date_data["keep_all_alerts_first_fetch"][1],
)
keep_all_alerts_not_first = (
    alerts_to_filter_by_date_data["keep_all_alerts_not_first"][0],
    dateparser.parse("2021-05-08 10:00:00 UTC").replace(tzinfo=utc, microsecond=0),
    2,
    alerts_to_filter_by_date_data["keep_all_alerts_not_first"][1],
)
# all alerts have the same time, last ID fetched is 2, so we want to get only ID 3 and not ID 1
keep_one_alert_greater_id_same_time = (
    alerts_to_filter_by_date_data["keep_one_alert_greater_id_same_time"][0],
    dateparser.parse("2021-07-08 12:08:40 UTC").replace(tzinfo=utc, microsecond=0),
    2,
    alerts_to_filter_by_date_data["keep_one_alert_greater_id_same_time"][1],
)
ALERTS_TO_FILTER_BY_DATE = [keep_all_alerts_first_fetch, keep_all_alerts_not_first, keep_one_alert_greater_id_same_time]


@pytest.mark.parametrize("alerts, last_fetch, last_id_fetched, expected_alerts", ALERTS_TO_FILTER_BY_DATE)
def test_filter_alerts_by_id(alerts, last_fetch, last_id_fetched, expected_alerts):
    """

    Given:
        - Alerts got from Grafana

    When:
        - Fetch incidents runs and needs to filter alerts so if more then one alert happened at the same time as the last fetched
        alert, only those that were not fetched will be fetched now

    Then:
        - Returns the alerts that need to be fetched

    """
    assert filter_alerts_by_id(alerts, last_fetch, last_id_fetched) == expected_alerts


with open("TestData/incidents_to_reduce.json") as incidents_to_reduce_file:
    incidents_to_reduce_data = json.load(incidents_to_reduce_file)

keep_all_incidents = (
    incidents_to_reduce_data["keep_all_incidents"][0],
    100,
    dateparser.parse("2020-06-08 10:00:00 UTC").replace(tzinfo=utc, microsecond=0),
    0,
    dateparser.parse("2021-07-29 14:03:20 UTC").replace(tzinfo=utc, microsecond=0),
    2,
    incidents_to_reduce_data["keep_all_incidents"][1],
)
limit_to_two = (
    incidents_to_reduce_data["limit_to_two"][0],
    2,
    dateparser.parse("2020-06-08 10:00:00 UTC").replace(tzinfo=utc, microsecond=0),
    5,
    dateparser.parse("2021-07-08 12:08:40 UTC").replace(tzinfo=utc, microsecond=0),
    3,
    incidents_to_reduce_data["limit_to_two"][1],
)
no_alerts = (
    [],
    150,
    dateparser.parse("2020-06-08 10:00:00 UTC").replace(tzinfo=utc, microsecond=0),
    5,
    dateparser.parse("2020-06-08 10:00:00 UTC").replace(tzinfo=utc, microsecond=0),
    5,
    [],
)
INCIDENTS_TO_REDUCE = [keep_all_incidents, limit_to_two, no_alerts]


@pytest.mark.parametrize(
    "alerts, limit, last_fetch, last_id_fetched, expected_last_fetch, expected_last_id, expected_incidents", INCIDENTS_TO_REDUCE
)
def test_reduce_incidents_to_limit(
    alerts, limit, last_fetch, last_id_fetched, expected_last_fetch, expected_last_id, expected_incidents
):
    """

    Given:
        - Alerts got from Grafana

    When:
        - Fetch incidents runs, after filtering alerts by date and by id, and after sorting it by date and then by id

    Then:
        - Returns new time and id fetched, and the alerts only up to the limit wanted

    """
    output_last_fetch, output_last_id, output_incidents = reduce_incidents_to_limit(alerts, limit, last_fetch, last_id_fetched)
    assert output_last_fetch == expected_last_fetch
    assert output_last_id == expected_last_id
    assert output_incidents == expected_incidents


STATES = ((None, []), ("", []), ("all", []), ("no_data,all", []), ("no_data,alerting", ["no_data", "alerting"]))


@pytest.mark.parametrize("state_input, state_output", STATES)
def test_set_state(state_input, state_output):
    """

    Given:
        - 'state' argument is or isn't given to the `alerts-list` command

    When:
        - `alerts-list` command is executed

    Then:
        - Returns the right states to get

    """
    assert set_state(state_input) == state_output


TIME_TO_EPOCH = ((None, None), ("now", 1596020400000), ("2021-10-04T15:21:57Z", 1633360917000))


@freeze_time("2020-07-29 11:00:00 UTC")
@pytest.mark.parametrize("time_input, time_output", TIME_TO_EPOCH)
def test_set_time_for_annotation(time_input, time_output):
    """

    Given:
        - 'time' and 'time_end' arguments are or aren't given to the `annotation-create` command

    When:
        - `annotation-create` command is executed

    Then:
        - Returns the right epoch time in millisecond resolution

    """
    # works only with lint due to freeze_time
    assert set_time_to_epoch_millisecond(time_input) == time_output


no_page_number = (None, "100", "Showing 100 results:\n")
no_page_size = ("50", None, "Showing results from page 50:\n")
no_page_number_size = (None, None, "")
page_number_size = ("1", "20", "Showing 20 results from page 1:\n")
PAGING_HEADING = (no_page_number, no_page_size, no_page_number_size, page_number_size)


@pytest.mark.parametrize("page_number, page_size, expected_output", PAGING_HEADING)
def test_paging_heading(page_number, page_size, expected_output):
    """

    Given:
        - 'page_number' and 'page_size' arguments are or aren't given to commands that have paging

    When:
        - A command that has paging is executed

    Then:
        - Returns the right sentence to write in the beginning of the readable output

    """
    assert paging_heading(page_number, page_size) == expected_output


""" COMMAND FUNCTIONS TESTS """


@pytest.fixture
def grafana_client():
    return Client("url")


def test_alerts_list_command(mocker, grafana_client):
    """
    Given:
        - All relevant arguments for the command that is executed

    When:
        - alerts-list command is executed

    Then:
        - The http request is called with the right arguments
    """
    http_request = mocker.patch.object(grafana_client, "_http_request")
    args = {
        "dashboard_id": "1",
        "panel_id": "2",
        "name": "ADash",
        "state": "no_data,paused",
        "limit": "50",
        "folder_id": "1",
        "dashboard_name": "Dash",
        "dashboard_tag": "tag",
    }
    alerts_list_command(grafana_client, args)
    http_request.assert_called_with(
        "GET",
        "api/alerts",
        params={
            "dashboardId": ["1"],
            "panelId": "2",
            "query": "ADash",
            "state": ["no_data", "paused"],
            "limit": "50",
            "folderId": ["1"],
            "dashboardQuery": "Dash",
            "dashboardTag": ["tag"],
        },
        headers=None,
    )


def test_alert_pause_command(mocker, grafana_client):
    """
    Given:
        - All relevant arguments for the command that is executed

    When:
        - alert-pause command is executed

    Then:
        - The http request is called with the right arguments
    """
    http_request = mocker.patch.object(grafana_client, "_http_request")
    args = {"alert_id": "4"}
    alert_pause_command(grafana_client, args)
    http_request.assert_called_with("POST", "api/alerts/4/pause", json_data={"paused": True}, headers=None)


def test_alert_unpause_command(mocker, grafana_client):
    """
    Given:
        - All relevant arguments for the command that is executed

    When:
        - alert-unpause command is executed

    Then:
        - The http request is called with the right arguments
    """
    http_request = mocker.patch.object(grafana_client, "_http_request")
    args = {"alert_id": "4"}
    alert_unpause_command(grafana_client, args)
    http_request.assert_called_with("POST", "api/alerts/4/pause", json_data={"paused": False}, headers=None)


def test_users_search_command(mocker, grafana_client):
    """
    Given:
        - All relevant arguments for the command that is executed

    When:
        - users-search command is executed

    Then:
        - The http request is called with the right arguments
    """
    http_request = mocker.patch.object(grafana_client, "_http_request")
    args = {"page_size": "1000", "page_number": "1", "query": "admin"}
    users_search_command(grafana_client, args)
    http_request.assert_called_with("GET", "api/users", params={"perpage": "1000", "page": "1", "query": "admin"}, headers=None)


def test_users_teams_command(mocker, grafana_client):
    """
    Given:
        - All relevant arguments for the command that is executed

    When:
        - user-teams-get command is executed

    Then:
        - The http request is called with the right arguments
    """
    http_request = mocker.patch.object(grafana_client, "_http_request")
    args = {"user_id": "4"}
    users_teams_command(grafana_client, args)
    http_request.assert_called_with("GET", "api/users/4/teams", headers=None)


def test_users_organization_command(mocker, grafana_client):
    """
    Given:
        - All relevant arguments for the command that is executed

    When:
        - user-orgs-get command is executed

    Then:
        - The http request is called with the right arguments
    """
    http_request = mocker.patch.object(grafana_client, "_http_request")
    args = {"user_id": "4"}
    users_organization_command(grafana_client, args)
    http_request.assert_called_with("GET", "api/users/4/orgs", headers=None)


def test_user_update_command(mocker, grafana_client):
    """
    Given:
        - All relevant arguments for the command that is executed

    When:
        - user-update command is executed

    Then:
        - The http request is called with the right arguments
    """
    http_request = mocker.patch.object(grafana_client, "_http_request")
    args = {"email": "e@mail", "name": "Name", "login": "login", "theme": "dark", "user_id": "2"}
    user_update_command(grafana_client, args)
    http_request.assert_called_with(
        "PUT", "api/users/2", json_data={"email": "e@mail", "login": "login", "name": "Name", "theme": "dark"}, headers=None
    )


def test_annotation_create_command(mocker, grafana_client):
    """
    Given:
        - All relevant arguments for the command that is executed

    When:
        - annotation-create command is executed

    Then:
        - The http request is called with the right arguments
    """
    # to pass this test you must run it using lint due to time conflicts
    http_request = mocker.patch.object(grafana_client, "_http_request")
    args = {
        "dashboard_id": "3",
        "panel_id": "2",
        "time": "2019-10-21T23:45:00",
        "time_end": "2019-10-21T23:45:01",
        "tags": "tag1",
        "text": "Text",
    }
    annotation_create_command(grafana_client, args)
    http_request.assert_called_with(
        "POST",
        "api/annotations",
        json_data={
            "dashboardId": 3,
            "panelId": 2,
            "tags": ["tag1"],
            "text": "Text",
            "time": 1571701500000,
            "timeEnd": 1571701501000,
        },
        headers=None,
    )


def test_teams_search_command(mocker, grafana_client):
    """
    Given:
        - All relevant arguments for the command that is executed

    When:
        - teams-search command is executed

    Then:
        - The http request is called with the right arguments
    """
    http_request = mocker.patch.object(grafana_client, "_http_request")
    args = {"page_size": "60", "page_number": "2", "query": "team", "name": "team_name"}
    teams_search_command(grafana_client, args)
    http_request.assert_called_with(
        "GET", "api/teams/search", params={"perpage": "60", "page": "2", "query": "team", "name": "team_name"}, headers=None
    )


def test_team_members_command(mocker, grafana_client):
    """
    Given:
        - All relevant arguments for the command that is executed

    When:
        - team-members-list command is executed

    Then:
        - The http request is called with the right arguments
    """
    http_request = mocker.patch.object(grafana_client, "_http_request")
    args = {"team_id": "16"}
    team_members_command(grafana_client, args)
    http_request.assert_called_with("GET", "api/teams/16/members", headers=None)


def test_user_add_to_team_command(mocker, grafana_client):
    """
    Given:
        - All relevant arguments for the command that is executed

    When:
        - user-add-to-team command is executed

    Then:
        - The http request is called with the right arguments
    """
    http_request = mocker.patch.object(grafana_client, "_http_request")
    args = {"user_id": "2", "team_id": "15"}
    user_add_to_team_command(grafana_client, args)
    http_request.assert_called_with("POST", "api/teams/15/members", json_data={"userId": 2}, headers=None, ok_codes=(200, 400))


def test_user_remove_from_team_command(mocker, grafana_client):
    """
    Given:
        - All relevant arguments for the command that is executed

    When:
        - user-remove-from-team command is executed

    Then:
        - The http request is called with the right arguments
    """
    http_request = mocker.patch.object(grafana_client, "_http_request")
    args = {"user_id": "3", "team_id": "17"}
    user_remove_from_team_command(grafana_client, args)
    http_request.assert_called_with("DELETE", "api/teams/17/members/3", headers=None)


def test_team_add_command(mocker, grafana_client):
    """
    Given:
        - All relevant arguments for the command that is executed

    When:
        - team-add command is executed

    Then:
        - The http request is called with the right arguments
    """
    http_request = mocker.patch.object(grafana_client, "_http_request")
    args = {"name": "New Team", "email": "new@email", "org_id": "2"}
    team_add_command(grafana_client, args)
    http_request.assert_called_with(
        "POST", "api/teams", json_data={"email": "new@email", "name": "New Team", "orgId": "2"}, headers=None
    )


def test_team_delete_command(mocker, grafana_client):
    """
    Given:
        - All relevant arguments for the command that is executed

    When:
        - team-delete command is executed

    Then:
        - The http request is called with the right arguments
    """
    http_request = mocker.patch.object(grafana_client, "_http_request")
    args = {"team_id": "4"}
    team_delete_command(grafana_client, args)
    http_request.assert_called_with("DELETE", "api/teams/4", headers=None)


def test_org_create_command(mocker, grafana_client):
    """
    Given:
        - All relevant arguments for the command that is executed

    When:
        - org-create command is executed

    Then:
        - The http request is called with the right arguments
    """
    http_request = mocker.patch.object(grafana_client, "_http_request")
    args = {"name": "NewOrg"}
    org_create_command(grafana_client, args)
    http_request.assert_called_with("POST", "api/orgs", json_data={"name": "NewOrg"}, headers=None)


def test_dashboards_search_command(mocker, grafana_client):
    """
    Given:
        - All relevant arguments for the command that is executed

    When:
        - dashboards-search command is executed

    Then:
        - The http request is called with the right arguments
    """
    http_request = mocker.patch.object(grafana_client, "_http_request")
    args = {
        "query": "dash",
        "tag": "tag1,tag2",
        "type": "dash-db",
        "dashboard_ids": "2,1",
        "folder_ids": "1,3",
        "starred": "false",
        "limit": "30",
        "page_number": "2",
    }
    dashboards_search_command(grafana_client, args)
    http_request.assert_called_with(
        "GET",
        "api/search",
        params={
            "query": "dash",
            "tag": ["tag1", "tag2"],
            "type": "dash-db",
            "dashboardIds": ["2", "1"],
            "folderIds": ["1", "3"],
            "starred": "false",
            "limit": "30",
            "page": "2",
        },
        headers=None,
    )


def test_user_get_by_id_command(mocker, grafana_client):
    """
    Given:
        - All relevant arguments for the command that is executed

    When:
        - user-get-by-id command is executed

    Then:
        - The http request is called with the right arguments
    """
    http_request = mocker.patch.object(grafana_client, "_http_request")
    args = {"user_id": "6"}
    user_get_by_id_command(grafana_client, args)
    http_request.assert_called_with("GET", "api/users/6", headers=None)


def test_team_get_by_id_command(mocker, grafana_client):
    """
    Given:
        - All relevant arguments for the command that is executed

    When:
        - team-get-by-id command is executed

    Then:
        - The http request is called with the right arguments
    """
    http_request = mocker.patch.object(grafana_client, "_http_request")
    args = {"team_id": "7"}
    team_get_by_id_command(grafana_client, args)
    http_request.assert_called_with("GET", "api/teams/7", headers=None)


def test_alert_get_by_id_command(mocker, grafana_client):
    """
    Given:
        - All relevant arguments for the command that is executed

    When:
        - alert-get-by-id command is executed

    Then:
        - The http request is called with the right arguments
    """
    http_request = mocker.patch.object(grafana_client, "_http_request")
    args = {"alert_id": "4"}
    alert_get_by_id_command(grafana_client, args)
    http_request.assert_called_with("GET", "api/alerts/4", headers=None)


def test_org_list_command(mocker, grafana_client):
    """
    Given:
        - All relevant arguments for the command that is executed

    When:
        - org-list command is executed

    Then:
        - The http request is called with the right arguments
    """
    http_request = mocker.patch.object(grafana_client, "_http_request")
    args = {"page_size": "40", "page_number": "0"}
    org_list_command(grafana_client, args)
    http_request.assert_called_with("GET", "api/orgs", params={"perpage": "40", "page": "0"}, headers=None)


def test_org_get_by_name_command(mocker, grafana_client):
    """
    Given:
        - All relevant arguments for the command that is executed

    When:
        - org-get-by-name command is executed

    Then:
        - The http request is called with the right arguments
    """
    http_request = mocker.patch.object(grafana_client, "_http_request")
    args = {"name": "OrgName"}
    org_get_by_name_command(grafana_client, args)
    http_request.assert_called_with("GET", "api/orgs/name/OrgName", headers=None)


def test_org_get_by_id_command(mocker, grafana_client):
    """
    Given:
        - All relevant arguments for the command that is executed

    When:
        - org-get-by-id command is executed

    Then:
        - The http request is called with the right arguments
    """
    http_request = mocker.patch.object(grafana_client, "_http_request")
    args = {"org_id": "114"}
    org_get_by_id_command(grafana_client, args)
    http_request.assert_called_with("GET", "api/orgs/114", headers=None)