integrations: Add Rundeck webhook integration.

Co-authored-by: sbansal1999 <sbansal1999@gmail.com>
This commit is contained in:
Satyam Bansal 2023-04-07 22:43:21 +05:30 committed by GitHub
parent ee1a83996a
commit 338436dfbd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 290 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

@ -445,6 +445,7 @@ WEBHOOK_INTEGRATIONS: List[WebhookIntegration] = [
WebhookIntegration("raygun", ["monitoring"], display_name="Raygun"), WebhookIntegration("raygun", ["monitoring"], display_name="Raygun"),
WebhookIntegration("reviewboard", ["version-control"], display_name="Review Board"), WebhookIntegration("reviewboard", ["version-control"], display_name="Review Board"),
WebhookIntegration("rhodecode", ["version-control"], display_name="RhodeCode"), WebhookIntegration("rhodecode", ["version-control"], display_name="RhodeCode"),
WebhookIntegration("rundeck", ["deployment"], display_name="Rundeck"),
WebhookIntegration("semaphore", ["continuous-integration", "deployment"]), WebhookIntegration("semaphore", ["continuous-integration", "deployment"]),
WebhookIntegration("sentry", ["monitoring"]), WebhookIntegration("sentry", ["monitoring"]),
WebhookIntegration( WebhookIntegration(
@ -789,6 +790,7 @@ DOC_SCREENSHOT_CONFIG: Dict[str, List[BaseScreenshotConfig]] = {
"raygun": [ScreenshotConfig("new_error.json")], "raygun": [ScreenshotConfig("new_error.json")],
"reviewboard": [ScreenshotConfig("review_request_published.json")], "reviewboard": [ScreenshotConfig("review_request_published.json")],
"rhodecode": [ScreenshotConfig("push.json")], "rhodecode": [ScreenshotConfig("push.json")],
"rundeck": [ScreenshotConfig("start.json")],
"semaphore": [ScreenshotConfig("pull_request.json")], "semaphore": [ScreenshotConfig("pull_request.json")],
"sentry": [ "sentry": [
ScreenshotConfig("event_for_exception_python.json"), ScreenshotConfig("event_for_exception_python.json"),

View File

View File

@ -0,0 +1,18 @@
Receive Job Notifications in Zulip!
1. {!create-stream.md!}
1. {!create-bot-construct-url.md!}
1. Go to your Rundeck web interface and click on the desired job.
Click on **Actions** and then select **Edit this Job...**.
Go to the **Notifications** tab.
1. Next to the desired event, click **Add Notification**. Select
**Send Webhook** as the Notification Type. Enter the URL constructed
above. Ensure payload format is **JSON** and Method is **POST**.
Click **Save**.
{!congrats.md!}
![Rundeck Integration](/static/images/integrations/rundeck/001.png)

View File

@ -0,0 +1,31 @@
{
"trigger": "avgduration",
"status": "running",
"executionId": 6,
"execution": {
"id": 6,
"href": "http://localhost:4440/project/welcome-project-community/execution/show/6",
"permalink": null,
"status": "running",
"project": "welcome-project-community",
"executionType": "user",
"user": "admin",
"date-started": {
"unixtime": 1680848069313,
"date": "2023-04-07T06:14:29Z"
},
"job": {
"id": "a0296d93-4b10-48d7-8b7d-86ad3f603b85",
"averageDuration": 2408,
"name": "Global Log Filter Usage",
"group": "Basic Examples/Basic Workflows",
"project": "welcome-project-community",
"description": "Global Log Filter basic example.\r\n\r\nGlobal Log Filter allows you to capture information from the whole job. This example shows how to capture env command data and use it later in the next step as [key-value](https://docs.rundeck.com/docs/manual/log-filters/key-value-data.html#key-value-data) data.\r\n\r\nMore information [here](https://docs.rundeck.com/docs/manual/log-filters/#log-filters).",
"href": "http://localhost:4440/api/42/job/a0296d93-4b10-48d7-8b7d-86ad3f603b85",
"permalink": "http://localhost:4440/project/welcome-project-community/job/show/a0296d93-4b10-48d7-8b7d-86ad3f603b85"
},
"description": "env ('Using env command we can extract a lot of keys/values :-)') [... 3 steps]",
"argstring": null,
"serverUUID": "a14bc3e6-75e8-4fe4-a90d-a16dcc976bf6"
}
}

View File

@ -0,0 +1,31 @@
{
"trigger": "failure",
"status": "failed",
"executionId": 7,
"execution": {
"id": 7,
"href": "http://localhost:4440/project/welcome-project-community/execution/show/7",
"permalink": null,
"status": "failed",
"project": "welcome-project-community",
"executionType": "user",
"user": "admin",
"date-started": {
"unixtime": 1680848123396,
"date": "2023-04-07T06:15:23Z"
},
"job": {
"id": "a0296d93-4b10-48d7-8b7d-86ad3f603b85",
"averageDuration": 2659,
"name": "Global Log Filter Usage",
"group": "Basic Examples/Basic Workflows",
"project": "welcome-project-community",
"description": "Global Log Filter basic example.\r\n\r\nGlobal Log Filter allows you to capture information from the whole job. This example shows how to capture env command data and use it later in the next step as [key-value](https://docs.rundeck.com/docs/manual/log-filters/key-value-data.html#key-value-data) data.\r\n\r\nMore information [here](https://docs.rundeck.com/docs/manual/log-filters/#log-filters).",
"href": "http://localhost:4440/api/42/job/a0296d93-4b10-48d7-8b7d-86ad3f603b85",
"permalink": "http://localhost:4440/project/welcome-project-community/job/show/a0296d93-4b10-48d7-8b7d-86ad3f603b85"
},
"description": "env ('Using env command we can extract a lot of keys/values :-)') [... 4 steps]",
"argstring": null,
"serverUUID": "a14bc3e6-75e8-4fe4-a90d-a16dcc976bf6"
}
}

View File

@ -0,0 +1,23 @@
{
"trigger": "start",
"status": "scheduled",
"executionId": 12,
"execution": {
"id": 12,
"href": "https://rundeck.com/project/myproject/execution/follow/12",
"permalink": null,
"status": "scheduled",
"project": "myproject",
"executionType": "user",
"user": "guest",
"job": {
"id": "a0296d93-4b10-48d7-8b7d-86ad3f603b85",
"name": "Global Log Filter Usage",
"group": "Basic Examples/Basic Workflows",
"project": "MyProject",
"description": "Global Log Filter basic example. \n\nMore information: https://docs.rundeck.com/docs/manual/log-filters/#log-filters",
"href": "https://rundeck.com/api/1/job/a0296d93-4b10-48d7-8b7d-86ad3f603b85",
"permalink": "https://rundeck.com/project/myproject/job/show/a0296d93-4b10-48d7-8b7d-86ad3f603b85"
}
}
}

View File

@ -0,0 +1,31 @@
{
"trigger": "start",
"status": "running",
"executionId": 3,
"execution": {
"id": 3,
"href": "http://localhost:4440/project/welcome-project-community/execution/show/3",
"permalink": null,
"status": "running",
"project": "welcome-project-community",
"executionType": "user",
"user": "admin",
"date-started": {
"unixtime": 1680847933368,
"date": "2023-04-07T06:12:13Z"
},
"job": {
"id": "a0296d93-4b10-48d7-8b7d-86ad3f603b85",
"averageDuration": 2354,
"name": "Global Log Filter Usage",
"group": "Basic Examples/Basic Workflows",
"project": "welcome-project-community",
"description": "Global Log Filter basic example.\r\n\r\nGlobal Log Filter allows you to capture information from the whole job. This example shows how to capture env command data and use it later in the next step as [key-value](https://docs.rundeck.com/docs/manual/log-filters/key-value-data.html#key-value-data) data.\r\n\r\nMore information [here](https://docs.rundeck.com/docs/manual/log-filters/#log-filters).",
"href": "http://localhost:4440/api/42/job/a0296d93-4b10-48d7-8b7d-86ad3f603b85",
"permalink": "http://localhost:4440/project/welcome-project-community/job/show/a0296d93-4b10-48d7-8b7d-86ad3f603b85"
},
"description": "env ('Using env command we can extract a lot of keys/values :-)') [... 2 steps]",
"argstring": null,
"serverUUID": "a14bc3e6-75e8-4fe4-a90d-a16dcc976bf6"
}
}

View File

@ -0,0 +1,31 @@
{
"trigger": "success",
"status": "succeeded",
"executionId": 3,
"execution": {
"id": 3,
"href": "http://localhost:4440/project/welcome-project-community/execution/show/3",
"permalink": null,
"status": "succeeded",
"project": "welcome-project-community",
"executionType": "user",
"user": "admin",
"date-started": {
"unixtime": 1680847933368,
"date": "2023-04-07T06:12:13Z"
},
"job": {
"id": "a0296d93-4b10-48d7-8b7d-86ad3f603b85",
"averageDuration": 2354,
"name": "Global Log Filter Usage",
"group": "Basic Examples/Basic Workflows",
"project": "welcome-project-community",
"description": "Global Log Filter basic example.\r\n\r\nGlobal Log Filter allows you to capture information from the whole job. This example shows how to capture env command data and use it later in the next step as [key-value](https://docs.rundeck.com/docs/manual/log-filters/key-value-data.html#key-value-data) data.\r\n\r\nMore information [here](https://docs.rundeck.com/docs/manual/log-filters/#log-filters).",
"href": "http://localhost:4440/api/42/job/a0296d93-4b10-48d7-8b7d-86ad3f603b85",
"permalink": "http://localhost:4440/project/welcome-project-community/job/show/a0296d93-4b10-48d7-8b7d-86ad3f603b85"
},
"description": "env ('Using env command we can extract a lot of keys/values :-)') [... 2 steps]",
"argstring": null,
"serverUUID": "a14bc3e6-75e8-4fe4-a90d-a16dcc976bf6"
}
}

View File

@ -0,0 +1,58 @@
from zerver.lib.test_classes import WebhookTestCase
class RundeckHookTests(WebhookTestCase):
STREAM_NAME = "Rundeck"
TOPIC_NAME = "Global Log Filter Usage"
URL_TEMPLATE = "/api/v1/external/rundeck?&api_key={api_key}&stream={stream}"
WEBHOOK_DIR_NAME = "rundeck"
def test_start_message(self) -> None:
expected_message = "[Global Log Filter Usage](http://localhost:4440/project/welcome-project-community/job/show/a0296d93-4b10-48d7-8b7d-86ad3f603b85) execution [#3](http://localhost:4440/project/welcome-project-community/execution/show/3) for welcome-project-community has started. :running:"
self.check_webhook(
"start",
RundeckHookTests.TOPIC_NAME,
expected_message,
content_type="application/x-www-form-urlencoded",
)
def test_success_message(self) -> None:
expected_message = "[Global Log Filter Usage](http://localhost:4440/project/welcome-project-community/job/show/a0296d93-4b10-48d7-8b7d-86ad3f603b85) execution [#3](http://localhost:4440/project/welcome-project-community/execution/show/3) for welcome-project-community has succeeded. :check:"
self.check_webhook(
"success",
RundeckHookTests.TOPIC_NAME,
expected_message,
content_type="application/x-www-form-urlencoded",
)
def test_failure_message(self) -> None:
expected_message = "[Global Log Filter Usage](http://localhost:4440/project/welcome-project-community/job/show/a0296d93-4b10-48d7-8b7d-86ad3f603b85) execution [#7](http://localhost:4440/project/welcome-project-community/execution/show/7) for welcome-project-community has failed. :cross_mark:"
self.check_webhook(
"failure",
RundeckHookTests.TOPIC_NAME,
expected_message,
content_type="application/x-www-form-urlencoded",
)
def test_duration_message(self) -> None:
expected_message = "[Global Log Filter Usage](http://localhost:4440/project/welcome-project-community/job/show/a0296d93-4b10-48d7-8b7d-86ad3f603b85) execution [#6](http://localhost:4440/project/welcome-project-community/execution/show/6) for welcome-project-community is running long. :time_ticking:"
self.check_webhook(
"duration",
RundeckHookTests.TOPIC_NAME,
expected_message,
content_type="application/x-www-form-urlencoded",
)
def test_scheduled_start_message(self) -> None:
expected_message = "[Global Log Filter Usage](https://rundeck.com/project/myproject/job/show/a0296d93-4b10-48d7-8b7d-86ad3f603b85) execution [#12](https://rundeck.com/project/myproject/execution/follow/12) for myproject has started. :running:"
self.check_webhook(
"scheduled_start",
RundeckHookTests.TOPIC_NAME,
expected_message,
content_type="application/x-www-form-urlencoded",
)

View File

@ -0,0 +1,65 @@
from django.http import HttpRequest, HttpResponse
from zerver.decorator import webhook_view
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_success
from zerver.lib.validator import WildValue, check_int, check_string, to_wild_value
from zerver.lib.webhooks.common import check_send_webhook_message
from zerver.models import UserProfile
RUNDECK_MESSAGE_TEMPLATE = "[{job_name}]({job_link}) execution [#{execution_id}]({execution_link}) for {project_name} {status}. :{emoji}:"
RUNDECK_TOPIC_TEMPLATE = "{job_name}"
@webhook_view("Rundeck")
@has_request_variables
def api_rundeck_webhook(
request: HttpRequest,
user_profile: UserProfile,
payload: WildValue = REQ(argument_type="body", converter=to_wild_value),
) -> HttpResponse:
subject = get_topic(payload)
body = get_body(payload)
check_send_webhook_message(request, user_profile, subject, body)
return json_success(request)
def get_topic(payload: WildValue) -> str:
return RUNDECK_TOPIC_TEMPLATE.format(
job_name=payload["execution"]["job"]["name"].tame(check_string)
)
def get_body(payload: WildValue) -> str:
message_data = {
"job_name": payload["execution"]["job"]["name"].tame(check_string),
"job_link": payload["execution"]["job"]["permalink"].tame(check_string),
"execution_id": payload["execution"]["id"].tame(check_int),
"execution_link": payload["execution"]["href"].tame(check_string),
"project_name": payload["execution"]["project"].tame(check_string),
"status": payload["execution"]["status"].tame(check_string),
}
status = payload["execution"]["status"].tame(check_string)
if status == "failed":
message_data["status"] = "has failed"
message_data["emoji"] = "cross_mark"
if status == "succeeded":
message_data["status"] = "has succeeded"
message_data["emoji"] = "check"
if status == "running":
if payload["trigger"].tame(check_string) == "avgduration":
message_data["status"] = "is running long"
message_data["emoji"] = "time_ticking"
else:
message_data["status"] = "has started"
message_data["emoji"] = "running"
if status == "scheduled":
message_data["status"] = "has started"
message_data["emoji"] = "running"
return RUNDECK_MESSAGE_TEMPLATE.format(**message_data)