{
  "description": "ExtensionService is the schema for the Contour extension services API.\nAn ExtensionService resource binds a network service to the Contour\nAPI so that Contour API features can be implemented by collaborating\ncomponents.",
  "properties": {
    "apiVersion": {
      "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
      "type": [
        "string",
        "null"
      ]
    },
    "kind": {
      "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
      "type": [
        "string",
        "null"
      ]
    },
    "metadata": {
      "type": [
        "object",
        "null"
      ]
    },
    "spec": {
      "additionalProperties": false,
      "description": "ExtensionServiceSpec defines the desired state of an ExtensionService resource.",
      "properties": {
        "circuitBreakerPolicy": {
          "additionalProperties": false,
          "description": "CircuitBreakerPolicy specifies the circuit breaker budget across the extension service.\nIf defined this overrides the global circuit breaker budget.",
          "properties": {
            "maxConnections": {
              "description": "The maximum number of connections that a single Envoy instance allows to the Kubernetes Service; defaults to 1024.",
              "format": "int32",
              "type": [
                "integer",
                "null"
              ]
            },
            "maxPendingRequests": {
              "description": "The maximum number of pending requests that a single Envoy instance allows to the Kubernetes Service; defaults to 1024.",
              "format": "int32",
              "type": [
                "integer",
                "null"
              ]
            },
            "maxRequests": {
              "description": "The maximum parallel requests a single Envoy instance allows to the Kubernetes Service; defaults to 1024",
              "format": "int32",
              "type": [
                "integer",
                "null"
              ]
            },
            "maxRetries": {
              "description": "The maximum number of parallel retries a single Envoy instance allows to the Kubernetes Service; defaults to 3.",
              "format": "int32",
              "type": [
                "integer",
                "null"
              ]
            },
            "perHostMaxConnections": {
              "description": "PerHostMaxConnections is the maximum number of connections\nthat Envoy will allow to each individual host in a cluster.",
              "format": "int32",
              "type": [
                "integer",
                "null"
              ]
            }
          },
          "type": [
            "object",
            "null"
          ]
        },
        "loadBalancerPolicy": {
          "additionalProperties": false,
          "description": "The policy for load balancing GRPC service requests. Note that the\n`Cookie` and `RequestHash` load balancing strategies cannot be used\nhere.",
          "properties": {
            "requestHashPolicies": {
              "description": "RequestHashPolicies contains a list of hash policies to apply when the\n`RequestHash` load balancing strategy is chosen. If an element of the\nsupplied list of hash policies is invalid, it will be ignored. If the\nlist of hash policies is empty after validation, the load balancing\nstrategy will fall back to the default `RoundRobin`.",
              "items": {
                "additionalProperties": false,
                "description": "RequestHashPolicy contains configuration for an individual hash policy\non a request attribute.",
                "properties": {
                  "hashSourceIP": {
                    "description": "HashSourceIP should be set to true when request source IP hash based\nload balancing is desired. It must be the only hash option field set,\notherwise this request hash policy object will be ignored.",
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "headerHashOptions": {
                    "additionalProperties": false,
                    "description": "HeaderHashOptions should be set when request header hash based load\nbalancing is desired. It must be the only hash option field set,\notherwise this request hash policy object will be ignored.",
                    "properties": {
                      "headerName": {
                        "description": "HeaderName is the name of the HTTP request header that will be used to\ncalculate the hash key. If the header specified is not present on a\nrequest, no hash will be produced.",
                        "minLength": 1,
                        "type": [
                          "string",
                          "null"
                        ]
                      }
                    },
                    "type": [
                      "object",
                      "null"
                    ]
                  },
                  "queryParameterHashOptions": {
                    "additionalProperties": false,
                    "description": "QueryParameterHashOptions should be set when request query parameter hash based load\nbalancing is desired. It must be the only hash option field set,\notherwise this request hash policy object will be ignored.",
                    "properties": {
                      "parameterName": {
                        "description": "ParameterName is the name of the HTTP request query parameter that will be used to\ncalculate the hash key. If the query parameter specified is not present on a\nrequest, no hash will be produced.",
                        "minLength": 1,
                        "type": [
                          "string",
                          "null"
                        ]
                      }
                    },
                    "type": [
                      "object",
                      "null"
                    ]
                  },
                  "terminal": {
                    "description": "Terminal is a flag that allows for short-circuiting computing of a hash\nfor a given request. If set to true, and the request attribute specified\nin the attribute hash options is present, no further hash policies will\nbe used to calculate a hash for the request.",
                    "type": [
                      "boolean",
                      "null"
                    ]
                  }
                },
                "type": "object"
              },
              "type": [
                "array",
                "null"
              ]
            },
            "strategy": {
              "description": "Strategy specifies the policy used to balance requests\nacross the pool of backend pods. Valid policy names are\n`Random`, `RoundRobin`, `WeightedLeastRequest`, `Cookie`,\nand `RequestHash`. If an unknown strategy name is specified\nor no policy is supplied, the default `RoundRobin` policy\nis used.",
              "type": [
                "string",
                "null"
              ]
            }
          },
          "type": [
            "object",
            "null"
          ]
        },
        "protocol": {
          "description": "Protocol may be used to specify (or override) the protocol used to reach this Service.\nValues may be h2 or h2c. If omitted, protocol-selection falls back on Service annotations.",
          "enum": [
            "h2",
            "h2c"
          ],
          "type": [
            "string",
            "null"
          ]
        },
        "protocolVersion": {
          "description": "This field sets the version of the GRPC protocol that Envoy uses to\nsend requests to the extension service. Since Contour always uses the\nv3 Envoy API, this is currently fixed at \"v3\". However, other\nprotocol options will be available in future.",
          "enum": [
            "v3"
          ],
          "type": [
            "string",
            "null"
          ]
        },
        "services": {
          "description": "Services specifies the set of Kubernetes Service resources that\nreceive GRPC extension API requests.\nIf no weights are specified for any of the entries in\nthis array, traffic will be spread evenly across all the\nservices.\nOtherwise, traffic is balanced proportionally to the\nWeight field in each entry.",
          "items": {
            "additionalProperties": false,
            "description": "ExtensionServiceTarget defines an Kubernetes Service to target with\nextension service traffic.",
            "properties": {
              "name": {
                "description": "Name is the name of Kubernetes service that will accept service\ntraffic.",
                "type": "string"
              },
              "port": {
                "description": "Port (defined as Integer) to proxy traffic to since a service can have multiple defined.",
                "exclusiveMaximum": true,
                "maximum": 65536,
                "minimum": 1,
                "type": "integer"
              },
              "weight": {
                "description": "Weight defines proportion of traffic to balance to the Kubernetes Service.",
                "format": "int32",
                "type": [
                  "integer",
                  "null"
                ]
              }
            },
            "required": [
              "name",
              "port"
            ],
            "type": "object"
          },
          "minItems": 1,
          "type": "array"
        },
        "timeoutPolicy": {
          "additionalProperties": false,
          "description": "The timeout policy for requests to the services.",
          "properties": {
            "idle": {
              "description": "Timeout for how long the proxy should wait while there is no activity during single request/response (for HTTP/1.1) or stream (for HTTP/2).\nTimeout will not trigger while HTTP/1.1 connection is idle between two consecutive requests.\nIf not specified, there is no per-route idle timeout, though a connection manager-wide\nstream_idle_timeout default of 5m still applies.",
              "pattern": "^(((\\d*(\\.\\d*)?h)|(\\d*(\\.\\d*)?m)|(\\d*(\\.\\d*)?s)|(\\d*(\\.\\d*)?ms)|(\\d*(\\.\\d*)?us)|(\\d*(\\.\\d*)?µs)|(\\d*(\\.\\d*)?ns))+|infinity|infinite)$",
              "type": [
                "string",
                "null"
              ]
            },
            "idleConnection": {
              "description": "Timeout for how long connection from the proxy to the upstream service is kept when there are no active requests.\nIf not supplied, Envoy's default value of 1h applies.",
              "pattern": "^(((\\d*(\\.\\d*)?h)|(\\d*(\\.\\d*)?m)|(\\d*(\\.\\d*)?s)|(\\d*(\\.\\d*)?ms)|(\\d*(\\.\\d*)?us)|(\\d*(\\.\\d*)?µs)|(\\d*(\\.\\d*)?ns))+|infinity|infinite)$",
              "type": [
                "string",
                "null"
              ]
            },
            "response": {
              "description": "Timeout for receiving a response from the server after processing a request from client.\nIf not supplied, Envoy's default value of 15s applies.",
              "pattern": "^(((\\d*(\\.\\d*)?h)|(\\d*(\\.\\d*)?m)|(\\d*(\\.\\d*)?s)|(\\d*(\\.\\d*)?ms)|(\\d*(\\.\\d*)?us)|(\\d*(\\.\\d*)?µs)|(\\d*(\\.\\d*)?ns))+|infinity|infinite)$",
              "type": [
                "string",
                "null"
              ]
            }
          },
          "type": [
            "object",
            "null"
          ]
        },
        "validation": {
          "additionalProperties": false,
          "description": "UpstreamValidation defines how to verify the backend service's certificate",
          "properties": {
            "caSecret": {
              "description": "Name or namespaced name of the Kubernetes secret used to validate the certificate presented by the backend.\nThe secret must contain key named ca.crt.\nThe name can be optionally prefixed with namespace \"namespace/name\".\nWhen cross-namespace reference is used, TLSCertificateDelegation resource must exist in the namespace to grant access to the secret.\nMax length should be the actual max possible length of a namespaced name (63 + 253 + 1 = 317)",
              "maxLength": 317,
              "minLength": 1,
              "type": "string"
            },
            "subjectName": {
              "description": "Key which is expected to be present in the 'subjectAltName' of the presented certificate.\nDeprecated: migrate to using the plural field subjectNames.",
              "maxLength": 250,
              "minLength": 1,
              "type": "string"
            },
            "subjectNames": {
              "description": "List of keys, of which at least one is expected to be present in the 'subjectAltName of the\npresented certificate.",
              "items": {
                "type": "string"
              },
              "maxItems": 8,
              "minItems": 1,
              "type": [
                "array",
                "null"
              ]
            }
          },
          "required": [
            "caSecret",
            "subjectName"
          ],
          "type": [
            "object",
            "null"
          ],
          "x-kubernetes-validations": [
            {
              "message": "subjectNames[0] must equal subjectName if set",
              "rule": "has(self.subjectNames) ? self.subjectNames[0] == self.subjectName : true"
            }
          ]
        }
      },
      "required": [
        "services"
      ],
      "type": [
        "object",
        "null"
      ]
    },
    "status": {
      "additionalProperties": false,
      "description": "ExtensionServiceStatus defines the observed state of an\nExtensionService resource.",
      "properties": {
        "conditions": {
          "description": "Conditions contains the current status of the ExtensionService resource.\nContour will update a single condition, `Valid`, that is in normal-true polarity.\nContour will not modify any other Conditions set in this block,\nin case some other controller wants to add a Condition.",
          "items": {
            "additionalProperties": false,
            "description": "DetailedCondition is an extension of the normal Kubernetes conditions, with two extra\nfields to hold sub-conditions, which provide more detailed reasons for the state (True or False)\nof the condition.\n`errors` holds information about sub-conditions which are fatal to that condition and render its state False.\n`warnings` holds information about sub-conditions which are not fatal to that condition and do not force the state to be False.\nRemember that Conditions have a type, a status, and a reason.\nThe type is the type of the condition, the most important one in this CRD set is `Valid`.\n`Valid` is a positive-polarity condition: when it is `status: true` there are no problems.\nIn more detail, `status: true` means that the object is has been ingested into Contour with no errors.\n`warnings` may still be present, and will be indicated in the Reason field. There must be zero entries in the `errors`\nslice in this case.\n`Valid`, `status: false` means that the object has had one or more fatal errors during processing into Contour.\nThe details of the errors will be present under the `errors` field. There must be at least one error in the `errors`\nslice if `status` is `false`.\nFor DetailedConditions of types other than `Valid`, the Condition must be in the negative polarity.\nWhen they have `status` `true`, there is an error. There must be at least one entry in the `errors` Subcondition slice.\nWhen they have `status` `false`, there are no serious errors, and there must be zero entries in the `errors` slice.\nIn either case, there may be entries in the `warnings` slice.\nRegardless of the polarity, the `reason` and `message` fields must be updated with either the detail of the reason\n(if there is one and only one entry in total across both the `errors` and `warnings` slices), or\n`MultipleReasons` if there is more than one entry.",
            "properties": {
              "errors": {
                "description": "Errors contains a slice of relevant error subconditions for this object.\nSubconditions are expected to appear when relevant (when there is a error), and disappear when not relevant.\nAn empty slice here indicates no errors.",
                "items": {
                  "additionalProperties": false,
                  "description": "SubCondition is a Condition-like type intended for use as a subcondition inside a DetailedCondition.\nIt contains a subset of the Condition fields.\nIt is intended for warnings and errors, so `type` names should use abnormal-true polarity,\nthat is, they should be of the form \"ErrorPresent: true\".\nThe expected lifecycle for these errors is that they should only be present when the error or warning is,\nand should be removed when they are not relevant.",
                  "properties": {
                    "message": {
                      "description": "Message is a human readable message indicating details about the transition.\nThis may be an empty string.",
                      "maxLength": 32768,
                      "type": "string"
                    },
                    "reason": {
                      "description": "Reason contains a programmatic identifier indicating the reason for the condition's last transition.\nProducers of specific condition types may define expected values and meanings for this field,\nand whether the values are considered a guaranteed API.\nThe value should be a CamelCase string.\nThis field may not be empty.",
                      "maxLength": 1024,
                      "minLength": 1,
                      "pattern": "^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$",
                      "type": "string"
                    },
                    "status": {
                      "description": "Status of the condition, one of True, False, Unknown.",
                      "enum": [
                        "True",
                        "False",
                        "Unknown"
                      ],
                      "type": "string"
                    },
                    "type": {
                      "description": "Type of condition in `CamelCase` or in `foo.example.com/CamelCase`.\nThis must be in abnormal-true polarity, that is, `ErrorFound` or `controller.io/ErrorFound`.\nThe regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)",
                      "maxLength": 316,
                      "pattern": "^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$",
                      "type": "string"
                    }
                  },
                  "required": [
                    "message",
                    "reason",
                    "status",
                    "type"
                  ],
                  "type": "object"
                },
                "type": [
                  "array",
                  "null"
                ]
              },
              "lastTransitionTime": {
                "description": "lastTransitionTime is the last time the condition transitioned from one status to another.\nThis should be when the underlying condition changed.  If that is not known, then using the time when the API field changed is acceptable.",
                "format": "date-time",
                "type": "string"
              },
              "message": {
                "description": "message is a human readable message indicating details about the transition.\nThis may be an empty string.",
                "maxLength": 32768,
                "type": "string"
              },
              "observedGeneration": {
                "description": "observedGeneration represents the .metadata.generation that the condition was set based upon.\nFor instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date\nwith respect to the current state of the instance.",
                "format": "int64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "reason": {
                "description": "reason contains a programmatic identifier indicating the reason for the condition's last transition.\nProducers of specific condition types may define expected values and meanings for this field,\nand whether the values are considered a guaranteed API.\nThe value should be a CamelCase string.\nThis field may not be empty.",
                "maxLength": 1024,
                "minLength": 1,
                "pattern": "^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$",
                "type": "string"
              },
              "status": {
                "description": "status of the condition, one of True, False, Unknown.",
                "enum": [
                  "True",
                  "False",
                  "Unknown"
                ],
                "type": "string"
              },
              "type": {
                "description": "type of condition in CamelCase or in foo.example.com/CamelCase.\n---\nMany .condition.type values are consistent across resources like Available, but because arbitrary conditions can be\nuseful (see .node.status.conditions), the ability to deconflict is important.\nThe regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)",
                "maxLength": 316,
                "pattern": "^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$",
                "type": "string"
              },
              "warnings": {
                "description": "Warnings contains a slice of relevant warning subconditions for this object.\nSubconditions are expected to appear when relevant (when there is a warning), and disappear when not relevant.\nAn empty slice here indicates no warnings.",
                "items": {
                  "additionalProperties": false,
                  "description": "SubCondition is a Condition-like type intended for use as a subcondition inside a DetailedCondition.\nIt contains a subset of the Condition fields.\nIt is intended for warnings and errors, so `type` names should use abnormal-true polarity,\nthat is, they should be of the form \"ErrorPresent: true\".\nThe expected lifecycle for these errors is that they should only be present when the error or warning is,\nand should be removed when they are not relevant.",
                  "properties": {
                    "message": {
                      "description": "Message is a human readable message indicating details about the transition.\nThis may be an empty string.",
                      "maxLength": 32768,
                      "type": "string"
                    },
                    "reason": {
                      "description": "Reason contains a programmatic identifier indicating the reason for the condition's last transition.\nProducers of specific condition types may define expected values and meanings for this field,\nand whether the values are considered a guaranteed API.\nThe value should be a CamelCase string.\nThis field may not be empty.",
                      "maxLength": 1024,
                      "minLength": 1,
                      "pattern": "^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$",
                      "type": "string"
                    },
                    "status": {
                      "description": "Status of the condition, one of True, False, Unknown.",
                      "enum": [
                        "True",
                        "False",
                        "Unknown"
                      ],
                      "type": "string"
                    },
                    "type": {
                      "description": "Type of condition in `CamelCase` or in `foo.example.com/CamelCase`.\nThis must be in abnormal-true polarity, that is, `ErrorFound` or `controller.io/ErrorFound`.\nThe regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)",
                      "maxLength": 316,
                      "pattern": "^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$",
                      "type": "string"
                    }
                  },
                  "required": [
                    "message",
                    "reason",
                    "status",
                    "type"
                  ],
                  "type": "object"
                },
                "type": [
                  "array",
                  "null"
                ]
              }
            },
            "required": [
              "lastTransitionTime",
              "message",
              "reason",
              "status",
              "type"
            ],
            "type": "object"
          },
          "type": [
            "array",
            "null"
          ],
          "x-kubernetes-list-map-keys": [
            "type"
          ],
          "x-kubernetes-list-type": "map"
        }
      },
      "type": [
        "object",
        "null"
      ]
    }
  },
  "type": "object"
}