From 9bff09f35dfbf7b5f8ef2afa9b7fa7191d622791 Mon Sep 17 00:00:00 2001 From: kyle Date: Tue, 30 Jun 2026 21:52:37 -0400 Subject: [PATCH] Add documentation for: - all runCronWorkload properties - quota management now exposed through billing-ng --- concepts/quota.mdx | 54 +++++++++++ concepts/workload.mdx | 2 +- docs.json | 3 +- guides/manage-quotas.mdx | 170 +++++++++++++++++++++++++++++++++++ reference/quota.mdx | 2 +- reference/workload/types.mdx | 23 +++-- 6 files changed, 242 insertions(+), 12 deletions(-) create mode 100644 concepts/quota.mdx create mode 100644 guides/manage-quotas.mdx diff --git a/concepts/quota.mdx b/concepts/quota.mdx new file mode 100644 index 00000000..5faaec57 --- /dev/null +++ b/concepts/quota.mdx @@ -0,0 +1,54 @@ +--- +title: Quotas +description: "Understand Control Plane quotas — the per-resource limits applied to your org, how to view current usage against the allowed maximum, and how to request a higher limit through a quota increase request." +keywords: ['limits', 'caps', 'resource limit', 'usage limits', 'increase quota', 'quota increase request', 'quota catalog', 'allotment', 'max', 'current usage', 'raise limit'] +--- + +## Overview + +A quota is a limit on how many of a given Control Plane resource your [org](/reference/org) may use. Each quota tracks two values: + +- **Current** — how much of the resource the org is using right now. +- **Max** — the highest value the org is allowed to reach. + +When the current usage of a resource reaches its max, further attempts to create that resource are rejected until usage drops or the max is raised. + +Quotas are applied per org. Some are counted at the org level (for example, the number of domains), while others are counted within each [GVC](/reference/gvc) (for example, the number of workloads per GVC). See the [Quota reference](/reference/quota) for the full list of resources that have a quota. + +## Quota Catalog + +The **quota catalog** is the read-only list of every quota that can exist on an org. Each catalog entry describes a quota by name, along with the unit it is measured in and a short description. Use the catalog to discover which quotas you can view and request increases for, and the exact `quotaName` to use when submitting a request. + +A catalog entry is not org-specific — it describes the quota in general. To see the current and max values for a quota on your own org, list your org's quotas instead. + +## Increasing a Quota + +When you need a higher limit, submit a **quota increase request** for a single quota and the new max you want. Control Plane then evaluates the request: + +- Requests that fall within the range Control Plane can grant automatically are **approved immediately**, and the higher limit is applied to your org shortly afterward. +- Larger requests are placed in the **pending** state and reviewed by the Control Plane team before being approved or denied. + +A quota increase request moves through one of the following statuses: + +| Status | Meaning | +| :--------- | :--------------------------------------------------------------------- | +| `pending` | The request has been received and is awaiting review. | +| `approved` | The request was granted. The new max is applied to your org. | +| `denied` | The request was reviewed and not granted. The quota max is unchanged. | + +Each request records the new max you asked for (`requestedMax`), who submitted it, when it was created, and—once it is no longer pending—when and by whom it was resolved. Approved requests, whether automatic or reviewed, raise the quota's max only when the current max is below the requested value; a request for a value at or below the current max is considered already satisfied. + +You can track a request after submitting it by retrieving it by its ID, or by listing all of your org's requests (optionally filtered by status). See [Check the status of a request](/guides/manage-quotas#check-the-status-of-a-request) in the guide. + + +Requesting an increase never lowers a quota. To request a value below your current max, contact [support@controlplane.com](mailto:support@controlplane.com). + + +## Permissions + +Viewing quotas and submitting quota increase requests for an org require the org-level `view` permission. See [Quota permissions](/reference/quota#permissions) for the permissions used to define [policies](/reference/policy). + +## Next Steps + +- Follow the [Manage Quotas guide](/guides/manage-quotas) to view quotas, browse the catalog, and submit and track increase requests through the API. +- See the [Quota reference](/reference/quota) for the list of quota resources and their permissions. diff --git a/concepts/workload.mdx b/concepts/workload.mdx index 9bd1b6da..51b21b50 100644 --- a/concepts/workload.mdx +++ b/concepts/workload.mdx @@ -99,7 +99,7 @@ The default is `none`, which blocks all inter-workload traffic. - **Standard**: - Workloads serve network traffic on multiple ports and can scale to zero only when using KEDA. - **Cron**: - - Workloads that run on a schedule, and do not serve network traffic. + - Workloads that run on a schedule and do not serve network traffic. Each execution is expected to run to completion and exit. Scheduling, concurrency, retention, retry, and run-time deadline behavior are configured under the workload's `job` spec — see [Cron Configuration](/reference/workload/types#cron-configuration). - **Stateful**: - Similar to a `standard` workload, `stateful` workloads have stable replica identities and hostnames, and can mount a [volume set](/reference/volumeset) for persistent storage. - **VM**: diff --git a/docs.json b/docs.json index 7c79bb9a..197fb246 100644 --- a/docs.json +++ b/docs.json @@ -35,7 +35,7 @@ }, { "group": "Concepts", - "pages": ["concepts/billing", "concepts/org", "concepts/gvc", "concepts/workload", "concepts/access-control"] + "pages": ["concepts/billing", "concepts/org", "concepts/gvc", "concepts/workload", "concepts/quota", "concepts/access-control"] }, { "group": "Core", @@ -140,6 +140,7 @@ "guides/setup-agent", "guides/setup-agent-legacy", "guides/invite-users", + "guides/manage-quotas", "guides/rate-limiting", "guides/resource-protection", "guides/service-to-service" diff --git a/guides/manage-quotas.mdx b/guides/manage-quotas.mdx new file mode 100644 index 00000000..6a88cf77 --- /dev/null +++ b/guides/manage-quotas.mdx @@ -0,0 +1,170 @@ +--- +title: Manage Quotas +description: View your org's current quotas, browse the quota catalog, submit a quota increase request, and track its status using the Control Plane quota API. +keywords: ['view quota', 'quota usage', 'request quota increase', 'raise limit', 'quota catalog', 'quota increase request', 'check quota status', 'billing-ng', 'increase workloads', 'increase limit api'] +--- + +## Prerequisites + +- Review the [Quotas](/concepts/quota) concept page and the [Quota reference](/reference/quota). +- Have the org-level `view` [permission](/reference/quota#permissions) for the org whose quotas you are managing. (Browsing the [quota catalog](#browse-the-quota-catalog) requires only a valid token, since it is not org-specific.) +- An authorization token (see [Authentication](#authentication)). + +## Authentication + +The quota endpoints are served from `https://billing-ng.cpln.io` and use the same Bearer token authentication as the rest of the Control Plane API. + +Obtain a token using either method: + +- **Service account key** — [create a service account](/guides/create-service-account) with the necessary permissions and generate a key. +- **User access token** — log in with [`cpln login`](/cli-reference/commands/login), then run `cpln profile token `. + +Include the token in the `Authorization` header of every request: + +```bash +Authorization: Bearer YOUR_TOKEN_HERE +``` + +In the examples below, replace `YOUR_TOKEN_HERE` with your token and `my-org` with your org name. + +## View Your Current Quotas + +List every quota on your org, including its current usage and allowed maximum: + +```bash +curl --request GET \ + --url https://billing-ng.cpln.io/org/my-org/quotas \ + --header 'Authorization: Bearer YOUR_TOKEN_HERE' +``` + +The response is an array of quotas: + +```json +[ + { + "id": "5d2c0a1e-7b3f-4d8a-9c11-2f6e8b4a1c90", + "name": "workloads-per-gvc", + "description": "Maximum number of workloads in a GVC", + "unit": "count", + "max": 50, + "current": 32, + "origin": "default" + } +] +``` + +| Field | Description | +| :------------ | :----------------------------------------------------------------------- | +| `id` | Unique identifier of the quota. Used when correlating an increase. | +| `name` | The quota name. Use this value as `quotaName` when requesting an increase.| +| `description` | Human-readable description of the resource the quota limits. | +| `unit` | The unit the quota is measured in. | +| `max` | The highest value your org is allowed to reach. | +| `current` | The org's current usage of the resource. | +| `origin` | Where the limit comes from — `default` (the standard limit) or `builtin`.| + +## Browse the Quota Catalog + +The catalog lists every quota that can exist, with its unit and description. Use it to find the exact `quotaName` to request an increase for: + +```bash +curl --request GET \ + --url https://billing-ng.cpln.io/quota_catalog \ + --header 'Authorization: Bearer YOUR_TOKEN_HERE' +``` + +```json +[ + { + "name": "workloads-per-gvc", + "unit": "count", + "description": "Maximum number of workloads in a GVC", + "defaultMax": 50 + } +] +``` + +## Request a Quota Increase + +Submit a request for a single quota and the new max you want. Provide the `quotaName` (from your current quotas or the catalog) and a `requestedMax`: + +```bash +curl --request POST \ + --url https://billing-ng.cpln.io/org/my-org/quota-increase-requests \ + --header 'Authorization: Bearer YOUR_TOKEN_HERE' \ + --header 'Content-Type: application/json' \ + --data '{ + "quotaName": "workloads-per-gvc", + "requestedMax": 100 + }' +``` + +The response is the created request, including its `id` and `status`: + +```json +{ + "id": "a1b2c3d4-e5f6-47a8-9b0c-1d2e3f4a5b6c", + "org": "my-org", + "quotaName": "workloads-per-gvc", + "requestedMax": 100, + "status": "approved", + "autoApproved": true, + "createdBy": "user@example.com", + "created": "2026-06-30T15:04:05Z", + "resolvedBy": "system", + "resolved": "2026-06-30T15:04:05Z" +} +``` + +The `status` tells you what happened: + +- `approved` — the increase was granted. When `autoApproved` is `true`, it was granted automatically and the new max is applied to your org shortly after. A `resolvedBy` of `system` indicates an automatic approval. +- `pending` — the request was larger than can be granted automatically and is awaiting review by the Control Plane team. Note the returned `id` so you can [check its status](#check-the-status-of-a-request) later. + + +A quota increase request only ever raises a limit. A request for a value at or below your current max is treated as already satisfied and leaves the quota unchanged. + + +## Check the Status of a Request + +Retrieve a request by its `id` to see its current status: + +```bash +curl --request GET \ + --url https://billing-ng.cpln.io/quota-increase-requests/a1b2c3d4-e5f6-47a8-9b0c-1d2e3f4a5b6c \ + --header 'Authorization: Bearer YOUR_TOKEN_HERE' +``` + +```json +{ + "id": "a1b2c3d4-e5f6-47a8-9b0c-1d2e3f4a5b6c", + "org": "my-org", + "quotaName": "workloads-per-gvc", + "requestedMax": 100, + "status": "approved", + "autoApproved": false, + "createdBy": "user@example.com", + "created": "2026-06-30T15:04:05Z", + "resolvedBy": "ops@controlplane.com", + "resolved": "2026-06-30T17:22:41Z" +} +``` + +A `pending` request becomes `approved` or `denied` once it has been reviewed. After a request is approved, the new max appears on the quota when you [view your current quotas](#view-your-current-quotas). + +### List Your Org's Requests + +To see all increase requests for your org, list them with the `org` query parameter. Add an optional `status` filter (`pending`, `approved`, or `denied`): + +```bash +curl --request GET \ + --url 'https://billing-ng.cpln.io/quota-increase-requests?org=my-org&status=pending' \ + --header 'Authorization: Bearer YOUR_TOKEN_HERE' +``` + +The response is an array of the requests for your org. + +## Next Steps + +- Learn how quotas and increase requests work in the [Quotas](/concepts/quota) concept page. +- See the [Quota reference](/reference/quota) for the list of quota resources and their permissions. diff --git a/reference/quota.mdx b/reference/quota.mdx index de928d85..5446131c 100644 --- a/reference/quota.mdx +++ b/reference/quota.mdx @@ -17,7 +17,7 @@ Current resources with a quota: | identities-per-gvc | Max number of workload identities in a gvc | | workloads-per-gvc | Max number of workloads in a gvc | -If your [org](/reference/org) requires additional resources, please email [support@controlplane.com](mailto:support@controlplane.com) +If your [org](/reference/org) requires a higher limit, submit a [quota increase request](/concepts/quota#increasing-a-quota). See the [Manage Quotas guide](/guides/manage-quotas) for the steps, or email [support@controlplane.com](mailto:support@controlplane.com) for requests that need review. ## Permissions diff --git a/reference/workload/types.mdx b/reference/workload/types.mdx index 6715aff9..2e60eca4 100644 --- a/reference/workload/types.mdx +++ b/reference/workload/types.mdx @@ -174,7 +174,7 @@ Cron workloads **must**: - Exit upon completion of the task at hand. Control Plane will start a new replica of your workload at the next scheduled execution time. -A cron workload can be suspended by setting `job.suspend` to `true`. While suspended, no new executions start. Use [Run Now](#run-now) for on-demand execution even while suspended. +A cron workload can be suspended by setting `defaultOptions.suspend` to `true`. While suspended, no new executions start. Use [Run Now](#run-now) for on-demand execution even while suspended. @@ -188,19 +188,21 @@ Cron workloads are always deployed to all locations within their GVC. Unlike wor - `job.schedule` - - A string, which determines how often the cron workload should execute. This field uses the [Kubernetes cron schedule syntax](https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/#cron-schedule-syntax). + - **Required**: A 5-field cron expression, which determines how often the cron workload should execute. This field uses the [Kubernetes cron schedule syntax](https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/#cron-schedule-syntax). - `job.concurrencyPolicy` - - This determines what Control Plane will do when a prior execution of your workload is still running when the next scheduled execution time arrives. + - **Optional**: Defaults to `Forbid`. This determines what Control Plane will do when a prior execution of your workload is still running when the next scheduled execution time arrives. - `Forbid`: subsequent executions will be forgone until the running execution completes. - `Replace`: the running execution will be stopped so that a new execution can begin. - `Allow`: subsequent executions will be allowed to proceed as normal. - `job.historyLimit` - - An integer between 1 and 10 representing the number of prior executions to be retained for reference. + - **Optional**: Defaults to `5`. An integer between 1 and 10 representing the number of prior executions to be retained for reference. - `job.restartPolicy` - - Either `Never` or `OnFailure`. This determines whether your workload will be restarted when it fails on execution. + - **Optional**: Either `Never` or `OnFailure`. This determines whether your workload will be restarted when it fails on execution. - `job.activeDeadlineSeconds` - - **Optional**: By default there is no deadline. Job executions are allowed to run indefinitely. - - If this property is set, this is the maximum number of a seconds a job execution can run. If the job does not exit in the allotted time, Control Plane will remove it. + - **Optional**: By default there is no deadline, and job executions are allowed to run indefinitely. + - If this property is set, it is the maximum number of seconds a job execution can run, between `1` and `86400` (24 hours). If the job does not exit in the allotted time, Control Plane will stop it, moving it into the `Removed` status. + +To suspend a cron workload, set `defaultOptions.suspend` to `true` (this is a workload option, not a `job` field). See [Run Now](#run-now) for running a suspended workload on demand. ### Run Now @@ -215,6 +217,7 @@ Cron workloads can be run on-demand by submitting a `runCronWorkload` command vi type: runCronWorkload spec: location: aws-us-west-2 + activeDeadlineSeconds: 300 containerOverrides: - name: my-container command: '/bin/sh' @@ -232,11 +235,13 @@ spec: #### runCronWorkload Spec - `location` - - The name of the location as specified in your [GVC](/reference/gvc) configuration. + - **Required**: The name of the location as specified in your [GVC](/reference/gvc) configuration. +- `activeDeadlineSeconds` + - **Optional**: The maximum number of seconds this on-demand execution may run before Control Plane stops it. Overrides the workload's `job.activeDeadlineSeconds` for this run only. When omitted, the on-demand execution has no deadline. - `containerOverrides` - **Optional**: A list of objects that override specific parts of a container's configuration. - `containerOverrides[].name` - - The name of the container to override in the workload specification. + - **Required**: The name of the container to override in the workload specification. - `containerOverrides[].command` - A new command for the container during this execution only. This field corresponds to `workload.containers[].command` in the workload specification. - `containerOverrides[].cpu`