From 46e4e522c36744d6beec077274d9efbc4f329d09 Mon Sep 17 00:00:00 2001 From: Joao Fernandes Date: Fri, 6 Jan 2017 15:15:50 -0800 Subject: [PATCH] Introduce webhooks in DTR --- _data/toc.yaml | 2 + datacenter/dtr/2.2/guides/webhooks.md | 313 ++++++++++++++++++++++++++ 2 files changed, 315 insertions(+) create mode 100644 datacenter/dtr/2.2/guides/webhooks.md diff --git a/_data/toc.yaml b/_data/toc.yaml index bfb6b84b0a..de6b7f2508 100644 --- a/_data/toc.yaml +++ b/_data/toc.yaml @@ -1261,6 +1261,8 @@ toc: title: Cache Docker images - path: /datacenter/dtr/2.2/guides/security-scan-dtr/ title: Docker Security Scanning in DTR + - path: /datacenter/dtr/2.2/guides/webhooks/ + title: Create and manage webhooks - sectiontitle: API and CLI reference section: - path: /datacenter/dtr/2.2/reference/api/ diff --git a/datacenter/dtr/2.2/guides/webhooks.md b/datacenter/dtr/2.2/guides/webhooks.md new file mode 100644 index 0000000000..da9cab69eb --- /dev/null +++ b/datacenter/dtr/2.2/guides/webhooks.md @@ -0,0 +1,313 @@ +--- +title: Manage webhooks +description: Learn how to create, configure, and test webhooks in Docker Trusted Registry. +keywords: docker, registry, webhooks +--- + +DTR includes webhooks for common events, such as pushing a new tag or deleting +an image. This lets you build complex CI and CD pipelines from your own DTR +cluster. + +The webhook events you can subscribe to are: + +**Repository specific events** + +- Tag push +- Tag delete +- Manifest push +- Manifest delete +- Security scan completed +- Security scan failed + +**Namespace specific events** + +- Repo events (created/updated/deleted) + +**Global events** + +- Security scanner update complete + +In order to subscribe to an event you need to be at least an admin of the +particular repository (for repository events) or namespace +(for namespace events). A global administrator can subscribe to any event. +For example, a user must be an admin of repository "foo/bar" to subscribe to +its tag push events. + +## Subscribing to events + +In order to subscribe to events you must send an API query to +`/api/v0/webhooks` with the following payload: + +``` +{ + "type": "", + "key": "", + "endpoint": "https://example.com" +} +``` + +The keys in the payload are: + +- `type`: The event type. These are listed below. +- `key`: The namespace or repo to subscribe to (eg "foo/bar" to subscribe to +pushes to repo "bar" within namespace "foo") +- `endpoint`: The URL to send the POST payload to. + +Normal users **must** supply a "key" to scope a particular webhook event to +a repository or namespace. System administrators can choose to omit this, +meaning a webhook payload will be sent for **every** repository or namespace. + +### Event types + +**Repository specific events** + +- Tag push (type `TAG_PUSH`) +- Tag delete (type `TAG_DELETE`) +- Manifest push (type `MANIFEST_PUSH`) +- Manifest delete (type `MANIFEST_DELETE`) +- Security scan completed (type `SCAN_COMPLETED`) +- Security scan failed (type `SCAN_FAILED`) + +**Namespace specific events** + +- Repo created/updated/deleted (type `REPO_EVENT`) + +**Global events** + +- Security scanner update complete (type `SCANNER_UPDATE_COMPLETED`) + + +### Receiving a payload + +Whenever a suitable action occurs DTR will send a POST request to the given +endpoint with a JSON encoded payload. The payload will always have the +following wrapper: + +``` +{ + "type": "...", + "createdAt": "2012-04-23T18:25:43.511Z", + "contents": {...} +} +``` + +`type` refers to the event type being sent, and `contents` refers to +the payload of the event itself. Each event is different, therefore the +structure of the JSON object in `contents` will change depending on the event +type. These are listed in a section below. + +### Testing payload subscriptions + +Before subscribing to a payload you can view and test your endpoints using +fake data. To send a test payload, fire a `POST` request to +`/api/v0/webhooks/test` with the following payload: + +``` +{ + "type": "...", + "endpoint": "https://www.example.com/" +} +``` + +Change `type` to the event type that you want to receive. DTR will then send +an example payload to the endpoint specified. Note that the example +payload sent is always the same. + +## Content structure + +Note that comments (`// here`) are added for documentation only; they are not +present in POST payloads. + +### Repository event content structure + +**Tag push** + +``` +{ + "namespace": "", // (string) repository's namespace name + "repository": "", // (string) repository name + "tag": "", // (string) the name of the tag just pushed + "digest": "", // (string) sha256 digest of the manifest the tag points to (eg. "sha256:0afb...") + "imageName": "", // (string) the fully-qualified image name including DTR host used to pull the image (eg. 10.10.10.1/foo/bar:tag) + "os": "", // (string) the OS for the tag's manifest + "architecture": "", // (string) the architecture for the tag's manifest + "author": "", // (string) the username of the person who pushed the tag + "pushedAt": "", // (string) JSON encoded timestamp of when the push occurred +} +``` + +**Tag delete** + +``` +{ + "namespace": "", // (string) repository's namespace name + "repository": "", // (string) repository name + "tag": "", // (string) the name of the tag just deleted + "digest": "", // (string) sha256 digest of the manifest the tag points to (eg. "sha256:0afb...") + "imageName": "", // (string) the fully-qualified image name including DTR host used to pull the image (eg. 10.10.10.1/foo/bar:tag) + "os": "", // (string) the OS for the tag's manifest + "architecture": "", // (string) the architecture for the tag's manifest + "author": "", // (string) the username of the person who deleted the tag + "deletedAt": "", // (string) JSON encoded timestamp of when the delete occurred +} +``` +**Manifest push** + +``` +{ + "namespace": "", // (string) repository's namespace name + "repository": "", // (string) repository name + "digest": "", // (string) sha256 digest of the manifest (eg. "sha256:0afb...") + "imageName": "", // (string) the fully-qualified image name including DTR host used to pull the image (eg. 10.10.10.1/foo/bar@sha256:0afb...) + "os": "", // (string) the OS for the manifest + "architecture": "", // (string) the architecture for the manifest + "author": "", // (string) the username of the person who pushed the manifest + "pushedAt": "", // (string) JSON encoded timestamp of when the push occurred +} +``` + +**Manifest delete** + +``` +{ + "namespace": "", // (string) repository's namespace name + "repository": "", // (string) repository name + "digest": "", // (string) sha256 digest of the manifest (eg. "sha256:0afb...") + "imageName": "", // (string) the fully-qualified image name including DTR host used to pull the image (eg. 10.10.10.1/foo/bar@sha256:0afb...) + "os": "", // (string) the OS for the manifest + "architecture": "", // (string) the architecture for the manifest + "author": "", // (string) the username of the person who deleted the manifest + "deletedAt": "", // (string) JSON encoded timestamp of when the delete occurred +} +``` + +**Security scan completed** + +``` +{ + "namespace": "", // (string) repository's namespace name + "repository": "", // (string) repository name + "tag": "", // (string) the name of the tag scanned + "imageName": "", // (string) the fully-qualified image name including DTR host used to pull the image (eg. 10.10.10.1/foo/bar:tag) + "scanSummary": { + "namespace": "", // (string) repository's namespace name + "repository": "", // (string) repository name + "tag": "", // (string) the name of the tag just pushed + "critical": 0, // (int) number of critical issues, where CVSS >= 7.0 + "major": 0, // (int) number of major issues, where CVSS >= 4.0 && CVSS < 7 + "minor": 0, // (int) number of minor issues, where CVSS > 0 && CVSS < + "last_scan_status": 0, // (int) enum; see scan status section + "check_completed_at": "", // (string) JSON encoded timestamp of when the scan completed + } +} +``` + +**Security scan failed** + +``` +{ + "namespace": "", // (string) repository's namespace name + "repository": "", // (string) repository name + "tag": "", // (string) the name of the tag scanned + "imageName": "", // (string) the fully-qualified image name including DTR host used to pull the image (eg. 10.10.10.1/foo/bar@sha256:0afb...) + "error": "", // (string) the error that occurred whilst scanning +} +``` + +### Namespace specific event structure + +**Repository event (created/updated/deleted)** + +``` +{ + "namespace": "", // (string) repository's namespace name + "repository": "", // (string) repository name + "event": "", // (string) enum: "REPO_CREATED", "REPO_DELETED" or "REPO_UPDATED" + "author": "", // (string) the name of the user which authored the event + "data": {} // (object) when updating or creating a repo this follows the same format as an API response from /api/v0/repositories/{namespace}/{repository} +} +``` + +### Global event structure + +**Security scanner update complete** + +``` +{ + "scanner_version": "", + "scanner_updated_at": "", // (string) JSON encoded timestamp of when the scanner updated + "db_version": 0, // (int) newly updated database version + "db_updated_at": "", // (string) JSON encoded timestamp of when the database updated + "success": // (bool) whether the update was successful + "replicas": { // (object) a map keyed by replica ID containing update information for each replica + "replica_id": { + "db_updated_at": "", // (string) JSON encoded time of when the replica updated + "version": "", // (string) version updated to + "replica_id": "" // (string) replica ID + }, + ... + } +} +``` + +### Security scan status enums + + +- 0: Failed. An error occurred checking an image's layer +- 1: Unscanned. The image has not yet been scanned +- 2: Scanning: Scanning in progress +- 3: Pending: The image will be scanned when a worker is available +- 4: Scanned: The image has been scanned but vulnerabilities have not yet been checked +- 5: Checking: The image is being checked for vulnerabilities +- 6: Completed: The image has been fully security scanned + + +## Viewing and managing existing subscriptions + +### Viewing all subscriptions + +To view existing subscriptions make a GET request to `/api/v0/webhooks`. As +a normal user (ie. not a system administrator), this will show all of your +current subscriptions across every namespace and repository. As a system +administrator this will show **every** webhook within DTR. + +The API response will be in the following format: + +``` +[ + { + "id": "", // (string): UUID of the webhook subscription + "type": "", // (string): webhook event type + "key": "", // (string): the individual resource this subscription is scoped to + "endpoint": "", // (string): the endpoint in which the payload will be sent to via a POST request + "authorID": "", // (string): the ID of the user which created this subscription + "createdAt": "", // (string): JSON encoded datetime when this subscription was created + }, + ... +] +``` + +For more information view the API documentation. + +### Viewing subscriptions for a particular resource + +You can also view subscriptions for a given resource that you are an +administrator of. For example, if you have admin rights to the repository +"foo/bar" you can view all subscriptions (even other people's) from a +particular API endpoint. These endpoints are: + +- `/api/v0/repositories/{namespace}/{repository}/webhooks`: GET to view all +webhooks for a repository resource's events +- `/api/v0/repositories/{namespace}/webhooks`: GET to view all webhooks for a +namespace resource's events + +### Deleting a subscription + +To delete a webhook subscription send a `DELETE` request to +`/api/v0/webhooks/{id}`, replacing `{id}` with the webhook subscription ID +which you would like to delete. + +Note that in order to delete a subscription you must be either a system +administrator or an admistrator for the resource which the payload subscribes +to. For example, as a normal user you can only delete subscriptions for +repositories which you are an admin of.