JFrog
In this example you are going to create a webhook integration between your JFrog Server and Port. The integration will facilitate the ingestion of JFrog artifact, Docker tag and build entities into Port.
Port configuration
Create the following blueprint definitions:
Jfrog artifact blueprint
{
"identifier": "jfrogArtifact",
"description": "This blueprint represents an artifact in our JFrog catalog",
"title": "JFrog Artifact",
"icon": "JfrogXray",
"schema": {
"properties": {
"name": {
"type": "string",
"title": "Name",
"description": "Name of the artifact"
},
"path": {
"type": "string",
"title": "Path",
"description": "Path to artifact"
},
"sha256": {
"type": "string",
"title": "SHA 256",
"description": "SHA256 of the artifact"
},
"size": {
"type": "number",
"title": "Size",
"description": "Size of the artifact"
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"aggregationProperties": {},
"relations": {
"repository": {
"title": "Repository",
"description": "Repository of the artifact",
"target": "jfrogRepository",
"required": false,
"many": false
}
}
}
Jfrog Docker tag blueprint
{
"identifier": "jfrogDockerTag",
"description": "This blueprint represents a Docker tag in our Jfrog catalog",
"title": "JFrog Docker Tag",
"icon": "JfrogXray",
"schema": {
"properties": {
"name": {
"type": "string",
"title": "Name",
"description": "Name of the Docker tag"
},
"imageName": {
"type": "string",
"title": "Image Name",
"description": "Name of the Docker image"
},
"path": {
"type": "string",
"title": "Path",
"description": "Path to Docker tag"
},
"sha256": {
"type": "string",
"title": "SHA 256",
"description": "SHA256 of the Docker tag"
},
"size": {
"type": "number",
"title": "Size",
"description": "Size of the Docker tag"
},
"tag": {
"type": "string",
"title": "Docker tag",
"description": "Docker tag"
},
"platforms": {
"type": "array",
"title": "Platforms",
"description": "Platforms supported by image"
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"aggregationProperties": {},
"relations": {
"repository": {
"title": "Repository",
"description": "Repository of the artifact",
"target": "jfrogRepository",
"required": false,
"many": false
}
}
}
Jfrog repository blueprint
{
"identifier": "jfrogRepository",
"description": "This blueprint represents a repository on Jfrog",
"title": "JFrog Repository",
"icon": "JfrogXray",
"schema": {
"properties": {
"key": {
"type": "string",
"title": "Key",
"description": "Name of the repository"
},
"description": {
"type": "string",
"title": "Description",
"description": "Description of the repository"
},
"type": {
"type": "string",
"title": "Repository Type",
"description": "Type of the repository",
"enum": ["LOCAL", "REMOTE", "VIRTUAL", "FEDERATED", "DISTRIBUTION"],
"enumColors": {
"LOCAL": "blue",
"REMOTE": "bronze",
"VIRTUAL": "darkGray",
"FEDERATED": "green",
"DISTRIBUTION": "lightGray"
}
},
"url": {
"type": "string",
"title": "Repository URL",
"description": "URL to the repository",
"format": "url"
},
"packageType": {
"type": "string",
"title": "Package type",
"description": "Type of the package"
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"aggregationProperties": {},
"relations": {}
}
Jfrog build blueprint
{
"identifier": "jfrogBuild",
"description": "This blueprint represents a build from JFrog",
"title": "JFrog Build",
"icon": "JfrogXray",
"schema": {
"properties": {
"name": {
"type": "string",
"title": "Build name",
"description": "Name of the build"
},
"uri": {
"type": "string",
"title": "Build URI",
"description": "URI to the build"
},
"lastStarted": {
"type": "string",
"title": "Last build time",
"description": "Last time the build ran",
"format": "date-time"
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"aggregationProperties": {},
"relations": {}
}
You may modify the properties in your blueprints depending on what you want to track in your JFrog repositories and builds.
Create the following webhook configuration using Port's UI
JFrog webhook configuration
- Basic details tab - fill the following details:
- Title :
JFrog mapper
; - Identifier :
jfrogMapper
; - Description :
A webhook configuration to map JFrog repositories and builds to Port
; - Icon :
JfrogXray
;
- Title :
- Integration configuration tab - fill the following JQ mapping:
[
{
"blueprint": "jfrogBuild",
"filter": ".body.event_type == 'uploaded'",
"entity": {
"identifier": ".body.build_name",
"title": ".body.build_name",
"properties": {
"name": ".body.build_name",
"uri": "'/' + .body.build_name",
"lastStarted": ".body.build_started"
}
}
},
{
"blueprint": "jfrogDockerTag",
"filter": ".body.event_type == 'pushed'",
"entity": {
"identifier": ".body.name",
"title": ".body.name",
"properties": {
"name": ".body.name",
"imageName": ".body.image_name",
"path": ".body.path",
"sha256": ".body.sha256",
"size": ".body.size",
"tag": ".body.tag",
"platforms": ".body.platforms[] | \"(.os):(.architecture)\""
},
"relations": {
"repository": ".body.repo_key"
}
}
},
{
"blueprint": "jfrogArtifact",
"filter": ".body.event_type == 'deployed'",
"entity": {
"identifier": ".body.data.name",
"title": ".body.data.name",
"properties": {
"name": ".body.data.name",
"path": ".body.data.path",
"sha256": ".body.data.sha256",
"size": ".body.data.size"
},
"relations": {
"repository": ".body.data.repo_key"
}
}
}
]
Take note of, and copy the Webhook URL that is provided in this tab
- Click Save at the bottom of the page.
Create a webhook in JFrog
- Log in to JFrog as a user with admin privileges
- Click the gear icon at the top right corner at the left side of the user icon;
- Choose Platform Management;
- At the bottom of the sidebar on the left, just below General, choose Webhooks;
- Click on Create a WebHook
- Input the following details:
Name
- use a meaningful name such as Port-Artifact;Description
- enter a description for the webhook;URL
- enter the value of theurl
key you received after creating the webhook configuration in Port;Events
- Under Artifacts, select Artifact was deployed and select all repositories that apply;
- Click Create at the bottom of the page.
- Create two more webhooks using the details:
- For builds:
- Name: Port-Build;
- Events: Under Builds, select Build was uploaded and select all builds that apply;
Description
- enter a description for the webhook;URL
- enter the value of theurl
key you received after creating the webhook configuration in Port;
- For Docker tags:
- Name: Port-Docker-Tag;
- Events: Under Docker, select Docker tag was pushed and select all repositories that apply
- For builds:
In order to view the different payloads and events available in JFrog webhooks, look here
Done! Any artifact you publish, build you trigger, or artifact you upload will trigger a webhook event that JFrog will send to the webhook URL provided by Port. Port will parse the events according to the mapping and update the catalog entities accordingly.
Let's Test It
This section includes a sample webhook event sent from JFrog when a build is uploaded. In addition, it includes the entity created from the event based on the webhook configuration provided in the previous section.
Payload
Here is an example of the payload structure sent to the webhook URL when a JFrob build is uploaded:
Webhook event payload
{
"build_name": "sample_build_name",
"event_type": "uploaded",
"build_number": "1",
"build_started": "2020-06-18T14:40:49.869+0300"
}
Mapping Result
{
"identifier": "sample_build_name",
"title": "sample_build_name",
"blueprint": "jfrogBuild",
"properties": {
"name": "sample_build_name",
"uri": "/sample_build_name",
"lastStarted": "21 hours ago"
},
"relations": {},
"filter": true
}
Import JFrog Historical Builds And Repositories
In this example you are going to use the provided Python script to fetch data from the JFrog Server API and ingest it to Port.
Prerequisites
This example utilizes the same blueprint and webhook definition from the previous section.
In addition, you require the following environment variables:
PORT_CLIENT_ID
- Your Port client idPORT_CLIENT_SECRET
- Your Port client secretJFROG_ACCESS_TOKEN
- You can get that by following instructions in the Jfrog documentationJFROG_HOST_URL
- The host URL of your Jfrog instance
Find your Port credentials using this guide
Use the following Python script to ingest historical JFrog builds and repositories into port:
JFrog Python script for historical builds and repositories
# Dependencies to install
# pip install python-dotenv
# pip install requests
import logging
import os
import dotenv
import requests
dotenv.load_dotenv()
logger = logging.getLogger(__name__)
PORT_API_URL = "https://api.getport.io/v1"
PORT_CLIENT_ID = os.getenv("PORT_CLIENT_ID")
PORT_CLIENT_SECRET = os.getenv("PORT_CLIENT_SECRET")
JFROG_ACCESS_TOKEN = os.getenv("JFROG_ACCESS_TOKEN")
JFROG_HOST_URL = os.getenv("JFROG_HOST_URL")
class Blueprint:
REPOSITORY = "jfrogRepository"
BUILD = "jfrogBuild"
## Get Port Access Token
credentials = {"clientId": PORT_CLIENT_ID, "clientSecret": PORT_CLIENT_SECRET}
token_response = requests.post(f"{PORT_API_URL}/auth/access_token", json=credentials)
access_token = token_response.json()["accessToken"]
# You can now use the value in access_token when making further requests
headers = {"Authorization": f"Bearer {access_token}"}
def add_entity_to_port(blueprint_id, entity_object, transform_function):
"""A function to create the passed entity in Port
Params
--------------
blueprint_id: str
The blueprint id to create the entity in Port
entity_object: dict
The entity to add in your Port catalog
transform_function: function
A function to transform the entity object to the Port entity object
Returns
--------------
response: dict
The response object after calling the webhook
"""
logger.info(f"Adding entity to Port: {entity_object}")
entity_payload = transform_function(entity_object)
response = requests.post(
(
f"{PORT_API_URL}/blueprints/"
f"{blueprint_id}/entities?upsert=true&merge=true"
),
json=entity_payload,
headers=headers,
)
logger.info(response.json())
def get_all_builds():
logger.info("Getting all builds")
url = f"{JFROG_HOST_URL}/artifactory/api/build"
response = requests.get(
url, headers={"Authorization": "Bearer " + JFROG_ACCESS_TOKEN}
)
response.raise_for_status()
builds = response.json()["builds"]
return builds
def get_all_repositories():
logger.info("Getting all repositories")
url = f"{JFROG_HOST_URL}/artifactory/api/repositories"
response = requests.get(
url, headers={"Authorization": "Bearer " + JFROG_ACCESS_TOKEN}
)
response.raise_for_status()
repositories = response.json()
return repositories
if __name__ == "__main__":
logger.info("Starting Port integration")
for repository in get_all_repositories():
repository_object = {
"key": repository["key"],
"description": repository.get("description", ""),
"type": repository["type"].upper(),
"url": repository["url"],
"packageType": repository["packageType"].upper(),
}
transform_build_function = lambda x: {
"identifier": repository_object["key"],
"title": repository_object["key"],
"properties": {
**repository_object,
},
}
logger.info(f"Added repository: {repository_object['key']}")
add_entity_to_port(
Blueprint.REPOSITORY, repository_object, transform_build_function
)
logger.info("Completed repositories, starting builds")
for build in get_all_builds():
build_object = {
"name": build["uri"].split("/")[-1],
"uri": build["uri"],
"lastStarted": build["lastStarted"],
}
transform_build_function = lambda x: {
"identifier": build_object["name"],
"title": build_object["name"],
"properties": {
**build_object,
},
}
logger.info(f"Added build: {build_object['name']}")
add_entity_to_port(Blueprint.BUILD, build_object, transform_build_function)
Done! you can now import historical builds and repositories from JFrog into Port. Port will parse the builds and repository according to the mapping and update the catalog entities accordingly.