diff --git a/OMICRON_VERSION b/OMICRON_VERSION index f654fb9e0..5fe4ed630 100644 --- a/OMICRON_VERSION +++ b/OMICRON_VERSION @@ -1 +1 @@ -1848d1833df1df880c609992aaf6ea6934b38d28 +80e992229b52cecb517a59a0f686f8916549343f diff --git a/app/api/__generated__/Api.ts b/app/api/__generated__/Api.ts index e39f813d2..96005fc75 100644 --- a/app/api/__generated__/Api.ts +++ b/app/api/__generated__/Api.ts @@ -302,6 +302,218 @@ export type AggregateBgpMessageHistory = { switchHistories: SwitchBgpHistory[] } +/** + * An alert class. + */ +export type AlertClass = { + /** A description of what this alert class represents. */ + description: string + /** The name of the alert class. */ + name: string +} + +/** + * A single page of results + */ +export type AlertClassResultsPage = { + /** list of items on this page of results */ + items: AlertClass[] + /** token used to fetch the next page of results (if any) */ + nextPage?: string | null +} + +export type TypedUuidForAlertKind = string + +/** + * The response received from a webhook receiver endpoint. + */ +export type WebhookDeliveryResponse = { + /** The response time of the webhook endpoint, in milliseconds. */ + durationMs: number + /** The HTTP status code returned from the webhook endpoint. */ + status: number +} + +export type WebhookDeliveryAttemptResult = + /** The webhook event has been delivered successfully. */ + | 'succeeded' + + /** A webhook request was sent to the endpoint, and it returned a HTTP error status code indicating an error. */ + | 'failed_http_error' + + /** The webhook request could not be sent to the receiver endpoint. */ + | 'failed_unreachable' + + /** A connection to the receiver endpoint was successfully established, but no response was received within the delivery timeout. */ + | 'failed_timeout' + +/** + * An individual delivery attempt for a webhook event. + * + * This represents a single HTTP request that was sent to the receiver, and its outcome. + */ +export type WebhookDeliveryAttempt = { + /** The attempt number. */ + attempt: number + response?: WebhookDeliveryResponse | null + /** The outcome of this delivery attempt: either the event was delivered successfully, or the request failed for one of several reasons. */ + result: WebhookDeliveryAttemptResult + /** The time at which the webhook delivery was attempted. */ + timeSent: Date +} + +/** + * A list of attempts to deliver an alert to a receiver. + * + * The type of the delivery attempt model depends on the receiver type, as it may contain information specific to that delivery mechanism. For example, webhook delivery attempts contain the HTTP status code of the webhook request. + */ +export type AlertDeliveryAttempts = { webhook: WebhookDeliveryAttempt[] } + +export type TypedUuidForAlertReceiverKind = string + +/** + * The state of a webhook delivery attempt. + */ +export type AlertDeliveryState = + /** The webhook event has not yet been delivered successfully. + +Either no delivery attempts have yet been performed, or the delivery has failed at least once but has retries remaining. */ + | 'pending' + + /** The webhook event has been delivered successfully. */ + | 'delivered' + + /** The webhook delivery attempt has failed permanently and will not be retried again. */ + | 'failed' + +/** + * The reason an alert was delivered + */ +export type AlertDeliveryTrigger = + /** Delivery was triggered by the alert itself. */ + | 'alert' + + /** Delivery was triggered by a request to resend the alert. */ + | 'resend' + + /** This delivery is a liveness probe. */ + | 'probe' + +/** + * A delivery of a webhook event. + */ +export type AlertDelivery = { + /** The event class. */ + alertClass: string + /** The UUID of the event. */ + alertId: TypedUuidForAlertKind + /** Individual attempts to deliver this webhook event, and their outcomes. */ + attempts: AlertDeliveryAttempts + /** The UUID of this delivery attempt. */ + id: string + /** The UUID of the alert receiver that this event was delivered to. */ + receiverId: TypedUuidForAlertReceiverKind + /** The state of this delivery. */ + state: AlertDeliveryState + /** The time at which this delivery began (i.e. the event was dispatched to the receiver). */ + timeStarted: Date + /** Why this delivery was performed. */ + trigger: AlertDeliveryTrigger +} + +export type AlertDeliveryId = { deliveryId: string } + +/** + * A single page of results + */ +export type AlertDeliveryResultsPage = { + /** list of items on this page of results */ + items: AlertDelivery[] + /** token used to fetch the next page of results (if any) */ + nextPage?: string | null +} + +/** + * Data describing the result of an alert receiver liveness probe attempt. + */ +export type AlertProbeResult = { + /** The outcome of the probe delivery. */ + probe: AlertDelivery + /** If the probe request succeeded, and resending failed deliveries on success was requested, the number of new delivery attempts started. Otherwise, if the probe did not succeed, or resending failed deliveries was not requested, this is null. + +Note that this may be 0, if there were no events found which had not been delivered successfully to this receiver. */ + resendsStarted?: number | null +} + +/** + * A view of a shared secret key assigned to a webhook receiver. + * + * Once a secret is created, the value of the secret is not available in the API, as it must remain secret. Instead, secrets are referenced by their unique IDs assigned when they are created. + */ +export type WebhookSecret = { + /** The public unique ID of the secret. */ + id: string + /** The UTC timestamp at which this secret was created. */ + timeCreated: Date +} + +/** + * The possible alert delivery mechanisms for an alert receiver. + */ +export type AlertReceiverKind = { + /** The URL that webhook notification requests are sent to. */ + endpoint: string + kind: 'webhook' + secrets: WebhookSecret[] +} + +/** + * A webhook event class subscription + * + * A webhook event class subscription matches either a single event class exactly, or a glob pattern including wildcards that may match multiple event classes + */ +export type AlertSubscription = string + +/** + * The configuration for an alert receiver. + */ +export type AlertReceiver = { + /** human-readable free-form text about a resource */ + description: string + /** unique, immutable, system-controlled identifier for each resource */ + id: string + /** Configuration specific to the kind of alert receiver that this is. */ + kind: AlertReceiverKind + /** unique, mutable, user-controlled identifier for each resource */ + name: Name + /** The list of alert classes to which this receiver is subscribed. */ + subscriptions: AlertSubscription[] + /** timestamp when this resource was created */ + timeCreated: Date + /** timestamp when this resource was last modified */ + timeModified: Date +} + +/** + * A single page of results + */ +export type AlertReceiverResultsPage = { + /** list of items on this page of results */ + items: AlertReceiver[] + /** token used to fetch the next page of results (if any) */ + nextPage?: string | null +} + +export type AlertSubscriptionCreate = { + /** The event class pattern to subscribe to. */ + subscription: AlertSubscription +} + +export type AlertSubscriptionCreated = { + /** The new subscription added to the receiver. */ + subscription: AlertSubscription +} + /** * Description of source IPs allowed to reach rack services. */ @@ -1573,26 +1785,6 @@ export type EphemeralIpCreate = { pool?: NameOrId | null } -/** - * A webhook event class. - */ -export type EventClass = { - /** A description of what this event class represents. */ - description: string - /** The name of the event class. */ - name: string -} - -/** - * A single page of results - */ -export type EventClassResultsPage = { - /** list of items on this page of results */ - items: EventClass[] - /** token used to fetch the next page of results (if any) */ - nextPage?: string | null -} - export type ExternalIp = | { ip: string; kind: 'ephemeral' } /** A Floating IP is a well-known IP address which can be attached and detached from instances. */ @@ -2033,14 +2225,20 @@ This policy determines whether the instance should be automatically restarted by Currently, the global default auto-restart policy is "best-effort", so instances with `null` auto-restart policies will be automatically restarted. However, in the future, the default policy may be configurable through other mechanisms, such as on a per-project basis. In that case, any configured default policy will be used if this is `null`. */ autoRestartPolicy?: InstanceAutoRestartPolicy | null - /** The disk this instance should boot into. This disk can either be attached if it already exists, or created, if it should be a new disk. + /** The disk the instance is configured to boot from. -It is strongly recommended to either provide a boot disk at instance creation, or update the instance after creation to set a boot disk. +This disk can either be attached if it already exists or created along with the instance. -An instance without an explicit boot disk can be booted: the options are as managed by UEFI, and as controlled by the guest OS, but with some risk. If this instance later has a disk attached or detached, it is possible that boot options can end up reordered, with the intended boot disk moved after the EFI shell in boot priority. This may result in an instance that only boots to the EFI shell until the desired disk is set as an explicit boot disk and the instance rebooted. */ +Specifying a boot disk is optional but recommended to ensure predictable boot behavior. The boot disk can be set during instance creation or later if the instance is stopped. + +An instance that does not have a boot disk set will use the boot options specified in its UEFI settings, which are controlled by both the instance's UEFI firmware and the guest operating system. Boot options can change as disks are attached and detached, which may result in an instance that only boots to the EFI shell until a boot disk is set. */ bootDisk?: InstanceDiskAttachment | null description: string - /** The disks to be created or attached for this instance. */ + /** A list of disks to be attached to the instance. + +Disk attachments of type "create" will be created, while those of type "attach" must already exist. + +The order of this list does not guarantee a boot order for the instance. Use the boot_disk attribute to specify a boot disk. */ disks?: InstanceDiskAttachment[] /** The external IP addresses provided to this instance. @@ -4010,10 +4208,6 @@ export type TimeseriesSchemaResultsPage = { nextPage?: string | null } -export type TypedUuidForWebhookEventKind = string - -export type TypedUuidForWebhookReceiverKind = string - /** * A sled that has not been added to an initialized rack yet */ @@ -4269,7 +4463,7 @@ export type VpcFirewallRuleUpdate = { /** * Updated list of firewall rules. Will replace all existing rules. */ -export type VpcFirewallRuleUpdateParams = { rules: VpcFirewallRuleUpdate[] } +export type VpcFirewallRuleUpdateParams = { rules?: VpcFirewallRuleUpdate[] } /** * Collection of a Vpc's firewall rules @@ -4400,13 +4594,6 @@ export type VpcUpdate = { name?: Name | null } -/** - * A webhook event class subscription - * - * A webhook event class subscription matches either a single event class exactly, or a glob pattern including wildcards that may match multiple event classes - */ -export type WebhookSubscription = string - /** * Create-time identity-related parameters */ @@ -4420,135 +4607,11 @@ export type WebhookCreate = { /** A list of webhook event class subscriptions. If this list is empty or is not included in the request body, the webhook will not be subscribed to any events. */ - subscriptions?: WebhookSubscription[] + subscriptions?: AlertSubscription[] } /** - * The response received from a webhook receiver endpoint. - */ -export type WebhookDeliveryResponse = { - /** The response time of the webhook endpoint, in milliseconds. */ - durationMs: number - /** The HTTP status code returned from the webhook endpoint. */ - status: number -} - -export type WebhookDeliveryAttemptResult = - /** The webhook event has been delivered successfully. */ - | 'succeeded' - - /** A webhook request was sent to the endpoint, and it returned a HTTP error status code indicating an error. */ - | 'failed_http_error' - - /** The webhook request could not be sent to the receiver endpoint. */ - | 'failed_unreachable' - - /** A connection to the receiver endpoint was successfully established, but no response was received within the delivery timeout. */ - | 'failed_timeout' - -/** - * An individual delivery attempt for a webhook event. - * - * This represents a single HTTP request that was sent to the receiver, and its outcome. - */ -export type WebhookDeliveryAttempt = { - /** The attempt number. */ - attempt: number - response?: WebhookDeliveryResponse | null - /** The outcome of this delivery attempt: either the event was delivered successfully, or the request failed for one of several reasons. */ - result: WebhookDeliveryAttemptResult - /** The time at which the webhook delivery was attempted. */ - timeSent: Date -} - -/** - * The state of a webhook delivery attempt. - */ -export type WebhookDeliveryState = - /** The webhook event has not yet been delivered successfully. - -Either no delivery attempts have yet been performed, or the delivery has failed at least once but has retries remaining. */ - | 'pending' - - /** The webhook event has been delivered successfully. */ - | 'delivered' - - /** The webhook delivery attempt has failed permanently and will not be retried again. */ - | 'failed' - -/** - * The reason a webhook event was delivered - */ -export type WebhookDeliveryTrigger = - /** Delivery was triggered by the event occurring for the first time. */ - | 'event' - - /** Delivery was triggered by a request to resend the event. */ - | 'resend' - - /** This delivery is a liveness probe. */ - | 'probe' - -/** - * A delivery of a webhook event. - */ -export type WebhookDelivery = { - /** Individual attempts to deliver this webhook event, and their outcomes. */ - attempts: WebhookDeliveryAttempt[] - /** The event class. */ - eventClass: string - /** The UUID of the event. */ - eventId: TypedUuidForWebhookEventKind - /** The UUID of this delivery attempt. */ - id: string - /** The state of this delivery. */ - state: WebhookDeliveryState - /** The time at which this delivery began (i.e. the event was dispatched to the receiver). */ - timeStarted: Date - /** Why this delivery was performed. */ - trigger: WebhookDeliveryTrigger - /** The UUID of the webhook receiver that this event was delivered to. */ - webhookId: TypedUuidForWebhookReceiverKind -} - -export type WebhookDeliveryId = { deliveryId: string } - -/** - * A single page of results - */ -export type WebhookDeliveryResultsPage = { - /** list of items on this page of results */ - items: WebhookDelivery[] - /** token used to fetch the next page of results (if any) */ - nextPage?: string | null -} - -/** - * Data describing the result of a webhook liveness probe attempt. - */ -export type WebhookProbeResult = { - /** The outcome of the probe request. */ - probe: WebhookDelivery - /** If the probe request succeeded, and resending failed deliveries on success was requested, the number of new delivery attempts started. Otherwise, if the probe did not succeed, or resending failed deliveries was not requested, this is null. - -Note that this may be 0, if there were no events found which had not been delivered successfully to this receiver. */ - resendsStarted?: number | null -} - -/** - * A view of a shared secret key assigned to a webhook receiver. - * - * Once a secret is created, the value of the secret is not available in the API, as it must remain secret. Instead, secrets are referenced by their unique IDs assigned when they are created. - */ -export type WebhookSecret = { - /** The public unique ID of the secret. */ - id: string - /** The UTC timestamp at which this secret was created. */ - timeCreated: Date -} - -/** - * The configuration for a webhook. + * The configuration for a webhook alert receiver. */ export type WebhookReceiver = { /** human-readable free-form text about a resource */ @@ -4560,24 +4623,14 @@ export type WebhookReceiver = { /** unique, mutable, user-controlled identifier for each resource */ name: Name secrets: WebhookSecret[] - /** The list of event classes to which this receiver is subscribed. */ - subscriptions: WebhookSubscription[] + /** The list of alert classes to which this receiver is subscribed. */ + subscriptions: AlertSubscription[] /** timestamp when this resource was created */ timeCreated: Date /** timestamp when this resource was last modified */ timeModified: Date } -/** - * A single page of results - */ -export type WebhookReceiverResultsPage = { - /** list of items on this page of results */ - items: WebhookReceiver[] - /** token used to fetch the next page of results (if any) */ - nextPage?: string | null -} - /** * Parameters to update a webhook configuration. */ @@ -4594,20 +4647,10 @@ export type WebhookSecretCreate = { } /** - * A list of the IDs of secrets associated with a webhook. + * A list of the IDs of secrets associated with a webhook receiver. */ export type WebhookSecrets = { secrets: WebhookSecret[] } -export type WebhookSubscriptionCreate = { - /** The event class pattern to subscribe to. */ - subscription: WebhookSubscription -} - -export type WebhookSubscriptionCreated = { - /** The new subscription added to the receiver. */ - subscription: WebhookSubscription -} - /** * Supported set of sort modes for scanning by name or id */ @@ -4628,6 +4671,16 @@ export type NameOrIdSortMode = */ export type IdSortMode = 'id_ascending' +/** + * Supported set of sort modes for scanning by timestamp and ID + */ +export type TimeAndIdSortMode = + /** sort in increasing order of timestamp and ID, i.e., earliest first */ + | 'ascending' + + /** sort in increasing order of timestamp and ID, i.e., most recent first */ + | 'descending' + export type DiskMetricName = | 'activated' | 'flush' @@ -4653,16 +4706,6 @@ export type SystemMetricName = */ export type NameSortMode = 'name_ascending' -/** - * Supported set of sort modes for scanning by timestamp and ID - */ -export type TimeAndIdSortMode = - /** sort in increasing order of timestamp and ID, i.e., earliest first */ - | 'ascending' - - /** sort in increasing order of timestamp and ID, i.e., most recent first */ - | 'descending' - export interface ProbeListQueryParams { limit?: number | null pageToken?: string | null @@ -4697,33 +4740,33 @@ export interface SupportBundleListQueryParams { } export interface SupportBundleViewPathParams { - supportBundle: string + bundleId: string } export interface SupportBundleDeletePathParams { - supportBundle: string + bundleId: string } export interface SupportBundleDownloadPathParams { - supportBundle: string + bundleId: string } export interface SupportBundleHeadPathParams { - supportBundle: string + bundleId: string } export interface SupportBundleDownloadFilePathParams { + bundleId: string file: string - supportBundle: string } export interface SupportBundleHeadFilePathParams { + bundleId: string file: string - supportBundle: string } export interface SupportBundleIndexPathParams { - supportBundle: string + bundleId: string } export interface LoginSamlPathParams { @@ -4770,38 +4813,96 @@ export interface AffinityGroupMemberListPathParams { affinityGroup: NameOrId } -export interface AffinityGroupMemberListQueryParams { +export interface AffinityGroupMemberListQueryParams { + limit?: number | null + pageToken?: string | null + project?: NameOrId + sortBy?: NameOrIdSortMode +} + +export interface AffinityGroupMemberInstanceViewPathParams { + affinityGroup: NameOrId + instance: NameOrId +} + +export interface AffinityGroupMemberInstanceViewQueryParams { + project?: NameOrId +} + +export interface AffinityGroupMemberInstanceAddPathParams { + affinityGroup: NameOrId + instance: NameOrId +} + +export interface AffinityGroupMemberInstanceAddQueryParams { + project?: NameOrId +} + +export interface AffinityGroupMemberInstanceDeletePathParams { + affinityGroup: NameOrId + instance: NameOrId +} + +export interface AffinityGroupMemberInstanceDeleteQueryParams { + project?: NameOrId +} + +export interface AlertClassListQueryParams { + limit?: number | null + pageToken?: string | null + filter?: AlertSubscription +} + +export interface AlertReceiverListQueryParams { + limit?: number | null + pageToken?: string | null + sortBy?: NameOrIdSortMode +} + +export interface AlertReceiverViewPathParams { + receiver: NameOrId +} + +export interface AlertReceiverDeletePathParams { + receiver: NameOrId +} + +export interface AlertDeliveryListPathParams { + receiver: NameOrId +} + +export interface AlertDeliveryListQueryParams { + delivered?: boolean | null + failed?: boolean | null + pending?: boolean | null limit?: number | null pageToken?: string | null - project?: NameOrId - sortBy?: NameOrIdSortMode + sortBy?: TimeAndIdSortMode } -export interface AffinityGroupMemberInstanceViewPathParams { - affinityGroup: NameOrId - instance: NameOrId +export interface AlertReceiverProbePathParams { + receiver: NameOrId } -export interface AffinityGroupMemberInstanceViewQueryParams { - project?: NameOrId +export interface AlertReceiverProbeQueryParams { + resend?: boolean } -export interface AffinityGroupMemberInstanceAddPathParams { - affinityGroup: NameOrId - instance: NameOrId +export interface AlertReceiverSubscriptionAddPathParams { + receiver: NameOrId } -export interface AffinityGroupMemberInstanceAddQueryParams { - project?: NameOrId +export interface AlertReceiverSubscriptionRemovePathParams { + receiver: NameOrId + subscription: AlertSubscription } -export interface AffinityGroupMemberInstanceDeletePathParams { - affinityGroup: NameOrId - instance: NameOrId +export interface AlertDeliveryResendPathParams { + alertId: string } -export interface AffinityGroupMemberInstanceDeleteQueryParams { - project?: NameOrId +export interface AlertDeliveryResendQueryParams { + receiver: NameOrId } export interface AntiAffinityGroupListQueryParams { @@ -5624,7 +5725,7 @@ export interface SamlIdentityProviderViewPathParams { } export interface SamlIdentityProviderViewQueryParams { - silo: NameOrId + silo?: NameOrId } export interface IpPoolListQueryParams { @@ -6076,65 +6177,10 @@ export interface VpcDeleteQueryParams { project?: NameOrId } -export interface WebhookDeliveryListQueryParams { - receiver: NameOrId - delivered?: boolean | null - failed?: boolean | null - pending?: boolean | null - limit?: number | null - pageToken?: string | null - sortBy?: TimeAndIdSortMode -} - -export interface WebhookDeliveryResendPathParams { - eventId: string -} - -export interface WebhookDeliveryResendQueryParams { - receiver: NameOrId -} - -export interface WebhookEventClassListQueryParams { - limit?: number | null - pageToken?: string | null - filter?: WebhookSubscription -} - -export interface WebhookReceiverListQueryParams { - limit?: number | null - pageToken?: string | null - sortBy?: NameOrIdSortMode -} - -export interface WebhookReceiverViewPathParams { - receiver: NameOrId -} - export interface WebhookReceiverUpdatePathParams { receiver: NameOrId } -export interface WebhookReceiverDeletePathParams { - receiver: NameOrId -} - -export interface WebhookReceiverProbePathParams { - receiver: NameOrId -} - -export interface WebhookReceiverProbeQueryParams { - resend?: boolean -} - -export interface WebhookReceiverSubscriptionAddPathParams { - receiver: NameOrId -} - -export interface WebhookReceiverSubscriptionRemovePathParams { - receiver: NameOrId - subscription: WebhookSubscription -} - export interface WebhookSecretsListQueryParams { receiver: NameOrId } @@ -6270,7 +6316,7 @@ export class Api extends HttpClient { params: FetchParams = {} ) => { return this.request({ - path: `/experimental/v1/system/support-bundles/${path.supportBundle}`, + path: `/experimental/v1/system/support-bundles/${path.bundleId}`, method: 'GET', ...params, }) @@ -6283,7 +6329,7 @@ export class Api extends HttpClient { params: FetchParams = {} ) => { return this.request({ - path: `/experimental/v1/system/support-bundles/${path.supportBundle}`, + path: `/experimental/v1/system/support-bundles/${path.bundleId}`, method: 'DELETE', ...params, }) @@ -6296,7 +6342,7 @@ export class Api extends HttpClient { params: FetchParams = {} ) => { return this.request({ - path: `/experimental/v1/system/support-bundles/${path.supportBundle}/download`, + path: `/experimental/v1/system/support-bundles/${path.bundleId}/download`, method: 'GET', ...params, }) @@ -6309,7 +6355,7 @@ export class Api extends HttpClient { params: FetchParams = {} ) => { return this.request({ - path: `/experimental/v1/system/support-bundles/${path.supportBundle}/download`, + path: `/experimental/v1/system/support-bundles/${path.bundleId}/download`, method: 'HEAD', ...params, }) @@ -6322,7 +6368,7 @@ export class Api extends HttpClient { params: FetchParams = {} ) => { return this.request({ - path: `/experimental/v1/system/support-bundles/${path.supportBundle}/download/${path.file}`, + path: `/experimental/v1/system/support-bundles/${path.bundleId}/download/${path.file}`, method: 'GET', ...params, }) @@ -6335,7 +6381,7 @@ export class Api extends HttpClient { params: FetchParams = {} ) => { return this.request({ - path: `/experimental/v1/system/support-bundles/${path.supportBundle}/download/${path.file}`, + path: `/experimental/v1/system/support-bundles/${path.bundleId}/download/${path.file}`, method: 'HEAD', ...params, }) @@ -6348,7 +6394,7 @@ export class Api extends HttpClient { params: FetchParams = {} ) => { return this.request({ - path: `/experimental/v1/system/support-bundles/${path.supportBundle}/index`, + path: `/experimental/v1/system/support-bundles/${path.bundleId}/index`, method: 'GET', ...params, }) @@ -6529,6 +6575,141 @@ export class Api extends HttpClient { ...params, }) }, + /** + * List alert classes + */ + alertClassList: ( + { query = {} }: { query?: AlertClassListQueryParams }, + params: FetchParams = {} + ) => { + return this.request({ + path: `/v1/alert-classes`, + method: 'GET', + query, + ...params, + }) + }, + /** + * List alert receivers + */ + alertReceiverList: ( + { query = {} }: { query?: AlertReceiverListQueryParams }, + params: FetchParams = {} + ) => { + return this.request({ + path: `/v1/alert-receivers`, + method: 'GET', + query, + ...params, + }) + }, + /** + * Fetch alert receiver + */ + alertReceiverView: ( + { path }: { path: AlertReceiverViewPathParams }, + params: FetchParams = {} + ) => { + return this.request({ + path: `/v1/alert-receivers/${path.receiver}`, + method: 'GET', + ...params, + }) + }, + /** + * Delete alert receiver + */ + alertReceiverDelete: ( + { path }: { path: AlertReceiverDeletePathParams }, + params: FetchParams = {} + ) => { + return this.request({ + path: `/v1/alert-receivers/${path.receiver}`, + method: 'DELETE', + ...params, + }) + }, + /** + * List delivery attempts to alert receiver + */ + alertDeliveryList: ( + { + path, + query = {}, + }: { path: AlertDeliveryListPathParams; query?: AlertDeliveryListQueryParams }, + params: FetchParams = {} + ) => { + return this.request({ + path: `/v1/alert-receivers/${path.receiver}/deliveries`, + method: 'GET', + query, + ...params, + }) + }, + /** + * Send liveness probe to alert receiver + */ + alertReceiverProbe: ( + { + path, + query = {}, + }: { path: AlertReceiverProbePathParams; query?: AlertReceiverProbeQueryParams }, + params: FetchParams = {} + ) => { + return this.request({ + path: `/v1/alert-receivers/${path.receiver}/probe`, + method: 'POST', + query, + ...params, + }) + }, + /** + * Add alert receiver subscription + */ + alertReceiverSubscriptionAdd: ( + { + path, + body, + }: { path: AlertReceiverSubscriptionAddPathParams; body: AlertSubscriptionCreate }, + params: FetchParams = {} + ) => { + return this.request({ + path: `/v1/alert-receivers/${path.receiver}/subscriptions`, + method: 'POST', + body, + ...params, + }) + }, + /** + * Remove alert receiver subscription + */ + alertReceiverSubscriptionRemove: ( + { path }: { path: AlertReceiverSubscriptionRemovePathParams }, + params: FetchParams = {} + ) => { + return this.request({ + path: `/v1/alert-receivers/${path.receiver}/subscriptions/${path.subscription}`, + method: 'DELETE', + ...params, + }) + }, + /** + * Request re-delivery of alert + */ + alertDeliveryResend: ( + { + path, + query, + }: { path: AlertDeliveryResendPathParams; query: AlertDeliveryResendQueryParams }, + params: FetchParams = {} + ) => { + return this.request({ + path: `/v1/alerts/${path.alertId}/resend`, + method: 'POST', + query, + ...params, + }) + }, /** * List anti-affinity groups */ @@ -8510,10 +8691,10 @@ export class Api extends HttpClient { samlIdentityProviderView: ( { path, - query, + query = {}, }: { path: SamlIdentityProviderViewPathParams - query: SamlIdentityProviderViewQueryParams + query?: SamlIdentityProviderViewQueryParams }, params: FetchParams = {} ) => { @@ -9859,65 +10040,6 @@ export class Api extends HttpClient { ...params, }) }, - /** - * List delivery attempts to webhook receiver - */ - webhookDeliveryList: ( - { query }: { query: WebhookDeliveryListQueryParams }, - params: FetchParams = {} - ) => { - return this.request({ - path: `/v1/webhooks/deliveries`, - method: 'GET', - query, - ...params, - }) - }, - /** - * Request re-delivery of webhook event - */ - webhookDeliveryResend: ( - { - path, - query, - }: { path: WebhookDeliveryResendPathParams; query: WebhookDeliveryResendQueryParams }, - params: FetchParams = {} - ) => { - return this.request({ - path: `/v1/webhooks/deliveries/${path.eventId}/resend`, - method: 'POST', - query, - ...params, - }) - }, - /** - * List webhook event classes - */ - webhookEventClassList: ( - { query = {} }: { query?: WebhookEventClassListQueryParams }, - params: FetchParams = {} - ) => { - return this.request({ - path: `/v1/webhooks/event-classes`, - method: 'GET', - query, - ...params, - }) - }, - /** - * List webhook receivers - */ - webhookReceiverList: ( - { query = {} }: { query?: WebhookReceiverListQueryParams }, - params: FetchParams = {} - ) => { - return this.request({ - path: `/v1/webhooks/receivers`, - method: 'GET', - query, - ...params, - }) - }, /** * Create webhook receiver */ @@ -9926,25 +10048,12 @@ export class Api extends HttpClient { params: FetchParams = {} ) => { return this.request({ - path: `/v1/webhooks/receivers`, + path: `/v1/webhook-receivers`, method: 'POST', body, ...params, }) }, - /** - * Fetch webhook receiver - */ - webhookReceiverView: ( - { path }: { path: WebhookReceiverViewPathParams }, - params: FetchParams = {} - ) => { - return this.request({ - path: `/v1/webhooks/receivers/${path.receiver}`, - method: 'GET', - ...params, - }) - }, /** * Update webhook receiver */ @@ -9956,75 +10065,12 @@ export class Api extends HttpClient { params: FetchParams = {} ) => { return this.request({ - path: `/v1/webhooks/receivers/${path.receiver}`, + path: `/v1/webhook-receivers/${path.receiver}`, method: 'PUT', body, ...params, }) }, - /** - * Delete webhook receiver - */ - webhookReceiverDelete: ( - { path }: { path: WebhookReceiverDeletePathParams }, - params: FetchParams = {} - ) => { - return this.request({ - path: `/v1/webhooks/receivers/${path.receiver}`, - method: 'DELETE', - ...params, - }) - }, - /** - * Send liveness probe to webhook receiver - */ - webhookReceiverProbe: ( - { - path, - query = {}, - }: { path: WebhookReceiverProbePathParams; query?: WebhookReceiverProbeQueryParams }, - params: FetchParams = {} - ) => { - return this.request({ - path: `/v1/webhooks/receivers/${path.receiver}/probe`, - method: 'POST', - query, - ...params, - }) - }, - /** - * Add webhook receiver subscription - */ - webhookReceiverSubscriptionAdd: ( - { - path, - body, - }: { - path: WebhookReceiverSubscriptionAddPathParams - body: WebhookSubscriptionCreate - }, - params: FetchParams = {} - ) => { - return this.request({ - path: `/v1/webhooks/receivers/${path.receiver}/subscriptions`, - method: 'POST', - body, - ...params, - }) - }, - /** - * Remove webhook receiver subscription - */ - webhookReceiverSubscriptionRemove: ( - { path }: { path: WebhookReceiverSubscriptionRemovePathParams }, - params: FetchParams = {} - ) => { - return this.request({ - path: `/v1/webhooks/receivers/${path.receiver}/subscriptions/${path.subscription}`, - method: 'DELETE', - ...params, - }) - }, /** * List webhook receiver secret IDs */ @@ -10033,7 +10079,7 @@ export class Api extends HttpClient { params: FetchParams = {} ) => { return this.request({ - path: `/v1/webhooks/secrets`, + path: `/v1/webhook-secrets`, method: 'GET', query, ...params, @@ -10047,7 +10093,7 @@ export class Api extends HttpClient { params: FetchParams = {} ) => { return this.request({ - path: `/v1/webhooks/secrets`, + path: `/v1/webhook-secrets`, method: 'POST', body, query, @@ -10062,7 +10108,7 @@ export class Api extends HttpClient { params: FetchParams = {} ) => { return this.request({ - path: `/v1/webhooks/secrets/${path.secretId}`, + path: `/v1/webhook-secrets/${path.secretId}`, method: 'DELETE', ...params, }) diff --git a/app/api/__generated__/OMICRON_VERSION b/app/api/__generated__/OMICRON_VERSION index bf1eafc66..023d451d7 100644 --- a/app/api/__generated__/OMICRON_VERSION +++ b/app/api/__generated__/OMICRON_VERSION @@ -1,2 +1,2 @@ # generated file. do not update manually. see docs/update-pinned-api.md -1848d1833df1df880c609992aaf6ea6934b38d28 +80e992229b52cecb517a59a0f686f8916549343f diff --git a/app/api/__generated__/msw-handlers.ts b/app/api/__generated__/msw-handlers.ts index 90dbaab17..d47419ac7 100644 --- a/app/api/__generated__/msw-handlers.ts +++ b/app/api/__generated__/msw-handlers.ts @@ -99,43 +99,43 @@ export interface MSWHandlers { req: Request cookies: Record }) => Promisable> - /** `GET /experimental/v1/system/support-bundles/:supportBundle` */ + /** `GET /experimental/v1/system/support-bundles/:bundleId` */ supportBundleView: (params: { path: Api.SupportBundleViewPathParams req: Request cookies: Record }) => Promisable> - /** `DELETE /experimental/v1/system/support-bundles/:supportBundle` */ + /** `DELETE /experimental/v1/system/support-bundles/:bundleId` */ supportBundleDelete: (params: { path: Api.SupportBundleDeletePathParams req: Request cookies: Record }) => Promisable - /** `GET /experimental/v1/system/support-bundles/:supportBundle/download` */ + /** `GET /experimental/v1/system/support-bundles/:bundleId/download` */ supportBundleDownload: (params: { path: Api.SupportBundleDownloadPathParams req: Request cookies: Record }) => Promisable - /** `HEAD /experimental/v1/system/support-bundles/:supportBundle/download` */ + /** `HEAD /experimental/v1/system/support-bundles/:bundleId/download` */ supportBundleHead: (params: { path: Api.SupportBundleHeadPathParams req: Request cookies: Record }) => Promisable - /** `GET /experimental/v1/system/support-bundles/:supportBundle/download/:file` */ + /** `GET /experimental/v1/system/support-bundles/:bundleId/download/:file` */ supportBundleDownloadFile: (params: { path: Api.SupportBundleDownloadFilePathParams req: Request cookies: Record }) => Promisable - /** `HEAD /experimental/v1/system/support-bundles/:supportBundle/download/:file` */ + /** `HEAD /experimental/v1/system/support-bundles/:bundleId/download/:file` */ supportBundleHeadFile: (params: { path: Api.SupportBundleHeadFilePathParams req: Request cookies: Record }) => Promisable - /** `GET /experimental/v1/system/support-bundles/:supportBundle/index` */ + /** `GET /experimental/v1/system/support-bundles/:bundleId/index` */ supportBundleIndex: (params: { path: Api.SupportBundleIndexPathParams req: Request @@ -210,6 +210,64 @@ export interface MSWHandlers { req: Request cookies: Record }) => Promisable + /** `GET /v1/alert-classes` */ + alertClassList: (params: { + query: Api.AlertClassListQueryParams + req: Request + cookies: Record + }) => Promisable> + /** `GET /v1/alert-receivers` */ + alertReceiverList: (params: { + query: Api.AlertReceiverListQueryParams + req: Request + cookies: Record + }) => Promisable> + /** `GET /v1/alert-receivers/:receiver` */ + alertReceiverView: (params: { + path: Api.AlertReceiverViewPathParams + req: Request + cookies: Record + }) => Promisable> + /** `DELETE /v1/alert-receivers/:receiver` */ + alertReceiverDelete: (params: { + path: Api.AlertReceiverDeletePathParams + req: Request + cookies: Record + }) => Promisable + /** `GET /v1/alert-receivers/:receiver/deliveries` */ + alertDeliveryList: (params: { + path: Api.AlertDeliveryListPathParams + query: Api.AlertDeliveryListQueryParams + req: Request + cookies: Record + }) => Promisable> + /** `POST /v1/alert-receivers/:receiver/probe` */ + alertReceiverProbe: (params: { + path: Api.AlertReceiverProbePathParams + query: Api.AlertReceiverProbeQueryParams + req: Request + cookies: Record + }) => Promisable> + /** `POST /v1/alert-receivers/:receiver/subscriptions` */ + alertReceiverSubscriptionAdd: (params: { + path: Api.AlertReceiverSubscriptionAddPathParams + body: Json + req: Request + cookies: Record + }) => Promisable> + /** `DELETE /v1/alert-receivers/:receiver/subscriptions/:subscription` */ + alertReceiverSubscriptionRemove: (params: { + path: Api.AlertReceiverSubscriptionRemovePathParams + req: Request + cookies: Record + }) => Promisable + /** `POST /v1/alerts/:alertId/resend` */ + alertDeliveryResend: (params: { + path: Api.AlertDeliveryResendPathParams + query: Api.AlertDeliveryResendQueryParams + req: Request + cookies: Record + }) => Promisable> /** `GET /v1/anti-affinity-groups` */ antiAffinityGroupList: (params: { query: Api.AntiAffinityGroupListQueryParams @@ -1626,90 +1684,33 @@ export interface MSWHandlers { req: Request cookies: Record }) => Promisable - /** `GET /v1/webhooks/deliveries` */ - webhookDeliveryList: (params: { - query: Api.WebhookDeliveryListQueryParams - req: Request - cookies: Record - }) => Promisable> - /** `POST /v1/webhooks/deliveries/:eventId/resend` */ - webhookDeliveryResend: (params: { - path: Api.WebhookDeliveryResendPathParams - query: Api.WebhookDeliveryResendQueryParams - req: Request - cookies: Record - }) => Promisable> - /** `GET /v1/webhooks/event-classes` */ - webhookEventClassList: (params: { - query: Api.WebhookEventClassListQueryParams - req: Request - cookies: Record - }) => Promisable> - /** `GET /v1/webhooks/receivers` */ - webhookReceiverList: (params: { - query: Api.WebhookReceiverListQueryParams - req: Request - cookies: Record - }) => Promisable> - /** `POST /v1/webhooks/receivers` */ + /** `POST /v1/webhook-receivers` */ webhookReceiverCreate: (params: { body: Json req: Request cookies: Record }) => Promisable> - /** `GET /v1/webhooks/receivers/:receiver` */ - webhookReceiverView: (params: { - path: Api.WebhookReceiverViewPathParams - req: Request - cookies: Record - }) => Promisable> - /** `PUT /v1/webhooks/receivers/:receiver` */ + /** `PUT /v1/webhook-receivers/:receiver` */ webhookReceiverUpdate: (params: { path: Api.WebhookReceiverUpdatePathParams body: Json req: Request cookies: Record }) => Promisable - /** `DELETE /v1/webhooks/receivers/:receiver` */ - webhookReceiverDelete: (params: { - path: Api.WebhookReceiverDeletePathParams - req: Request - cookies: Record - }) => Promisable - /** `POST /v1/webhooks/receivers/:receiver/probe` */ - webhookReceiverProbe: (params: { - path: Api.WebhookReceiverProbePathParams - query: Api.WebhookReceiverProbeQueryParams - req: Request - cookies: Record - }) => Promisable> - /** `POST /v1/webhooks/receivers/:receiver/subscriptions` */ - webhookReceiverSubscriptionAdd: (params: { - path: Api.WebhookReceiverSubscriptionAddPathParams - body: Json - req: Request - cookies: Record - }) => Promisable> - /** `DELETE /v1/webhooks/receivers/:receiver/subscriptions/:subscription` */ - webhookReceiverSubscriptionRemove: (params: { - path: Api.WebhookReceiverSubscriptionRemovePathParams - req: Request - cookies: Record - }) => Promisable - /** `GET /v1/webhooks/secrets` */ + /** `GET /v1/webhook-secrets` */ webhookSecretsList: (params: { query: Api.WebhookSecretsListQueryParams req: Request cookies: Record }) => Promisable> - /** `POST /v1/webhooks/secrets` */ + /** `POST /v1/webhook-secrets` */ webhookSecretsAdd: (params: { query: Api.WebhookSecretsAddQueryParams body: Json req: Request cookies: Record }) => Promisable> - /** `DELETE /v1/webhooks/secrets/:secretId` */ + /** `DELETE /v1/webhook-secrets/:secretId` */ webhookSecretsDelete: (params: { path: Api.WebhookSecretsDeletePathParams req: Request @@ -1851,23 +1852,23 @@ export function makeHandlers(handlers: MSWHandlers): HttpHandler[] { handler(handlers['supportBundleCreate'], null, null) ), http.get( - '/experimental/v1/system/support-bundles/:supportBundle', + '/experimental/v1/system/support-bundles/:bundleId', handler(handlers['supportBundleView'], schema.SupportBundleViewParams, null) ), http.delete( - '/experimental/v1/system/support-bundles/:supportBundle', + '/experimental/v1/system/support-bundles/:bundleId', handler(handlers['supportBundleDelete'], schema.SupportBundleDeleteParams, null) ), http.get( - '/experimental/v1/system/support-bundles/:supportBundle/download', + '/experimental/v1/system/support-bundles/:bundleId/download', handler(handlers['supportBundleDownload'], schema.SupportBundleDownloadParams, null) ), http.head( - '/experimental/v1/system/support-bundles/:supportBundle/download', + '/experimental/v1/system/support-bundles/:bundleId/download', handler(handlers['supportBundleHead'], schema.SupportBundleHeadParams, null) ), http.get( - '/experimental/v1/system/support-bundles/:supportBundle/download/:file', + '/experimental/v1/system/support-bundles/:bundleId/download/:file', handler( handlers['supportBundleDownloadFile'], schema.SupportBundleDownloadFileParams, @@ -1875,11 +1876,11 @@ export function makeHandlers(handlers: MSWHandlers): HttpHandler[] { ) ), http.head( - '/experimental/v1/system/support-bundles/:supportBundle/download/:file', + '/experimental/v1/system/support-bundles/:bundleId/download/:file', handler(handlers['supportBundleHeadFile'], schema.SupportBundleHeadFileParams, null) ), http.get( - '/experimental/v1/system/support-bundles/:supportBundle/index', + '/experimental/v1/system/support-bundles/:bundleId/index', handler(handlers['supportBundleIndex'], schema.SupportBundleIndexParams, null) ), http.post( @@ -1946,6 +1947,50 @@ export function makeHandlers(handlers: MSWHandlers): HttpHandler[] { null ) ), + http.get( + '/v1/alert-classes', + handler(handlers['alertClassList'], schema.AlertClassListParams, null) + ), + http.get( + '/v1/alert-receivers', + handler(handlers['alertReceiverList'], schema.AlertReceiverListParams, null) + ), + http.get( + '/v1/alert-receivers/:receiver', + handler(handlers['alertReceiverView'], schema.AlertReceiverViewParams, null) + ), + http.delete( + '/v1/alert-receivers/:receiver', + handler(handlers['alertReceiverDelete'], schema.AlertReceiverDeleteParams, null) + ), + http.get( + '/v1/alert-receivers/:receiver/deliveries', + handler(handlers['alertDeliveryList'], schema.AlertDeliveryListParams, null) + ), + http.post( + '/v1/alert-receivers/:receiver/probe', + handler(handlers['alertReceiverProbe'], schema.AlertReceiverProbeParams, null) + ), + http.post( + '/v1/alert-receivers/:receiver/subscriptions', + handler( + handlers['alertReceiverSubscriptionAdd'], + schema.AlertReceiverSubscriptionAddParams, + schema.AlertSubscriptionCreate + ) + ), + http.delete( + '/v1/alert-receivers/:receiver/subscriptions/:subscription', + handler( + handlers['alertReceiverSubscriptionRemove'], + schema.AlertReceiverSubscriptionRemoveParams, + null + ) + ), + http.post( + '/v1/alerts/:alertId/resend', + handler(handlers['alertDeliveryResend'], schema.AlertDeliveryResendParams, null) + ), http.get( '/v1/anti-affinity-groups', handler(handlers['antiAffinityGroupList'], schema.AntiAffinityGroupListParams, null) @@ -3105,68 +3150,24 @@ export function makeHandlers(handlers: MSWHandlers): HttpHandler[] { '/v1/vpcs/:vpc', handler(handlers['vpcDelete'], schema.VpcDeleteParams, null) ), - http.get( - '/v1/webhooks/deliveries', - handler(handlers['webhookDeliveryList'], schema.WebhookDeliveryListParams, null) - ), http.post( - '/v1/webhooks/deliveries/:eventId/resend', - handler(handlers['webhookDeliveryResend'], schema.WebhookDeliveryResendParams, null) - ), - http.get( - '/v1/webhooks/event-classes', - handler(handlers['webhookEventClassList'], schema.WebhookEventClassListParams, null) - ), - http.get( - '/v1/webhooks/receivers', - handler(handlers['webhookReceiverList'], schema.WebhookReceiverListParams, null) - ), - http.post( - '/v1/webhooks/receivers', + '/v1/webhook-receivers', handler(handlers['webhookReceiverCreate'], null, schema.WebhookCreate) ), - http.get( - '/v1/webhooks/receivers/:receiver', - handler(handlers['webhookReceiverView'], schema.WebhookReceiverViewParams, null) - ), http.put( - '/v1/webhooks/receivers/:receiver', + '/v1/webhook-receivers/:receiver', handler( handlers['webhookReceiverUpdate'], schema.WebhookReceiverUpdateParams, schema.WebhookReceiverUpdate ) ), - http.delete( - '/v1/webhooks/receivers/:receiver', - handler(handlers['webhookReceiverDelete'], schema.WebhookReceiverDeleteParams, null) - ), - http.post( - '/v1/webhooks/receivers/:receiver/probe', - handler(handlers['webhookReceiverProbe'], schema.WebhookReceiverProbeParams, null) - ), - http.post( - '/v1/webhooks/receivers/:receiver/subscriptions', - handler( - handlers['webhookReceiverSubscriptionAdd'], - schema.WebhookReceiverSubscriptionAddParams, - schema.WebhookSubscriptionCreate - ) - ), - http.delete( - '/v1/webhooks/receivers/:receiver/subscriptions/:subscription', - handler( - handlers['webhookReceiverSubscriptionRemove'], - schema.WebhookReceiverSubscriptionRemoveParams, - null - ) - ), http.get( - '/v1/webhooks/secrets', + '/v1/webhook-secrets', handler(handlers['webhookSecretsList'], schema.WebhookSecretsListParams, null) ), http.post( - '/v1/webhooks/secrets', + '/v1/webhook-secrets', handler( handlers['webhookSecretsAdd'], schema.WebhookSecretsAddParams, @@ -3174,7 +3175,7 @@ export function makeHandlers(handlers: MSWHandlers): HttpHandler[] { ) ), http.delete( - '/v1/webhooks/secrets/:secretId', + '/v1/webhook-secrets/:secretId', handler(handlers['webhookSecretsDelete'], schema.WebhookSecretsDeleteParams, null) ), ] diff --git a/app/api/__generated__/validate.ts b/app/api/__generated__/validate.ts index 2d75aeaec..158b4bb52 100644 --- a/app/api/__generated__/validate.ts +++ b/app/api/__generated__/validate.ts @@ -312,6 +312,190 @@ export const AggregateBgpMessageHistory = z.preprocess( z.object({ switchHistories: SwitchBgpHistory.array() }) ) +/** + * An alert class. + */ +export const AlertClass = z.preprocess( + processResponseBody, + z.object({ description: z.string(), name: z.string() }) +) + +/** + * A single page of results + */ +export const AlertClassResultsPage = z.preprocess( + processResponseBody, + z.object({ items: AlertClass.array(), nextPage: z.string().nullable().optional() }) +) + +export const TypedUuidForAlertKind = z.preprocess(processResponseBody, z.string().uuid()) + +/** + * The response received from a webhook receiver endpoint. + */ +export const WebhookDeliveryResponse = z.preprocess( + processResponseBody, + z.object({ durationMs: z.number().min(0), status: z.number().min(0).max(65535) }) +) + +export const WebhookDeliveryAttemptResult = z.preprocess( + processResponseBody, + z.enum(['succeeded', 'failed_http_error', 'failed_unreachable', 'failed_timeout']) +) + +/** + * An individual delivery attempt for a webhook event. + * + * This represents a single HTTP request that was sent to the receiver, and its outcome. + */ +export const WebhookDeliveryAttempt = z.preprocess( + processResponseBody, + z.object({ + attempt: z.number().min(0), + response: WebhookDeliveryResponse.nullable().optional(), + result: WebhookDeliveryAttemptResult, + timeSent: z.coerce.date(), + }) +) + +/** + * A list of attempts to deliver an alert to a receiver. + * + * The type of the delivery attempt model depends on the receiver type, as it may contain information specific to that delivery mechanism. For example, webhook delivery attempts contain the HTTP status code of the webhook request. + */ +export const AlertDeliveryAttempts = z.preprocess( + processResponseBody, + z.object({ webhook: WebhookDeliveryAttempt.array() }) +) + +export const TypedUuidForAlertReceiverKind = z.preprocess( + processResponseBody, + z.string().uuid() +) + +/** + * The state of a webhook delivery attempt. + */ +export const AlertDeliveryState = z.preprocess( + processResponseBody, + z.enum(['pending', 'delivered', 'failed']) +) + +/** + * The reason an alert was delivered + */ +export const AlertDeliveryTrigger = z.preprocess( + processResponseBody, + z.enum(['alert', 'resend', 'probe']) +) + +/** + * A delivery of a webhook event. + */ +export const AlertDelivery = z.preprocess( + processResponseBody, + z.object({ + alertClass: z.string(), + alertId: TypedUuidForAlertKind, + attempts: AlertDeliveryAttempts, + id: z.string().uuid(), + receiverId: TypedUuidForAlertReceiverKind, + state: AlertDeliveryState, + timeStarted: z.coerce.date(), + trigger: AlertDeliveryTrigger, + }) +) + +export const AlertDeliveryId = z.preprocess( + processResponseBody, + z.object({ deliveryId: z.string().uuid() }) +) + +/** + * A single page of results + */ +export const AlertDeliveryResultsPage = z.preprocess( + processResponseBody, + z.object({ items: AlertDelivery.array(), nextPage: z.string().nullable().optional() }) +) + +/** + * Data describing the result of an alert receiver liveness probe attempt. + */ +export const AlertProbeResult = z.preprocess( + processResponseBody, + z.object({ + probe: AlertDelivery, + resendsStarted: z.number().min(0).nullable().optional(), + }) +) + +/** + * A view of a shared secret key assigned to a webhook receiver. + * + * Once a secret is created, the value of the secret is not available in the API, as it must remain secret. Instead, secrets are referenced by their unique IDs assigned when they are created. + */ +export const WebhookSecret = z.preprocess( + processResponseBody, + z.object({ id: z.string().uuid(), timeCreated: z.coerce.date() }) +) + +/** + * The possible alert delivery mechanisms for an alert receiver. + */ +export const AlertReceiverKind = z.preprocess( + processResponseBody, + z.object({ + endpoint: z.string(), + kind: z.enum(['webhook']), + secrets: WebhookSecret.array(), + }) +) + +/** + * A webhook event class subscription + * + * A webhook event class subscription matches either a single event class exactly, or a glob pattern including wildcards that may match multiple event classes + */ +export const AlertSubscription = z.preprocess( + processResponseBody, + z.string().regex(/^([a-zA-Z0-9_]+|\*|\*\*)(\.([a-zA-Z0-9_]+|\*|\*\*))*$/) +) + +/** + * The configuration for an alert receiver. + */ +export const AlertReceiver = z.preprocess( + processResponseBody, + z.object({ + description: z.string(), + id: z.string().uuid(), + kind: AlertReceiverKind, + name: Name, + subscriptions: AlertSubscription.array(), + timeCreated: z.coerce.date(), + timeModified: z.coerce.date(), + }) +) + +/** + * A single page of results + */ +export const AlertReceiverResultsPage = z.preprocess( + processResponseBody, + z.object({ items: AlertReceiver.array(), nextPage: z.string().nullable().optional() }) +) + +export const AlertSubscriptionCreate = z.preprocess( + processResponseBody, + z.object({ subscription: AlertSubscription }) +) + +export const AlertSubscriptionCreated = z.preprocess( + processResponseBody, + z.object({ subscription: AlertSubscription }) +) + /** * Description of source IPs allowed to reach rack services. */ @@ -1501,22 +1685,6 @@ export const Error = z.preprocess( z.object({ errorCode: z.string().optional(), message: z.string(), requestId: z.string() }) ) -/** - * A webhook event class. - */ -export const EventClass = z.preprocess( - processResponseBody, - z.object({ description: z.string(), name: z.string() }) -) - -/** - * A single page of results - */ -export const EventClassResultsPage = z.preprocess( - processResponseBody, - z.object({ items: EventClass.array(), nextPage: z.string().nullable().optional() }) -) - export const ExternalIp = z.preprocess( processResponseBody, z.union([ @@ -3751,16 +3919,6 @@ export const TimeseriesSchemaResultsPage = z.preprocess( z.object({ items: TimeseriesSchema.array(), nextPage: z.string().nullable().optional() }) ) -export const TypedUuidForWebhookEventKind = z.preprocess( - processResponseBody, - z.string().uuid() -) - -export const TypedUuidForWebhookReceiverKind = z.preprocess( - processResponseBody, - z.string().uuid() -) - /** * A sled that has not been added to an initialized rack yet */ @@ -4017,7 +4175,7 @@ export const VpcFirewallRuleUpdate = z.preprocess( */ export const VpcFirewallRuleUpdateParams = z.preprocess( processResponseBody, - z.object({ rules: VpcFirewallRuleUpdate.array() }) + z.object({ rules: VpcFirewallRuleUpdate.array().default([]).optional() }) ) /** @@ -4145,16 +4303,6 @@ export const VpcUpdate = z.preprocess( }) ) -/** - * A webhook event class subscription - * - * A webhook event class subscription matches either a single event class exactly, or a glob pattern including wildcards that may match multiple event classes - */ -export const WebhookSubscription = z.preprocess( - processResponseBody, - z.string().regex(/^([a-zA-Z0-9_]+|\*|\*\*)(\.([a-zA-Z0-9_]+|\*|\*\*))*$/) -) - /** * Create-time identity-related parameters */ @@ -4165,107 +4313,12 @@ export const WebhookCreate = z.preprocess( endpoint: z.string(), name: Name, secrets: z.string().array(), - subscriptions: WebhookSubscription.array().default([]).optional(), + subscriptions: AlertSubscription.array().default([]).optional(), }) ) /** - * The response received from a webhook receiver endpoint. - */ -export const WebhookDeliveryResponse = z.preprocess( - processResponseBody, - z.object({ durationMs: z.number().min(0), status: z.number().min(0).max(65535) }) -) - -export const WebhookDeliveryAttemptResult = z.preprocess( - processResponseBody, - z.enum(['succeeded', 'failed_http_error', 'failed_unreachable', 'failed_timeout']) -) - -/** - * An individual delivery attempt for a webhook event. - * - * This represents a single HTTP request that was sent to the receiver, and its outcome. - */ -export const WebhookDeliveryAttempt = z.preprocess( - processResponseBody, - z.object({ - attempt: z.number().min(0), - response: WebhookDeliveryResponse.nullable().optional(), - result: WebhookDeliveryAttemptResult, - timeSent: z.coerce.date(), - }) -) - -/** - * The state of a webhook delivery attempt. - */ -export const WebhookDeliveryState = z.preprocess( - processResponseBody, - z.enum(['pending', 'delivered', 'failed']) -) - -/** - * The reason a webhook event was delivered - */ -export const WebhookDeliveryTrigger = z.preprocess( - processResponseBody, - z.enum(['event', 'resend', 'probe']) -) - -/** - * A delivery of a webhook event. - */ -export const WebhookDelivery = z.preprocess( - processResponseBody, - z.object({ - attempts: WebhookDeliveryAttempt.array(), - eventClass: z.string(), - eventId: TypedUuidForWebhookEventKind, - id: z.string().uuid(), - state: WebhookDeliveryState, - timeStarted: z.coerce.date(), - trigger: WebhookDeliveryTrigger, - webhookId: TypedUuidForWebhookReceiverKind, - }) -) - -export const WebhookDeliveryId = z.preprocess( - processResponseBody, - z.object({ deliveryId: z.string().uuid() }) -) - -/** - * A single page of results - */ -export const WebhookDeliveryResultsPage = z.preprocess( - processResponseBody, - z.object({ items: WebhookDelivery.array(), nextPage: z.string().nullable().optional() }) -) - -/** - * Data describing the result of a webhook liveness probe attempt. - */ -export const WebhookProbeResult = z.preprocess( - processResponseBody, - z.object({ - probe: WebhookDelivery, - resendsStarted: z.number().min(0).nullable().optional(), - }) -) - -/** - * A view of a shared secret key assigned to a webhook receiver. - * - * Once a secret is created, the value of the secret is not available in the API, as it must remain secret. Instead, secrets are referenced by their unique IDs assigned when they are created. - */ -export const WebhookSecret = z.preprocess( - processResponseBody, - z.object({ id: z.string().uuid(), timeCreated: z.coerce.date() }) -) - -/** - * The configuration for a webhook. + * The configuration for a webhook alert receiver. */ export const WebhookReceiver = z.preprocess( processResponseBody, @@ -4275,20 +4328,12 @@ export const WebhookReceiver = z.preprocess( id: z.string().uuid(), name: Name, secrets: WebhookSecret.array(), - subscriptions: WebhookSubscription.array(), + subscriptions: AlertSubscription.array(), timeCreated: z.coerce.date(), timeModified: z.coerce.date(), }) ) -/** - * A single page of results - */ -export const WebhookReceiverResultsPage = z.preprocess( - processResponseBody, - z.object({ items: WebhookReceiver.array(), nextPage: z.string().nullable().optional() }) -) - /** * Parameters to update a webhook configuration. */ @@ -4307,23 +4352,13 @@ export const WebhookSecretCreate = z.preprocess( ) /** - * A list of the IDs of secrets associated with a webhook. + * A list of the IDs of secrets associated with a webhook receiver. */ export const WebhookSecrets = z.preprocess( processResponseBody, z.object({ secrets: WebhookSecret.array() }) ) -export const WebhookSubscriptionCreate = z.preprocess( - processResponseBody, - z.object({ subscription: WebhookSubscription }) -) - -export const WebhookSubscriptionCreated = z.preprocess( - processResponseBody, - z.object({ subscription: WebhookSubscription }) -) - /** * Supported set of sort modes for scanning by name or id */ @@ -4339,6 +4374,14 @@ export const NameOrIdSortMode = z.preprocess( */ export const IdSortMode = z.preprocess(processResponseBody, z.enum(['id_ascending'])) +/** + * Supported set of sort modes for scanning by timestamp and ID + */ +export const TimeAndIdSortMode = z.preprocess( + processResponseBody, + z.enum(['ascending', 'descending']) +) + export const DiskMetricName = z.preprocess( processResponseBody, z.enum(['activated', 'flush', 'read', 'read_bytes', 'write', 'write_bytes']) @@ -4364,14 +4407,6 @@ export const SystemMetricName = z.preprocess( */ export const NameSortMode = z.preprocess(processResponseBody, z.enum(['name_ascending'])) -/** - * Supported set of sort modes for scanning by timestamp and ID - */ -export const TimeAndIdSortMode = z.preprocess( - processResponseBody, - z.enum(['ascending', 'descending']) -) - export const DeviceAuthRequestParams = z.preprocess( processResponseBody, z.object({ @@ -4467,7 +4502,7 @@ export const SupportBundleViewParams = z.preprocess( processResponseBody, z.object({ path: z.object({ - supportBundle: z.string().uuid(), + bundleId: z.string().uuid(), }), query: z.object({}), }) @@ -4477,7 +4512,7 @@ export const SupportBundleDeleteParams = z.preprocess( processResponseBody, z.object({ path: z.object({ - supportBundle: z.string().uuid(), + bundleId: z.string().uuid(), }), query: z.object({}), }) @@ -4487,7 +4522,7 @@ export const SupportBundleDownloadParams = z.preprocess( processResponseBody, z.object({ path: z.object({ - supportBundle: z.string().uuid(), + bundleId: z.string().uuid(), }), query: z.object({}), }) @@ -4497,7 +4532,7 @@ export const SupportBundleHeadParams = z.preprocess( processResponseBody, z.object({ path: z.object({ - supportBundle: z.string().uuid(), + bundleId: z.string().uuid(), }), query: z.object({}), }) @@ -4507,8 +4542,8 @@ export const SupportBundleDownloadFileParams = z.preprocess( processResponseBody, z.object({ path: z.object({ + bundleId: z.string().uuid(), file: z.string(), - supportBundle: z.string().uuid(), }), query: z.object({}), }) @@ -4518,8 +4553,8 @@ export const SupportBundleHeadFileParams = z.preprocess( processResponseBody, z.object({ path: z.object({ + bundleId: z.string().uuid(), file: z.string(), - supportBundle: z.string().uuid(), }), query: z.object({}), }) @@ -4529,7 +4564,7 @@ export const SupportBundleIndexParams = z.preprocess( processResponseBody, z.object({ path: z.object({ - supportBundle: z.string().uuid(), + bundleId: z.string().uuid(), }), query: z.object({}), }) @@ -4659,6 +4694,112 @@ export const AffinityGroupMemberInstanceDeleteParams = z.preprocess( }) ) +export const AlertClassListParams = z.preprocess( + processResponseBody, + z.object({ + path: z.object({}), + query: z.object({ + limit: z.number().min(1).max(4294967295).nullable().optional(), + pageToken: z.string().nullable().optional(), + filter: AlertSubscription.optional(), + }), + }) +) + +export const AlertReceiverListParams = z.preprocess( + processResponseBody, + z.object({ + path: z.object({}), + query: z.object({ + limit: z.number().min(1).max(4294967295).nullable().optional(), + pageToken: z.string().nullable().optional(), + sortBy: NameOrIdSortMode.optional(), + }), + }) +) + +export const AlertReceiverViewParams = z.preprocess( + processResponseBody, + z.object({ + path: z.object({ + receiver: NameOrId, + }), + query: z.object({}), + }) +) + +export const AlertReceiverDeleteParams = z.preprocess( + processResponseBody, + z.object({ + path: z.object({ + receiver: NameOrId, + }), + query: z.object({}), + }) +) + +export const AlertDeliveryListParams = z.preprocess( + processResponseBody, + z.object({ + path: z.object({ + receiver: NameOrId, + }), + query: z.object({ + delivered: SafeBoolean.nullable().optional(), + failed: SafeBoolean.nullable().optional(), + pending: SafeBoolean.nullable().optional(), + limit: z.number().min(1).max(4294967295).nullable().optional(), + pageToken: z.string().nullable().optional(), + sortBy: TimeAndIdSortMode.optional(), + }), + }) +) + +export const AlertReceiverProbeParams = z.preprocess( + processResponseBody, + z.object({ + path: z.object({ + receiver: NameOrId, + }), + query: z.object({ + resend: SafeBoolean.optional(), + }), + }) +) + +export const AlertReceiverSubscriptionAddParams = z.preprocess( + processResponseBody, + z.object({ + path: z.object({ + receiver: NameOrId, + }), + query: z.object({}), + }) +) + +export const AlertReceiverSubscriptionRemoveParams = z.preprocess( + processResponseBody, + z.object({ + path: z.object({ + receiver: NameOrId, + subscription: AlertSubscription, + }), + query: z.object({}), + }) +) + +export const AlertDeliveryResendParams = z.preprocess( + processResponseBody, + z.object({ + path: z.object({ + alertId: z.string().uuid(), + }), + query: z.object({ + receiver: NameOrId, + }), + }) +) + export const AntiAffinityGroupListParams = z.preprocess( processResponseBody, z.object({ @@ -6105,7 +6246,7 @@ export const SamlIdentityProviderViewParams = z.preprocess( provider: NameOrId, }), query: z.object({ - silo: NameOrId, + silo: NameOrId.optional(), }), }) ) @@ -7137,58 +7278,6 @@ export const VpcDeleteParams = z.preprocess( }) ) -export const WebhookDeliveryListParams = z.preprocess( - processResponseBody, - z.object({ - path: z.object({}), - query: z.object({ - receiver: NameOrId, - delivered: SafeBoolean.nullable().optional(), - failed: SafeBoolean.nullable().optional(), - pending: SafeBoolean.nullable().optional(), - limit: z.number().min(1).max(4294967295).nullable().optional(), - pageToken: z.string().nullable().optional(), - sortBy: TimeAndIdSortMode.optional(), - }), - }) -) - -export const WebhookDeliveryResendParams = z.preprocess( - processResponseBody, - z.object({ - path: z.object({ - eventId: z.string().uuid(), - }), - query: z.object({ - receiver: NameOrId, - }), - }) -) - -export const WebhookEventClassListParams = z.preprocess( - processResponseBody, - z.object({ - path: z.object({}), - query: z.object({ - limit: z.number().min(1).max(4294967295).nullable().optional(), - pageToken: z.string().nullable().optional(), - filter: WebhookSubscription.optional(), - }), - }) -) - -export const WebhookReceiverListParams = z.preprocess( - processResponseBody, - z.object({ - path: z.object({}), - query: z.object({ - limit: z.number().min(1).max(4294967295).nullable().optional(), - pageToken: z.string().nullable().optional(), - sortBy: NameOrIdSortMode.optional(), - }), - }) -) - export const WebhookReceiverCreateParams = z.preprocess( processResponseBody, z.object({ @@ -7197,16 +7286,6 @@ export const WebhookReceiverCreateParams = z.preprocess( }) ) -export const WebhookReceiverViewParams = z.preprocess( - processResponseBody, - z.object({ - path: z.object({ - receiver: NameOrId, - }), - query: z.object({}), - }) -) - export const WebhookReceiverUpdateParams = z.preprocess( processResponseBody, z.object({ @@ -7217,49 +7296,6 @@ export const WebhookReceiverUpdateParams = z.preprocess( }) ) -export const WebhookReceiverDeleteParams = z.preprocess( - processResponseBody, - z.object({ - path: z.object({ - receiver: NameOrId, - }), - query: z.object({}), - }) -) - -export const WebhookReceiverProbeParams = z.preprocess( - processResponseBody, - z.object({ - path: z.object({ - receiver: NameOrId, - }), - query: z.object({ - resend: SafeBoolean.optional(), - }), - }) -) - -export const WebhookReceiverSubscriptionAddParams = z.preprocess( - processResponseBody, - z.object({ - path: z.object({ - receiver: NameOrId, - }), - query: z.object({}), - }) -) - -export const WebhookReceiverSubscriptionRemoveParams = z.preprocess( - processResponseBody, - z.object({ - path: z.object({ - receiver: NameOrId, - subscription: WebhookSubscription, - }), - query: z.object({}), - }) -) - export const WebhookSecretsListParams = z.preprocess( processResponseBody, z.object({ diff --git a/app/forms/firewall-rules-edit.tsx b/app/forms/firewall-rules-edit.tsx index 7a5ac6e54..59c9b22c2 100644 --- a/app/forms/firewall-rules-edit.tsx +++ b/app/forms/firewall-rules-edit.tsx @@ -78,8 +78,15 @@ export default function EditFirewallRuleForm() { // invalidate managed to complete while the modal was still open. onDismiss() queryClient.invalidateQueries('vpcFirewallRulesView') - const updatedRule = body.rules[body.rules.length - 1] - addToast(<>Firewall rule {updatedRule.name} updated) // prettier-ignore + + // We are pretty sure here that there is a rule in the list because we are + // in the form updating it. We also know the one being updated is last in + // the body because we put it it here. We use the request body instead of + // the response because the server could change the order. + const updatedRule = body.rules?.at(-1) + if (updatedRule) { + addToast(<>Firewall rule {updatedRule.name} updated) // prettier-ignore + } }, }) diff --git a/mock-api/msw/handlers.ts b/mock-api/msw/handlers.ts index b1caf43fe..bd7ccff7a 100644 --- a/mock-api/msw/handlers.ts +++ b/mock-api/msw/handlers.ts @@ -1210,7 +1210,7 @@ export const handlers = makeHandlers({ vpcFirewallRulesUpdate({ body, query }) { const vpc = lookup.vpc(query) - const rules = body.rules.map((rule) => ({ + const rules = (body.rules ?? []).map((rule) => ({ vpc_id: vpc.id, id: uuid(), ...rule, @@ -1789,6 +1789,15 @@ export const handlers = makeHandlers({ affinityGroupMemberInstanceDelete: NotImplemented, affinityGroupMemberInstanceView: NotImplemented, affinityGroupUpdate: NotImplemented, + alertClassList: NotImplemented, + alertDeliveryList: NotImplemented, + alertDeliveryResend: NotImplemented, + alertReceiverDelete: NotImplemented, + alertReceiverList: NotImplemented, + alertReceiverProbe: NotImplemented, + alertReceiverSubscriptionAdd: NotImplemented, + alertReceiverSubscriptionRemove: NotImplemented, + alertReceiverView: NotImplemented, antiAffinityGroupMemberInstanceView: NotImplemented, certificateCreate: NotImplemented, certificateDelete: NotImplemented, @@ -1873,21 +1882,12 @@ export const handlers = makeHandlers({ systemPolicyUpdate: NotImplemented, systemQuotasList: NotImplemented, systemTimeseriesSchemaList: NotImplemented, - targetReleaseView: NotImplemented, targetReleaseUpdate: NotImplemented, + targetReleaseView: NotImplemented, userBuiltinList: NotImplemented, userBuiltinView: NotImplemented, - webhookDeliveryList: NotImplemented, - webhookDeliveryResend: NotImplemented, - webhookEventClassList: NotImplemented, webhookReceiverCreate: NotImplemented, - webhookReceiverDelete: NotImplemented, - webhookReceiverList: NotImplemented, - webhookReceiverProbe: NotImplemented, - webhookReceiverSubscriptionAdd: NotImplemented, - webhookReceiverSubscriptionRemove: NotImplemented, webhookReceiverUpdate: NotImplemented, - webhookReceiverView: NotImplemented, webhookSecretsAdd: NotImplemented, webhookSecretsDelete: NotImplemented, webhookSecretsList: NotImplemented,