diff --git a/.agents/skills/fetch-spec/SKILL.md b/.agents/skills/fetch-spec/SKILL.md index 584ad3d..c0fb5d0 100644 --- a/.agents/skills/fetch-spec/SKILL.md +++ b/.agents/skills/fetch-spec/SKILL.md @@ -3,6 +3,7 @@ ## Description Use this skill when you need to look up details about the Oxide API, including: + - Finding endpoint definitions, paths, or HTTP methods - Looking up schema/type definitions from the API spec - Understanding request/response formats for API operations diff --git a/DESIGN.md b/DESIGN.md new file mode 100644 index 0000000..46a5ea9 --- /dev/null +++ b/DESIGN.md @@ -0,0 +1,296 @@ +# Design Notes + +## oneOf Type Generation + +### Overview + +OpenAPI `oneOf` types represent sum types, which are values that can be one of several variant +types. Go doesn't have a native sum type, so we have to decide how to represent these values in a +safe and ergonomic way. There are a few distinct patterns of `oneOf` types in the Oxide API, related +to different `serde` tagging strategies, and we handle each of them differently. + +### Tagged union + +When a `oneOf` has: + +1. Exactly one discriminator property (a field with a single enum value per variant) +2. Exactly one multi-type property (a field whose type varies across variants) + +We generate an **interface with variant wrapper types** pattern. + +**Example: `PrivateIpStack`** + +In Rust, `PrivateIpStack` is defined as: + +```rust +#[serde(tag = "type", content = "value", rename_all = "snake_case")] +pub enum PrivateIpStack { + V4(PrivateIpv4Stack), + V6(PrivateIpv6Stack), + DualStack { v4: PrivateIpv4Stack, v6: PrivateIpv6Stack }, +} +``` + +This generates the following OpenAPI spec: + +```yaml +PrivateIpStack: + oneOf: + - type: object + properties: + type: { enum: ["v4"] } + value: { $ref: "#/components/schemas/PrivateIpv4Stack" } + required: [type, value] + - type: object + properties: + type: { enum: ["v6"] } + value: { $ref: "#/components/schemas/PrivateIpv6Stack" } + required: [type, value] + - type: object + properties: + type: { enum: ["dual_stack"] } + value: + type: object + properties: + v4: { $ref: "#/components/schemas/PrivateIpv4Stack" } + v6: { $ref: "#/components/schemas/PrivateIpv6Stack" } + required: [type, value] +``` + +This has: + +- One discriminator: `type` (with values `v4`, `v6`, `dual_stack`) +- One multi-type property: `value` (which is `PrivateIpv4Stack`, `PrivateIpv6Stack`, or an inline + object depending on variant) + +So it generates: + +```go +// Interface with marker method that all variants implement +type privateIpStackVariant interface { + isPrivateIpStackVariant() +} + +// Variant wrapper types (one per discriminator value) +type PrivateIpStackV4 struct { + Value PrivateIpv4Stack `json:"value"` +} +func (PrivateIpStackV4) isPrivateIpStackVariant() {} + +type PrivateIpStackV6 struct { + Value PrivateIpv6Stack `json:"value"` +} +func (PrivateIpStackV6) isPrivateIpStackVariant() {} + +type PrivateIpStackDualStack struct { + Value PrivateIpStackValue `json:"value"` +} +func (PrivateIpStackDualStack) isPrivateIpStackVariant() {} + +// Main type with only the value field +type PrivateIpStack struct { + Value privateIpStackVariant `json:"value,omitempty"` +} + +// Type() method derives the discriminator from the concrete Value type +func (v PrivateIpStack) Type() PrivateIpStackType { + switch v.Value.(type) { + case *PrivateIpStackV4: + return PrivateIpStackTypeV4 + case *PrivateIpStackV6: + return PrivateIpStackTypeV6 + case *PrivateIpStackDualStack: + return PrivateIpStackTypeDualStack + default: + return "" + } +} +``` + +The discriminator field is not stored in the struct. We don't want users to be able to set its value +so that it doesn't match the type of the value field. Instead, we expose a public method named after +the discriminator that returns the discriminator value. + +We also implement custom `MarshalJSON` and `UnmarshalJSON` methods for the main type. To unmarshal, +we check the discriminator field in the JSON to determine which concrete type to use for +unmarshalling the value. To marshal, we call the `Type()` method to determine which discriminator to +emit. + +**Usage examples:** + +```go +// Reading a network interface's IP stack from the API +nic, _ := client.InstanceNetworkInterfaceView(ctx, params) +ipStack := nic.IpStack + +switch v := ipStack.Value.(type) { +case *oxide.PrivateIpStackV4: + fmt.Printf("IPv4 only: %s\n", v.Value.Ip) +case *oxide.PrivateIpStackV6: + fmt.Printf("IPv6 only: %s\n", v.Value.Ip) +case *oxide.PrivateIpStackDualStack: + fmt.Printf("Dual stack: %s / %s\n", v.Value.V4.Ip, v.Value.V6.Ip) +} +``` + +```go +// Creating a network interface with an IPv4-only stack +params := oxide.InstanceNetworkInterfaceCreateParams{ + Body: &oxide.InstanceNetworkInterfaceCreate{ + Name: "my-nic", + SubnetName: "my-subnet", + VpcName: "my-vpc", + IpConfig: oxide.PrivateIpStackCreate{ + Value: &oxide.PrivateIpStackCreateV4{ + Value: oxide.PrivateIpv4StackCreate{ + Ip: oxide.Ipv4Assignment{ + Type: oxide.Ipv4AssignmentTypeExplicit, + Value: "10.0.0.5", + }, + }, + }, + }, + }, +} +``` + +**Why wrapper structs?** + +We represent each variant type using a wrapper struct, e.g. + +```go +type PrivateIpStackV4 struct { + Value PrivateIpv4Stack `json:"value"` +} +``` + +The wrapper struct implements the marker method for the relevant interface: + +```go +func (PrivateIpStackV4) isPrivateIpStackVariant() {} +``` + +Why use wrapper structs? For some variant types, we could omit the wrapper and implement the marker +method on the wrapped type instead: + +```go +func (PrivateIpv4Stack) isPrivateIpStackVariant() {} +``` + +Primitive types can't implement methods, but we could use type definitions instead: + +```go +type MyPrimitiveVariant string + +func (MyPrimitiveVariant) isMyTypeVariant() {} +``` + +However, this presents a few problems: + +- Some variant types are `interface{}` or `any`. We can't implement methods on `any`. +- Some variant types are represented by pointers to primitive types, like `*bool` or `*int`. We + can't implement methods on pointers to primitive types. + +We could represent some variant types with wrapper structs and others as unwrapped structs or type +definitions. But the complexity of conditionally wrapping variant types is potentially more +confusing to end users than consistent use of wrappers. + +Note: we can reconsider this choice if we're able to drop the use of `interface{}` types and +pointers to primitives for variants, and if we're confident that those cases won't emerge again. + +### Discriminator with multiple value fields + +When a `oneOf` has a discriminator field and _multiple_ value fields, we use a flat struct that +contains all properties from all variants. Properties that have different types across variants +become `any`. + +**Example: `DiskSource`** + +In Rust, `DiskSource` is defined as: + +```rust +#[serde(tag = "type", rename_all = "snake_case")] +pub enum DiskSource { + Blank { block_size: BlockSize }, + Snapshot { snapshot_id: Uuid }, + Image { image_id: Uuid }, + ImportingBlocks { block_size: BlockSize }, +} +``` + +This generates the following OpenAPI spec: + +```yaml +DiskSource: + oneOf: + - type: object + properties: + type: { enum: ["blank"] } + block_size: { $ref: "#/components/schemas/BlockSize" } + - type: object + properties: + type: { enum: ["snapshot"] } + snapshot_id: { type: string, format: uuid } + - type: object + properties: + type: { enum: ["image"] } + image_id: { type: string, format: uuid } + - type: object + properties: + type: { enum: ["importing_blocks"] } + block_size: { $ref: "#/components/schemas/BlockSize" } +``` + +This has a discriminator (`type`) but no multi-type property. Each variant has different fields +(`block_size`, `snapshot_id`, `image_id`), not different types for the same field. So we generate a +flat struct: + +```go +type DiskSource struct { + BlockSize BlockSize `json:"block_size,omitempty"` + Type DiskSourceType `json:"type,omitempty"` + SnapshotId string `json:"snapshot_id,omitempty"` + ImageId string `json:"image_id,omitempty"` +} +``` + +If any property had different types across variants, it would become `any`. + +### Untagged union + +When a `oneOf` has no object properties (i.e., variants are primitive types or references wrapped in +`allOf`), the type becomes `interface{}`. + +**Example: `IpNet`** + +In Rust, `IpNet` is defined as: + +```rust +#[serde(untagged)] +pub enum IpNet { + V4(Ipv4Net), + V6(Ipv6Net), +} +``` + +This generates the following OpenAPI spec: + +```yaml +IpNet: + oneOf: + - title: v4 + allOf: + - $ref: "#/components/schemas/Ipv4Net" + - title: v6 + allOf: + - $ref: "#/components/schemas/Ipv6Net" +``` + +```go +type IpNet interface{} +``` + +Note: we may be able to handle these types better in the future. For example, we could detect that +all variants are effectively strings and represent `IpNet` as `string`. Alternatively, we could +represent `Ipv4Net` and `Ipv6Net` as distinct types with their own validation logic, and attempt to +unmarshal into each variant type until we find a match. diff --git a/internal/generate/templates/type.go.tpl b/internal/generate/templates/type.go.tpl index 3a18b2e..a3352d1 100644 --- a/internal/generate/templates/type.go.tpl +++ b/internal/generate/templates/type.go.tpl @@ -1,5 +1,10 @@ {{splitDocString .Description}} -{{- if .Fields}} +{{- if eq .Type "interface"}} +type {{.Name}} interface { + {{.VariantMarker.Method}}() +} + +{{else if .Fields}} type {{.Name}} {{.Type}} { {{- range .Fields}} {{- if .Description}} @@ -9,6 +14,83 @@ type {{.Name}} {{.Type}} { {{- end}} } +{{- if .VariantMarker}} + +func ({{.Name}}) {{.VariantMarker.Method}}() {} +{{- end}} +{{- if .Variants}} + +func (v {{.Name}}) {{.Variants.DiscriminatorMethod}}() {{.Variants.DiscriminatorType}} { + switch v.{{.Variants.ValueFieldName}}.(type) { + {{- range .Variants.Variants}} + case *{{.TypeName}}: + return {{$.Variants.DiscriminatorType}}{{.TypeSuffix}} + {{- end}} + default: + return "" + } +} + +func (v *{{.Name}}) UnmarshalJSON(data []byte) error { + type discriminator struct { + Type string `json:"{{.Variants.Discriminator}}"` + } + var d discriminator + if err := json.Unmarshal(data, &d); err != nil { + return err + } + + var value {{.Variants.VariantType}} + switch d.Type { + {{- range .Variants.Variants}} + case "{{.DiscriminatorValue}}": + value = &{{.TypeName}}{} + {{- end}} + default: + return fmt.Errorf("unknown variant %q, expected {{range $i, $v := .Variants.Variants}}{{if $i}} or {{end}}'{{.DiscriminatorValue}}'{{end}}", d.Type) + } + if err := json.Unmarshal(data, value); err != nil { + return err + } + v.{{.Variants.ValueFieldName}} = value + return nil +} + +func (v {{.Name}}) MarshalJSON() ([]byte, error) { + m := make(map[string]any) + m["{{.Variants.Discriminator}}"] = v.{{.Variants.DiscriminatorMethod}}() + if v.{{.Variants.ValueFieldName}} != nil { + valueBytes, err := json.Marshal(v.{{.Variants.ValueFieldName}}) + if err != nil { + return nil, err + } + var valueMap map[string]any + if err := json.Unmarshal(valueBytes, &valueMap); err != nil { + return nil, err + } + for k, val := range valueMap { + m[k] = val + } + } + return json.Marshal(m) +} + +{{- range .Variants.Variants}} + +// As{{.TypeSuffix}} attempts to convert the {{$.Name}} to a {{.TypeName}}. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v {{$.Name}}) As{{.TypeSuffix}}() (*{{.TypeName}}, bool) { + val, ok := v.{{$.Variants.ValueFieldName}}.(*{{.TypeName}}) + return val, ok +} +{{- end}} +{{- end}} + +{{else if and (eq .Type "struct") .VariantMarker}} +type {{.Name}} struct{} + +func ({{.Name}}) {{.VariantMarker.Method}}() {} + {{else}} type {{.Name}} {{.Type}} -{{end -}} +{{end}} diff --git a/internal/generate/test_utils/responses_output b/internal/generate/test_utils/responses_output index 7f8560d..feb93f1 100644 --- a/internal/generate/test_utils/responses_output +++ b/internal/generate/test_utils/responses_output @@ -8,3 +8,4 @@ package oxide // ErrorResponse is the response given when error type ErrorResponse Error + diff --git a/internal/generate/test_utils/responses_output_expected b/internal/generate/test_utils/responses_output_expected index 7f8560d..feb93f1 100644 --- a/internal/generate/test_utils/responses_output_expected +++ b/internal/generate/test_utils/responses_output_expected @@ -8,3 +8,4 @@ package oxide // ErrorResponse is the response given when error type ErrorResponse Error + diff --git a/internal/generate/test_utils/types_output b/internal/generate/test_utils/types_output index 8609163..891be70 100644 --- a/internal/generate/test_utils/types_output +++ b/internal/generate/test_utils/types_output @@ -11,26 +11,31 @@ type DiskCreate struct { DiskSource DiskSource `json:"disk_source,omitempty" yaml:"disk_source,omitempty"` } + // DiskIdentifier is parameters for the [`Disk`](omicron_common::api::external::Disk) to be attached or // detached to an instance type DiskIdentifier struct { Name Name `json:"name,omitempty" yaml:"name,omitempty"` } + // DiskSourceType is the type definition for a DiskSourceType. type DiskSourceType string + // DiskSourceSnapshot is create a disk from a disk snapshot type DiskSourceSnapshot struct { SnapshotId string `json:"snapshot_id,omitempty" yaml:"snapshot_id,omitempty"` Type DiskSourceType `json:"type,omitempty" yaml:"type,omitempty"` } + // DiskSourceImage is create a disk from a project image type DiskSourceImage struct { ImageId string `json:"image_id,omitempty" yaml:"image_id,omitempty"` Type DiskSourceType `json:"type,omitempty" yaml:"type,omitempty"` } + // DiskSource is the type definition for a DiskSource. type DiskSource struct { // SnapshotId is the type definition for a SnapshotId. @@ -41,6 +46,7 @@ type DiskSource struct { ImageId string `json:"image_id,omitempty" yaml:"image_id,omitempty"` } + // DiskSourceTypeSnapshot represents the DiskSourceType `"snapshot"`. const DiskSourceTypeSnapshot DiskSourceType = "snapshot" diff --git a/internal/generate/test_utils/types_output_expected b/internal/generate/test_utils/types_output_expected index 8609163..891be70 100644 --- a/internal/generate/test_utils/types_output_expected +++ b/internal/generate/test_utils/types_output_expected @@ -11,26 +11,31 @@ type DiskCreate struct { DiskSource DiskSource `json:"disk_source,omitempty" yaml:"disk_source,omitempty"` } + // DiskIdentifier is parameters for the [`Disk`](omicron_common::api::external::Disk) to be attached or // detached to an instance type DiskIdentifier struct { Name Name `json:"name,omitempty" yaml:"name,omitempty"` } + // DiskSourceType is the type definition for a DiskSourceType. type DiskSourceType string + // DiskSourceSnapshot is create a disk from a disk snapshot type DiskSourceSnapshot struct { SnapshotId string `json:"snapshot_id,omitempty" yaml:"snapshot_id,omitempty"` Type DiskSourceType `json:"type,omitempty" yaml:"type,omitempty"` } + // DiskSourceImage is create a disk from a project image type DiskSourceImage struct { ImageId string `json:"image_id,omitempty" yaml:"image_id,omitempty"` Type DiskSourceType `json:"type,omitempty" yaml:"type,omitempty"` } + // DiskSource is the type definition for a DiskSource. type DiskSource struct { // SnapshotId is the type definition for a SnapshotId. @@ -41,6 +46,7 @@ type DiskSource struct { ImageId string `json:"image_id,omitempty" yaml:"image_id,omitempty"` } + // DiskSourceTypeSnapshot represents the DiskSourceType `"snapshot"`. const DiskSourceTypeSnapshot DiskSourceType = "snapshot" diff --git a/internal/generate/types.go b/internal/generate/types.go index 0a11c49..a5bad38 100644 --- a/internal/generate/types.go +++ b/internal/generate/types.go @@ -60,6 +60,49 @@ type TypeTemplate struct { Type string // Fields holds the information for the field Fields []TypeField + // VariantMarker is set when this type is part of a tagged union: either the marker + // interface itself (e.g., privateIpStackVariant) or a variant struct that implements + // it (e.g., PrivateIpStackV4, PrivateIpStackV6, PrivateIpStackDualStack). + VariantMarker *VariantMarker + // Variants is set when this type represents a tagged union (e.g., PrivateIpStack). + Variants *VariantConfig +} + +// VariantMarker describes a type that is a variant of a tagged union interface +type VariantMarker struct { + // Method is the marker method name (e.g., "isPrivateIpStackVariant") + Method string + // InterfaceType is the interface type name (e.g., "privateIpStackVariant") + // Empty for the interface type itself, set for variant structs + InterfaceType string +} + +// VariantConfig holds configuration for tagged union types +type VariantConfig struct { + // Discriminator is the JSON property name for the discriminator (e.g., "type") + Discriminator string + // DiscriminatorMethod is the Go method name that returns the discriminator (e.g., "Type") + DiscriminatorMethod string + // DiscriminatorType is the enum type for the discriminator (e.g., "PrivateIpStackType") + DiscriminatorType string + // ValueField is the JSON property name for the value field (e.g., "value") + ValueField string + // ValueFieldName is the Go field name for the value field (e.g., "Value") + ValueFieldName string + // VariantType is the interface type for the Value field (e.g., "privateIpStackVariant") + VariantType string + // Variants holds discriminator value -> variant type name mapping for JSON marshal/unmarshal + Variants []Variant +} + +// Variant represents a single variant in a tagged union (oneOf with discriminator). +type Variant struct { + // DiscriminatorValue is the raw JSON tag value (e.g., "ip_net"). + DiscriminatorValue string + // TypeSuffix is the Go-cased suffix used in type and enum names (e.g., "IpNet"). + TypeSuffix string + // TypeName is the full Go type name for this variant (e.g., "RouteDestinationIpNet"). + TypeName string } // Render renders the TypeTemplate to a Go type. @@ -746,27 +789,17 @@ func createAllOf( } func createOneOf(s *openapi3.Schema, name, typeName string) ([]TypeTemplate, []EnumTemplate) { - enumTpls := make([]EnumTemplate, 0) - typeTpls := make([]TypeTemplate, 0) - - // Loop over variants, creating types and enums for nested types, and gathering metadata about - // the oneOf overall. - - // Set of candidate discriminator keys. There must be exactly zero or one discriminator key. + // First pass: identify discriminator key and find properties with multiple types across + // variants. discriminatorKeys := map[string]struct{}{} - // Map of properties to sets of variant types. We use this to identify fields with multiple - // types across variants. propToVariantTypes := map[string]map[string]struct{}{} for _, variantRef := range s.OneOf { - enumField := "" for _, propName := range sortedKeys(variantRef.Value.Properties) { propRef := variantRef.Value.Properties[propName] - propField := strcase.ToCamel(propName) if len(propRef.Value.Enum) == 1 { discriminatorKeys[propName] = struct{}{} - enumField = strcase.ToCamel(propRef.Value.Enum[0].(string)) } else if len(propRef.Value.Enum) > 1 { fmt.Printf( "[WARN] TODO: oneOf for %q -> %q enum %#v\n", @@ -774,18 +807,14 @@ func createOneOf(s *openapi3.Schema, name, typeName string) ([]TypeTemplate, []E propName, propRef.Value.Enum, ) - } else if propRef.Value.Enum == nil && len(variantRef.Value.Properties) == 1 { - enumField = propField } + if _, ok := propToVariantTypes[propName]; !ok { propToVariantTypes[propName] = map[string]struct{}{} } goType := convertToValidGoType(propName, typeName, propRef) propToVariantTypes[propName][goType] = struct{}{} } - tt, et := populateTypeTemplates(name, variantRef.Value, enumField) - typeTpls = append(typeTpls, tt...) - enumTpls = append(enumTpls, et...) } // Check invariant: there must be exactly zero or one discriminator field. @@ -807,7 +836,173 @@ func createOneOf(s *openapi3.Schema, name, typeName string) ([]TypeTemplate, []E } } - // Build the struct type for the oneOf field, if defined. + // If we have a discriminator and a multi-type property, use interface + variants pattern. + // This gives us type safety instead of using `any`. + if len(discriminatorKeys) == 1 && len(multiTypeProps) == 1 { + var discriminatorKey, valuePropertyName string + for k := range discriminatorKeys { + discriminatorKey = k + } + for k := range multiTypeProps { + valuePropertyName = k + } + return createInterfaceOneOf(s, typeName, discriminatorKey, valuePropertyName) + } + + // Otherwise, use flat struct pattern. + return createFlatOneOf(s, name, typeName, multiTypeProps) +} + +// createInterfaceOneOf creates types representing a tagged union. We build an interface type to +// represent the `oneOf`, a concrete variant struct for each `oneOf` variant, and a wrapper type +// with a single field of the interface type. +func createInterfaceOneOf( + s *openapi3.Schema, + typeName, discriminatorKey, valuePropertyName string, +) ([]TypeTemplate, []EnumTemplate) { + enumTpls := make([]EnumTemplate, 0) + typeTpls := make([]TypeTemplate, 0) + + discriminatorType := typeName + strcase.ToCamel(discriminatorKey) + + // Build the interface type. + interfaceName := toLowerFirstLetter(typeName) + "Variant" + markerMethod := "is" + typeName + "Variant" + interfaceTpl := TypeTemplate{ + Description: fmt.Sprintf("// %s is implemented by %s variants.", interfaceName, typeName), + Name: interfaceName, + Type: "interface", + VariantMarker: &VariantMarker{Method: markerMethod}, + } + typeTpls = append(typeTpls, interfaceTpl) + + var variants []Variant + for _, variantRef := range s.OneOf { + discProp, ok := variantRef.Value.Properties[discriminatorKey] + if !ok || len(discProp.Value.Enum) != 1 { + panic(fmt.Sprintf( + "[ERROR] Variant in %s oneOf missing discriminator %q or has invalid enum: %+v", + typeName, discriminatorKey, variantRef.Value, + )) + } + discValue := discProp.Value.Enum[0].(string) + + enums, tt, et := createStringEnum( + discProp.Value, + collectEnumStringTypes, + discriminatorType, + discriminatorType, + ) + collectEnumStringTypes = enums + typeTpls = append(typeTpls, tt...) + enumTpls = append(enumTpls, et...) + + variantTypeName := typeName + strcase.ToCamel(discValue) + variants = append(variants, Variant{ + DiscriminatorValue: discValue, + TypeSuffix: strcase.ToCamel(discValue), + TypeName: variantTypeName, + }) + + // Find the value property in this variant. `ok` is false for "unit" variants + // that carry no data: e.g., RouteTarget's "drop" variant is just {"type": "drop"}. + valueRef, ok := variantRef.Value.Properties[valuePropertyName] + + var fields []TypeField + if ok { + valueType := convertToValidGoType(valuePropertyName, typeName, valueRef) + + // If the value is an inline object (not a $ref), generate its type. + if valueRef.Ref == "" && valueRef.Value != nil && valueRef.Value.Type != nil && + valueRef.Value.Type.Is("object") { + inlineTypeName := typeName + strcase.ToCamel(valuePropertyName) + tt, et := populateTypeTemplates(inlineTypeName, valueRef.Value, "") + typeTpls = append(typeTpls, tt...) + enumTpls = append(enumTpls, et...) + } + + isRequired := slices.Contains(variantRef.Value.Required, valuePropertyName) + fields = []TypeField{ + { + Name: strcase.ToCamel(valuePropertyName), + Type: valueType, + MarshalKey: valuePropertyName, + Schema: valueRef, + Required: isRequired, + }, + } + } + + variantTpl := TypeTemplate{ + Description: fmt.Sprintf("// %s is a variant of %s.", variantTypeName, typeName), + Name: variantTypeName, + Type: "struct", + Fields: fields, + VariantMarker: &VariantMarker{ + Method: markerMethod, + InterfaceType: interfaceName, + }, + } + typeTpls = append(typeTpls, variantTpl) + } + + // Create the wrapper struct with only the interface-typed value field. + wrapperFields := []TypeField{ + { + Name: strcase.ToCamel(valuePropertyName), + Type: interfaceName, + MarshalKey: valuePropertyName, + }, + } + + wrapperTpl := TypeTemplate{ + Description: formatTypeDescription(typeName, s), + Name: typeName, + Type: "struct", + Fields: wrapperFields, + Variants: &VariantConfig{ + Discriminator: discriminatorKey, + DiscriminatorMethod: strcase.ToCamel(discriminatorKey), + DiscriminatorType: discriminatorType, + ValueField: valuePropertyName, + ValueFieldName: strcase.ToCamel(valuePropertyName), + VariantType: interfaceName, + Variants: variants, + }, + } + typeTpls = append(typeTpls, wrapperTpl) + + return typeTpls, enumTpls +} + +// createFlatOneOf creates a oneOf type using a flat struct with all properties. +func createFlatOneOf( + s *openapi3.Schema, + name, typeName string, + multiTypeProps map[string]struct{}, +) ([]TypeTemplate, []EnumTemplate) { + enumTpls := make([]EnumTemplate, 0) + typeTpls := make([]TypeTemplate, 0) + + // Create variant types for nested enums + for _, variantRef := range s.OneOf { + enumField := "" + for _, propName := range sortedKeys(variantRef.Value.Properties) { + propRef := variantRef.Value.Properties[propName] + propField := strcase.ToCamel(propName) + + if len(propRef.Value.Enum) == 1 { + enumField = strcase.ToCamel(propRef.Value.Enum[0].(string)) + } else if propRef.Value.Enum == nil && len(variantRef.Value.Properties) == 1 { + enumField = propField + } + } + tt, et := populateTypeTemplates(name, variantRef.Value, enumField) + typeTpls = append(typeTpls, tt...) + enumTpls = append(enumTpls, et...) + } + + // Build the struct type for the oneOf field oneOfFields := []TypeField{} seenFields := map[string]struct{}{} for _, variantRef := range s.OneOf { diff --git a/internal/generate/types_test.go b/internal/generate/types_test.go index e79422a..fe1dceb 100644 --- a/internal/generate/types_test.go +++ b/internal/generate/types_test.go @@ -520,45 +520,67 @@ func Test_createOneOf(t *testing.T) { }, typeName: "IntOrString", wantTypes: []TypeTemplate{ + // Interface for variant types + { + Description: "// intOrStringVariant is implemented by IntOrString variants.", + Name: "intOrStringVariant", + Type: "interface", + VariantMarker: &VariantMarker{Method: "isIntOrStringVariant"}, + }, { Description: "// IntOrStringType is the type definition for a IntOrStringType.", Name: "IntOrStringType", Type: "string", }, { - Description: "// IntOrStringInt is the type definition for a IntOrStringInt.\n//\n// Required fields:\n// - Type\n// - Value", + Description: "// IntOrStringInt is a variant of IntOrString.", Name: "IntOrStringInt", Type: "struct", Fields: []TypeField{ - {Name: "Type", Type: "IntOrStringType", MarshalKey: "type", Required: true}, {Name: "Value", Type: "*int", MarshalKey: "value", Required: true}, }, + VariantMarker: &VariantMarker{ + Method: "isIntOrStringVariant", + InterfaceType: "intOrStringVariant", + }, }, { - Description: "// IntOrStringString is the type definition for a IntOrStringString.\n//\n// Required fields:\n// - Type\n// - Value", + Description: "// IntOrStringString is a variant of IntOrString.", Name: "IntOrStringString", Type: "struct", Fields: []TypeField{ - {Name: "Type", Type: "IntOrStringType", MarshalKey: "type", Required: true}, {Name: "Value", Type: "string", MarshalKey: "value", Required: true}, }, + VariantMarker: &VariantMarker{ + Method: "isIntOrStringVariant", + InterfaceType: "intOrStringVariant", + }, }, { Description: "// IntOrString is a value that can be an int or a string.", Name: "IntOrString", Type: "struct", Fields: []TypeField{ - { - Name: "Type", - Type: "IntOrStringType", - MarshalKey: "type", - FallbackDescription: true, - }, - { - Name: "Value", - Type: "any", - MarshalKey: "value", - FallbackDescription: true, + {Name: "Value", Type: "intOrStringVariant", MarshalKey: "value"}, + }, + Variants: &VariantConfig{ + Discriminator: "type", + DiscriminatorMethod: "Type", + DiscriminatorType: "IntOrStringType", + ValueField: "value", + ValueFieldName: "Value", + VariantType: "intOrStringVariant", + Variants: []Variant{ + { + DiscriminatorValue: "int", + TypeSuffix: "Int", + TypeName: "IntOrStringInt", + }, + { + DiscriminatorValue: "string", + TypeSuffix: "String", + TypeName: "IntOrStringString", + }, }, }, }, diff --git a/oxide/helpers.go b/oxide/helpers.go new file mode 100644 index 0000000..3a7da1d --- /dev/null +++ b/oxide/helpers.go @@ -0,0 +1,95 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +package oxide + +import "fmt" + +// String returns the string representation of the RouteDestination's value. +// Returns an empty string if no variant is set. +func (v RouteDestination) String() string { + if v.Value == nil { + return "" + } + switch val := v.Value.(type) { + case *RouteDestinationIp: + return val.Value + case *RouteDestinationIpNet: + return fmt.Sprintf("%v", val.Value) + case *RouteDestinationVpc: + return string(val.Value) + case *RouteDestinationSubnet: + return string(val.Value) + default: + panic(fmt.Sprintf("unhandled RouteDestination variant: %T", val)) + } +} + +// String returns the string representation of the VpcFirewallRuleHostFilter's value. +// Returns an empty string if no variant is set. +func (v VpcFirewallRuleHostFilter) String() string { + if v.Value == nil { + return "" + } + switch val := v.Value.(type) { + case *VpcFirewallRuleHostFilterVpc: + return string(val.Value) + case *VpcFirewallRuleHostFilterSubnet: + return string(val.Value) + case *VpcFirewallRuleHostFilterInstance: + return string(val.Value) + case *VpcFirewallRuleHostFilterIp: + return val.Value + case *VpcFirewallRuleHostFilterIpNet: + return fmt.Sprintf("%v", val.Value) + default: + panic(fmt.Sprintf("unhandled VpcFirewallRuleHostFilter variant: %T", val)) + } +} + +// String returns the string representation of the VpcFirewallRuleTarget's value. +// Returns an empty string if no variant is set. +func (v VpcFirewallRuleTarget) String() string { + if v.Value == nil { + return "" + } + switch val := v.Value.(type) { + case *VpcFirewallRuleTargetVpc: + return string(val.Value) + case *VpcFirewallRuleTargetSubnet: + return string(val.Value) + case *VpcFirewallRuleTargetInstance: + return string(val.Value) + case *VpcFirewallRuleTargetIp: + return val.Value + case *VpcFirewallRuleTargetIpNet: + return fmt.Sprintf("%v", val.Value) + default: + panic(fmt.Sprintf("unhandled VpcFirewallRuleTarget variant: %T", val)) + } +} + +// String returns the string representation of the RouteTarget's value. +// Returns an empty string if no variant is set or for Drop targets. +func (v RouteTarget) String() string { + if v.Value == nil { + return "" + } + switch val := v.Value.(type) { + case *RouteTargetIp: + return val.Value + case *RouteTargetVpc: + return string(val.Value) + case *RouteTargetSubnet: + return string(val.Value) + case *RouteTargetInstance: + return string(val.Value) + case *RouteTargetInternetGateway: + return string(val.Value) + case *RouteTargetDrop: + return "" + default: + panic(fmt.Sprintf("unhandled RouteTarget variant: %T", val)) + } +} diff --git a/oxide/types.go b/oxide/types.go index 01def1d..798d818 100644 --- a/oxide/types.go +++ b/oxide/types.go @@ -7,6 +7,7 @@ package oxide import ( + "encoding/json" "fmt" "io" "time" @@ -1969,188 +1970,138 @@ type CurrentUser struct { SiloName Name `json:"silo_name" yaml:"silo_name"` } +// datumVariant is implemented by Datum variants. +type datumVariant interface { + isDatumVariant() +} + // DatumType is the type definition for a DatumType. type DatumType string -// DatumBool is the type definition for a DatumBool. -// -// Required fields: -// - Datum -// - Type +// DatumBool is a variant of Datum. type DatumBool struct { - Datum *bool `json:"datum" yaml:"datum"` - Type DatumType `json:"type" yaml:"type"` + Datum *bool `json:"datum" yaml:"datum"` } -// DatumI8 is the type definition for a DatumI8. -// -// Required fields: -// - Datum -// - Type +func (DatumBool) isDatumVariant() {} + +// DatumI8 is a variant of Datum. type DatumI8 struct { - Datum *int `json:"datum" yaml:"datum"` - Type DatumType `json:"type" yaml:"type"` + Datum *int `json:"datum" yaml:"datum"` } -// DatumU8 is the type definition for a DatumU8. -// -// Required fields: -// - Datum -// - Type +func (DatumI8) isDatumVariant() {} + +// DatumU8 is a variant of Datum. type DatumU8 struct { - Datum *int `json:"datum" yaml:"datum"` - Type DatumType `json:"type" yaml:"type"` + Datum *int `json:"datum" yaml:"datum"` } -// DatumI16 is the type definition for a DatumI16. -// -// Required fields: -// - Datum -// - Type +func (DatumU8) isDatumVariant() {} + +// DatumI16 is a variant of Datum. type DatumI16 struct { - Datum *int `json:"datum" yaml:"datum"` - Type DatumType `json:"type" yaml:"type"` + Datum *int `json:"datum" yaml:"datum"` } -// DatumU16 is the type definition for a DatumU16. -// -// Required fields: -// - Datum -// - Type +func (DatumI16) isDatumVariant() {} + +// DatumU16 is a variant of Datum. type DatumU16 struct { - Datum *int `json:"datum" yaml:"datum"` - Type DatumType `json:"type" yaml:"type"` + Datum *int `json:"datum" yaml:"datum"` } -// DatumI32 is the type definition for a DatumI32. -// -// Required fields: -// - Datum -// - Type +func (DatumU16) isDatumVariant() {} + +// DatumI32 is a variant of Datum. type DatumI32 struct { - Datum *int `json:"datum" yaml:"datum"` - Type DatumType `json:"type" yaml:"type"` + Datum *int `json:"datum" yaml:"datum"` } -// DatumU32 is the type definition for a DatumU32. -// -// Required fields: -// - Datum -// - Type +func (DatumI32) isDatumVariant() {} + +// DatumU32 is a variant of Datum. type DatumU32 struct { - Datum *int `json:"datum" yaml:"datum"` - Type DatumType `json:"type" yaml:"type"` + Datum *int `json:"datum" yaml:"datum"` } -// DatumI64 is the type definition for a DatumI64. -// -// Required fields: -// - Datum -// - Type +func (DatumU32) isDatumVariant() {} + +// DatumI64 is a variant of Datum. type DatumI64 struct { - Datum *int `json:"datum" yaml:"datum"` - Type DatumType `json:"type" yaml:"type"` + Datum *int `json:"datum" yaml:"datum"` } -// DatumU64 is the type definition for a DatumU64. -// -// Required fields: -// - Datum -// - Type +func (DatumI64) isDatumVariant() {} + +// DatumU64 is a variant of Datum. type DatumU64 struct { - Datum *int `json:"datum" yaml:"datum"` - Type DatumType `json:"type" yaml:"type"` + Datum *int `json:"datum" yaml:"datum"` } -// DatumF32 is the type definition for a DatumF32. -// -// Required fields: -// - Datum -// - Type +func (DatumU64) isDatumVariant() {} + +// DatumF32 is a variant of Datum. type DatumF32 struct { - Datum float64 `json:"datum" yaml:"datum"` - Type DatumType `json:"type" yaml:"type"` + Datum float64 `json:"datum" yaml:"datum"` } -// DatumF64 is the type definition for a DatumF64. -// -// Required fields: -// - Datum -// - Type +func (DatumF32) isDatumVariant() {} + +// DatumF64 is a variant of Datum. type DatumF64 struct { - Datum float64 `json:"datum" yaml:"datum"` - Type DatumType `json:"type" yaml:"type"` + Datum float64 `json:"datum" yaml:"datum"` } -// DatumString is the type definition for a DatumString. -// -// Required fields: -// - Datum -// - Type +func (DatumF64) isDatumVariant() {} + +// DatumString is a variant of Datum. type DatumString struct { - Datum string `json:"datum" yaml:"datum"` - Type DatumType `json:"type" yaml:"type"` + Datum string `json:"datum" yaml:"datum"` } -// DatumBytes is the type definition for a DatumBytes. -// -// Required fields: -// - Datum -// - Type +func (DatumString) isDatumVariant() {} + +// DatumBytes is a variant of Datum. type DatumBytes struct { - Datum []int `json:"datum" yaml:"datum"` - Type DatumType `json:"type" yaml:"type"` + Datum []int `json:"datum" yaml:"datum"` } -// DatumCumulativeI64 is the type definition for a DatumCumulativeI64. -// -// Required fields: -// - Datum -// - Type +func (DatumBytes) isDatumVariant() {} + +// DatumCumulativeI64 is a variant of Datum. type DatumCumulativeI64 struct { // Datum is a cumulative or counter data type. Datum Cumulativeint64 `json:"datum" yaml:"datum"` - Type DatumType `json:"type" yaml:"type"` } -// DatumCumulativeU64 is the type definition for a DatumCumulativeU64. -// -// Required fields: -// - Datum -// - Type +func (DatumCumulativeI64) isDatumVariant() {} + +// DatumCumulativeU64 is a variant of Datum. type DatumCumulativeU64 struct { // Datum is a cumulative or counter data type. Datum Cumulativeuint64 `json:"datum" yaml:"datum"` - Type DatumType `json:"type" yaml:"type"` } -// DatumCumulativeF32 is the type definition for a DatumCumulativeF32. -// -// Required fields: -// - Datum -// - Type +func (DatumCumulativeU64) isDatumVariant() {} + +// DatumCumulativeF32 is a variant of Datum. type DatumCumulativeF32 struct { // Datum is a cumulative or counter data type. Datum Cumulativefloat `json:"datum" yaml:"datum"` - Type DatumType `json:"type" yaml:"type"` } -// DatumCumulativeF64 is the type definition for a DatumCumulativeF64. -// -// Required fields: -// - Datum -// - Type +func (DatumCumulativeF32) isDatumVariant() {} + +// DatumCumulativeF64 is a variant of Datum. type DatumCumulativeF64 struct { // Datum is a cumulative or counter data type. Datum Cumulativedouble `json:"datum" yaml:"datum"` - Type DatumType `json:"type" yaml:"type"` } -// DatumHistogramI8 is the type definition for a DatumHistogramI8. -// -// Required fields: -// - Datum -// - Type +func (DatumCumulativeF64) isDatumVariant() {} + +// DatumHistogramI8 is a variant of Datum. type DatumHistogramI8 struct { // Datum is histogram metric // @@ -2160,14 +2111,11 @@ type DatumHistogramI8 struct { // // Note that any gaps, unsorted bins, or non-finite values will result in an error. Datum Histogramint8 `json:"datum" yaml:"datum"` - Type DatumType `json:"type" yaml:"type"` } -// DatumHistogramU8 is the type definition for a DatumHistogramU8. -// -// Required fields: -// - Datum -// - Type +func (DatumHistogramI8) isDatumVariant() {} + +// DatumHistogramU8 is a variant of Datum. type DatumHistogramU8 struct { // Datum is histogram metric // @@ -2177,14 +2125,11 @@ type DatumHistogramU8 struct { // // Note that any gaps, unsorted bins, or non-finite values will result in an error. Datum Histogramuint8 `json:"datum" yaml:"datum"` - Type DatumType `json:"type" yaml:"type"` } -// DatumHistogramI16 is the type definition for a DatumHistogramI16. -// -// Required fields: -// - Datum -// - Type +func (DatumHistogramU8) isDatumVariant() {} + +// DatumHistogramI16 is a variant of Datum. type DatumHistogramI16 struct { // Datum is histogram metric // @@ -2194,14 +2139,11 @@ type DatumHistogramI16 struct { // // Note that any gaps, unsorted bins, or non-finite values will result in an error. Datum Histogramint16 `json:"datum" yaml:"datum"` - Type DatumType `json:"type" yaml:"type"` } -// DatumHistogramU16 is the type definition for a DatumHistogramU16. -// -// Required fields: -// - Datum -// - Type +func (DatumHistogramI16) isDatumVariant() {} + +// DatumHistogramU16 is a variant of Datum. type DatumHistogramU16 struct { // Datum is histogram metric // @@ -2211,14 +2153,11 @@ type DatumHistogramU16 struct { // // Note that any gaps, unsorted bins, or non-finite values will result in an error. Datum Histogramuint16 `json:"datum" yaml:"datum"` - Type DatumType `json:"type" yaml:"type"` } -// DatumHistogramI32 is the type definition for a DatumHistogramI32. -// -// Required fields: -// - Datum -// - Type +func (DatumHistogramU16) isDatumVariant() {} + +// DatumHistogramI32 is a variant of Datum. type DatumHistogramI32 struct { // Datum is histogram metric // @@ -2228,14 +2167,11 @@ type DatumHistogramI32 struct { // // Note that any gaps, unsorted bins, or non-finite values will result in an error. Datum Histogramint32 `json:"datum" yaml:"datum"` - Type DatumType `json:"type" yaml:"type"` } -// DatumHistogramU32 is the type definition for a DatumHistogramU32. -// -// Required fields: -// - Datum -// - Type +func (DatumHistogramI32) isDatumVariant() {} + +// DatumHistogramU32 is a variant of Datum. type DatumHistogramU32 struct { // Datum is histogram metric // @@ -2245,14 +2181,11 @@ type DatumHistogramU32 struct { // // Note that any gaps, unsorted bins, or non-finite values will result in an error. Datum Histogramuint32 `json:"datum" yaml:"datum"` - Type DatumType `json:"type" yaml:"type"` } -// DatumHistogramI64 is the type definition for a DatumHistogramI64. -// -// Required fields: -// - Datum -// - Type +func (DatumHistogramU32) isDatumVariant() {} + +// DatumHistogramI64 is a variant of Datum. type DatumHistogramI64 struct { // Datum is histogram metric // @@ -2262,14 +2195,11 @@ type DatumHistogramI64 struct { // // Note that any gaps, unsorted bins, or non-finite values will result in an error. Datum Histogramint64 `json:"datum" yaml:"datum"` - Type DatumType `json:"type" yaml:"type"` } -// DatumHistogramU64 is the type definition for a DatumHistogramU64. -// -// Required fields: -// - Datum -// - Type +func (DatumHistogramI64) isDatumVariant() {} + +// DatumHistogramU64 is a variant of Datum. type DatumHistogramU64 struct { // Datum is histogram metric // @@ -2279,14 +2209,11 @@ type DatumHistogramU64 struct { // // Note that any gaps, unsorted bins, or non-finite values will result in an error. Datum Histogramuint64 `json:"datum" yaml:"datum"` - Type DatumType `json:"type" yaml:"type"` } -// DatumHistogramF32 is the type definition for a DatumHistogramF32. -// -// Required fields: -// - Datum -// - Type +func (DatumHistogramU64) isDatumVariant() {} + +// DatumHistogramF32 is a variant of Datum. type DatumHistogramF32 struct { // Datum is histogram metric // @@ -2296,14 +2223,11 @@ type DatumHistogramF32 struct { // // Note that any gaps, unsorted bins, or non-finite values will result in an error. Datum Histogramfloat `json:"datum" yaml:"datum"` - Type DatumType `json:"type" yaml:"type"` } -// DatumHistogramF64 is the type definition for a DatumHistogramF64. -// -// Required fields: -// - Datum -// - Type +func (DatumHistogramF32) isDatumVariant() {} + +// DatumHistogramF64 is a variant of Datum. type DatumHistogramF64 struct { // Datum is histogram metric // @@ -2313,25 +2237,375 @@ type DatumHistogramF64 struct { // // Note that any gaps, unsorted bins, or non-finite values will result in an error. Datum Histogramdouble `json:"datum" yaml:"datum"` - Type DatumType `json:"type" yaml:"type"` } -// DatumMissing is the type definition for a DatumMissing. -// -// Required fields: -// - Datum -// - Type +func (DatumHistogramF64) isDatumVariant() {} + +// DatumMissing is a variant of Datum. type DatumMissing struct { Datum MissingDatum `json:"datum" yaml:"datum"` - Type DatumType `json:"type" yaml:"type"` } +func (DatumMissing) isDatumVariant() {} + // Datum is a `Datum` is a single sampled data point from a metric. type Datum struct { - // Datum is the type definition for a Datum. - Datum any `json:"datum,omitempty" yaml:"datum,omitempty"` - // Type is the type definition for a Type. - Type DatumType `json:"type,omitempty" yaml:"type,omitempty"` + Datum datumVariant `json:"datum,omitempty" yaml:"datum,omitempty"` +} + +func (v Datum) Type() DatumType { + switch v.Datum.(type) { + case *DatumBool: + return DatumTypeBool + case *DatumI8: + return DatumTypeI8 + case *DatumU8: + return DatumTypeU8 + case *DatumI16: + return DatumTypeI16 + case *DatumU16: + return DatumTypeU16 + case *DatumI32: + return DatumTypeI32 + case *DatumU32: + return DatumTypeU32 + case *DatumI64: + return DatumTypeI64 + case *DatumU64: + return DatumTypeU64 + case *DatumF32: + return DatumTypeF32 + case *DatumF64: + return DatumTypeF64 + case *DatumString: + return DatumTypeString + case *DatumBytes: + return DatumTypeBytes + case *DatumCumulativeI64: + return DatumTypeCumulativeI64 + case *DatumCumulativeU64: + return DatumTypeCumulativeU64 + case *DatumCumulativeF32: + return DatumTypeCumulativeF32 + case *DatumCumulativeF64: + return DatumTypeCumulativeF64 + case *DatumHistogramI8: + return DatumTypeHistogramI8 + case *DatumHistogramU8: + return DatumTypeHistogramU8 + case *DatumHistogramI16: + return DatumTypeHistogramI16 + case *DatumHistogramU16: + return DatumTypeHistogramU16 + case *DatumHistogramI32: + return DatumTypeHistogramI32 + case *DatumHistogramU32: + return DatumTypeHistogramU32 + case *DatumHistogramI64: + return DatumTypeHistogramI64 + case *DatumHistogramU64: + return DatumTypeHistogramU64 + case *DatumHistogramF32: + return DatumTypeHistogramF32 + case *DatumHistogramF64: + return DatumTypeHistogramF64 + case *DatumMissing: + return DatumTypeMissing + default: + return "" + } +} + +func (v *Datum) UnmarshalJSON(data []byte) error { + type discriminator struct { + Type string `json:"type"` + } + var d discriminator + if err := json.Unmarshal(data, &d); err != nil { + return err + } + + var value datumVariant + switch d.Type { + case "bool": + value = &DatumBool{} + case "i8": + value = &DatumI8{} + case "u8": + value = &DatumU8{} + case "i16": + value = &DatumI16{} + case "u16": + value = &DatumU16{} + case "i32": + value = &DatumI32{} + case "u32": + value = &DatumU32{} + case "i64": + value = &DatumI64{} + case "u64": + value = &DatumU64{} + case "f32": + value = &DatumF32{} + case "f64": + value = &DatumF64{} + case "string": + value = &DatumString{} + case "bytes": + value = &DatumBytes{} + case "cumulative_i64": + value = &DatumCumulativeI64{} + case "cumulative_u64": + value = &DatumCumulativeU64{} + case "cumulative_f32": + value = &DatumCumulativeF32{} + case "cumulative_f64": + value = &DatumCumulativeF64{} + case "histogram_i8": + value = &DatumHistogramI8{} + case "histogram_u8": + value = &DatumHistogramU8{} + case "histogram_i16": + value = &DatumHistogramI16{} + case "histogram_u16": + value = &DatumHistogramU16{} + case "histogram_i32": + value = &DatumHistogramI32{} + case "histogram_u32": + value = &DatumHistogramU32{} + case "histogram_i64": + value = &DatumHistogramI64{} + case "histogram_u64": + value = &DatumHistogramU64{} + case "histogram_f32": + value = &DatumHistogramF32{} + case "histogram_f64": + value = &DatumHistogramF64{} + case "missing": + value = &DatumMissing{} + default: + return fmt.Errorf("unknown variant %q, expected 'bool' or 'i8' or 'u8' or 'i16' or 'u16' or 'i32' or 'u32' or 'i64' or 'u64' or 'f32' or 'f64' or 'string' or 'bytes' or 'cumulative_i64' or 'cumulative_u64' or 'cumulative_f32' or 'cumulative_f64' or 'histogram_i8' or 'histogram_u8' or 'histogram_i16' or 'histogram_u16' or 'histogram_i32' or 'histogram_u32' or 'histogram_i64' or 'histogram_u64' or 'histogram_f32' or 'histogram_f64' or 'missing'", d.Type) + } + if err := json.Unmarshal(data, value); err != nil { + return err + } + v.Datum = value + return nil +} + +func (v Datum) MarshalJSON() ([]byte, error) { + m := make(map[string]any) + m["type"] = v.Type() + if v.Datum != nil { + valueBytes, err := json.Marshal(v.Datum) + if err != nil { + return nil, err + } + var valueMap map[string]any + if err := json.Unmarshal(valueBytes, &valueMap); err != nil { + return nil, err + } + for k, val := range valueMap { + m[k] = val + } + } + return json.Marshal(m) +} + +// AsBool attempts to convert the Datum to a DatumBool. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v Datum) AsBool() (*DatumBool, bool) { + val, ok := v.Datum.(*DatumBool) + return val, ok +} + +// AsI8 attempts to convert the Datum to a DatumI8. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v Datum) AsI8() (*DatumI8, bool) { + val, ok := v.Datum.(*DatumI8) + return val, ok +} + +// AsU8 attempts to convert the Datum to a DatumU8. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v Datum) AsU8() (*DatumU8, bool) { + val, ok := v.Datum.(*DatumU8) + return val, ok +} + +// AsI16 attempts to convert the Datum to a DatumI16. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v Datum) AsI16() (*DatumI16, bool) { + val, ok := v.Datum.(*DatumI16) + return val, ok +} + +// AsU16 attempts to convert the Datum to a DatumU16. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v Datum) AsU16() (*DatumU16, bool) { + val, ok := v.Datum.(*DatumU16) + return val, ok +} + +// AsI32 attempts to convert the Datum to a DatumI32. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v Datum) AsI32() (*DatumI32, bool) { + val, ok := v.Datum.(*DatumI32) + return val, ok +} + +// AsU32 attempts to convert the Datum to a DatumU32. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v Datum) AsU32() (*DatumU32, bool) { + val, ok := v.Datum.(*DatumU32) + return val, ok +} + +// AsI64 attempts to convert the Datum to a DatumI64. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v Datum) AsI64() (*DatumI64, bool) { + val, ok := v.Datum.(*DatumI64) + return val, ok +} + +// AsU64 attempts to convert the Datum to a DatumU64. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v Datum) AsU64() (*DatumU64, bool) { + val, ok := v.Datum.(*DatumU64) + return val, ok +} + +// AsF32 attempts to convert the Datum to a DatumF32. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v Datum) AsF32() (*DatumF32, bool) { + val, ok := v.Datum.(*DatumF32) + return val, ok +} + +// AsF64 attempts to convert the Datum to a DatumF64. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v Datum) AsF64() (*DatumF64, bool) { + val, ok := v.Datum.(*DatumF64) + return val, ok +} + +// AsString attempts to convert the Datum to a DatumString. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v Datum) AsString() (*DatumString, bool) { + val, ok := v.Datum.(*DatumString) + return val, ok +} + +// AsBytes attempts to convert the Datum to a DatumBytes. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v Datum) AsBytes() (*DatumBytes, bool) { + val, ok := v.Datum.(*DatumBytes) + return val, ok +} + +// AsCumulativeI64 attempts to convert the Datum to a DatumCumulativeI64. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v Datum) AsCumulativeI64() (*DatumCumulativeI64, bool) { + val, ok := v.Datum.(*DatumCumulativeI64) + return val, ok +} + +// AsCumulativeU64 attempts to convert the Datum to a DatumCumulativeU64. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v Datum) AsCumulativeU64() (*DatumCumulativeU64, bool) { + val, ok := v.Datum.(*DatumCumulativeU64) + return val, ok +} + +// AsCumulativeF32 attempts to convert the Datum to a DatumCumulativeF32. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v Datum) AsCumulativeF32() (*DatumCumulativeF32, bool) { + val, ok := v.Datum.(*DatumCumulativeF32) + return val, ok +} + +// AsCumulativeF64 attempts to convert the Datum to a DatumCumulativeF64. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v Datum) AsCumulativeF64() (*DatumCumulativeF64, bool) { + val, ok := v.Datum.(*DatumCumulativeF64) + return val, ok +} + +// AsHistogramI8 attempts to convert the Datum to a DatumHistogramI8. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v Datum) AsHistogramI8() (*DatumHistogramI8, bool) { + val, ok := v.Datum.(*DatumHistogramI8) + return val, ok +} + +// AsHistogramU8 attempts to convert the Datum to a DatumHistogramU8. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v Datum) AsHistogramU8() (*DatumHistogramU8, bool) { + val, ok := v.Datum.(*DatumHistogramU8) + return val, ok +} + +// AsHistogramI16 attempts to convert the Datum to a DatumHistogramI16. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v Datum) AsHistogramI16() (*DatumHistogramI16, bool) { + val, ok := v.Datum.(*DatumHistogramI16) + return val, ok +} + +// AsHistogramU16 attempts to convert the Datum to a DatumHistogramU16. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v Datum) AsHistogramU16() (*DatumHistogramU16, bool) { + val, ok := v.Datum.(*DatumHistogramU16) + return val, ok +} + +// AsHistogramI32 attempts to convert the Datum to a DatumHistogramI32. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v Datum) AsHistogramI32() (*DatumHistogramI32, bool) { + val, ok := v.Datum.(*DatumHistogramI32) + return val, ok +} + +// AsHistogramU32 attempts to convert the Datum to a DatumHistogramU32. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v Datum) AsHistogramU32() (*DatumHistogramU32, bool) { + val, ok := v.Datum.(*DatumHistogramU32) + return val, ok +} + +// AsHistogramI64 attempts to convert the Datum to a DatumHistogramI64. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v Datum) AsHistogramI64() (*DatumHistogramI64, bool) { + val, ok := v.Datum.(*DatumHistogramI64) + return val, ok +} + +// AsHistogramU64 attempts to convert the Datum to a DatumHistogramU64. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v Datum) AsHistogramU64() (*DatumHistogramU64, bool) { + val, ok := v.Datum.(*DatumHistogramU64) + return val, ok +} + +// AsHistogramF32 attempts to convert the Datum to a DatumHistogramF32. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v Datum) AsHistogramF32() (*DatumHistogramF32, bool) { + val, ok := v.Datum.(*DatumHistogramF32) + return val, ok +} + +// AsHistogramF64 attempts to convert the Datum to a DatumHistogramF64. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v Datum) AsHistogramF64() (*DatumHistogramF64, bool) { + val, ok := v.Datum.(*DatumHistogramF64) + return val, ok +} + +// AsMissing attempts to convert the Datum to a DatumMissing. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v Datum) AsMissing() (*DatumMissing, bool) { + val, ok := v.Datum.(*DatumMissing) + return val, ok } // DerEncodedKeyPair is the type definition for a DerEncodedKeyPair. @@ -2948,135 +3222,280 @@ type FieldSource string // FieldType is the `FieldType` identifies the data type of a target or metric field. type FieldType string +// fieldValueVariant is implemented by FieldValue variants. +type fieldValueVariant interface { + isFieldValueVariant() +} + // FieldValueType is the type definition for a FieldValueType. type FieldValueType string -// FieldValueString is the type definition for a FieldValueString. -// -// Required fields: -// - Type -// - Value +// FieldValueString is a variant of FieldValue. type FieldValueString struct { - Type FieldValueType `json:"type" yaml:"type"` - Value string `json:"value" yaml:"value"` + Value string `json:"value" yaml:"value"` } -// FieldValueI8 is the type definition for a FieldValueI8. -// -// Required fields: -// - Type -// - Value +func (FieldValueString) isFieldValueVariant() {} + +// FieldValueI8 is a variant of FieldValue. type FieldValueI8 struct { - Type FieldValueType `json:"type" yaml:"type"` - Value *int `json:"value" yaml:"value"` + Value *int `json:"value" yaml:"value"` } -// FieldValueU8 is the type definition for a FieldValueU8. -// -// Required fields: -// - Type -// - Value +func (FieldValueI8) isFieldValueVariant() {} + +// FieldValueU8 is a variant of FieldValue. type FieldValueU8 struct { - Type FieldValueType `json:"type" yaml:"type"` - Value *int `json:"value" yaml:"value"` + Value *int `json:"value" yaml:"value"` } -// FieldValueI16 is the type definition for a FieldValueI16. -// -// Required fields: -// - Type -// - Value +func (FieldValueU8) isFieldValueVariant() {} + +// FieldValueI16 is a variant of FieldValue. type FieldValueI16 struct { - Type FieldValueType `json:"type" yaml:"type"` - Value *int `json:"value" yaml:"value"` + Value *int `json:"value" yaml:"value"` } -// FieldValueU16 is the type definition for a FieldValueU16. -// -// Required fields: -// - Type -// - Value +func (FieldValueI16) isFieldValueVariant() {} + +// FieldValueU16 is a variant of FieldValue. type FieldValueU16 struct { - Type FieldValueType `json:"type" yaml:"type"` - Value *int `json:"value" yaml:"value"` + Value *int `json:"value" yaml:"value"` } -// FieldValueI32 is the type definition for a FieldValueI32. -// -// Required fields: -// - Type -// - Value +func (FieldValueU16) isFieldValueVariant() {} + +// FieldValueI32 is a variant of FieldValue. type FieldValueI32 struct { - Type FieldValueType `json:"type" yaml:"type"` - Value *int `json:"value" yaml:"value"` + Value *int `json:"value" yaml:"value"` } -// FieldValueU32 is the type definition for a FieldValueU32. -// -// Required fields: -// - Type -// - Value +func (FieldValueI32) isFieldValueVariant() {} + +// FieldValueU32 is a variant of FieldValue. type FieldValueU32 struct { - Type FieldValueType `json:"type" yaml:"type"` - Value *int `json:"value" yaml:"value"` + Value *int `json:"value" yaml:"value"` } -// FieldValueI64 is the type definition for a FieldValueI64. -// -// Required fields: -// - Type -// - Value +func (FieldValueU32) isFieldValueVariant() {} + +// FieldValueI64 is a variant of FieldValue. type FieldValueI64 struct { - Type FieldValueType `json:"type" yaml:"type"` - Value *int `json:"value" yaml:"value"` + Value *int `json:"value" yaml:"value"` } -// FieldValueU64 is the type definition for a FieldValueU64. -// -// Required fields: -// - Type -// - Value +func (FieldValueI64) isFieldValueVariant() {} + +// FieldValueU64 is a variant of FieldValue. type FieldValueU64 struct { - Type FieldValueType `json:"type" yaml:"type"` - Value *int `json:"value" yaml:"value"` + Value *int `json:"value" yaml:"value"` } -// FieldValueIpAddr is the type definition for a FieldValueIpAddr. -// -// Required fields: -// - Type -// - Value +func (FieldValueU64) isFieldValueVariant() {} + +// FieldValueIpAddr is a variant of FieldValue. type FieldValueIpAddr struct { - Type FieldValueType `json:"type" yaml:"type"` - Value string `json:"value" yaml:"value"` + Value string `json:"value" yaml:"value"` } -// FieldValueUuid is the type definition for a FieldValueUuid. -// -// Required fields: -// - Type -// - Value +func (FieldValueIpAddr) isFieldValueVariant() {} + +// FieldValueUuid is a variant of FieldValue. type FieldValueUuid struct { - Type FieldValueType `json:"type" yaml:"type"` - Value string `json:"value" yaml:"value"` + Value string `json:"value" yaml:"value"` } -// FieldValueBool is the type definition for a FieldValueBool. -// -// Required fields: -// - Type -// - Value +func (FieldValueUuid) isFieldValueVariant() {} + +// FieldValueBool is a variant of FieldValue. type FieldValueBool struct { - Type FieldValueType `json:"type" yaml:"type"` - Value *bool `json:"value" yaml:"value"` + Value *bool `json:"value" yaml:"value"` } +func (FieldValueBool) isFieldValueVariant() {} + // FieldValue is the `FieldValue` contains the value of a target or metric field. type FieldValue struct { - // Type is the type definition for a Type. - Type FieldValueType `json:"type,omitempty" yaml:"type,omitempty"` - // Value is the type definition for a Value. - Value any `json:"value,omitempty" yaml:"value,omitempty"` + Value fieldValueVariant `json:"value,omitempty" yaml:"value,omitempty"` +} + +func (v FieldValue) Type() FieldValueType { + switch v.Value.(type) { + case *FieldValueString: + return FieldValueTypeString + case *FieldValueI8: + return FieldValueTypeI8 + case *FieldValueU8: + return FieldValueTypeU8 + case *FieldValueI16: + return FieldValueTypeI16 + case *FieldValueU16: + return FieldValueTypeU16 + case *FieldValueI32: + return FieldValueTypeI32 + case *FieldValueU32: + return FieldValueTypeU32 + case *FieldValueI64: + return FieldValueTypeI64 + case *FieldValueU64: + return FieldValueTypeU64 + case *FieldValueIpAddr: + return FieldValueTypeIpAddr + case *FieldValueUuid: + return FieldValueTypeUuid + case *FieldValueBool: + return FieldValueTypeBool + default: + return "" + } +} + +func (v *FieldValue) UnmarshalJSON(data []byte) error { + type discriminator struct { + Type string `json:"type"` + } + var d discriminator + if err := json.Unmarshal(data, &d); err != nil { + return err + } + + var value fieldValueVariant + switch d.Type { + case "string": + value = &FieldValueString{} + case "i8": + value = &FieldValueI8{} + case "u8": + value = &FieldValueU8{} + case "i16": + value = &FieldValueI16{} + case "u16": + value = &FieldValueU16{} + case "i32": + value = &FieldValueI32{} + case "u32": + value = &FieldValueU32{} + case "i64": + value = &FieldValueI64{} + case "u64": + value = &FieldValueU64{} + case "ip_addr": + value = &FieldValueIpAddr{} + case "uuid": + value = &FieldValueUuid{} + case "bool": + value = &FieldValueBool{} + default: + return fmt.Errorf("unknown variant %q, expected 'string' or 'i8' or 'u8' or 'i16' or 'u16' or 'i32' or 'u32' or 'i64' or 'u64' or 'ip_addr' or 'uuid' or 'bool'", d.Type) + } + if err := json.Unmarshal(data, value); err != nil { + return err + } + v.Value = value + return nil +} + +func (v FieldValue) MarshalJSON() ([]byte, error) { + m := make(map[string]any) + m["type"] = v.Type() + if v.Value != nil { + valueBytes, err := json.Marshal(v.Value) + if err != nil { + return nil, err + } + var valueMap map[string]any + if err := json.Unmarshal(valueBytes, &valueMap); err != nil { + return nil, err + } + for k, val := range valueMap { + m[k] = val + } + } + return json.Marshal(m) +} + +// AsString attempts to convert the FieldValue to a FieldValueString. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v FieldValue) AsString() (*FieldValueString, bool) { + val, ok := v.Value.(*FieldValueString) + return val, ok +} + +// AsI8 attempts to convert the FieldValue to a FieldValueI8. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v FieldValue) AsI8() (*FieldValueI8, bool) { + val, ok := v.Value.(*FieldValueI8) + return val, ok +} + +// AsU8 attempts to convert the FieldValue to a FieldValueU8. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v FieldValue) AsU8() (*FieldValueU8, bool) { + val, ok := v.Value.(*FieldValueU8) + return val, ok +} + +// AsI16 attempts to convert the FieldValue to a FieldValueI16. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v FieldValue) AsI16() (*FieldValueI16, bool) { + val, ok := v.Value.(*FieldValueI16) + return val, ok +} + +// AsU16 attempts to convert the FieldValue to a FieldValueU16. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v FieldValue) AsU16() (*FieldValueU16, bool) { + val, ok := v.Value.(*FieldValueU16) + return val, ok +} + +// AsI32 attempts to convert the FieldValue to a FieldValueI32. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v FieldValue) AsI32() (*FieldValueI32, bool) { + val, ok := v.Value.(*FieldValueI32) + return val, ok +} + +// AsU32 attempts to convert the FieldValue to a FieldValueU32. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v FieldValue) AsU32() (*FieldValueU32, bool) { + val, ok := v.Value.(*FieldValueU32) + return val, ok +} + +// AsI64 attempts to convert the FieldValue to a FieldValueI64. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v FieldValue) AsI64() (*FieldValueI64, bool) { + val, ok := v.Value.(*FieldValueI64) + return val, ok +} + +// AsU64 attempts to convert the FieldValue to a FieldValueU64. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v FieldValue) AsU64() (*FieldValueU64, bool) { + val, ok := v.Value.(*FieldValueU64) + return val, ok +} + +// AsIpAddr attempts to convert the FieldValue to a FieldValueIpAddr. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v FieldValue) AsIpAddr() (*FieldValueIpAddr, bool) { + val, ok := v.Value.(*FieldValueIpAddr) + return val, ok +} + +// AsUuid attempts to convert the FieldValue to a FieldValueUuid. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v FieldValue) AsUuid() (*FieldValueUuid, bool) { + val, ok := v.Value.(*FieldValueUuid) + return val, ok +} + +// AsBool attempts to convert the FieldValue to a FieldValueBool. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v FieldValue) AsBool() (*FieldValueBool, bool) { + val, ok := v.Value.(*FieldValueBool) + return val, ok } // FinalizeDisk is parameters for finalizing a disk @@ -5447,31 +5866,30 @@ type PoolSelector struct { IpVersion IpVersion `json:"ip_version,omitzero" yaml:"ip_version,omitzero"` } +// privateIpConfigVariant is implemented by PrivateIpConfig variants. +type privateIpConfigVariant interface { + isPrivateIpConfigVariant() +} + // PrivateIpConfigType is the type definition for a PrivateIpConfigType. type PrivateIpConfigType string -// PrivateIpConfigV4 is the interface has only an IPv4 configuration. -// -// Required fields: -// - Type -// - Value +// PrivateIpConfigV4 is a variant of PrivateIpConfig. type PrivateIpConfigV4 struct { - Type PrivateIpConfigType `json:"type" yaml:"type"` // Value is vPC-private IPv4 configuration for a network interface. Value PrivateIpv4Config `json:"value" yaml:"value"` } -// PrivateIpConfigV6 is the interface has only an IPv6 configuration. -// -// Required fields: -// - Type -// - Value +func (PrivateIpConfigV4) isPrivateIpConfigVariant() {} + +// PrivateIpConfigV6 is a variant of PrivateIpConfig. type PrivateIpConfigV6 struct { - Type PrivateIpConfigType `json:"type" yaml:"type"` // Value is vPC-private IPv6 configuration for a network interface. Value PrivateIpv6Config `json:"value" yaml:"value"` } +func (PrivateIpConfigV6) isPrivateIpConfigVariant() {} + // PrivateIpConfigValue is the type definition for a PrivateIpConfigValue. // // Required fields: @@ -5484,104 +5902,250 @@ type PrivateIpConfigValue struct { V6 PrivateIpv6Config `json:"v6" yaml:"v6"` } -// PrivateIpConfigDualStack is the interface is dual-stack. -// -// Required fields: -// - Type -// - Value +// PrivateIpConfigDualStack is a variant of PrivateIpConfig. type PrivateIpConfigDualStack struct { - Type PrivateIpConfigType `json:"type" yaml:"type"` Value PrivateIpConfigValue `json:"value" yaml:"value"` } +func (PrivateIpConfigDualStack) isPrivateIpConfigVariant() {} + // PrivateIpConfig is vPC-private IP address configuration for a network interface. type PrivateIpConfig struct { - // Type is the type definition for a Type. - Type PrivateIpConfigType `json:"type,omitempty" yaml:"type,omitempty"` - // Value is vPC-private IPv4 configuration for a network interface. - Value any `json:"value,omitempty" yaml:"value,omitempty"` + Value privateIpConfigVariant `json:"value,omitempty" yaml:"value,omitempty"` +} + +func (v PrivateIpConfig) Type() PrivateIpConfigType { + switch v.Value.(type) { + case *PrivateIpConfigV4: + return PrivateIpConfigTypeV4 + case *PrivateIpConfigV6: + return PrivateIpConfigTypeV6 + case *PrivateIpConfigDualStack: + return PrivateIpConfigTypeDualStack + default: + return "" + } +} + +func (v *PrivateIpConfig) UnmarshalJSON(data []byte) error { + type discriminator struct { + Type string `json:"type"` + } + var d discriminator + if err := json.Unmarshal(data, &d); err != nil { + return err + } + + var value privateIpConfigVariant + switch d.Type { + case "v4": + value = &PrivateIpConfigV4{} + case "v6": + value = &PrivateIpConfigV6{} + case "dual_stack": + value = &PrivateIpConfigDualStack{} + default: + return fmt.Errorf("unknown variant %q, expected 'v4' or 'v6' or 'dual_stack'", d.Type) + } + if err := json.Unmarshal(data, value); err != nil { + return err + } + v.Value = value + return nil +} + +func (v PrivateIpConfig) MarshalJSON() ([]byte, error) { + m := make(map[string]any) + m["type"] = v.Type() + if v.Value != nil { + valueBytes, err := json.Marshal(v.Value) + if err != nil { + return nil, err + } + var valueMap map[string]any + if err := json.Unmarshal(valueBytes, &valueMap); err != nil { + return nil, err + } + for k, val := range valueMap { + m[k] = val + } + } + return json.Marshal(m) +} + +// AsV4 attempts to convert the PrivateIpConfig to a PrivateIpConfigV4. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v PrivateIpConfig) AsV4() (*PrivateIpConfigV4, bool) { + val, ok := v.Value.(*PrivateIpConfigV4) + return val, ok +} + +// AsV6 attempts to convert the PrivateIpConfig to a PrivateIpConfigV6. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v PrivateIpConfig) AsV6() (*PrivateIpConfigV6, bool) { + val, ok := v.Value.(*PrivateIpConfigV6) + return val, ok +} + +// AsDualStack attempts to convert the PrivateIpConfig to a PrivateIpConfigDualStack. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v PrivateIpConfig) AsDualStack() (*PrivateIpConfigDualStack, bool) { + val, ok := v.Value.(*PrivateIpConfigDualStack) + return val, ok +} + +// privateIpStackVariant is implemented by PrivateIpStack variants. +type privateIpStackVariant interface { + isPrivateIpStackVariant() } // PrivateIpStackType is the type definition for a PrivateIpStackType. type PrivateIpStackType string -// PrivateIpStackV4 is the interface has only an IPv4 stack. -// -// Required fields: -// - Type -// - Value +// PrivateIpStackV4 is a variant of PrivateIpStack. type PrivateIpStackV4 struct { - Type PrivateIpStackType `json:"type" yaml:"type"` // Value is the VPC-private IPv4 stack for a network interface Value PrivateIpv4Stack `json:"value" yaml:"value"` } -// PrivateIpStackV6 is the interface has only an IPv6 stack. -// -// Required fields: -// - Type -// - Value +func (PrivateIpStackV4) isPrivateIpStackVariant() {} + +// PrivateIpStackV6 is a variant of PrivateIpStack. type PrivateIpStackV6 struct { - Type PrivateIpStackType `json:"type" yaml:"type"` // Value is the VPC-private IPv6 stack for a network interface Value PrivateIpv6Stack `json:"value" yaml:"value"` } -// PrivateIpStackValue is the type definition for a PrivateIpStackValue. -// -// Required fields: -// - V4 -// - V6 -type PrivateIpStackValue struct { - // V4 is the VPC-private IPv4 stack for a network interface - V4 PrivateIpv4Stack `json:"v4" yaml:"v4"` - // V6 is the VPC-private IPv6 stack for a network interface - V6 PrivateIpv6Stack `json:"v6" yaml:"v6"` +func (PrivateIpStackV6) isPrivateIpStackVariant() {} + +// PrivateIpStackValue is the type definition for a PrivateIpStackValue. +// +// Required fields: +// - V4 +// - V6 +type PrivateIpStackValue struct { + // V4 is the VPC-private IPv4 stack for a network interface + V4 PrivateIpv4Stack `json:"v4" yaml:"v4"` + // V6 is the VPC-private IPv6 stack for a network interface + V6 PrivateIpv6Stack `json:"v6" yaml:"v6"` +} + +// PrivateIpStackDualStack is a variant of PrivateIpStack. +type PrivateIpStackDualStack struct { + Value PrivateIpStackValue `json:"value" yaml:"value"` +} + +func (PrivateIpStackDualStack) isPrivateIpStackVariant() {} + +// PrivateIpStack is the VPC-private IP stack for a network interface. +type PrivateIpStack struct { + Value privateIpStackVariant `json:"value,omitempty" yaml:"value,omitempty"` +} + +func (v PrivateIpStack) Type() PrivateIpStackType { + switch v.Value.(type) { + case *PrivateIpStackV4: + return PrivateIpStackTypeV4 + case *PrivateIpStackV6: + return PrivateIpStackTypeV6 + case *PrivateIpStackDualStack: + return PrivateIpStackTypeDualStack + default: + return "" + } +} + +func (v *PrivateIpStack) UnmarshalJSON(data []byte) error { + type discriminator struct { + Type string `json:"type"` + } + var d discriminator + if err := json.Unmarshal(data, &d); err != nil { + return err + } + + var value privateIpStackVariant + switch d.Type { + case "v4": + value = &PrivateIpStackV4{} + case "v6": + value = &PrivateIpStackV6{} + case "dual_stack": + value = &PrivateIpStackDualStack{} + default: + return fmt.Errorf("unknown variant %q, expected 'v4' or 'v6' or 'dual_stack'", d.Type) + } + if err := json.Unmarshal(data, value); err != nil { + return err + } + v.Value = value + return nil +} + +func (v PrivateIpStack) MarshalJSON() ([]byte, error) { + m := make(map[string]any) + m["type"] = v.Type() + if v.Value != nil { + valueBytes, err := json.Marshal(v.Value) + if err != nil { + return nil, err + } + var valueMap map[string]any + if err := json.Unmarshal(valueBytes, &valueMap); err != nil { + return nil, err + } + for k, val := range valueMap { + m[k] = val + } + } + return json.Marshal(m) +} + +// AsV4 attempts to convert the PrivateIpStack to a PrivateIpStackV4. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v PrivateIpStack) AsV4() (*PrivateIpStackV4, bool) { + val, ok := v.Value.(*PrivateIpStackV4) + return val, ok +} + +// AsV6 attempts to convert the PrivateIpStack to a PrivateIpStackV6. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v PrivateIpStack) AsV6() (*PrivateIpStackV6, bool) { + val, ok := v.Value.(*PrivateIpStackV6) + return val, ok } -// PrivateIpStackDualStack is the interface is dual-stack IPv4 and IPv6. -// -// Required fields: -// - Type -// - Value -type PrivateIpStackDualStack struct { - Type PrivateIpStackType `json:"type" yaml:"type"` - Value PrivateIpStackValue `json:"value" yaml:"value"` +// AsDualStack attempts to convert the PrivateIpStack to a PrivateIpStackDualStack. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v PrivateIpStack) AsDualStack() (*PrivateIpStackDualStack, bool) { + val, ok := v.Value.(*PrivateIpStackDualStack) + return val, ok } -// PrivateIpStack is the VPC-private IP stack for a network interface. -type PrivateIpStack struct { - // Type is the type definition for a Type. - Type PrivateIpStackType `json:"type,omitempty" yaml:"type,omitempty"` - // Value is the VPC-private IPv4 stack for a network interface - Value any `json:"value,omitempty" yaml:"value,omitempty"` +// privateIpStackCreateVariant is implemented by PrivateIpStackCreate variants. +type privateIpStackCreateVariant interface { + isPrivateIpStackCreateVariant() } // PrivateIpStackCreateType is the type definition for a PrivateIpStackCreateType. type PrivateIpStackCreateType string -// PrivateIpStackCreateV4 is the interface has only an IPv4 stack. -// -// Required fields: -// - Type -// - Value +// PrivateIpStackCreateV4 is a variant of PrivateIpStackCreate. type PrivateIpStackCreateV4 struct { - Type PrivateIpStackCreateType `json:"type" yaml:"type"` // Value is configuration for a network interface's IPv4 addressing. Value PrivateIpv4StackCreate `json:"value" yaml:"value"` } -// PrivateIpStackCreateV6 is the interface has only an IPv6 stack. -// -// Required fields: -// - Type -// - Value +func (PrivateIpStackCreateV4) isPrivateIpStackCreateVariant() {} + +// PrivateIpStackCreateV6 is a variant of PrivateIpStackCreate. type PrivateIpStackCreateV6 struct { - Type PrivateIpStackCreateType `json:"type" yaml:"type"` // Value is configuration for a network interface's IPv6 addressing. Value PrivateIpv6StackCreate `json:"value" yaml:"value"` } +func (PrivateIpStackCreateV6) isPrivateIpStackCreateVariant() {} + // PrivateIpStackCreateValue is the type definition for a PrivateIpStackCreateValue. // // Required fields: @@ -5594,22 +6158,96 @@ type PrivateIpStackCreateValue struct { V6 PrivateIpv6StackCreate `json:"v6" yaml:"v6"` } -// PrivateIpStackCreateDualStack is the interface has both an IPv4 and IPv6 stack. -// -// Required fields: -// - Type -// - Value +// PrivateIpStackCreateDualStack is a variant of PrivateIpStackCreate. type PrivateIpStackCreateDualStack struct { - Type PrivateIpStackCreateType `json:"type" yaml:"type"` Value PrivateIpStackCreateValue `json:"value" yaml:"value"` } +func (PrivateIpStackCreateDualStack) isPrivateIpStackCreateVariant() {} + // PrivateIpStackCreate is create parameters for a network interface's IP stack. type PrivateIpStackCreate struct { - // Type is the type definition for a Type. - Type PrivateIpStackCreateType `json:"type,omitempty" yaml:"type,omitempty"` - // Value is configuration for a network interface's IPv4 addressing. - Value any `json:"value,omitempty" yaml:"value,omitempty"` + Value privateIpStackCreateVariant `json:"value,omitempty" yaml:"value,omitempty"` +} + +func (v PrivateIpStackCreate) Type() PrivateIpStackCreateType { + switch v.Value.(type) { + case *PrivateIpStackCreateV4: + return PrivateIpStackCreateTypeV4 + case *PrivateIpStackCreateV6: + return PrivateIpStackCreateTypeV6 + case *PrivateIpStackCreateDualStack: + return PrivateIpStackCreateTypeDualStack + default: + return "" + } +} + +func (v *PrivateIpStackCreate) UnmarshalJSON(data []byte) error { + type discriminator struct { + Type string `json:"type"` + } + var d discriminator + if err := json.Unmarshal(data, &d); err != nil { + return err + } + + var value privateIpStackCreateVariant + switch d.Type { + case "v4": + value = &PrivateIpStackCreateV4{} + case "v6": + value = &PrivateIpStackCreateV6{} + case "dual_stack": + value = &PrivateIpStackCreateDualStack{} + default: + return fmt.Errorf("unknown variant %q, expected 'v4' or 'v6' or 'dual_stack'", d.Type) + } + if err := json.Unmarshal(data, value); err != nil { + return err + } + v.Value = value + return nil +} + +func (v PrivateIpStackCreate) MarshalJSON() ([]byte, error) { + m := make(map[string]any) + m["type"] = v.Type() + if v.Value != nil { + valueBytes, err := json.Marshal(v.Value) + if err != nil { + return nil, err + } + var valueMap map[string]any + if err := json.Unmarshal(valueBytes, &valueMap); err != nil { + return nil, err + } + for k, val := range valueMap { + m[k] = val + } + } + return json.Marshal(m) +} + +// AsV4 attempts to convert the PrivateIpStackCreate to a PrivateIpStackCreateV4. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v PrivateIpStackCreate) AsV4() (*PrivateIpStackCreateV4, bool) { + val, ok := v.Value.(*PrivateIpStackCreateV4) + return val, ok +} + +// AsV6 attempts to convert the PrivateIpStackCreate to a PrivateIpStackCreateV6. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v PrivateIpStackCreate) AsV6() (*PrivateIpStackCreateV6, bool) { + val, ok := v.Value.(*PrivateIpStackCreateV6) + return val, ok +} + +// AsDualStack attempts to convert the PrivateIpStackCreate to a PrivateIpStackCreateDualStack. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v PrivateIpStackCreate) AsDualStack() (*PrivateIpStackCreateDualStack, bool) { + val, ok := v.Value.(*PrivateIpStackCreateDualStack) + return val, ok } // PrivateIpv4Config is vPC-private IPv4 configuration for a network interface. @@ -5940,147 +6578,325 @@ type RouteConfig struct { Routes []Route `json:"routes" yaml:"routes"` } +// routeDestinationVariant is implemented by RouteDestination variants. +type routeDestinationVariant interface { + isRouteDestinationVariant() +} + // RouteDestinationType is the type definition for a RouteDestinationType. type RouteDestinationType string -// RouteDestinationIp is route applies to traffic destined for the specified IP address -// -// Required fields: -// - Type -// - Value +// RouteDestinationIp is a variant of RouteDestination. type RouteDestinationIp struct { - Type RouteDestinationType `json:"type" yaml:"type"` - Value string `json:"value" yaml:"value"` + Value string `json:"value" yaml:"value"` } -// RouteDestinationIpNet is route applies to traffic destined for the specified IP subnet -// -// Required fields: -// - Type -// - Value +func (RouteDestinationIp) isRouteDestinationVariant() {} + +// RouteDestinationIpNet is a variant of RouteDestination. type RouteDestinationIpNet struct { - Type RouteDestinationType `json:"type" yaml:"type"` - Value IpNet `json:"value" yaml:"value"` + Value IpNet `json:"value" yaml:"value"` } -// RouteDestinationVpc is route applies to traffic destined for the specified VPC -// -// Required fields: -// - Type -// - Value +func (RouteDestinationIpNet) isRouteDestinationVariant() {} + +// RouteDestinationVpc is a variant of RouteDestination. type RouteDestinationVpc struct { - Type RouteDestinationType `json:"type" yaml:"type"` // Value is names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase // ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID, but they may contain a UUID. They // can be at most 63 characters long. Value Name `json:"value" yaml:"value"` } -// RouteDestinationSubnet is route applies to traffic destined for the specified VPC subnet -// -// Required fields: -// - Type -// - Value +func (RouteDestinationVpc) isRouteDestinationVariant() {} + +// RouteDestinationSubnet is a variant of RouteDestination. type RouteDestinationSubnet struct { - Type RouteDestinationType `json:"type" yaml:"type"` // Value is names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase // ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID, but they may contain a UUID. They // can be at most 63 characters long. Value Name `json:"value" yaml:"value"` } +func (RouteDestinationSubnet) isRouteDestinationVariant() {} + // RouteDestination is a `RouteDestination` is used to match traffic with a routing rule based on the destination // of that traffic. // // When traffic is to be sent to a destination that is within a given `RouteDestination`, the corresponding `RouterRoute` // applies, and traffic will be forward to the `RouteTarget` for that rule. type RouteDestination struct { - // Type is the type definition for a Type. - Type RouteDestinationType `json:"type,omitempty" yaml:"type,omitempty"` - // Value is the type definition for a Value. - Value any `json:"value,omitempty" yaml:"value,omitempty"` + Value routeDestinationVariant `json:"value,omitempty" yaml:"value,omitempty"` +} + +func (v RouteDestination) Type() RouteDestinationType { + switch v.Value.(type) { + case *RouteDestinationIp: + return RouteDestinationTypeIp + case *RouteDestinationIpNet: + return RouteDestinationTypeIpNet + case *RouteDestinationVpc: + return RouteDestinationTypeVpc + case *RouteDestinationSubnet: + return RouteDestinationTypeSubnet + default: + return "" + } +} + +func (v *RouteDestination) UnmarshalJSON(data []byte) error { + type discriminator struct { + Type string `json:"type"` + } + var d discriminator + if err := json.Unmarshal(data, &d); err != nil { + return err + } + + var value routeDestinationVariant + switch d.Type { + case "ip": + value = &RouteDestinationIp{} + case "ip_net": + value = &RouteDestinationIpNet{} + case "vpc": + value = &RouteDestinationVpc{} + case "subnet": + value = &RouteDestinationSubnet{} + default: + return fmt.Errorf("unknown variant %q, expected 'ip' or 'ip_net' or 'vpc' or 'subnet'", d.Type) + } + if err := json.Unmarshal(data, value); err != nil { + return err + } + v.Value = value + return nil +} + +func (v RouteDestination) MarshalJSON() ([]byte, error) { + m := make(map[string]any) + m["type"] = v.Type() + if v.Value != nil { + valueBytes, err := json.Marshal(v.Value) + if err != nil { + return nil, err + } + var valueMap map[string]any + if err := json.Unmarshal(valueBytes, &valueMap); err != nil { + return nil, err + } + for k, val := range valueMap { + m[k] = val + } + } + return json.Marshal(m) +} + +// AsIp attempts to convert the RouteDestination to a RouteDestinationIp. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v RouteDestination) AsIp() (*RouteDestinationIp, bool) { + val, ok := v.Value.(*RouteDestinationIp) + return val, ok +} + +// AsIpNet attempts to convert the RouteDestination to a RouteDestinationIpNet. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v RouteDestination) AsIpNet() (*RouteDestinationIpNet, bool) { + val, ok := v.Value.(*RouteDestinationIpNet) + return val, ok +} + +// AsVpc attempts to convert the RouteDestination to a RouteDestinationVpc. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v RouteDestination) AsVpc() (*RouteDestinationVpc, bool) { + val, ok := v.Value.(*RouteDestinationVpc) + return val, ok +} + +// AsSubnet attempts to convert the RouteDestination to a RouteDestinationSubnet. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v RouteDestination) AsSubnet() (*RouteDestinationSubnet, bool) { + val, ok := v.Value.(*RouteDestinationSubnet) + return val, ok +} + +// routeTargetVariant is implemented by RouteTarget variants. +type routeTargetVariant interface { + isRouteTargetVariant() } // RouteTargetType is the type definition for a RouteTargetType. type RouteTargetType string -// RouteTargetIp is forward traffic to a particular IP address. -// -// Required fields: -// - Type -// - Value +// RouteTargetIp is a variant of RouteTarget. type RouteTargetIp struct { - Type RouteTargetType `json:"type" yaml:"type"` - Value string `json:"value" yaml:"value"` + Value string `json:"value" yaml:"value"` } -// RouteTargetVpc is forward traffic to a VPC -// -// Required fields: -// - Type -// - Value +func (RouteTargetIp) isRouteTargetVariant() {} + +// RouteTargetVpc is a variant of RouteTarget. type RouteTargetVpc struct { - Type RouteTargetType `json:"type" yaml:"type"` // Value is names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase // ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID, but they may contain a UUID. They // can be at most 63 characters long. Value Name `json:"value" yaml:"value"` } -// RouteTargetSubnet is forward traffic to a VPC Subnet -// -// Required fields: -// - Type -// - Value +func (RouteTargetVpc) isRouteTargetVariant() {} + +// RouteTargetSubnet is a variant of RouteTarget. type RouteTargetSubnet struct { - Type RouteTargetType `json:"type" yaml:"type"` // Value is names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase // ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID, but they may contain a UUID. They // can be at most 63 characters long. Value Name `json:"value" yaml:"value"` } -// RouteTargetInstance is forward traffic to a specific instance -// -// Required fields: -// - Type -// - Value +func (RouteTargetSubnet) isRouteTargetVariant() {} + +// RouteTargetInstance is a variant of RouteTarget. type RouteTargetInstance struct { - Type RouteTargetType `json:"type" yaml:"type"` // Value is names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase // ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID, but they may contain a UUID. They // can be at most 63 characters long. Value Name `json:"value" yaml:"value"` } -// RouteTargetInternetGateway is forward traffic to an internet gateway -// -// Required fields: -// - Type -// - Value +func (RouteTargetInstance) isRouteTargetVariant() {} + +// RouteTargetInternetGateway is a variant of RouteTarget. type RouteTargetInternetGateway struct { - Type RouteTargetType `json:"type" yaml:"type"` // Value is names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase // ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID, but they may contain a UUID. They // can be at most 63 characters long. Value Name `json:"value" yaml:"value"` } -// RouteTargetDrop is drop matching traffic -// -// Required fields: -// - Type -type RouteTargetDrop struct { - Type RouteTargetType `json:"type" yaml:"type"` -} +func (RouteTargetInternetGateway) isRouteTargetVariant() {} + +// RouteTargetDrop is a variant of RouteTarget. +type RouteTargetDrop struct{} + +func (RouteTargetDrop) isRouteTargetVariant() {} // RouteTarget is a `RouteTarget` describes the possible locations that traffic matching a route destination can // be sent. type RouteTarget struct { - // Type is the type definition for a Type. - Type RouteTargetType `json:"type,omitempty" yaml:"type,omitempty"` - // Value is the type definition for a Value. - Value any `json:"value,omitempty" yaml:"value,omitempty"` + Value routeTargetVariant `json:"value,omitempty" yaml:"value,omitempty"` +} + +func (v RouteTarget) Type() RouteTargetType { + switch v.Value.(type) { + case *RouteTargetIp: + return RouteTargetTypeIp + case *RouteTargetVpc: + return RouteTargetTypeVpc + case *RouteTargetSubnet: + return RouteTargetTypeSubnet + case *RouteTargetInstance: + return RouteTargetTypeInstance + case *RouteTargetInternetGateway: + return RouteTargetTypeInternetGateway + case *RouteTargetDrop: + return RouteTargetTypeDrop + default: + return "" + } +} + +func (v *RouteTarget) UnmarshalJSON(data []byte) error { + type discriminator struct { + Type string `json:"type"` + } + var d discriminator + if err := json.Unmarshal(data, &d); err != nil { + return err + } + + var value routeTargetVariant + switch d.Type { + case "ip": + value = &RouteTargetIp{} + case "vpc": + value = &RouteTargetVpc{} + case "subnet": + value = &RouteTargetSubnet{} + case "instance": + value = &RouteTargetInstance{} + case "internet_gateway": + value = &RouteTargetInternetGateway{} + case "drop": + value = &RouteTargetDrop{} + default: + return fmt.Errorf("unknown variant %q, expected 'ip' or 'vpc' or 'subnet' or 'instance' or 'internet_gateway' or 'drop'", d.Type) + } + if err := json.Unmarshal(data, value); err != nil { + return err + } + v.Value = value + return nil +} + +func (v RouteTarget) MarshalJSON() ([]byte, error) { + m := make(map[string]any) + m["type"] = v.Type() + if v.Value != nil { + valueBytes, err := json.Marshal(v.Value) + if err != nil { + return nil, err + } + var valueMap map[string]any + if err := json.Unmarshal(valueBytes, &valueMap); err != nil { + return nil, err + } + for k, val := range valueMap { + m[k] = val + } + } + return json.Marshal(m) +} + +// AsIp attempts to convert the RouteTarget to a RouteTargetIp. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v RouteTarget) AsIp() (*RouteTargetIp, bool) { + val, ok := v.Value.(*RouteTargetIp) + return val, ok +} + +// AsVpc attempts to convert the RouteTarget to a RouteTargetVpc. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v RouteTarget) AsVpc() (*RouteTargetVpc, bool) { + val, ok := v.Value.(*RouteTargetVpc) + return val, ok +} + +// AsSubnet attempts to convert the RouteTarget to a RouteTargetSubnet. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v RouteTarget) AsSubnet() (*RouteTargetSubnet, bool) { + val, ok := v.Value.(*RouteTargetSubnet) + return val, ok +} + +// AsInstance attempts to convert the RouteTarget to a RouteTargetInstance. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v RouteTarget) AsInstance() (*RouteTargetInstance, bool) { + val, ok := v.Value.(*RouteTargetInstance) + return val, ok +} + +// AsInternetGateway attempts to convert the RouteTarget to a RouteTargetInternetGateway. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v RouteTarget) AsInternetGateway() (*RouteTargetInternetGateway, bool) { + val, ok := v.Value.(*RouteTargetInternetGateway) + return val, ok +} + +// AsDrop attempts to convert the RouteTarget to a RouteTargetDrop. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v RouteTarget) AsDrop() (*RouteTargetDrop, bool) { + val, ok := v.Value.(*RouteTargetDrop) + return val, ok } // RouterRoute is a route defines a rule that governs where traffic should be sent based on its destination. @@ -7732,77 +8548,174 @@ type Utilization struct { Provisioned VirtualResourceCounts `json:"provisioned" yaml:"provisioned"` } +// valueArrayVariant is implemented by ValueArray variants. +type valueArrayVariant interface { + isValueArrayVariant() +} + // ValueArrayType is the type definition for a ValueArrayType. type ValueArrayType string -// ValueArrayInteger is the type definition for a ValueArrayInteger. -// -// Required fields: -// - Type -// - Values +// ValueArrayInteger is a variant of ValueArray. type ValueArrayInteger struct { - Type ValueArrayType `json:"type" yaml:"type"` - Values []int `json:"values" yaml:"values"` + Values []int `json:"values" yaml:"values"` } -// ValueArrayDouble is the type definition for a ValueArrayDouble. -// -// Required fields: -// - Type -// - Values +func (ValueArrayInteger) isValueArrayVariant() {} + +// ValueArrayDouble is a variant of ValueArray. type ValueArrayDouble struct { - Type ValueArrayType `json:"type" yaml:"type"` - Values []float64 `json:"values" yaml:"values"` + Values []float64 `json:"values" yaml:"values"` } -// ValueArrayBoolean is the type definition for a ValueArrayBoolean. -// -// Required fields: -// - Type -// - Values +func (ValueArrayDouble) isValueArrayVariant() {} + +// ValueArrayBoolean is a variant of ValueArray. type ValueArrayBoolean struct { - Type ValueArrayType `json:"type" yaml:"type"` - Values []bool `json:"values" yaml:"values"` + Values []bool `json:"values" yaml:"values"` } -// ValueArrayString is the type definition for a ValueArrayString. -// -// Required fields: -// - Type -// - Values +func (ValueArrayBoolean) isValueArrayVariant() {} + +// ValueArrayString is a variant of ValueArray. type ValueArrayString struct { - Type ValueArrayType `json:"type" yaml:"type"` - Values []string `json:"values" yaml:"values"` + Values []string `json:"values" yaml:"values"` } -// ValueArrayIntegerDistribution is the type definition for a ValueArrayIntegerDistribution. -// -// Required fields: -// - Type -// - Values +func (ValueArrayString) isValueArrayVariant() {} + +// ValueArrayIntegerDistribution is a variant of ValueArray. type ValueArrayIntegerDistribution struct { - Type ValueArrayType `json:"type" yaml:"type"` Values []Distributionint64 `json:"values" yaml:"values"` } -// ValueArrayDoubleDistribution is the type definition for a ValueArrayDoubleDistribution. -// -// Required fields: -// - Type -// - Values +func (ValueArrayIntegerDistribution) isValueArrayVariant() {} + +// ValueArrayDoubleDistribution is a variant of ValueArray. type ValueArrayDoubleDistribution struct { - Type ValueArrayType `json:"type" yaml:"type"` Values []Distributiondouble `json:"values" yaml:"values"` } +func (ValueArrayDoubleDistribution) isValueArrayVariant() {} + // ValueArray is list of data values for one timeseries. // // Each element is an option, where `None` represents a missing sample. type ValueArray struct { - // Type is the type definition for a Type. - Type ValueArrayType `json:"type,omitempty" yaml:"type,omitempty"` - // Values is the type definition for a Values. - Values any `json:"values,omitempty" yaml:"values,omitempty"` + Values valueArrayVariant `json:"values,omitempty" yaml:"values,omitempty"` +} + +func (v ValueArray) Type() ValueArrayType { + switch v.Values.(type) { + case *ValueArrayInteger: + return ValueArrayTypeInteger + case *ValueArrayDouble: + return ValueArrayTypeDouble + case *ValueArrayBoolean: + return ValueArrayTypeBoolean + case *ValueArrayString: + return ValueArrayTypeString + case *ValueArrayIntegerDistribution: + return ValueArrayTypeIntegerDistribution + case *ValueArrayDoubleDistribution: + return ValueArrayTypeDoubleDistribution + default: + return "" + } +} + +func (v *ValueArray) UnmarshalJSON(data []byte) error { + type discriminator struct { + Type string `json:"type"` + } + var d discriminator + if err := json.Unmarshal(data, &d); err != nil { + return err + } + + var value valueArrayVariant + switch d.Type { + case "integer": + value = &ValueArrayInteger{} + case "double": + value = &ValueArrayDouble{} + case "boolean": + value = &ValueArrayBoolean{} + case "string": + value = &ValueArrayString{} + case "integer_distribution": + value = &ValueArrayIntegerDistribution{} + case "double_distribution": + value = &ValueArrayDoubleDistribution{} + default: + return fmt.Errorf("unknown variant %q, expected 'integer' or 'double' or 'boolean' or 'string' or 'integer_distribution' or 'double_distribution'", d.Type) + } + if err := json.Unmarshal(data, value); err != nil { + return err + } + v.Values = value + return nil +} + +func (v ValueArray) MarshalJSON() ([]byte, error) { + m := make(map[string]any) + m["type"] = v.Type() + if v.Values != nil { + valueBytes, err := json.Marshal(v.Values) + if err != nil { + return nil, err + } + var valueMap map[string]any + if err := json.Unmarshal(valueBytes, &valueMap); err != nil { + return nil, err + } + for k, val := range valueMap { + m[k] = val + } + } + return json.Marshal(m) +} + +// AsInteger attempts to convert the ValueArray to a ValueArrayInteger. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v ValueArray) AsInteger() (*ValueArrayInteger, bool) { + val, ok := v.Values.(*ValueArrayInteger) + return val, ok +} + +// AsDouble attempts to convert the ValueArray to a ValueArrayDouble. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v ValueArray) AsDouble() (*ValueArrayDouble, bool) { + val, ok := v.Values.(*ValueArrayDouble) + return val, ok +} + +// AsBoolean attempts to convert the ValueArray to a ValueArrayBoolean. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v ValueArray) AsBoolean() (*ValueArrayBoolean, bool) { + val, ok := v.Values.(*ValueArrayBoolean) + return val, ok +} + +// AsString attempts to convert the ValueArray to a ValueArrayString. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v ValueArray) AsString() (*ValueArrayString, bool) { + val, ok := v.Values.(*ValueArrayString) + return val, ok +} + +// AsIntegerDistribution attempts to convert the ValueArray to a ValueArrayIntegerDistribution. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v ValueArray) AsIntegerDistribution() (*ValueArrayIntegerDistribution, bool) { + val, ok := v.Values.(*ValueArrayIntegerDistribution) + return val, ok +} + +// AsDoubleDistribution attempts to convert the ValueArray to a ValueArrayDoubleDistribution. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v ValueArray) AsDoubleDistribution() (*ValueArrayDoubleDistribution, bool) { + val, ok := v.Values.(*ValueArrayDoubleDistribution) + return val, ok } // Values is a single list of values, for one dimension of a timeseries. @@ -7964,77 +8877,164 @@ type VpcFirewallRuleFilter struct { Protocols []VpcFirewallRuleProtocol `json:"protocols" yaml:"protocols"` } +// vpcFirewallRuleHostFilterVariant is implemented by VpcFirewallRuleHostFilter variants. +type vpcFirewallRuleHostFilterVariant interface { + isVpcFirewallRuleHostFilterVariant() +} + // VpcFirewallRuleHostFilterType is the type definition for a VpcFirewallRuleHostFilterType. type VpcFirewallRuleHostFilterType string -// VpcFirewallRuleHostFilterVpc is the rule applies to traffic from/to all instances in the VPC -// -// Required fields: -// - Type -// - Value +// VpcFirewallRuleHostFilterVpc is a variant of VpcFirewallRuleHostFilter. type VpcFirewallRuleHostFilterVpc struct { - Type VpcFirewallRuleHostFilterType `json:"type" yaml:"type"` // Value is names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase // ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID, but they may contain a UUID. They // can be at most 63 characters long. Value Name `json:"value" yaml:"value"` } -// VpcFirewallRuleHostFilterSubnet is the rule applies to traffic from/to all instances in the VPC Subnet -// -// Required fields: -// - Type -// - Value +func (VpcFirewallRuleHostFilterVpc) isVpcFirewallRuleHostFilterVariant() {} + +// VpcFirewallRuleHostFilterSubnet is a variant of VpcFirewallRuleHostFilter. type VpcFirewallRuleHostFilterSubnet struct { - Type VpcFirewallRuleHostFilterType `json:"type" yaml:"type"` // Value is names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase // ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID, but they may contain a UUID. They // can be at most 63 characters long. Value Name `json:"value" yaml:"value"` } -// VpcFirewallRuleHostFilterInstance is the rule applies to traffic from/to this specific instance -// -// Required fields: -// - Type -// - Value +func (VpcFirewallRuleHostFilterSubnet) isVpcFirewallRuleHostFilterVariant() {} + +// VpcFirewallRuleHostFilterInstance is a variant of VpcFirewallRuleHostFilter. type VpcFirewallRuleHostFilterInstance struct { - Type VpcFirewallRuleHostFilterType `json:"type" yaml:"type"` // Value is names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase // ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID, but they may contain a UUID. They // can be at most 63 characters long. Value Name `json:"value" yaml:"value"` } -// VpcFirewallRuleHostFilterIp is the rule applies to traffic from/to a specific IP address -// -// Required fields: -// - Type -// - Value +func (VpcFirewallRuleHostFilterInstance) isVpcFirewallRuleHostFilterVariant() {} + +// VpcFirewallRuleHostFilterIp is a variant of VpcFirewallRuleHostFilter. type VpcFirewallRuleHostFilterIp struct { - Type VpcFirewallRuleHostFilterType `json:"type" yaml:"type"` - Value string `json:"value" yaml:"value"` + Value string `json:"value" yaml:"value"` } -// VpcFirewallRuleHostFilterIpNet is the rule applies to traffic from/to a specific IP subnet -// -// Required fields: -// - Type -// - Value +func (VpcFirewallRuleHostFilterIp) isVpcFirewallRuleHostFilterVariant() {} + +// VpcFirewallRuleHostFilterIpNet is a variant of VpcFirewallRuleHostFilter. type VpcFirewallRuleHostFilterIpNet struct { - Type VpcFirewallRuleHostFilterType `json:"type" yaml:"type"` - Value IpNet `json:"value" yaml:"value"` + Value IpNet `json:"value" yaml:"value"` } +func (VpcFirewallRuleHostFilterIpNet) isVpcFirewallRuleHostFilterVariant() {} + // VpcFirewallRuleHostFilter is the `VpcFirewallRuleHostFilter` is used to filter traffic on the basis of // its source or destination host. type VpcFirewallRuleHostFilter struct { - // Type is the type definition for a Type. - Type VpcFirewallRuleHostFilterType `json:"type,omitempty" yaml:"type,omitempty"` - // Value is names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase - // ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID, but they may contain a UUID. They - // can be at most 63 characters long. - Value any `json:"value,omitempty" yaml:"value,omitempty"` + Value vpcFirewallRuleHostFilterVariant `json:"value,omitempty" yaml:"value,omitempty"` +} + +func (v VpcFirewallRuleHostFilter) Type() VpcFirewallRuleHostFilterType { + switch v.Value.(type) { + case *VpcFirewallRuleHostFilterVpc: + return VpcFirewallRuleHostFilterTypeVpc + case *VpcFirewallRuleHostFilterSubnet: + return VpcFirewallRuleHostFilterTypeSubnet + case *VpcFirewallRuleHostFilterInstance: + return VpcFirewallRuleHostFilterTypeInstance + case *VpcFirewallRuleHostFilterIp: + return VpcFirewallRuleHostFilterTypeIp + case *VpcFirewallRuleHostFilterIpNet: + return VpcFirewallRuleHostFilterTypeIpNet + default: + return "" + } +} + +func (v *VpcFirewallRuleHostFilter) UnmarshalJSON(data []byte) error { + type discriminator struct { + Type string `json:"type"` + } + var d discriminator + if err := json.Unmarshal(data, &d); err != nil { + return err + } + + var value vpcFirewallRuleHostFilterVariant + switch d.Type { + case "vpc": + value = &VpcFirewallRuleHostFilterVpc{} + case "subnet": + value = &VpcFirewallRuleHostFilterSubnet{} + case "instance": + value = &VpcFirewallRuleHostFilterInstance{} + case "ip": + value = &VpcFirewallRuleHostFilterIp{} + case "ip_net": + value = &VpcFirewallRuleHostFilterIpNet{} + default: + return fmt.Errorf("unknown variant %q, expected 'vpc' or 'subnet' or 'instance' or 'ip' or 'ip_net'", d.Type) + } + if err := json.Unmarshal(data, value); err != nil { + return err + } + v.Value = value + return nil +} + +func (v VpcFirewallRuleHostFilter) MarshalJSON() ([]byte, error) { + m := make(map[string]any) + m["type"] = v.Type() + if v.Value != nil { + valueBytes, err := json.Marshal(v.Value) + if err != nil { + return nil, err + } + var valueMap map[string]any + if err := json.Unmarshal(valueBytes, &valueMap); err != nil { + return nil, err + } + for k, val := range valueMap { + m[k] = val + } + } + return json.Marshal(m) +} + +// AsVpc attempts to convert the VpcFirewallRuleHostFilter to a VpcFirewallRuleHostFilterVpc. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v VpcFirewallRuleHostFilter) AsVpc() (*VpcFirewallRuleHostFilterVpc, bool) { + val, ok := v.Value.(*VpcFirewallRuleHostFilterVpc) + return val, ok +} + +// AsSubnet attempts to convert the VpcFirewallRuleHostFilter to a VpcFirewallRuleHostFilterSubnet. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v VpcFirewallRuleHostFilter) AsSubnet() (*VpcFirewallRuleHostFilterSubnet, bool) { + val, ok := v.Value.(*VpcFirewallRuleHostFilterSubnet) + return val, ok +} + +// AsInstance attempts to convert the VpcFirewallRuleHostFilter to a VpcFirewallRuleHostFilterInstance. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v VpcFirewallRuleHostFilter) AsInstance() (*VpcFirewallRuleHostFilterInstance, bool) { + val, ok := v.Value.(*VpcFirewallRuleHostFilterInstance) + return val, ok +} + +// AsIp attempts to convert the VpcFirewallRuleHostFilter to a VpcFirewallRuleHostFilterIp. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v VpcFirewallRuleHostFilter) AsIp() (*VpcFirewallRuleHostFilterIp, bool) { + val, ok := v.Value.(*VpcFirewallRuleHostFilterIp) + return val, ok +} + +// AsIpNet attempts to convert the VpcFirewallRuleHostFilter to a VpcFirewallRuleHostFilterIpNet. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v VpcFirewallRuleHostFilter) AsIpNet() (*VpcFirewallRuleHostFilterIpNet, bool) { + val, ok := v.Value.(*VpcFirewallRuleHostFilterIpNet) + return val, ok } // VpcFirewallRuleProtocolType is the type definition for a VpcFirewallRuleProtocolType. @@ -8077,79 +9077,166 @@ type VpcFirewallRuleProtocol struct { // VpcFirewallRuleStatus is the type definition for a VpcFirewallRuleStatus. type VpcFirewallRuleStatus string +// vpcFirewallRuleTargetVariant is implemented by VpcFirewallRuleTarget variants. +type vpcFirewallRuleTargetVariant interface { + isVpcFirewallRuleTargetVariant() +} + // VpcFirewallRuleTargetType is the type definition for a VpcFirewallRuleTargetType. type VpcFirewallRuleTargetType string -// VpcFirewallRuleTargetVpc is the rule applies to all instances in the VPC -// -// Required fields: -// - Type -// - Value +// VpcFirewallRuleTargetVpc is a variant of VpcFirewallRuleTarget. type VpcFirewallRuleTargetVpc struct { - Type VpcFirewallRuleTargetType `json:"type" yaml:"type"` // Value is names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase // ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID, but they may contain a UUID. They // can be at most 63 characters long. Value Name `json:"value" yaml:"value"` } -// VpcFirewallRuleTargetSubnet is the rule applies to all instances in the VPC Subnet -// -// Required fields: -// - Type -// - Value +func (VpcFirewallRuleTargetVpc) isVpcFirewallRuleTargetVariant() {} + +// VpcFirewallRuleTargetSubnet is a variant of VpcFirewallRuleTarget. type VpcFirewallRuleTargetSubnet struct { - Type VpcFirewallRuleTargetType `json:"type" yaml:"type"` // Value is names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase // ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID, but they may contain a UUID. They // can be at most 63 characters long. Value Name `json:"value" yaml:"value"` } -// VpcFirewallRuleTargetInstance is the rule applies to this specific instance -// -// Required fields: -// - Type -// - Value +func (VpcFirewallRuleTargetSubnet) isVpcFirewallRuleTargetVariant() {} + +// VpcFirewallRuleTargetInstance is a variant of VpcFirewallRuleTarget. type VpcFirewallRuleTargetInstance struct { - Type VpcFirewallRuleTargetType `json:"type" yaml:"type"` // Value is names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase // ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID, but they may contain a UUID. They // can be at most 63 characters long. Value Name `json:"value" yaml:"value"` } -// VpcFirewallRuleTargetIp is the rule applies to a specific IP address -// -// Required fields: -// - Type -// - Value +func (VpcFirewallRuleTargetInstance) isVpcFirewallRuleTargetVariant() {} + +// VpcFirewallRuleTargetIp is a variant of VpcFirewallRuleTarget. type VpcFirewallRuleTargetIp struct { - Type VpcFirewallRuleTargetType `json:"type" yaml:"type"` - Value string `json:"value" yaml:"value"` + Value string `json:"value" yaml:"value"` } -// VpcFirewallRuleTargetIpNet is the rule applies to a specific IP subnet -// -// Required fields: -// - Type -// - Value +func (VpcFirewallRuleTargetIp) isVpcFirewallRuleTargetVariant() {} + +// VpcFirewallRuleTargetIpNet is a variant of VpcFirewallRuleTarget. type VpcFirewallRuleTargetIpNet struct { - Type VpcFirewallRuleTargetType `json:"type" yaml:"type"` - Value IpNet `json:"value" yaml:"value"` + Value IpNet `json:"value" yaml:"value"` } +func (VpcFirewallRuleTargetIpNet) isVpcFirewallRuleTargetVariant() {} + // VpcFirewallRuleTarget is a `VpcFirewallRuleTarget` is used to specify the set of instances to which a // firewall rule applies. You can target instances directly by name, or specify a VPC, VPC subnet, IP, or IP // subnet, which will apply the rule to traffic going to all matching instances. Targets are additive: the rule // applies to instances matching ANY target. type VpcFirewallRuleTarget struct { - // Type is the type definition for a Type. - Type VpcFirewallRuleTargetType `json:"type,omitempty" yaml:"type,omitempty"` - // Value is names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase - // ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID, but they may contain a UUID. They - // can be at most 63 characters long. - Value any `json:"value,omitempty" yaml:"value,omitempty"` + Value vpcFirewallRuleTargetVariant `json:"value,omitempty" yaml:"value,omitempty"` +} + +func (v VpcFirewallRuleTarget) Type() VpcFirewallRuleTargetType { + switch v.Value.(type) { + case *VpcFirewallRuleTargetVpc: + return VpcFirewallRuleTargetTypeVpc + case *VpcFirewallRuleTargetSubnet: + return VpcFirewallRuleTargetTypeSubnet + case *VpcFirewallRuleTargetInstance: + return VpcFirewallRuleTargetTypeInstance + case *VpcFirewallRuleTargetIp: + return VpcFirewallRuleTargetTypeIp + case *VpcFirewallRuleTargetIpNet: + return VpcFirewallRuleTargetTypeIpNet + default: + return "" + } +} + +func (v *VpcFirewallRuleTarget) UnmarshalJSON(data []byte) error { + type discriminator struct { + Type string `json:"type"` + } + var d discriminator + if err := json.Unmarshal(data, &d); err != nil { + return err + } + + var value vpcFirewallRuleTargetVariant + switch d.Type { + case "vpc": + value = &VpcFirewallRuleTargetVpc{} + case "subnet": + value = &VpcFirewallRuleTargetSubnet{} + case "instance": + value = &VpcFirewallRuleTargetInstance{} + case "ip": + value = &VpcFirewallRuleTargetIp{} + case "ip_net": + value = &VpcFirewallRuleTargetIpNet{} + default: + return fmt.Errorf("unknown variant %q, expected 'vpc' or 'subnet' or 'instance' or 'ip' or 'ip_net'", d.Type) + } + if err := json.Unmarshal(data, value); err != nil { + return err + } + v.Value = value + return nil +} + +func (v VpcFirewallRuleTarget) MarshalJSON() ([]byte, error) { + m := make(map[string]any) + m["type"] = v.Type() + if v.Value != nil { + valueBytes, err := json.Marshal(v.Value) + if err != nil { + return nil, err + } + var valueMap map[string]any + if err := json.Unmarshal(valueBytes, &valueMap); err != nil { + return nil, err + } + for k, val := range valueMap { + m[k] = val + } + } + return json.Marshal(m) +} + +// AsVpc attempts to convert the VpcFirewallRuleTarget to a VpcFirewallRuleTargetVpc. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v VpcFirewallRuleTarget) AsVpc() (*VpcFirewallRuleTargetVpc, bool) { + val, ok := v.Value.(*VpcFirewallRuleTargetVpc) + return val, ok +} + +// AsSubnet attempts to convert the VpcFirewallRuleTarget to a VpcFirewallRuleTargetSubnet. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v VpcFirewallRuleTarget) AsSubnet() (*VpcFirewallRuleTargetSubnet, bool) { + val, ok := v.Value.(*VpcFirewallRuleTargetSubnet) + return val, ok +} + +// AsInstance attempts to convert the VpcFirewallRuleTarget to a VpcFirewallRuleTargetInstance. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v VpcFirewallRuleTarget) AsInstance() (*VpcFirewallRuleTargetInstance, bool) { + val, ok := v.Value.(*VpcFirewallRuleTargetInstance) + return val, ok +} + +// AsIp attempts to convert the VpcFirewallRuleTarget to a VpcFirewallRuleTargetIp. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v VpcFirewallRuleTarget) AsIp() (*VpcFirewallRuleTargetIp, bool) { + val, ok := v.Value.(*VpcFirewallRuleTargetIp) + return val, ok +} + +// AsIpNet attempts to convert the VpcFirewallRuleTarget to a VpcFirewallRuleTargetIpNet. +// Returns the variant and true if the conversion succeeded, nil and false otherwise. +func (v VpcFirewallRuleTarget) AsIpNet() (*VpcFirewallRuleTargetIpNet, bool) { + val, ok := v.Value.(*VpcFirewallRuleTargetIpNet) + return val, ok } // VpcFirewallRuleUpdate is a single rule in a VPC firewall