This documentation and the Cisco Observability Platform functionalities it describes are subject to change. Data saved on the platform may disappear and APIs may change without notice.


Solution Services Integration

In a solution, you can leverage the capabilities of zodiac:function in your Codex workflows to process any complex logic. The zodiac:function is invoked from the Codex workflow.

Important

You can invoke zodiac:function in your Codex workflows that are part of a solution layer, which tenants can subscribe to. It can not be invoked in Codex workflows that are part of a tenant layer.

To use the zodiac:function in a Codex workflow of your solution, you need to deploy:

  1. a solution with zodiac:function, iam:Permission, iam:RoleToPermissionMapping, and contracts:openAPI objects.

  2. a solution with the Codex workflow where the zodiac:function is invoked.

The solution with zodiac:function objects must be deployed before the solution with the Codex workflow.

Deploy Solution with Zodiac Function Objects

To add the zodiac:function objects in your solution bundle:

  1. Create an object of type zodiac:function. For example, the following codex-function.json is an object of the type zodiac:function:

        {
            "name": "codex-function",
            "image": "<CONTAINER_REGISTRY_ENDPOINT>:/codex-zodiac-image:1.0-65",
            "openAPI":"contracts:openAPI/codexzodiactest:/info/title=codexzodiactest;/info/version=0.1",
            "scaleBounds": {
                "lower": 2,
                "upper": 20
                },
            "concurrency": {
                "softLimit": 500,
                "targetUtilizationPercentage" : 20
                },
            "resources": {
                "requests": {
                "memory":"1Gi",
                "cpu": "2"
                },
            "limits": {
                "memory":"2Gi",
                "cpu":"4"
                }
            }
        }
    
  2. Create an object of the type contracts:openAPI and refer it inside the function object. For example, the following codexzodiactest.json is an object of the type contracts:openAPI:

        {
            "openapi": "3.0.1",
            "info": {
                "title": "codexzodiactest",
                "description": "A Codex Zodiac integration Function API",
                "contact": {
                "name": "CodexZodiacIntegration",
                "url": "https://appd-server.com",
                "email": "support@appd-server.com"
                },
                "license": {
                "name": "Apache 2.0",
                "url": "https://foo.bar"
                },
                "version": "0.1"
            },
            "servers": [
                {
                "url": "",
                "description": "Codex Zodiac integration Function call"
                }
            ],
            "paths": {
                "/data": {
                "get": {
                    "tags": [
                    "test-controller"
                    ],
                    "summary": "Retrieve data by codextest parameter",
                    "description": "Retrieves data based on the provided codextest parameter or returns default data if not provided",
                    "operationId": "getData",
                    "parameters": [
                    {
                        "name": "codextest",
                        "in": "query",
                        "required": false,
                        "schema": {
                        "type": "string"
                        }
                    }
                    ],
                    "responses": {
                    "200": {
                        "description": "Successful retrieval of data",
                        "content": {
                        "application/json": {
                            "schema": {
                            "$ref": "#/components/schemas/DataDto"
                            }
                        }
                        }
                    }
                    }
                }
            },
            "components": {
                "schemas": {
                "KeyValueDto": {
                    "type": "object",
                    "properties": {
                    "key": {
                        "type": "string"
                    },
                    "value": {
                        "type": "string"
                    }
                    }
                },
                "DataDto": {
                    "type": "object",
                    "properties": {
                    "data": {
                        "type": "object",
                        "additionalProperties": {
                        "type": "string"
                        }
                    }
                    }
                }
                }
            }
            }
       }
    
  3. Create an object of the type iam:Permission. For example, the following zodiac-permission.json is an object of the type iam:Permission:

      [
      {
          "name": "data",
          "description": "Permissions to use function endpoint",
          "displayName": "Codex Zodiac Function",
          "actionAndResources": [
              {
                  "action": {
                    "type": "HttpAction",
                    "method": "GET",
                    "classification": "READ",
                    "pathPattern": "/codex-function-perf-test/data"
                  }
              }
          ]
      },
      {
          "name": "testdata",
          "description": "Permissions to use function endpoint",
          "displayName": "Codex Zodiac Function",
          "actionAndResources": [
              {
                  "action": {
                    "type": "HttpAction",
                    "method": "POST",
                    "classification": "READ",
                    "pathPattern": "/codex-function-perf-test/testdata"
                  }
              }
          ]
      },
      {
          "name": "codexqe",
          "description": "Permissions to use function endpoint",
          "displayName": "Codex Zodiac Function",
          "actionAndResources": [
              {
                  "action": {
                    "type": "HttpAction",
                    "method": "POST",
                    "classification": "CREATE",
                    "pathPattern": "/codex-function-perf-test/codexqe"
                  }
              },
              {
                  "action": {
                    "type": "HttpAction",
                    "method": "GET",
                    "classification": "READ",
                    "pathPattern": "/codex-function-perf-test/codexqe"
                  }
              },
              {
                  "action": {
                    "type": "HttpAction",
                    "method": "PUT",
                    "classification": "UPDATE",
                    "pathPattern": "/codex-function-perf-test/codexqe"
                  }
              },
              {
                  "action": {
                    "type": "HttpAction",
                    "method": "DELETE",
                    "classification": "DELETE",
                    "pathPattern": "/codex-function-perf-test/codexqe"
                  }
              },
              {
                  "action": {
                    "type": "HttpAction",
                    "method": "PATCH",
                    "classification": "UPDATE",
                    "pathPattern": "/codex-function-perf-test/codexqe"
                  }
              }
            ]
      }
      ]
    
  4. Create an object of the type iam:RoleToPermissionMapping. For example, the following role-to-permission-mappings.json is an object of the type iam:RoleToPermissionMapping:

    
      [
      {
          "name": "tenantAdminPermissions",
          "roles": [
            "iam:tenantAdmin",
            "iam:observer"
          ],
          "permissions": [
            {
              "id": "codexzodiacperf:data"
            },
            {
              "id": "codexzodiacperf:testdata"
            },
            {
              "id": "codexzodiacperf:codexqe"
            }
          ]
      }
      ]
    
  5. In your solution's manifest.json file, declare contracts and zodiac as dependencies and define the objects. For example:

            {
            "name": "codexzodiactest",
            "solutionVersion": "1.0.1",
            "manifestVersion": "1.0.0",
            "dependencies": ["zodiac", "contracts"],
            "description": "Zodiac objects for Perf testing",
            "contact": "support@appd.com",
            "gitRepoUrl": "<Your git URL>",
            "types": [],
            "objects": [
                {
                    "type": "zodiac:function",
                    "objectsFile": "objects/functions/codex-function-perf.json"
                },
                {
                  "type": "iam:Permission"
                  "objectsFile": "objects/iam/zodiac-permission.json",
                },
                {
                  "type": "iam:RoleToPermissionMapping"
                  "objectsFile": "objects/iam/role-to-permission-mappings.json",
                },
                {
                    "type": "contracts:openAPI",
                    "objectsFile": "objects/openapi/codexzodiactest.json"
                }
            ]
            }
    
  6. Each time you modify your solution:

Deploy a Solution with Codex Workflow

In the solution with the Codex workflow, do the following:

  1. In the Codex workflow, define the zodiac:function definition. For example:

        {
        "name": "getrestFunction",
        "type": "rest",
        "operation": "zodiac://zodiac:function/codexzodiac:codex-function#getData"
        }
    
  2. In the Codex workflow, invoke the zodiac:function. For example:

        {
            "name": "InvokeRestFunction",
            "type": "operation",
            "actions": [
                {
                "functionRef": {
                    "refName": "getrestFunction",
                    "arguments": {
                    "codextest":"trace2event-http-get"
                    }
                },
                "actionDataFilter": {
                    "toStateData": "${ getOutput }"
                }
                }
            ],
            "transition": "CreateEvent"
            }
    
  3. Create an object of the type iam:SolutionPermissions that provides access between your Codex solution and the Zodiac function. For example, the following solutionPermissions.json is an object of the type iam:SolutionPermissions:

      {
        "permissions": [
          {
            "id": "codexzodiactest:codexqe",
            "can_access_in_background": true
          }
        ],
        "name": "default"
      }
    
  4. In your solution's manifest.json file,  declare the types codex and iam as dependencies and the objects. For example:

    
      {
        "name": "codexzodiacwfperf",
        "description": "codex zodiac workflow for validation",
        "readme": "readme.md",
        "dependencies": ["codex", "iam"],
        "homepage": "solutions.appd.com/codex",
        "solutionVersion": "1.0.12",
        "manifestVersion": "1.0.0",
        "contact": "support@appd.com",
        "gitRepoUrl": "<Your Git Repo URL>",
        "objects": [{
        "objectsFile": "objects/codex/trace2eventget.json",
        "type": "codex:workflow"
      },
      {
        "type": "iam:SolutionPermissions",
        "objectsFile": "objects/iam/solutionPermissions.json"
      }]
      }
    
  5. Each time you modify your solution:

Workflow example:

{
  "id": "trace2event-zodiac-codex",
  "version": "1.0",
  "specVersion": "0.8",
  "name": "trace2event-zodiac-codex",
  "description": "trace to event workflow with zodiac function call",
  "expressionLang": "Jsonata",
  "start": "ReadTrace",
  "events": [
    {
      "name": "TraceReceived",
      "type": "contracts:cloudevent/platform:trace.enriched.v1",
      "source": "platform",
      "kind": "consumed"
    },
    {
      "name": "EventCreated",
      "type": "contracts:cloudevent/platform:event.received.v1",
      "source": "platform",
      "kind": "produced"
    }
  ],
  "functions": [
    {
      "name": "generateEvents",
      "type": "expression",
      "operation": "{\"event\" :groupedSpans[0].spans.{\"entities\" : entities, \"type\": \"k8s:native_event\", \"timestamp\" : startedAt, \"raw\":\"trace to event workflow and zodiac function perf\", \"spanId\": \"\", \"traceId\": \"\", \"attributes\": $merge([{\"severity\": \"DEBUG\", \"workflow\":\"trace2event-zodiac-get\", \"appd.isevent\": true},$$.getOutput.data]) }}"
    },
    {
      "name": "getrestFunction",
      "type": "rest",
      "operation": "zodiac://zodiac:function/codexzodiactest:codex-function#getData"
    }
  ],
  "states": [
    {
      "name": "ReadTrace",
      "type": "event",
      "onEvents": [
        {
          "eventRefs": [
            "TraceReceived"
          ],
          "eventDataFilter": {
            "data": "${ data }"
          }
        }
      ],
      "transition": "InvokeRestFunction"
    },
    {
      "name": "InvokeRestFunction",
      "type": "operation",
      "actions": [
        {
          "functionRef": {
            "refName": "getrestFunction",
            "arguments": {
              "codextest":"trace2event-http-get"
             }
          },
          "actionDataFilter": {
            "toStateData": "${ getOutput }"
          }
        }
      ],
      "transition": "CreateEvent"
    },
    {
      "name": "CreateEvent",
      "type": "operation",
      "actions": [
        {
          "functionRef": {
            "refName": "generateEvents"
          }
        }
      ],
      "end": {
        "terminate": true,
        "produceEvents": [
          {
            "eventRef": "EventCreated",
            "data": "${ event }"
          }
        ]
      }
    }
  ]
}

Points to consider:

  • The type of the zodiac:function must be rest.

  • The operation must begin with zodiac:function/solutionName:functionName#operationId.

    • solutionName is the name of the solution where the function has been defined.

    • functionName is the name of the zodiac function.

    • operationId is the operation ID in the OpenAPI spec of the zodiac function that needs to be invoked.

  • zodiac:function object must contain a reference to the OpenAPI spec. For example:

    "openAPI":"contracts:openAPI/codexzodiactest:/info/title=codexzodiactest;/info/version=0.1",
    
  • OpenAPI spec referred inside the zodiac:function should exist in the solution.

  • contracts:openAPI object should follow the following:

    • For POST, PUT, or PATCH, the requestBody is mandatory.
    • For POST, PUT, or PATCH, the requestBody schema should always be of the type object.
    • For POST, PUT, or PATCH, the requestBody the contentType should always be application/json.
    • For GET or DELETE , the requestBody must be null.