Skip to content

Creating enum type in YAML causes duplicate data produced in resulting schema file when array of objects parameter used multiple times. #52

@rhys-kitikion

Description

@rhys-kitikion

Creating enum type in YAML causes duplicate data produced in resulting schema file when running the following command
fast validate {path_to_file}

This appears to happen when the object is called multiple times within the JSON section of the YAML by use of a mustache parameter. Example in this case is when monitors are being created, and then re-used in the same FAST template to assign them to specified pools.

Example:

title: poolMonitors_issue
description: Monitors enum duplicate issue.
definitions:
    poolMonitors:
        title: Monitor configuration for the pool members
        description: Set up the pool members monitors for monitoring availability on the BIG-IP
        type: array
        uniqueItems: true
        default:
          - {}
        items:
            type: object
            properties:
                monitorType:
                    title: Type of monitor
                    type: string
                    default: "https"
                    enum: ["hello"]
                monitorSend:
                    title: Data to send to pool member
                    type: string
                    default: "/"
                monitorReceive:
                    title: Data expected to receive from pool member
                    type: string
                    default: "200.OK"
                monitorInterval:
                    title: Amount of time between monitor pings
                    type: integer
                    minimum: 1
                    maximum: 3600
                    default: 0
                monitorTimeout:
                    title: Amount of time before monitor marks pool member down
                    description: This is the amount of time before  monitor will mark a pool member down.  This is 3 * monitorInterval + 1 typically.
                    type: integer
                    minimum: 1
                    maximum: 10800
                    default: 0
    poolMemberDef:
        template: |
            "servicePort": {{memberPort:f5:port}},
            {{#memberIpAddress:f5:ipv4_ipv6}}
            "serverAddresses": [
                "{{memberIpAddress:f5:ipv4_ipv6}}"
            ],
            {{/memberIpAddress:f5:ipv4_ipv6}}
            {{^memberIpAddress:f5:ipv4_ipv6}}
            "serverAddresses": [],
            {{/memberIpAddress:f5:ipv4_ipv6}}
            "shareNodes": true,
template: |
    {
        "class": "AS3",
        "declaration": {
            "class": "ADC",
            "schemaVersion": "3.46.0",
            "constants": {
                "class": "Constants",
                "timestamp": "{{buildTimeStamp}}",
                "version": "{{buildNumber}}"
            },
            "id": "{{appName:f5:bigip_name}}",
            "remark": "##templateVersion##",
            "{{appName:f5:bigip_name}}": {
                "constants": {
                    "class": "Constants",
                    "schemaVersion": "3.46.0",
                    "templateVersion": "##templateVersion##",
                    "templateName": "poolMonitors_issue",
                    "configTimestamp": "{{buildTimeStamp}}",
                    "configVersion": "{{buildNumber}}"
                },
                "class": "Tenant",
                "app": {
                    "class": "Application",
                    {{#poolMonitors}}
                    "{{monitorName:f5:bigip_name}}-monitor" : {
                        "class": "Monitor",
                        "monitorType": "{{monitorType}}",
                        "send": "{{monitorSend}}",
                        "receive": "{{monitorReceive}}",
                        "interval": {{monitorInterval}},
                        "timeout": {{monitorTimeout}}
                    },
                    {{/poolMonitors}}
                    "{{appName:f5:bigip_name}}-pool": {
                        "class": "Pool",
                        "loadBalancingMode": "{{poolLoadBalancingMode:f5:load_balancing_mode}}",
                        "members": [
                        {{#poolMembers}}
                        {
                            {{> poolMemberDef}}
                            "enabled": {{enablePoolMember::boolean}}
                        },
                        {{/poolMembers}}
                        ],
                        "monitors": [
                            {{#poolMonitors}}
                            { "use": "{{monitorName:f5:bigip_name}}-monitor" },
                            {{/poolMonitors}}
                        ],
                        "serviceDownAction": "none"
                    }
                }
            }
        }
    }

This is the resulting message when the command is ran with the above example template code.

PS C:\BIG-IP\GIT\cubit-templates> fast validate .\templates\example-error.yaml
failed to load template: Failed to compile parameter validator
schema:
{
  "type": "object",
  "properties": {
    "poolMonitors": {
      "type": "array",
      "title": "Monitor configuration for the pool members",
      "description": "Set up the pool members monitors for monitoring availability on the BIG-IP",
      "default": [
        {},
        {}
      ],
      "items": {
        "type": "object",
        "properties": {
          "monitorName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "pattern": "^[A-Za-z][0-9A-Za-z_.-]*$"
          },
          "monitorType": {
            "type": "string",
            "title": "Type of monitor",
            "default": "https",
            "enum": [
              "hello",
              "hello"
            ]
          },
          "monitorSend": {
            "type": "string",
            "title": "Data to send to pool member",
            "default": "/"
          },
          "monitorReceive": {
            "type": "string",
            "title": "Data expected to receive from pool member",
            "default": "200.OK"
          },
          "monitorInterval": {
            "type": "integer",
            "title": "Amount of time between monitor pings",
            "minimum": 1,
            "maximum": 3600,
            "default": 0
          },
          "monitorTimeout": {
            "type": "integer",
            "title": "Amount of time before monitor marks pool member down",
            "description": "This is the amount of time before  monitor will mark a pool member down.  This is 3 * monitorInterval + 1 typically.",
            "minimum": 1,
            "maximum": 10800,
            "default": 0
          }
        },
        "required": [
          "monitorName"
        ]
      },
      "skip_xform": true
    },
    "buildTimeStamp": {
      "type": "string"
    },
    "buildNumber": {
      "type": "string"
    },
    "appName": {
      "type": "string",
      "minLength": 1,
      "maxLength": 255,
      "pattern": "^[A-Za-z][0-9A-Za-z_.-]*$"
    },
    "poolLoadBalancingMode": {
      "type": "string",
      "default": "least-connections-member",
      "enum": [
        "dynamic-ratio-member",
        "dynamic-ratio-node",
        "fastest-app-response",
        "fastest-node",
        "least-connections-member",
        "least-connections-node",
        "least-sessions",
        "observed-member",
        "observed-node",
        "predictive-member",
        "predictive-node",
        "ratio-least-connections-member",
        "ratio-least-connections-node",
        "ratio-member",
        "ratio-node",
        "ratio-session",
        "round-robin",
        "weighted-least-connections-member",
        "weighted-least-connections-node"
      ]
    },
    "poolMembers": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "memberPort": {
            "type": "integer",
            "minimum": 0,
            "maximum": 65535
          },
          "memberIpAddress": {
            "type": "string",
            "oneOf": [
              {
                "title": "IPv4 Address",
                "pattern": "^(((25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)[.]){3}(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d))(%(6553[0-5]|655[0-2]\\d|65[0-4]\\d{2}|6[0-4]\\d{3}|[1-5]\\d{4}|[1-9]\\d{3}|[1-9]\\d{2}|[1-9]?\\d))?(\\x2f(3[012]|2\\d|1\\d|\\d))?$"
              },
              {
                "title": "IPv6 Address",
                "pattern": "^(::(([0-9a-f]{1,4}:){0,5}((([0-9a-f]{1,4}:)?[0-9a-f]{1,4})|(((25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)[.]){3}(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d))))?)|([0-9a-f]{1,4}::(([0-9a-f]{1,4}:){0,4}((([0-9a-f]{1,4}:)?[0-9a-f]{1,4})|(((25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)[.]){3}(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d))))?)|([0-9a-f]{1,4}:[0-9a-f]{1,4}::(([0-9a-f]{1,4}:){0,3}((([0-9a-f]{1,4}:)?[0-9a-f]{1,4})|(((25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)[.]){3}(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d))))?)|([0-9a-f]{1,4}(:[0-9a-f]{1,4}){2}::(([0-9a-f]{1,4}:){0,2}((([0-9a-f]{1,4}:)?[0-9a-f]{1,4})|(((25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)[.]){3}(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d))))?)|([0-9a-f]{1,4}(:[0-9a-f]{1,4}){3}::(([0-9a-f]{1,4}:)?((([0-9a-f]{1,4}:)?[0-9a-f]{1,4})|(((25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)[.]){3}(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d))))?)|([0-9a-f]{1,4}(:[0-9a-f]{1,4}){4}::((([0-9a-f]{1,4}:)?[0-9a-f]{1,4})|(((25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)[.]){3}(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)))?)|([0-9a-f]{1,4}(:[0-9a-f]{1,4}){5}::([0-9a-f]{1,4})?)|([0-9a-f]{1,4}(:[0-9a-f]{1,4}){0,6}::)|(([0-9a-f]{1,4}:){7}[0-9a-f]{1,4})(%(6553[0-5]|655[0-2]\\d|65[0-4]\\d{2}|6[0-4]\\d{3}|[1-5]\\d{4}|[1-9]\\d{3}|[1-9]\\d{2}|[1-9]?\\d))?(\\x2f(12[0-8]|1[01]\\d|[1-9]?\\d))?$"
              }
            ],
            "default": "10.1.1.1"
          },
          "enablePoolMember": {
            "type": "boolean"
          }
        },
        "required": [
          "memberPort",
          "enablePoolMember"
        ],
        "dependencies": {
          "memberIpAddress": [
            "memberIpAddress"
          ]
        }
      },
      "skip_xform": true
    }
  },
  "required": [
    "buildTimeStamp",
    "buildNumber",
    "appName",
    "poolMembers"
  ],
  "dependencies": {
    "monitorName": [
      "poolMonitors"
    ],
    "monitorType": [
      "poolMonitors"
    ],
    "monitorSend": [
      "poolMonitors"
    ],
    "monitorReceive": [
      "poolMonitors"
    ],
    "monitorInterval": [
      "poolMonitors"
    ],
    "monitorTimeout": [
      "poolMonitors"
    ],
    "memberPort": [
      "poolMembers"
    ],
    "memberIpAddress": [
      "poolMembers"
    ],
    "enablePoolMember": [
      "poolMembers"
    ]
  },
  "title": "poolMonitors_issue",
  "description": "Pool monitor issue example",
  "definitions": {}
}
compile error:
schema is invalid: data.properties['poolMonitors'].items.properties['monitorType'].enum should NOT have duplicate items (items ## 0 and 1 are identical), data.properties['poolMonitors'].items should be array, data.properties['poolMonitors'].items should match some schema in anyOf

I originally ran this off of 0.19.0 and decided to ugrade to 0.24.0 as I saw that happened to be the latest version. This appears to not function in either version.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions