kubernetes openapi unmangler

Related tags

Utilities kopium
Overview

kopium

CI Crates.io

A kubernetes openapi unmangler.

Creates rust structs from a named crd by converting the live openapi schema.

⚠️ WARNING: ALPHA SOFTWARE ⚠️

Installation

Grab a prebuilt musl/darwin binary from the latest release, or install from crates.io:

cargo install kopium

Usage

kopium prometheusrules.monitoring.coreos.com > prometheusrule.rs
rustfmt +nightly --edition 2021 prometheusrule.rs

Output

use kube::CustomResource;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;

#[derive(CustomResource, Serialize, Deserialize, Clone, Debug)]
#[kube(
    group = "monitoring.coreos.com",
    version = "v1",
    kind = "PrometheusRule",
    plural = "prometheusrules"
)]
#[kube(namespaced)]
#[kube(schema = "disabled")]
pub struct PrometheusRuleSpec {
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub groups: Vec<PrometheusRuleGroups>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct PrometheusRuleGroups {
    pub interval: Option<String>,
    pub name: String,
    pub partial_response_strategy: Option<String>,
    pub rules: Vec<PrometheusRuleRules>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct PrometheusRuleRules {
    pub alert: Option<String>,
    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
    pub annotations: BTreeMap<String, String>,
    pub expr: String,
    pub r#for: Option<String>,
    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
    pub labels: BTreeMap<String, String>,
    pub record: Option<String>,
}

Testing

Generate a CRD, tell the test runner to try to use it.

cargo run --bin kopium -- prometheusrules.monitoring.coreos.com > tests/gen.rs
echo "pub type CR = PrometheusRule;" >> tests/gen.rs
kubectl apply -f tests/pr.yaml # needs to contain a CR with name "gen"
cargo test --test runner -- --nocapture

Requires kubernetes access to write customresourcedefinitions.

Comments
  • Optional array properties should be `Option<Vec<T>>`, not `Vec<T>` with `skip_serializing_if =

    Optional array properties should be `Option>`, not `Vec` with `skip_serializing_if = "Vec::is_empty"`

    Currently, optional array properties are required in the generated struct, but skipped if serializing. This is incorrect behavior, since an empty Vec is not the same as not supplying a Vec.

    This breaks server-side apply-ing new resources to remove things from the Vec, as well as cases where a property is required in a one-of, but you actually want to send the empty Vec as one of those properties.

    We should instead make it an Option<Vec<T>> with #[serde(default, skip_serializing_if = "Option::is_none")].

    Example:

                  podSelector:
                    description: Selects pods in the same namespace.
                    oneOf:
                    - required:
                      - matchExpressions
                    - required:
                      - matchLabels
                    properties:
                      matchExpressions:
                        items:
                          properties:
                            key:
                              type: string
                            operator:
                              enum:
                              - In
                              - NotIn
                              - Exists
                              - DoesNotExist
                              type: string
                            values:
                              items:
                                type: string
                              type: array
                          required:
                          - key
                          - operator
                          type: object
                        type: array
                      matchLabels:
                        type: object
                        x-kubernetes-preserve-unknown-fields: true
                    type: object
    

    This generates:

    /// Selects pods in the same namespace.
    #[derive(Serialize, Deserialize, Clone, Debug)]
    pub struct ServerPodSelector {
        #[serde(default, skip_serializing_if = "Vec::is_empty")]
        pub matchExpressions: Vec<ServerPodSelectorMatchExpressions>,
        pub matchLabels: Option<ServerPodSelectorMatchLabels>,
    }
    
    #[derive(Serialize, Deserialize, Clone, Debug)]
    pub struct ServerPodSelectorMatchExpressions {
        pub key: String,
        pub operator: String,
        #[serde(default, skip_serializing_if = "Vec::is_empty")]
        pub values: Vec<String>,
    }
    
    #[derive(Serialize, Deserialize, Clone, Debug)]
    pub struct ServerPodSelectorMatchLabels {
    }
    

    Complete CRD https://gist.github.com/alex-hunt-materialize/2743b1e2e58a49c4df0a11ecb39f46ab

    What we should get:

    /// Selects pods in the same namespace.
    #[derive(Serialize, Deserialize, Clone, Debug, Default)]
    pub struct ServerPodSelector {
        #[serde(default, skip_serializing_if = "Option::is_none")]
        pub matchExpressions: Option<Vec<ServerPodSelectorMatchExpressions>>,
        pub matchLabels: Option<ServerPodSelectorMatchLabels>,
    }
    
    #[derive(Serialize, Deserialize, Clone, Debug)]
    pub struct ServerPodSelectorMatchExpressions {
        pub key: String,
        pub operator: String,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        pub values: Option<Vec<String>>,
    }
    
    #[derive(Serialize, Deserialize, Clone, Debug)]
    pub struct ServerPodSelectorMatchLabels {
    }
    
    bug 
    opened by alex-hunt-materialize 8
  • Type name generation for complex spec is broken

    Type name generation for complex spec is broken

    I am running kopium against cluster-api CRDs and generated structs appear incorrect

    Here is what Rust code for top-level object clusters.cluster.x-k8s.io

    #[derive(CustomResource, Serialize, Deserialize, Clone, Debug)]
    #[kube(group = "cluster.x-k8s.io", version = "v1beta1", kind = "Cluster", plural = "clusters")]
    #[kube(namespaced)]
    #[kube(schema = "disabled")]
    pub struct ClusterSpec {
        pub clusterNetwork: Option<Cluster>,
        pub controlPlaneEndpoint: Option<Cluster>,
        pub controlPlaneRef: Option<Cluster>,
        pub infrastructureRef: Option<Cluster>,
        pub paused: Option<bool>,
        pub topology: Option<Cluster>,
    }
    ...
    

    This is definitely not correct as the struct cannot reference itself

    Here is what I think it should be producing (ignore field names, types are important)

    #[derive(Clone, Debug, Serialize, Deserialize, CustomResource)]
    #[serde(rename_all = "camelCase")]
    #[skip_serializing_none]
    #[kube(
        group = "cluster.x-k8s.io",
        version = "v1beta1",
        kind = "Cluster",
        plural = "clusters",
    )]
    #[kube(namespaced)]
    #[kube(schema = "disabled")]
    pub struct ClusterSpec {
        pub cluster_network: Option<ClusterNetwork>,
        pub control_plane_endpoint: Option<ApiEndpoint>,
        pub control_plane_ref: Option<core::v1::ObjectReference>,
        pub infrastructure_ref: Option<core::v1::ObjectReference>,
        pub paused: Option<bool>,
        pub topology: Option<Topology>,
    }
    ...
    
    bug 
    opened by imp 7
  • Replaces invalid enum identifiers with generated ones

    Replaces invalid enum identifiers with generated ones

    Related: #92 and #93

    Initial draft that simply replaces invalid enum variants with auto generated names.

    Things to discuss:

    • [ ] What to do with with empty "" variants, we could call them Empty (maybe a separate issue)
    • [ ] How do we name generated Variants?
    • [ ] Should there be a duplicate check for auto generated variants (what if Variant{i} is a valid variant defined by the CRD (unlikely))

    I also wasn't sure where to do the renaming, some of the renaming is done in Container::rename and some is done in main and there is also a little bit of logic in analyze_enum_properties.

    This currently also changes integer enum generation:

    #[derive(Serialize, Deserialize, Clone, Debug, JsonSchema)]
    pub enum HTTPRouteRulesBackendRefsFiltersRequestRedirectStatusCode {
        #[serde(rename = "301")]
        r#_301,
        #[serde(rename = "302")]
        r#_302,
    }
    

    But I think int enums need to be generated differently anyways using serde_repr e.g.:

    #[derive(Serialize_repr, Deserialize_repr, Clone, Debug, JsonSchema)]
    #[repr(u64)]
    pub enum HTTPRouteRulesBackendRefsFiltersRequestRedirectStatusCode {
        r#_301 = 301,
        r#_302 = 302,
    }
    
    opened by Dav1dde 6
  • use BTreeMap for empty objects with preserve-unknown-fields

    use BTreeMap for empty objects with preserve-unknown-fields

    If the object is empty and it has s-kubernetes-preserve-unknown-fields set, do not create an empty struct. Instead, use a BTreeMap<String, serde_json::Value>.

    opened by alex-hunt-materialize 6
  • Kopium uses `Array` instead of `Vec` for array fields

    Kopium uses `Array` instead of `Vec` for array fields

    I was generating the rust code for this CRD and noticed that the code generated is using Array instead of Vec for some fields.

    Here's the CRD

    apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.6.2 installer.open-cluster-management.io/last-applied-configuration: ce84b11fb18eb5436f84845f6c462e1f6773cc46 creationTimestamp: "2022-02-14T14:03:43Z" generation: 1 labels: installer.name: multiclusterhub installer.namespace: open-cluster-management name: agents.agent-install.openshift.io resourceVersion: "270891" uid: 741e93d1-2f89-4945-8975-09a90983ba8f spec: conversion: strategy: None group: agent-install.openshift.io names: kind: Agent listKind: AgentList plural: agents singular: agent scope: Namespaced versions:

    • additionalPrinterColumns:
      • description: The name of the cluster the Agent registered to. jsonPath: .spec.clusterDeploymentName.name name: Cluster type: string
      • description: The Approve state of the Agent. jsonPath: .spec.approved name: Approved type: boolean
      • description: The role (master/worker) of the Agent. jsonPath: .status.role name: Role type: string
      • description: The HostStage of the Agent. jsonPath: .status.progress.currentStage name: Stage type: string
      • description: The hostname of the Agent. jsonPath: .status.inventory.hostname name: Hostname priority: 1 type: string
      • description: The requested hostname for the Agent. jsonPath: .spec.hostname name: Requested Hostname priority: 1 type: string name: v1beta1 schema: openAPIV3Schema: description: Agent is the Schema for the hosts API properties: apiVersion: description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' type: string kind: description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' type: string metadata: type: object spec: description: AgentSpec defines the desired state of Agent properties: approved: type: boolean clusterDeploymentName: description: ClusterReference represents a Cluster Reference. It has enough information to retrieve cluster in any namespace properties: name: description: Name is unique within a namespace to reference a cluster resource. type: string namespace: description: Namespace defines the space within which the cluster name must be unique. type: string type: object hostname: type: string ignitionConfigOverrides: description: Json formatted string containing the user overrides for the host's ignition config type: string installation_disk_id: description: InstallationDiskID defines the installation destination disk (must be equal to the inventory disk id). type: string installerArgs: description: Json formatted string containing the user overrides for the host's coreos installer args type: string machineConfigPool: type: string role: description: "HostRole host role \n swagger:model host-role" type: string required: - approved - role type: object status: description: AgentStatus defines the observed state of Agent properties: bootstrap: type: boolean conditions: items: description: Condition represents the state of the operator's reconciliation functionality. properties: lastHeartbeatTime: format: date-time type: string lastTransitionTime: format: date-time type: string message: type: string reason: type: string status: type: string type: description: ConditionType is the state of the operator's reconciliation functionality. type: string required: - status - type type: object type: array debugInfo: description: DebugInfo includes information for debugging the installation process. properties: eventsURL: description: EventsURL specifies an HTTP/S URL that contains events which occured during the cluster installation process type: string state: description: Current state of the Agent type: string stateInfo: description: Additional information pertaining to the status of the Agent type: string type: object hostname: type: string inventory: properties: bmcAddress: type: string bmcV6Address: type: string boot: properties: currentBootMode: type: string pxeInterface: type: string type: object cpu: properties: architecture: type: string clockMegahertz: description: 'Name in REST API: frequency' format: int64 type: integer count: format: int64 type: integer flags: items: type: string type: array modelName: type: string type: object disks: items: properties: bootable: type: boolean byID: type: string byPath: type: string driveType: type: string hctl: type: string id: type: string installationEligibility: properties: eligible: type: boolean notEligibleReasons: items: type: string type: array required: - notEligibleReasons type: object ioPerf: properties: syncDurationMilliseconds: description: 99th percentile of fsync duration in milliseconds format: int64 type: integer type: object model: type: string name: type: string path: type: string serial: type: string sizeBytes: format: int64 type: integer smart: type: string vendor: type: string wwn: type: string required: - id type: object type: array hostname: type: string interfaces: items: properties: biosDevName: type: string clientID: type: string flags: items: type: string type: array hasCarrier: type: boolean ipV4Addresses: items: type: string type: array ipV6Addresses: items: type: string type: array macAddress: type: string mtu: format: int64 type: integer name: type: string product: type: string speedMbps: format: int64 type: integer vendor: type: string required: - flags - ipV4Addresses - ipV6Addresses type: object type: array memory: properties: physicalBytes: format: int64 type: integer usableBytes: format: int64 type: integer type: object reportTime: description: 'Name in REST API: timestamp' format: date-time type: string systemVendor: properties: manufacturer: type: string productName: type: string serialNumber: type: string virtual: type: boolean type: object type: object ntpSources: items: properties: sourceName: type: string sourceState: description: "SourceState source state \n swagger:model source_state" type: string type: object type: array progress: properties: currentStage: description: "HostStage host stage \n swagger:model host-stage" type: string progressInfo: type: string stageStartTime: description: 'Name in REST API: stage_started_at' format: date-time type: string stageUpdateTime: description: 'Name in REST API: stage_updated_at' format: date-time type: string type: object role: description: "HostRole host role \n swagger:model host-role" type: string validationsInfo: additionalProperties: items: properties: id: type: string message: type: string status: type: string required: - id - message - status type: object type: array description: ValidationsInfo is a JSON-formatted string containing the validation results for each validation id grouped by category (network, hosts-data, etc.) type: object type: object type: object served: true storage: true subresources: status: {} status: acceptedNames: kind: Agent listKind: AgentList plural: agents singular: agent conditions:
    • lastTransitionTime: "2022-02-14T14:03:43Z" message: no conflicts found reason: NoConflicts status: "True" type: NamesAccepted
    • lastTransitionTime: "2022-02-14T14:03:43Z" message: the initial names have been accepted reason: InitialNamesAccepted status: "True" type: Established storedVersions:
    • v1beta1
    
    use kube::CustomResource;
    use serde::{Serialize, Deserialize};
    use std::collections::BTreeMap;
    
    #[derive(CustomResource, Serialize, Deserialize, Clone, Debug)]
    #[kube(group = "agent-install.openshift.io", version = "v1beta1", kind = "Agent", plural = "agents")]
    #[kube(namespaced)]
    #[kube(schema = "disabled")]
    pub struct AgentSpec {
        pub approved: bool,
        pub clusterDeploymentName: Option<AgentClusterDeploymentName>,
        pub hostname: Option<String>,
        pub ignitionConfigOverrides: Option<String>,
        pub installation_disk_id: Option<String>,
        pub installerArgs: Option<String>,
        pub machineConfigPool: Option<String>,
        pub role: String,
    }
    
    #[derive(Serialize, Deserialize, Clone, Debug)]
    pub struct AgentClusterDeploymentName {
        pub name: Option<String>,
        pub namespace: Option<String>,
    }
    
    #[derive(Serialize, Deserialize, Clone, Debug)]
    pub struct AgentStatus {
        pub bootstrap: Option<bool>,
        #[serde(default, skip_serializing_if = "Vec::is_empty")]
        pub conditions: Vec<AgentStatusConditions>,
        pub debugInfo: Option<AgentStatusDebugInfo>,
        pub hostname: Option<String>,
        pub inventory: Option<AgentStatusInventory>,
        #[serde(default, skip_serializing_if = "Vec::is_empty")]
        pub ntpSources: Vec<AgentStatusNtpSources>,
        pub progress: Option<AgentStatusProgress>,
        pub role: Option<String>,
        #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
        pub validationsInfo: BTreeMap<String, Array>,
    }
    
    #[derive(Serialize, Deserialize, Clone, Debug)]
    pub struct AgentStatusConditions {
        pub lastHeartbeatTime: Option<String>,
        pub lastTransitionTime: Option<String>,
        pub message: Option<String>,
        pub reason: Option<String>,
        pub status: String,
        pub r#type: String,
    }
    
    #[derive(Serialize, Deserialize, Clone, Debug)]
    pub struct AgentStatusDebugInfo {
        pub eventsURL: Option<String>,
        pub state: Option<String>,
        pub stateInfo: Option<String>,
    }
    
    #[derive(Serialize, Deserialize, Clone, Debug)]
    pub struct AgentStatusInventory {
        pub bmcAddress: Option<String>,
        pub bmcV6Address: Option<String>,
        pub boot: Option<AgentStatusInventoryBoot>,
        pub cpu: Option<AgentStatusInventoryCpu>,
        #[serde(default, skip_serializing_if = "Vec::is_empty")]
        pub disks: Vec<AgentStatusInventoryDisks>,
        pub hostname: Option<String>,
        #[serde(default, skip_serializing_if = "Vec::is_empty")]
        pub interfaces: Vec<AgentStatusInventoryInterfaces>,
        pub memory: Option<AgentStatusInventoryMemory>,
        pub reportTime: Option<String>,
        pub systemVendor: Option<AgentStatusInventorySystemVendor>,
    }
    
    #[derive(Serialize, Deserialize, Clone, Debug)]
    pub struct AgentStatusInventoryBoot {
        pub currentBootMode: Option<String>,
        pub pxeInterface: Option<String>,
    }
    
    #[derive(Serialize, Deserialize, Clone, Debug)]
    pub struct AgentStatusInventoryCpu {
        pub architecture: Option<String>,
        pub clockMegahertz: Option<i64>,
        pub count: Option<i64>,
        #[serde(default, skip_serializing_if = "Vec::is_empty")]
        pub flags: Vec<String>,
        pub modelName: Option<String>,
    }
    
    #[derive(Serialize, Deserialize, Clone, Debug)]
    pub struct AgentStatusInventoryDisks {
        pub bootable: Option<bool>,
        pub byID: Option<String>,
        pub byPath: Option<String>,
        pub driveType: Option<String>,
        pub hctl: Option<String>,
        pub id: String,
        pub installationEligibility: Option<AgentStatusInventoryDisksInstallationEligibility>,
        pub ioPerf: Option<AgentStatusInventoryDisksIoPerf>,
        pub model: Option<String>,
        pub name: Option<String>,
        pub path: Option<String>,
        pub serial: Option<String>,
        pub sizeBytes: Option<i64>,
        pub smart: Option<String>,
        pub vendor: Option<String>,
        pub wwn: Option<String>,
    }
    
    #[derive(Serialize, Deserialize, Clone, Debug)]
    pub struct AgentStatusInventoryDisksInstallationEligibility {
        pub eligible: Option<bool>,
        pub notEligibleReasons: Vec<String>,
    }
    
    #[derive(Serialize, Deserialize, Clone, Debug)]
    pub struct AgentStatusInventoryDisksIoPerf {
        pub syncDurationMilliseconds: Option<i64>,
    }
    
    #[derive(Serialize, Deserialize, Clone, Debug)]
    pub struct AgentStatusInventoryInterfaces {
        pub biosDevName: Option<String>,
        pub clientID: Option<String>,
        pub flags: Vec<String>,
        pub hasCarrier: Option<bool>,
        pub ipV4Addresses: Vec<String>,
        pub ipV6Addresses: Vec<String>,
        pub macAddress: Option<String>,
        pub mtu: Option<i64>,
        pub name: Option<String>,
        pub product: Option<String>,
        pub speedMbps: Option<i64>,
        pub vendor: Option<String>,
    }
    
    #[derive(Serialize, Deserialize, Clone, Debug)]
    pub struct AgentStatusInventoryMemory {
        pub physicalBytes: Option<i64>,
        pub usableBytes: Option<i64>,
    }
    
    #[derive(Serialize, Deserialize, Clone, Debug)]
    pub struct AgentStatusInventorySystemVendor {
        pub manufacturer: Option<String>,
        pub productName: Option<String>,
        pub serialNumber: Option<String>,
        pub virtual: Option<bool>,
    }
    
    #[derive(Serialize, Deserialize, Clone, Debug)]
    pub struct AgentStatusNtpSources {
        pub sourceName: Option<String>,
        pub sourceState: Option<String>,
    }
    
    #[derive(Serialize, Deserialize, Clone, Debug)]
    pub struct AgentStatusProgress {
        pub currentStage: Option<String>,
        pub progressInfo: Option<String>,
        pub stageStartTime: Option<String>,
        pub stageUpdateTime: Option<String>,
    }
    
    opened by flaper87 6
  • struct members sometimes refer to wrong struct types

    struct members sometimes refer to wrong struct types

    Tried to run kopium on:

    kopium applications.argoproj.io --docs > argoapp.rs
    

    Get the following due to some of the CRD's being self-referential:

    error[E0072]: recursive type `ApplicationStatusSyncComparedToSourceDirectory` has infinite size
        --> src/argoapp.rs:1330:1
         |
    1330 | pub struct ApplicationStatusSyncComparedToSourceDirectory {
         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive type has infinite size
    ...
    1336 |     pub jsonnet: Option<ApplicationStatusSyncComparedToSourceDirectory>,
         |                  ------------------------------------------------------ recursive without indirection
         |
    help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `ApplicationStatusSyncComparedToSourceDirectory` representable
         |
    1336 |     pub jsonnet: Box<Option<ApplicationStatusSyncComparedToSourceDirectory>>,
         |                  ++++                                                      +
    

    I think I can fixup these myself by Boxing them, any other ideas?

    bug 
    opened by wseaton 6
  • Default version need to follow official Version Priority

    Default version need to follow official Version Priority

    When multiple versions are described in the CRD and no --api-version flag is given it may be better to use the one that is specified in storedVersion of the status, rather than just the first one.

    opened by imp 6
  • not handling non-string enum

    not handling non-string enum

    Hi :wave:

    When using kopium to generate Kubernetes Gateway API resources, I found that it's not capable of generating one of the APIs, HTTPRoute specifically:

    $ curl -sSL 'https://raw.githubusercontent.com/kubernetes-sigs/gateway-api/main/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml?ref=v0.5.1' | kopium -Af -
    // WARNING: generated by kopium - manual changes will be overwritten
    Error: not handling non-string enum
    

    I found the line here. Looks like there's just more TODO here to add support? Is there already work tracking this TODO?

    opened by shaneutt 5
  • Allow selecting required API version via --api-version

    Allow selecting required API version via --api-version

    I have quite a lot of positive experience with srtuctopt, and clap 3 is essentially it, so I rewrote arg parsing to use Parser trait. Hope you don't mind.

    Selecting required version - please have a look, I believe I got it right but would love to get feedback.

    And the last one - macro_use is so Rust 2015, just couldn't help it :)

    opened by imp 5
  • parametrise outputting

    parametrise outputting

    Add extra flags to clap args and handle them:

    • [x] --hide-prelude bool (in case people need custom crate names)
    • [x] --api-version 1 optional setter (otherwise we should pick .first version as is) - #15
    • [x] --derive PartialEq optional (multi) setter (appends to derive list per struct)
    good first issue help wanted 
    opened by clux 5
  • enum support in 0.12 breaks --derive Default

    enum support in 0.12 breaks --derive Default

    the enums generated by 0.12 (#65) don't label which variant is the default, so if you try using --derive Default, you will end up with a lot of errors like

    error: no default declared
        --> foo/bar/baz.rs:1116:48
         |
    1116 | #[derive(Serialize, Deserialize, Clone, Debug, Default)]
         |                                                ^^^^^^^
         |
         = help: make a unit variant default by placing `#[default]` above it
         = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
    
    bug 
    opened by doy-materialize 4
  • Allow integer enums to have correct integer serialization

    Allow integer enums to have correct integer serialization

    • [x] Add discriminant to integer enums
    • [x] Improve integration test for httproute so that it uses serde logic for the statusCode field
    • [ ] Add serde_repr
    • [ ] Drop #[serde(rename)] attrs on serde_repr enums

    Last thing I want to fix before next release.

    opened by clux 3
  • Top level enums are not handled

    Top level enums are not handled

    A rare case that we haven't seen, but should support because kube supports it, and it makes unit testing easier (no need to wrap enums in structs to check their output). Came out of #100

    There is a test for this top_level_enum_with_integers which is currently #[ignore]d because of this bug.

    We should handle enum members at the top level like we do for struct members.

    bug 
    opened by clux 0
  • Allow implementing generic getter traits

    Allow implementing generic getter traits

    In particular;

    • HasStatus
    • HasSpec

    and maybe more like HasConditions once we get going with https://github.com/kube-rs/k8s-pb/issues/4

    This is not really actionable yet since the traits need to find a common place to live first, but making a note of it.

    opened by clux 0
  • allow hiding status object

    allow hiding status object

    Sometimes when writing auxiliary tools/controllers for existing crds, we are sometimes only necessary to generate the spec object for a type. In these cases it would be OK to omit the status objects of the resources.

    We should add a --hide-status flag that hides the status object and everything only used by the status object.

    This can be done by pruning the schema yaml under:

    apiVersion: apiextensions.k8s.io/v1
    kind: CustomResourceDefinition
    spec:
      versions:
      - name: v1beta1
        schema:
          openAPIV3Schema:
            properties:
              status: <- remove this key for every spec.versions
    

    before running the analyzer.

    Leaving this here as a help wanted for now. It might be an interesting place to play around with the schema. We haven't done this type of short-circuiting before, so it might need its own file.

    enhancement help wanted 
    opened by clux 0
  • allow toggling what map containers to use

    allow toggling what map containers to use

    Currently kopium generates BTreeMap for all map types except arbitrary json (stored in HashMap).

    While this is OK on the surface level, I think we should probably move all containers to HashMap as the cheapest default, and let users do a big global --btreemap flag to switch all of them over to BTreeMap when users need deterministic ordering.

    enhancement good first issue help wanted 
    opened by clux 0
  • runtime.RawExtension processing

    runtime.RawExtension processing

    runtime.RawExtensions serves as a blob in the k8s CRD afaik and is reflected as an object in the openapi spec, like this.

    The specific objects are origin and target, which are defined in go as following

    // TransformInputSpec struct
    type TransformInputSpec struct {
    	Origin runtime.RawExtension `json:"origin,omitempty"`
    	Target runtime.RawExtension `json:"target,omitempty"`
    }
    
    apiVersion: apiextensions.k8s.io/v1
    kind: CustomResourceDefinition
    metadata:
      annotations:
        controller-gen.kubebuilder.io/version: v0.9.0
      creationTimestamp: null
      name: transforminputs.app.yndd.io
    spec:
      group: app.example.io
      names:
        categories:
        - app
        kind: TransformInput
        listKind: TransformInputList
        plural: transforminputs
        singular: transforminput
      scope: Namespaced
      versions:
      - name: v1alpha1
        schema:
          openAPIV3Schema:
            description: TransformInput is the Schema for the TransformInput API
            properties:
              apiVersion:
                description: 'APIVersion defines the versioned schema of this representation
                  of an object. Servers should convert recognized schemas to the latest
                  internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
                type: string
              kind:
                description: 'Kind is a string value representing the REST resource this
                  object represents. Servers may infer this from the endpoint the client
                  submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
                type: string
              metadata:
                type: object
              spec:
                description: TransformInputSpec struct
                properties:
                  origin:
                    type: object
                  target:
                    type: object
                type: object
            type: object
        served: true
        storage: true
    

    when I use kopium to generate the rust code I get this.

    use kube::CustomResource;
    use schemars::JsonSchema;
    use serde::{Serialize, Deserialize};
    
    /// TransformInputSpec struct
    #[derive(CustomResource, Serialize, Deserialize, Clone, Debug, JsonSchema)]
    #[kube(
        group = "app.example.io",
        version = "v1alpha1",
        kind = "TransformInput",
        plural = "transforminputs"
    )]
    #[kube(namespaced)]
    pub struct TransformInputSpec {
        #[serde(default, skip_serializing_if = "Option::is_none")]
        pub origin: Option<TransformInputOrigin>,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        pub target: Option<TransformInputTarget>,
    }
    
    #[derive(Serialize, Deserialize, Clone, Debug, JsonSchema)]
    pub struct TransformInputOrigin {
    }
    
    #[derive(Serialize, Deserialize, Clone, Debug, JsonSchema)]
    pub struct TransformInputTarget {
    }
    

    As you can see the struct TransformInputOrigin and TransformInputTarget are empty. The issue is that when you serializer/deserializerl it in json/yaml the data behind these object is no longer accessible. When I change it to the following manually the marshal/unmarshal function works as the serde_json::Value is seen as a generic object in the serializer/deserializer afaik.

    use kube::CustomResource;
    use schemars::JsonSchema;
    use serde::{Deserialize, Serialize};
    use serde_json::Value;
    
    /// TransformInputSpec struct
    #[derive(CustomResource, Serialize, Deserialize, Clone, Debug, JsonSchema)]
    #[kube(
        group = "app.example.io",
        version = "v1alpha1",
        kind = "TransformInput",
        plural = "transforminputs"
    )]
    #[kube(namespaced)]
    pub struct TransformInputSpec {
        #[serde(default, skip_serializing_if = "Option::is_none")]
        pub origin: Option<Value>,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        pub target: Option<Value>,
    }
    

    Can this be accommodated?

    help wanted 
    opened by henderiw 1
Releases(v0.14.0)
  • v0.14.0(Nov 18, 2022)

    Overview

    Lots of improvements to the robustness of the parsing and generation process giving us compatibility with some complicated crds (alertmanagers crd and sig network gateway api crds). There is also an elision flag in place to allow overriding generated output more easily, plus a much more informative kopium header in the generated output.

    What's Changed

    • Do not try to derive CustomResource when using --hide-kube by @clux in https://github.com/kube-rs/kopium/pull/97
    • Add generation command and kopium version to output header by @clux in https://github.com/kube-rs/kopium/pull/99
    • Allow simple integer enums by rawstring escaping variant names by @clux in https://github.com/kube-rs/kopium/pull/100
    • Add --elide flag to drop generated structs from the output by @clux in https://github.com/kube-rs/kopium/pull/102
    • Replaces invalid enum identifiers with generated ones by @Dav1dde in https://github.com/kube-rs/kopium/pull/103
    • Fixes clippy lints by @Dav1dde in https://github.com/kube-rs/kopium/pull/105

    New Contributors

    • @Dav1dde made their first contribution in https://github.com/kube-rs/kopium/pull/103

    Full Changelog: https://github.com/kube-rs/kopium/compare/v0.13.0...v0.14.0

    Source code(tar.gz)
    Source code(zip)
    kopium-darwin-amd64(6.40 MB)
    kopium-linux-amd64(15.86 MB)
  • v0.13.0(Oct 16, 2022)

    What's Changed

    • Pull up clap to 4.0 series by @imp in https://github.com/kube-rs/kopium/pull/86
    • Add warning on top of generated output by @clux in https://github.com/kube-rs/kopium/pull/88
    • Stop auto-deriving default for enum by @clux in https://github.com/kube-rs/kopium/pull/89
    • Fix Container recursion into additionalProperties by @clux in https://github.com/kube-rs/kopium/pull/90

    Full Changelog: https://github.com/kube-rs/kopium/compare/v0.12.0...v0.13.0

    Source code(tar.gz)
    Source code(zip)
    kopium-darwin-amd64(6.30 MB)
    kopium-linux-amd64(15.54 MB)
  • v0.12.0(Aug 3, 2022)

    Highlights

    Big features: rudimentary support for enums in #71, and some handling of preserve-unknown-fields in #76 and #77.

    There is also a breaking change with the removal of -z/--rust-case and -i flags. We now always convert member names to rust style casing because other languages can name members in rust-invalid ways that failed to generate without setting these flags. Removing this brittle default behaviour also avoids generating code with warnings when names did not match rust-conventions.

    What's Changed

    • Add optional typed-builder derives by @clux in https://github.com/kube-rs/kopium/pull/64
    • Add simple enum support by @clux in https://github.com/kube-rs/kopium/pull/65
    • Combine all serde field annotations by @clux in https://github.com/kube-rs/kopium/pull/63
    • Add support for enum renames and refactor analyzer interface by @clux in https://github.com/kube-rs/kopium/pull/71
    • Update clap to v3 by @imp in https://github.com/kube-rs/kopium/pull/72
    • Turn "preserve-unknown-fields" into serde_json::Value for more cases by @felipesere in https://github.com/kube-rs/kopium/pull/76
    • Nest serde_json::Value under HashMap for preserve-unknown-fields by @clux in https://github.com/kube-rs/kopium/pull/77
    • bump dependencies and fix clap minor by @clux in https://github.com/kube-rs/kopium/pull/80
    • Always rustify member names by @clux in https://github.com/kube-rs/kopium/pull/82

    New Contributors

    • @felipesere made their first contribution in https://github.com/kube-rs/kopium/pull/76

    Full Changelog: https://github.com/kube-rs/kopium/compare/v0.11.0...v0.12.0

    Source code(tar.gz)
    Source code(zip)
    kopium-darwin-amd64(6.44 MB)
    kopium-linux-amd64(16.09 MB)
  • v0.11.0(Apr 21, 2022)

    Highlights

    Snake Case members possible with -z in #56. Only slightly breaking change is a new #![allow(non_snake_case)] line at top of file if not converting to snake_case. This can be turned off with -i.

    In general, the output format is a lot more controllable now with flags, and can read from stdin and files with -f. Also more bugfixes.

    What's Changed

    • Allow reading file from stdin with kopium -f - by @clux in https://github.com/kube-rs/kopium/pull/50
    • Allow hiding kube derive instructions with --hide-kube by @clux in https://github.com/kube-rs/kopium/pull/51
    • Allow deriving JsonSchema on structs by @clux in https://github.com/kube-rs/kopium/pull/53
    • Add --schema flag to set kube-derive schema mode by @clux in https://github.com/kube-rs/kopium/pull/55
    • Add optional snake_case conversion of member names by @clux in https://github.com/kube-rs/kopium/pull/56
    • Add --auto shorthand for automation options by @clux in https://github.com/kube-rs/kopium/pull/58
    • Fix --derive not adding derives to child structs by @clux in https://github.com/kube-rs/kopium/pull/59
    • Fix Map of String case in ServiceMonitor by @clux in https://github.com/kube-rs/kopium/pull/62

    Plus these from the 0.10.0 release that was only out for a few hours:

    • Allow reading CRDs from yaml file by @clux in https://github.com/kube-rs/kopium/pull/46
    • Fix generation for maps of integers by @clux in https://github.com/kube-rs/kopium/pull/47

    Full Changelog: https://github.com/kube-rs/kopium/compare/v0.10.0...v0.11.0

    Source code(tar.gz)
    Source code(zip)
    kopium-darwin-amd64(6.00 MB)
    kopium-linux-amd64(14.82 MB)
  • v0.9.0(Apr 11, 2022)

    Option change

    We have identified a safety issue with our previously "smart" stripping of Option's in favour of serde default annotations. The only sensible way to rectify this was to add back Option wrapping of containers, which does make some of the code slightly less ergonomic. See #41

    Changelog

    • Handle optional Vec and BTreeMap as Option by @alex-hunt-materialize in https://github.com/kube-rs/kopium/pull/41
    • treat x-kubernetes-int-or-string as IntOrString by @alex-hunt-materialize in https://github.com/kube-rs/kopium/pull/43
    • use BTreeMap for empty objects with preserve-unknown-fields by @alex-hunt-materialize in https://github.com/kube-rs/kopium/pull/42

    New Contributors

    • @alex-hunt-materialize made their first contribution in https://github.com/kube-rs/kopium/pull/41

    Full Changelog: https://github.com/kube-rs/kopium/compare/v0.8.0...v0.9.0

    Source code(tar.gz)
    Source code(zip)
    kopium-darwin-amd64(5.38 MB)
    kopium-linux-amd64(14.32 MB)
  • v0.8.0(Mar 2, 2022)

    What's Changed

    • Continue docstring after newline by @antifuchs in https://github.com/kube-rs/kopium/pull/36
    • Handle maps to structs in schema by @clux in https://github.com/kube-rs/kopium/pull/37

    New Contributors

    • @antifuchs made their first contribution in https://github.com/kube-rs/kopium/pull/36

    Full Changelog: https://github.com/kube-rs/kopium/compare/v0.7.0...v0.8.0

    Source code(tar.gz)
    Source code(zip)
    kopium-darwin-amd64(5.73 MB)
    kopium-linux-amd64(13.38 MB)
  • v0.7.0(Feb 19, 2022)

    What's Changed

    • Fix agentshift array case by @clux in https://github.com/kube-rs/kopium/pull/33
    • Set status explicitly in the kube tag by @flaper87 in https://github.com/kube-rs/kopium/pull/34

    New Contributors

    • @flaper87 made their first contribution in https://github.com/kube-rs/kopium/pull/34

    Full Changelog: https://github.com/kube-rs/kopium/compare/v0.6.0...v0.7.0

    Source code(tar.gz)
    Source code(zip)
    kopium-darwin-amd64(5.74 MB)
    kopium-linux-amd64(13.82 MB)
  • v0.6.0(Jan 23, 2022)

  • v0.5.0(Jan 16, 2022)

  • v0.4.0(Dec 6, 2021)

  • v0.3.0(Dec 5, 2021)

Owner
kube-rs
rust kubernetes client and controller runtime
kube-rs
OpenAPI support for Poem

Poem OpenAPI Fast and Type-Safe OpenAPI implementation for Poem. Poem-openapi allows you to easily implement APIs that comply with the OpenAPIv3 speci

Poem Web 40 Sep 16, 2021
Detects orphan configmaps and secrets in a Kubernetes cluster

KubExplorer Warning: Proof of concept. Feedback is much welcome. Discovers and prints out any Configmaps and Secrets not linked to any of the followin

Pavel Pscheidl 56 Oct 21, 2022
A crate to implement leader election for Kubernetes workloads in Rust.

Kubernetes Leader Election in Rust This library provides simple leader election for Kubernetes workloads.

Hendrik Maus 33 Dec 29, 2022
💫 Small microservice to handle state changes of Kubernetes pods and post them to Instatus or Statuspages

?? Kanata Small microservice to handle state changes of Kubernetes pods and post to Instatus ?? Why? I don't really want to implement and repeat code

Noel ʕ •ᴥ•ʔ 4 Mar 4, 2022
Continuous Delivery for Declarative Kubernetes, Serverless and Infrastructure Applications

Continuous Delivery for Declarative Kubernetes, Serverless and Infrastructure Applications Explore PipeCD docs » Overview PipeCD provides a unified co

PipeCD 650 Dec 29, 2022
engula-operator creates/configures/manages engula clusters atop Kubernetes

Engula Operator The engula operator manages engula clusters deployed to Kubernetes and automates tasks related to operating an engula cluster. Backgro

小母牛坐飞机 12 Apr 27, 2022
Ultralight, security-first service mesh for Kubernetes. Main repo for Linkerd 2.x.

Linkerd ?? Welcome to Linkerd! ?? Linkerd is an ultralight, security-first service mesh for Kubernetes. Linkerd adds critical security, observability,

Linkerd 9.2k Jan 1, 2023
Northstar is a horizontally scalable and multi-tenant Kubernetes cluster provisioner and orchestrator

Northstar Northstar is a horizontally scalable and multi-tenant Kubernetes cluster provisioner and orchestrator. Explore the docs » View Demo · Report

Lucas Clerisse 1 Jan 22, 2022
Rust Kubernetes runtime helpers. Based on kube-rs.

kubert Rust Kubernetes runtime helpers. Based on kube-rs. Features clap command-line interface support; A basic admin server with /ready and /live pro

Oliver Gould 63 Dec 17, 2022
The last kubernetes tool you'll ever need.

Neatkube The last kubernetes tool you'll ever need. Kubernetes is a mess. Everthing ships it's own command line tools that you need to install and tra

git repositories with lazers 5 Aug 3, 2022
Kubernetes + wasmCloud

KasmCloud Managing and Running Actors, Providers, and Links in Kubernetes ⚠️ Warning This is a contributor-led experimental project and is not recomme

wasmcloud 22 Oct 8, 2023
KFtray - A tray application that manages port forwarding in Kubernetes.

Ktray is written in Rust and React, with Tauri framework. The app simplifies the process of starting and stopping multiple port forwarding configurations through a user-friendly interface.

Henrique Cavarsan 42 Dec 17, 2023
H2O Open Source Kubernetes operator and a command-line tool to ease deployment (and undeployment) of H2O open-source machine learning platform H2O-3 to Kubernetes.

H2O Kubernetes Repository with official tools to aid the deployment of H2O Machine Learning platform to Kubernetes. There are two essential tools to b

H2O.ai 16 Nov 12, 2022
openapi schema serialization for rust

open api Rust crate for serializing and deserializing open api documents Documentation install add the following to your Cargo.toml file [dependencies

Doug Tangren 107 Dec 6, 2022
Get a diff between two OpenAPI descriptions.

Get the difference between two OpenAPI descriptions.

Marc-Andre Giroux 25 Aug 22, 2022
OpenAPI support for Poem

Poem OpenAPI Fast and Type-Safe OpenAPI implementation for Poem. Poem-openapi allows you to easily implement APIs that comply with the OpenAPIv3 speci

Poem Web 40 Sep 16, 2021
Black-box fuzzer that fuzzes APIs based on OpenAPI specification. Find bugs for free!

OpenAPI fuzzer Black-box fuzzer that fuzzes APIs based on OpenAPI specification. All you need to do is to supply URL of the API and its specification.

Matúš Ferech 406 Dec 31, 2022
Longbridge OpenAPI SDK Base.

Longbridge OpenAPI SDK Longbridge OpenAPI provides programmatic quote trading interfaces for investors with research and development capabilities and

Longbridge 18 Nov 30, 2022
🦀 REST API client implementation for freee, auto-generated from OpenAPI specification.

freee-rs REST API client implementation for freee, auto-generated from OpenAPI specification. Getting Started Add to your Cargo.toml as follows: [depe

Naoki Ikeguchi 3 Jul 14, 2022
OpenAPI-based test coverage analysis tool that helps teams improve integration test coverage in CI/CD pipelines

Ready-to-use OpenAPI test coverage analysis tool that helps teams improve integration CoveAPI is an advanced test coverage analysis tool based on the

Yasser Tahiri 18 Aug 3, 2023