Add Line of Business Hierarchy - Aggregations and Dashboards

This sample step-by-step configuration is to expand your Service catalog data in configure8 by adding a higher level entity that is composed of multiple services

In this sample we are also showing how to create custom aggregations and dashboards based on the relations from the new schema, providing a great high level view of all catalog info from the sub-entities.

You can check this video for an overview or follow the step-by-step docs below to setup on yourself.

Create the schema

Logged in with an Admin user, go to the schemas page and "+ Add Schema".

Form JSON Schema

This is where you're defining the fields of your schema. You can customize this data to your organizations needs, by changing, adding or removing fields.

In this sample we are just adding a "Description" field. All the other data and aggregations will come through the services relation.

{
  "$schema": "http://json-schema.org/draft-07/schema",
  "properties": {
    "Description": {
      "type": "string"
    }
  }
}

Data Model JSON

This is where you define which and how the table columns will be showed in the Line of Business catalog menu.

This is where we build the aggregations that pull data from the relations with Services.

This JSON use the concepts of calculated properties and custom columns formatting. See more about calculated properties here. Full info on how to format columns display here.

Sample code with all aggregations and formatting:
[
  {
    "hidden": true,
    "name": "Description",
    "columnName": "Description",
    "calc": "details.Description"
  },
  {
    "hidden": false,
    "name": "openPR",
    "columnName": "Open PRs",
    "calc": {
      "type": "FUNCTION",
      "aggregation": "SUM",
      "path": "ProdServices.details.openedPR"
    },
    "format": {
      "displayValue": {
        "type": "number",
        "value": "{self}"
      },
      "label": {
        "type": "tag",
        "options": [
          {
            "color": "orange"
          }
        ]
      }
    }
  },
  {
    "hidden": false,
    "name": "TotalCosts",
    "columnName": "Total Costs",
    "calc": {
      "type": "FUNCTION",
      "aggregation": "SUM",
      "path": "ProdServices.resources.costs.cost"
    }
  },
  {
    "hidden": false,
    "name": "DevCosts",
    "columnName": "Dev Costs",
    "calc": {
      "type": "FUNCTION",
      "aggregation": "SUM",
      "path": "ProdServices.resources.costs.cost",
      "filter": [
        {
          "type": "compare",
          "field": "ProdServices.environments.name",
          "value": "dev",
          "compare": "eq"
        }
      ]
    }
  },
  {
    "hidden": false,
    "name": "QACosts",
    "columnName": "QA Costs",
    "calc": {
      "type": "FUNCTION",
      "aggregation": "SUM",
      "path": "ProdServices.resources.costs.cost",
      "filter": [
        {
          "type": "compare",
          "field": "ProdServices.environments.name",
          "value": "QA",
          "compare": "eq"
        }
      ]
    }
  },
  {
    "hidden": false,
    "name": "ProductionCosts",
    "columnName": "Production Costs",
    "calc": {
      "type": "FUNCTION",
      "aggregation": "SUM",
      "path": "ProdServices.resources.costs.cost",
      "filter": [
        {
          "type": "compare",
          "field": "ProdServices.environments.name",
          "value": "production",
          "compare": "eq"
        }
      ]
    }
  },
  {
    "hidden": true,
    "name": "ScorecardMetricResults",
    "columnName": "Scorecard checks number",
    "calc": {
      "type": "FUNCTION",
      "aggregation": "COUNT",
      "path": "ProdServices.scorecardMetricResultsServices.scorecard.metrics.id"
    }
  },
  {
    "hidden": false,
    "name": "ScorecardMetricResultsFail",
    "columnName": "Scorecard checks failing",
    "calc": {
      "type": "FUNCTION",
      "aggregation": "COUNT",
      "path": "ProdServices.scorecardMetricResultsServices.scorecard.metrics.id",
      "filter": [
        {
          "type": "compare",
          "field": "ProdServices.scorecardMetricResultsServices.pass",
          "value": "false",
          "compare": "eq"
        }
      ]
    }
  },
  {
    "hidden": false,
    "columnName": "Checks Passing",
    "name": "percentageScorecardsChecks",
    "format": {
      "displayValue": {
        "decimal": 0,
        "type": "number",
        "value": "{self}%"
      }
    },
    "calc": {
      "type": "MATH",
      "condition": "*",
      "values": [
        {
          "type": "MATH",
          "condition": "/",
          "values": [
            {
              "type": "REGULAR_FUNCTION",
              "function": "NVL",
              "values": [
                {
                  "type": "FUNCTION",
                  "aggregation": "COUNT",
                  "path": "ProdServices.scorecardMetricResultsServices.serviceId",
                  "filter": [
                    {
                      "type": "compare",
                      "field": "ProdServices.scorecardMetricResultsServices.pass",
                      "value": true,
                      "compare": "eq"
                    }
                  ]
                },
                {
                  "type": "NUMBER",
                  "value": 0
                }
              ]
            },
            {
              "type": "REGULAR_FUNCTION",
              "function": "NVL",
              "values": [
                {
                  "type": "FUNCTION",
                  "aggregation": "COUNT",
                  "path": "ProdServices.scorecardMetricResultsServices.serviceId"
                },
                {
                  "type": "NUMBER",
                  "value": 0
                }
              ]
            }
          ]
        },
        {
          "type": "NUMBER",
          "value": 100
        }
      ]
    }
  },
  {
    "hidden": true,
    "name": "passingScorecardsChecks",
    "columnName": "Scorecards checks passing",
    "calc": {
      "type": "REGULAR_FUNCTION",
      "function": "NVL",
      "values": [
        {
          "type": "FUNCTION",
          "aggregation": "COUNT",
          "path": "ProdServices.scorecardMetricResultsServices.serviceId",
          "filter": [
            {
              "type": "compare",
              "field": "ProdServices.scorecardMetricResultsServices.pass",
              "value": true,
              "compare": "eq"
            }
          ]
        },
        {
          "type": "NUMBER",
          "value": 0
        }
      ]
    }
  },
  {
    "hidden": true,
    "name": "ScorecardMetricResultsPass",
    "columnName": "Scorecard checks passing",
    "calc": {
      "type": "FUNCTION",
      "aggregation": "COUNT",
      "path": "ProdServices.scorecardMetricResultsServices.scorecard.metrics.id",
      "filter": [
        {
          "type": "compare",
          "field": "ProdServices.scorecardMetricResultsServices.pass",
          "value": "true",
          "compare": "eq"
        }
      ]
    }
  },
  {
    "hidden": false,
    "name": "DORADF",
    "columnName": "Deploys",
    "calc": {
      "type": "FUNCTION",
      "aggregation": "COUNT",
      "path": "ProdServices.ServiceDeploys.id",
      "filter": [
        {
          "type": "compare",
          "field": "ProdServices.ServiceDeploys.details.Stop",
          "compare": "gte",
          "value": {
            "context": "startDate"
          }
        },
        {
          "type": "compare",
          "field": "ProdServices.ServiceDeploys.details.Stop",
          "compare": "lte",
          "value": {
            "context": "endDate"
          }
        }
      ]
    }
  },
  {
    "hidden": false,
    "columnName": "Change Failure Rate %",
    "name": "DORACFR",
    "calc": {
      "type": "MATH",
      "condition": "*",
      "values": [
        {
          "type": "MATH",
          "condition": "/",
          "values": [
            {
              "type": "FUNCTION",
              "aggregation": "COUNT",
              "path": "ProdServices.ServiceDeploys.DeployIncidents.id"
            },
            {
              "type": "FUNCTION",
              "aggregation": "COUNT",
              "path": "ProdServices.ServiceDeploys.id"
            }
          ]
        },
        {
          "type": "NUMBER",
          "value": 100
        }
      ]
    },
    "format": {
      "displayValue": {
        "type": "number",
        "value": "{self}%"
      },
      "link": "/services/{id}/dora-metrics",
      "label": {
        "type": "tag",
        "options": [
          {
            "value": "15",
            "compare": "less",
            "color": "#8CC572"
          },
          {
            "value": "30",
            "compare": "less",
            "color": "#CCCCCC"
          },
          {
            "value": "30",
            "compare": "greater",
            "color": "#D67176"
          }
        ]
      }
    }
  },
  {
    "hidden": false,
    "columnName": "Cycle Time(s)",
    "name": "DORALTC",
    "calc": {
      "type": "FUNCTION",
      "aggregation": "AVG",
      "path": "ProdServices.ServiceDeploys.details.Duration"
    }
  },
  {
    "hidden": false,
    "columnName": "Time to Restore(s)",
    "name": "DORAMTTR",
    "calc": {
      "type": "FUNCTION",
      "aggregation": "AVG",
      "path": "ProdServices.ServiceIncidents.details.Duration"
    }
  },
  {
    "hidden": false,
    "name": "Vulnerabilities",
    "columnName": "Vulneratibilties",
    "calc": {
      "type": "FUNCTION",
      "aggregation": "COUNT",
      "path": "ProdServices.resources.vulnerabilities.id"
    },
    "format": {
      "displayValue": {
        "type": "number",
        "value": "{self}"
      },
      "label": {
        "type": "tag",
        "options": [
          {
            "color": "red"
          }
        ]
      }
    }
  },
  {
    "hidden": false,
    "name": "eksCluster",
    "columnName": "EKS Clusters",
    "calc": {
      "type": "FUNCTION",
      "aggregation": "COUNT",
      "path": "ProdServices.resources.id",
      "filter": [
        {
          "type": "compare",
          "field": "ProdServices.resources.providerResourceType",
          "value": "AWS:EKS:Cluster",
          "compare": "eq"
        }
      ]
    }
  },
  {
    "hidden": false,
    "name": "ServiceNames",
    "columnName": "Service Names",
    "calc": {
      "type": "FUNCTION",
      "aggregation": "ARRAY_AGG",
      "values": [
        {
          "type": "REGULAR_FUNCTION",
          "function": "OBJECT_CONSTRUCT",
          "values": [
            {
              "type": "STRING",
              "value": "id"
            },
            {
              "type": "PATH",
              "path": "ProdServices.id"
            },
            {
              "type": "STRING",
              "value": "name"
            },
            {
              "type": "PATH",
              "path": "ProdServices.name"
            }
          ]
        }
      ]
    },
    "format": {
      "link": "/services/{self.id}",
      "displayValue": {
        "type": "string",
        "value": "{self.name}"
      }
    }
  }
]

This is how the aggregations and formatting will look like once you push data:

Relations

Next step is to create relations with the other schemas in 3. Relations -> + Add Relation.

After saving the schema a new menu will be shown in our catalog menu, under the link that is composed with the Schema identifier field. In this case https://app.configure8.io/dnr-line_of_business.

Tabs

In the section 4. Tabs you can add custom tabs to this schema. In this example it's particularly useful as we have a lot of aggregations and data from the services to build graphs, tables and dashboards.

As an example, you could have:

Dashboard sample

You can add widgets and build a custom Line of Business dashboard that looks like this:

Ownership cards JSON
[
  {
    "displayType": "card",
    "schema": "ProdServices",
    "maxItems": 1,
    "item": {
      "title": "Services",
      "endContent": "{{total}}"
    }
  },
  {
    "displayType": "card",
    "schema": "ProdServices.repositories",
    "maxItems": 1,
    "item": {
      "title": "Repositories",
      "endContent": "{{total}}"
    }
  },
  {
    "displayType": "card",
    "schema": "ProdServices.environments",
    "maxItems": 1,
    "item": {
      "title": "Environments",
      "endContent": "{{total}}"
    }
  },
  {
    "displayType": "card",
    "schema": "ProdServices.resources",
    "maxItems": 1,
    "item": {
      "title": "Resources",
      "endContent": "{{total}}"
    }
  },
  {
    "displayType": "card",
    "schema": "ProdServices.resources.vulnerabilities",
    "maxItems": 1,
    "item": {
      "title": "Vulnerabilities",
      "endContent": "{{total}}"
    }
  }
]
Costs graph per environment JSON
[
  {
    "displayType": "chart",
    "variant": "bar",
    "options": {
      "datasets": [
        {
          "schema": "ProdServices.resources",
          "data": "{{ item.accruedCosts }}",
          "label": "Accrued Cost",
          "color": "orange",
          "aggregate": {
            "field": "environments.name"
          }
        },
        {
          "schema": "ProdServices.resources",
          "data": "{{ item.priorPeriodCosts }}",
          "label": "Prior Period Cost",
          "color": "red",
          "aggregate": {
            "field": "environments.name"
          }
        }
      ]
    },
    "dateRange": {
      "enabled": true
    }
  }
]
Scorecards checks graph JSON
[
  {
    "displayType": "chart",
    "variant": "doughnut",
    "options": {
      "datasets": [
        {
          "schema": "ProdServices.scorecardMetricResultsServices",
          "aggregate": {
            "field": "pass"
          },
          "sort": {
            "direction": "ASC",
            "field": "value"
          },
          "color": [
            "#D67176"
          ],
          "label": "checks result",
          "filters": [
            {
              "compare": "eq",
              "field": "pass",
              "type": "compare",
              "value": false
            }
          ],
          "axisLabel": "Fail"
        },
        {
          "schema": "ProdServices.scorecardMetricResultsServices",
          "aggregate": {
            "field": "pass"
          },
          "sort": {
            "direction": "ASC",
            "field": "value"
          },
          "color": [
            "#8CC572"
          ],
          "label": "checks result",
          "filters": [
            {
              "compare": "eq",
              "field": "pass",
              "type": "compare",
              "value": true
            }
          ],
          "axisLabel": "Pass"
        }
      ]
    }
  }
]
Costs graph per service JSON
[
  {
    "displayType": "chart",
    "variant": "bar",
    "options": {
      "datasets": [
        {
          "schema": "ProdServices",
          "axisLabel": "{{ item.name }}",
          "data": "{{ item.accruedCosts }}",
          "label": "Accrued Cost",
          "color": "orange"
        },
        {
          "schema": "ProdServices",
          "axisLabel": "{{ item.name }}",
          "data": "{{ item.priorPeriodCosts }}",
          "label": "Prior Period Cost",
          "color": "red"
        }
      ]
    },
    "dateRange": {
      "enabled": true
    }
  }
]
Costs timeline
[
  {
    "displayType": "chart",
    "variant": "line",
    "options": {
      "datasets": [
        {
          "schema": "ProdServices.resources",
          "data": "{{ item.accruedCosts }}",
          "label": "Accrued Cost",
          "color": "#86BC25",
          "aggregate": {
            "field": "costs.date",
            "modifier": "by_date"
          },
          "sort": {
            "direction": "ASC",
            "field": "value"
          }
        }
      ]
    },
    "dateRange": {
      "enabled": true
    }
  }
]

Pushing data

You can manual insert data in the menu page by + Add New Entity, or push data via configure8 public API.

Last updated

Copyright © 2023 configure8, Inc. All rights reserved.