Learn how to set up an event-triggered automation to assign tags to IT Component Fact Sheets based on the calculated energy consumption value.
Overview
IT components represent the technology (software and hardware) or services that an organization's applications depend on. To operate, IT components consume energy. Understanding the energy consumption levels of IT components allows organizations to effectively manage associated costs and plan their sustainability initiatives. For more information, see IT Component.
In this tutorial, you will learn how to set up an automation to assign tags to IT Component Fact Sheets based on their energy consumption values. Tags represent T-shirt sizes for each determined energy consumption range, such as XS, S, M, L, and XL.
The automation triggers every time the Fact Sheet field associated with energy consumption is updated. Based on this value, the corresponding tag representing a T-shirt size is assigned to the IT Component Fact Sheet.
Prerequisites
Before you start, do the following:
- Get admin access to your workspace.
- Obtain an API token by creating a technical user with admin permissions. For more information, see Creating a Technical User.
- Prepare a mapping matrix of T-shirt sizes to energy consumption ranges for IT components in your organization's infrastructure. The energy consumption of IT components can vary significantly depending on whether the component is a piece of software, server hardware, network equipment, or other forms of technology. See an example matrix in the following table.
Example mapping of T-shirt sizes to energy consumption ranges for server hardware:
T-Shirt Size | Energy Consumption Range |
---|---|
XS | 100-300 kWh/year |
S | 300-700 kWh/year |
M | 700-1,200 kWh/year |
L | 1,200-2,500 kWh/year |
XL | 2,500 kWh/year and higher |
This tutorial assumes you have basic knowledge of:
- Python
- GraphQL
- Webhooks
Step 1: Create a Custom Attribute for Energy Consumption on IT Component Fact Sheets
Follow these steps:
- On the user profile, select Administration, and then select Meta Model Configuration in the sidebar.
- On the Meta Model Configuration page, select the IT Component Fact Sheet. You land on the Fact Sheet configuration page.
- In the subsection where you want to place the custom attribute, click Add field. If needed, create a new section with a subsection.
- In the sidebar, specify the attribute details:
- In the Key field, enter a unique key that serves as the attribute identifier, such as
EnergyConsumptionLevel
. - In the Type list, select Integer.
- Specify other attribute details and click Create.
- On the tab indicated by the globe icon, enter translations for the attribute label to the target languages.
- In the Key field, enter a unique key that serves as the attribute identifier, such as
- In the sidebar, click Show changes, and then click Apply.
The custom attribute for energy consumption values is added to IT Component Fact Sheets.
Step 2: Create a Tag Group for T-Shirt Sizes
Create a tag group with tags representing T-shirt sizes. You can do it in the application user interface (UI) or through the GraphQL API. To learn how to manage tag groups in the application UI, see Tagging.
When creating a tag group, do the following:
- Restrict the tag group to IT Component Fact Sheets.
- Set the group mode to Single.
Step 3: Create a Webhook for Energy Consumption Updates
Create a webhook that triggers upon updates to the EnergyConsumptionLevel
field on IT Component Fact Sheets.
Follow these steps:
-
On the user profile, select Administration, and then select Webhooks in the sidebar.
-
On the Webhooks page, click New Webhook.
-
Specify the webhook details:
- Triggering Events: Select
FACT_SHEET_UPDATED
. - Managing User: Select a Technical User with admin permissions.
- Type: Select PUSH.
- Target URL: Enter the URL of the endpoint to send webhook notifications to. Before you complete other steps in this tutorial, enter a test target URL. To get a test URL, use tools such as Webhook.site.
- Triggering Events: Select
-
Optional: In the Callback field, enter JavaScript code to manipulate the webhook payload.
Example code:
var payload = delivery.payload; delivery.active = false; var tempDict = {}; tempDict['fields'] = []; var attributeList = ['EnergyConsumptionLevel']; if (payload.factSheet.type === 'ITComponent') { tempDict['id'] = payload.factSheet.id; tempDict['type'] = payload.factSheet.type; tempDict['rev'] = payload.factSheet.rev; for (var i = 0; i < payload.factSheet.fields.length; ++i) { if (attributeList.indexOf(payload.factSheet.fields[i].name) >= 0) { tempDict.fields.push({ key: payload.factSheet.fields[i].name, value: payload.factSheet.fields[i].data }); } } if (tempDict['fields'].length > 0) { delivery.payload = tempDict; delivery.active = true; } }
With the provided callback, the webhook payload appears as follows.
Example webhook payload:
{ "fields": [ { "key": "EnergyConsumptionLevel", "value": { "value": 820, "type": "IntegerValue" } } ], "id": "cb943942-39fd-4b45-8909-916b99c1286a", "type": "ITComponent", "rev": 15 }
-
Optional: Specify other optional webhook details.
-
Click Create.
A webhook with a test target URL is created. To test the webhook, update the energy consumption value on an IT Component Fact Sheet and verify the payload sent to the target URL.
Step 4: Create a Function to Assign Tags
Create a function to assign tags representing T-shirt sizes based on energy consumption ranges to IT Component Fact Sheets. You can use your preferred Function as a Service provider.
The function should do the following:
-
Perform authentication to SAP LeanIX services. For more information, see Authentication to SAP LeanIX Services.
-
Parse the webhook payload that contains the following:
- The updated value of the
EnergyConsumptionLevel
field - The ID of the associated IT Component Fact Sheet
- The updated value of the
-
Identify the tag to be assigned to the Fact Sheet based on the energy consumption value.
-
Retrieve the IDs of tags from the created tag group using a GraphQL query.
Example query:
{ allTags(filter: {tagGroupName: "Energy Consumption"}) { edges { node { id name } } } }
Example response:
{ "data": { "allTags": { "edges": [ { "node": { "id": "db9fbe30-8c75-4d3b-b498-e30b55da0872", "name": "XS" } }, { "node": { "id": "6977e724-d2ec-4692-b59b-fe47252ce28a", "name": "S" } }, { "node": { "id": "6b1e4df0-fea5-403f-90d5-755f79a5af9c", "name": "M" } }, { "node": { "id": "f84775e5-d57b-436c-8e37-342320e1aa21", "name": "L" } }, { "node": { "id": "0b16ee28-7c9d-43a9-b735-14d18a95a999", "name": "XL" } } ] } } }
-
Assign the appropriate tag to the Fact Sheet using a GraphQL mutation. For more information, see Add Tags to a Fact Sheet.
Example code:
import json
import logging
import os
import requests
logging.basicConfig(level=logging.INFO)
# Add a timeout to prevent the request hanging
TIMEOUT = 10
# API token and Subdomain are set as env variables.
# FaaS services support environment variables, it is adviced not to hard code
# sensitive information in your code.
LEANIX_API_TOKEN = os.getenv('LEANIX_API_TOKEN')
LEANIX_SUBDOMAIN = os.getenv('LEANIX_SUBDOMAIN')
LEANIX_GRAPHQL_URL = f'https://{LEANIX_SUBDOMAIN}.leanix.net/services/pathfinder/v1/graphql'
LEANIX_OAUTH2_URL = f'https://{LEANIX_SUBDOMAIN}.leanix.net/services/mtm/v1/oauth2/token'
# `T_SHIRT_SIZES` is a mapping of t-shirt sizes to their IDs, based on the output
# of a GraphQL query. Alternatively, you can programmatically call the query and
# parse the response, but this introduces overhead due to additional network
# requests.
T_SHIRT_SIZES = {
"XS": "db9fbe30-8c75-4d3b-b498-e30b55da0872",
"S": "6977e724-d2ec-4692-b59b-fe47252ce28a",
"M": "6b1e4df0-fea5-403f-90d5-755f79a5af9c",
"L": "f84775e5-d57b-436c-8e37-342320e1aa21",
"XL": "0b16ee28-7c9d-43a9-b735-14d18a95a999",
}
def _obtain_access_token():
"""Obtains a LeanIX Access token using the Technical User generated
API secret.
Returns:
str: The LeanIX Access Token
"""
if not LEANIX_API_TOKEN:
raise Exception('A valid token is required')
response = requests.post(
LEANIX_OAUTH2_URL,
auth=("apitoken", LEANIX_API_TOKEN),
data={"grant_type": "client_credentials"},
)
response.raise_for_status()
return response.json().get('access_token')
def _determine_t_shirt_size(payload):
"""Determines the appropriate T-shirt size tag based on the extracted energy
consumption value from the parsed payload.
Args:
payload (dict): The webhook payload
Returns:
Optional[str]: The t-shirt size of the energy consumption value.
"""
energy_consumption_level = None
t_shirt_size = None
# Loop through the payload fields
for field in payload["fields"]:
# Extract the `EnergyConsumptionLevel` value from the payload, convert it to
# an integer, and store it in the `energy_consumption_level` variable.
# Stop iterating the loop once the value has been found.
if field.get("key") == "EnergyConsumptionLevel":
energy_consumption_level = field.get("value", {}).get("value")
break
# Check the Energy Consumption t-shirt size
if energy_consumption_level is not None:
if 100 <= energy_consumption_level <= 300:
t_shirt_size = "XS"
elif 300 <= energy_consumption_level <= 700:
t_shirt_size = "S"
elif 700 <= energy_consumption_level <= 1200:
t_shirt_size = "M"
elif 1200 <= energy_consumption_level <= 2500:
t_shirt_size = "L"
return t_shirt_size
def update_fact_sheet(fact_sheet_id, t_shirt_size)
"""Tags the specified FactSheet with the appropriate t-shirt size
Energy Consumption tag.
Args:
fact_sheet_id (str): The FactSheet UUID to be updated.
t_shirt_size (str): The t-shirt size (XS, S, M, L, XL).
"""
# Fetch the `id` of the t-shirt size
t_shirt_size_id = T_SHIRT_SIZES.get(t_shirt_size)
# If there is no match `id` bail out
if not t_shirt_size_id:
logging.warning(f"Could not retrieve `id` for t-shirt size: {t_shirt_size}")
return
# The GraphQL mutation to `replace` the tag of the FactSheet
# `value` is a stringified list of the JSON object.
# NOTE: Use `\\` to escape the `value` fields
graphql_mutation = """
mutation {
updateFactSheet(
id: "%s",
patches:[
{
op: replace,
path: "/tags",
value: "[{\\"tagId\\": \\"%s\\"}]"
}
]
){
factSheet {
id
name
tags {
id
name
}
}
}
}
""" % (fact_sheet_id, t_shirt_size_id)
# Fetch the access token and set the Authorization Header
access_token = _obtain_access_token()
auth_header = f'Bearer {access_token}'
# Provide the headers
headers = {
"Authorization": auth_header,
}
response = requests.post(
LEANIX_GRAPHQL_URL,
data=json.dumps({"query": graphql_mutation}),
timeout=TIMEOUT,
headers=headers,
)
response.raise_for_status()
response_data = response.json()
# GraphQL always returns a 200 response even if errors are included
# as such we check if `errors` is not empty.
errors=response_data.get("errors", [])
if len(errors):
logging.error(f"Request was not successfull: {errors}")
return
logging.info(f"GraphQL mutation success: {response_data}")
def event_handler(payload):
"""Receives the webhook payload, extracts relevant information,
and initiates a GraphQL mutation to add the corresponding tag group.
Args:
payload (dict): The webhook payload
"""
if payload:
fact_sheet_id = payload.get("id")
t_shirt_size = _determine_t_shirt_size(payload)
if fact_sheet_id and t_shirt_size:
update_fact_sheet(fact_sheet_id, t_shirt_size)
else:
logging.error("Could not update FactSheet")
Before proceeding, test your function locally. When ready, deploy the function. For instructions, refer to the documentation of your FaaS provider.
Step 5: Update the Webhook with the Function URL
Once you've successfully tested the function, update the webhook with the function URL.
Follow these steps:
- On the user profile, select Administration, and then select Webhooks in the sidebar.
- On the Webhooks page, select the webhook that you created.
- In the Target URL field, enter the function URL.
- Click Save.
The automation is set up. To ensure that it works as expected, update the energy consumption value on a test Fact Sheet and verify that the corresponding tag is assigned.
Summary
In this tutorial, you learned how to calculate the total energy consumption value for IT component fact sheets and assign the corresponding tags representing T-shirt sizes using a Python script.