apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: vms.vmoperator.jdrupes.org
spec:
  group: vmoperator.jdrupes.org
  # list of versions supported by this CustomResourceDefinition
  versions:
    - name: v1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                image:
                  description: >-
                    The image to use for the pod. Must run a runner.
                  type: object
                  properties:
                    repository: 
                      type: string
                      default: "ghcr.io"
                    path:
                      type: string
                      default: "mnlipp/org.jdrupes.vmoperator.runner.qemu-arch"
                    version:
                      type: string
                      default: "latest"
                    pullPolicy:
                      type: string
                      enum: [ "IfNotPresent", "Always" ]
                      default: "IfNotPresent"
                vm:
                  type: object
                  description: Defines the VM.
                  oneOf:
                  - properties:
                      maximumCpus: {}
                      cpuTopology: {}
                  properties:
                    state:
                      description: >-
                        The (desired) state of the VM.
                      type: string
                      enum: [ "Stopped", "Running" ]
                      default: "Stopped"
                    machineUuid:
                      description: >-
                        The machine's uuid. If none is specified, a uuid 
                        is generated and stored in the data directory. 
                        If the uuid is important (e.g. because licenses 
                        depend on it) it is recommaned to specify it 
                        explicitly or to carefully backup the data 
                        directory.
                      type: string
                    useTpm:
                      description: Whether to provide a software TPM.
                      type: boolean
                      default: false
                    firmware:
                      description: >-
                        How to boot.
                      type: string
                      enum: ["bios", "uefi", "uefi-4m", "secure", "secure-4m"]
                      default: "uefi"
                    bootMenu:
                      description: Whether to show a boot menu.
                      type: boolean
                      default: false
                    powerdownTimeout:
                      description: >-
                        When terminating, a graceful powerdown is attempted. 
                        If it doesn't succeed within the given timeout 
                        (seconds) SIGTERM is sent to Qemu.
                      type: integer
                      default: 900
                    cpuModel:
                      description: Any model supported by Qemu.
                      type: string
                      default: "host"
                    maximumCpus:
                      description: >-
                        Either maximumCpus or cpuTopology may be specified.
                        If neither is specified, maximum cpus is set to 4.
                        Setting maximumCpus to 1 omits the "-smp" options.
                      type: integer
                    cpuTopology:
                      description: >-
                        Values of 0 cause the corresponding property 
                        to be omitted from the "-smp" option.
                      type: object
                      properties:
                        sockets:
                          type: integer
                          default: 1
                        diesPerSocket:
                          type: integer
                          default: 0
                        coresPerSocket:
                          type: integer
                          default: 0
                        threadsPerSocket:
                          type: integer
                          default: 0
                    currentCpus:
                      description: >-
                        Defaults to maximumCpus. 
                      type: integer
                    maximumRam:
                      type: string
                      default: "1G"
                    currentRam:
                      type: string
                    rtcBase:
                      description: Passed to Qemu unmodified.
                      type: string
                      default: "utc"
                    rtcClock:
                      description: Passed to Qemu unmodified.
                      type: string
                      default: "rt"
                    networks:
                      type: array
                      items:
                        description: >-
                          Supported types are "tap" and "user" (for debugging).
                        type: object
                        oneOf:
                        - properties:
                            tap: {}
                            user: {}
                        properties:
                          tap:
                            type: object
                            properties:
                              device:
                                description: The device to use.
                                type: string
                                default: "virtio-net"
                              bridge:
                                description: The bridge to attach to.
                                type: string
                                default: "br0"
                              mac: 
                                type: string
                          user:
                            type: object
                            properties:
                              device:
                                description: The device to use.
                                type: string
                                default: "virtio-net"
                              net:
                                type: string
                      default: []
                    disks:
                      description: >-
                        Disks make persistent storage available. The
                        storage may be provided by a device on the
                        host (preallocated, e.g. a LV).
                      type: array
                      items:
                        type: object
                        oneOf:
                        - required:
                          - volumeClaimTemplate
                        - required:
                          - cdrom
                        properties:
                          volumeClaimTemplate:
                            description: >-
                              A PVC spec to be used to provide the disk. The easiest
                              way to use a volume that cannot be automatically provisioned
                              (for whatever reason) is to use a label selector alongside 
                              manually created PersistentVolumes.
                            properties:
                              metadata:
                                description: >-
                                  EmbeddedMetadata contains metadata relevant to
                                  an EmbeddedResource.
                                type: object
                                properties:
                                  name:
                                    description: >-
                                      Name must be unique within a namespace.
                                      Is required when creating resources, although some resources
                                      may allow a client to request the generation of an appropriate
                                      name automatically. Name is primarily intended for creation
                                      idempotence and configuration definition. Cannot be
                                      updated. More info: http://kubernetes.io/docs/user-guide/identifiers#names.
                                      The name is generated automatically but can be overriden.
                                      Note that the name "<vm-name>-runner-data" is reserved.
                                    type: string
                                  labels:
                                    description: >-
                                      Map of string keys and values that can be
                                      used to organize and categorize (scope and select) objects.
                                      May match selectors of replication controllers and services.
                                      More info: http://kubernetes.io/docs/user-guide/labels
                                    type: object
                                    additionalProperties:
                                      type: string
                                  annotations:
                                    description: >-
                                      Annotations is an unstructured key value
                                      map stored with a resource that may be set by external
                                      tools to store and retrieve arbitrary metadata. They
                                      are not queryable and should be preserved when modifying
                                      objects. More info: http://kubernetes.io/docs/user-guide/annotations
                                    type: object
                                    additionalProperties:
                                      type: string
                              spec:
                                description: >-
                                  Spec defines the desired characteristics of
                                  a volume requested by a pod author. More info: 
                                  https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims
                                properties:
                                  accessModes:
                                    description: >-
                                      accessModes contains the desired access
                                      modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1
                                    items:
                                      type: string
                                    type: array
                                    default: [ "ReadWriteOnce" ]
                                  dataSource:
                                    description: >-
                                      dataSource field can be used to specify
                                      either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot)
                                      * An existing PVC (PersistentVolumeClaim) If the provisioner
                                      or an external controller can support the specified
                                      data source, it will create a new volume based on the
                                      contents of the specified data source. If the AnyVolumeDataSource
                                      feature gate is enabled, this field will always have
                                      the same contents as the DataSourceRef field.
                                    properties:
                                      apiGroup:
                                        description: >-
                                          APIGroup is the group for the resource
                                          being referenced. If APIGroup is not specified,
                                          the specified Kind must be in the core API group.
                                          For any other third-party types, APIGroup is required.
                                        type: string
                                      kind:
                                        description: >-
                                          Kind is the type of resource being referenced
                                        type: string
                                      name:
                                        description: >-
                                          Name is the name of resource being referenced
                                        type: string
                                    required:
                                    - kind
                                    - name
                                    type: object
                                    x-kubernetes-map-type: atomic
                                  dataSourceRef:
                                    description: >-
                                      dataSourceRef specifies the object from
                                      which to populate the volume with data, if a non-empty
                                      volume is desired. This may be any local object from
                                      a non-empty API group (non core object) or a PersistentVolumeClaim
                                      object. When this field is specified, volume binding
                                      will only succeed if the type of the specified object
                                      matches some installed volume populator or dynamic provisioner.
                                      This field will replace the functionality of the DataSource
                                      field and as such if both fields are non-empty, they
                                      must have the same value. For backwards compatibility,
                                      both fields (DataSource and DataSourceRef) will be set
                                      to the same value automatically if one of them is empty
                                      and the other is non-empty. There are two important
                                      differences between DataSource and DataSourceRef: *
                                      While DataSource only allows two specific types of objects,
                                      DataSourceRef allows any non-core object, as well as
                                      PersistentVolumeClaim objects. * While DataSource ignores
                                      disallowed values (dropping them), DataSourceRef preserves
                                      all values, and generates an error if a disallowed value
                                      is specified. (Beta) Using this field requires the AnyVolumeDataSource
                                      feature gate to be enabled.
                                    properties:
                                      apiGroup:
                                        description: >-
                                          APIGroup is the group for the resource
                                          being referenced. If APIGroup is not specified,
                                          the specified Kind must be in the core API group.
                                          For any other third-party types, APIGroup is required.
                                        type: string
                                      kind:
                                        description: >-
                                          Kind is the type of resource being referenced
                                        type: string
                                      name:
                                        description: >-
                                          Name is the name of resource being referenced
                                        type: string
                                    required:
                                    - kind
                                    - name
                                    type: object
                                    x-kubernetes-map-type: atomic
                                  resources:
                                    description: >-
                                      resources represents the minimum resources
                                      the volume should have. If RecoverVolumeExpansionFailure
                                      feature is enabled users are allowed to specify resource
                                      requirements that are lower than previous value but
                                      must still be higher than capacity recorded in the status
                                      field of the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources
                                    properties:
                                      limits:
                                        additionalProperties:
                                          anyOf:
                                          - type: integer
                                          - type: string
                                          pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
                                          x-kubernetes-int-or-string: true
                                        description: >-
                                          Limits describes the maximum amount
                                          of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
                                        type: object
                                      requests:
                                        additionalProperties:
                                          anyOf:
                                          - type: integer
                                          - type: string
                                          pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
                                          x-kubernetes-int-or-string: true
                                        description: >-
                                          Requests describes the minimum amount
                                          of compute resources required. If Requests is omitted
                                          for a container, it defaults to Limits if that is
                                          explicitly specified, otherwise to an implementation-defined
                                          value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
                                        type: object
                                    type: object
                                  selector:
                                    description: >-
                                      selector is a label query over volumes to
                                      consider for binding.
                                    properties:
                                      matchExpressions:
                                        description: >-
                                          matchExpressions is a list of label selector
                                          requirements. The requirements are ANDed.
                                        items:
                                          description: >-
                                            A label selector requirement is a selector
                                            that contains values, a key, and an operator that
                                            relates the key and values.
                                          properties:
                                            key:
                                              description: >-
                                                key is the label key that the selector
                                                applies to.
                                              type: string
                                            operator:
                                              description: >-
                                                operator represents a key's relationship
                                                to a set of values. Valid operators are In,
                                                NotIn, Exists and DoesNotExist.
                                              type: string
                                            values:
                                              description: >-
                                                values is an array of string values.
                                                If the operator is In or NotIn, the values
                                                array must be non-empty. If the operator is
                                                Exists or DoesNotExist, the values array must
                                                be empty. This array is replaced during a
                                                strategic merge patch.
                                              items:
                                                type: string
                                              type: array
                                          required:
                                          - key
                                          - operator
                                          type: object
                                        type: array
                                      matchLabels:
                                        additionalProperties:
                                          type: string
                                        description: >-
                                          matchLabels is a map of {key,value} pairs.
                                          A single {key,value} in the matchLabels map is equivalent
                                          to an element of matchExpressions, whose key field
                                          is "key", the operator is "In", and the values array
                                          contains only "value". The requirements are ANDed.
                                        type: object
                                    type: object
                                    x-kubernetes-map-type: atomic
                                  storageClassName:
                                    description: >-
                                      storageClassName is the name of the StorageClass
                                      required by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1
                                    type: string
                                  volumeMode:
                                    description: >-
                                      volumeMode defines what type of volume is
                                      required by the claim.
                                    type: string
                                    default: Block
                                  volumeName:
                                    description: >-
                                      volumeName is the binding reference to the
                                      PersistentVolume backing this claim.
                                    type: string
                                type: object
                            type: object
                          cdrom:
                            type: object
                            properties:
                              image:
                                type: string
                            required:
                            - image
                          bootindex:
                            type: integer
                      default: []
                    display:
                      type: object
                      properties:
                        spice:
                          type: object
                          properties:
                            port:
                              type: integer
                              default: 5900
                            ticket:
                              type: string
                            streamingVideo:
                              type: string
                            usbRedirects:
                              type: integer
                              default: 2
                      default: { spice: { port: 5900, usbRedirects: 2 } }
              required:
              - vm              
            status:
              type: object
              properties:            
                conditions:
                  description: >-
                    List of component conditions observed
                  type: array
                  items:
                    type: object
                    description: >-
                      Information about the condition of a component. See
                      https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
                      and https://github.com/kubernetes/apimachinery/blob/release-1.23/pkg/apis/meta/v1/types.go#L1432-L1492
                    properties: 
                      type:
                        type: string
                        description: >-
                          Type of condition in CamelCase or in 
                          foo.example.com/CamelCase. The type should make sense 
                          for humans.
                      status:
                        type: string
                        description: >-
                          Status of the condition, one of True, False, Unknown.
                        default: Unknown
                      observedGeneration:
                       type: integer
                       description: >-
                         OobservedGeneration represents the .metadata.generation
                         that the condition was set based upon. For instance, 
                         if .metadata.generation is currently 12, but the 
                         .status.conditions[x].observedGeneration is 9, 
                         the condition is out of date with respect to the 
                         current state of the instance.
                      lastTransitionTime:
                        type: string
                        description: >-
                          lastTransitionTime is the last time the condition 
                          transitioned from one status to another.
                          This should be when the underlying condition changed.
                          If that is not known, then using the time when the 
                          API field changed is acceptable.
                      reason:
                        type: string
                        description: >-
                          Reason contains a programmatic identifier indicating 
                          the reason for the condition's last transition.
                          Producers of specific condition types may define 
                          expected values and meanings for this field, and 
                          whether the values are considered a guaranteed API.
                          The value should be a CamelCase string.
                          This field may not be empty.
                      message:
                        type: string
                        description: >-
                          Message is a human readable message indicating 
                          details about the transition. This may be an empty string.
                        default: ""
                    required:
                    - type
                    - status
                    - lastTransitionTime
                    - reason
                    - message
  # either Namespaced or Cluster
  scope: Namespaced
  names:
    # plural name to be used in the URL: /apis/<group>/<version>/<plural>
    plural: vms
    # singular name to be used as an alias on the CLI and for display
    singular: vm
    # kind is normally the CamelCased singular type. Your resource manifests use this.
    kind: VirtualMachine
    listKind: VirtualMachineList
