k8s CRD definition: 4 mutually exclusive optional fields

3 min read 04-10-2024
k8s CRD definition: 4 mutually exclusive optional fields


Defining Mutually Exclusive Optional Fields in Kubernetes Custom Resource Definitions (CRDs)

Kubernetes Custom Resource Definitions (CRDs) allow you to extend Kubernetes with custom resources, enabling you to represent your own application-specific data within the Kubernetes ecosystem. One common challenge arises when you need to define multiple optional fields within a CRD that are mutually exclusive, meaning only one of them should be provided at any given time.

Scenario: Imagine you are creating a CRD for managing storage configurations. This CRD might have fields for different storage types: local, cloud, and network. You want to ensure that only one of these fields is specified for each storage configuration, allowing for a clear and consistent way to represent the desired storage setup.

Original Code: A naive approach might be to simply define these fields as optional:

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: storageconfigurations.mydomain.io
spec:
  versions:
  - name: v1
    served: true
    storage: true
  scope: Namespaced
  names:
    plural: storageconfigurations
    singular: storageconfiguration
  validation:
    openAPIV3Schema:
      type: object
      properties:
        spec:
          type: object
          properties:
            local:
              type: object # Define properties for local storage config
              description: Local storage configuration details
            cloud:
              type: object # Define properties for cloud storage config
              description: Cloud storage configuration details
            network:
              type: object # Define properties for network storage config
              description: Network storage configuration details

Analysis: This code doesn't enforce mutual exclusivity. Users could potentially specify multiple storage types simultaneously, leading to unexpected behavior and inconsistencies in your storage configuration.

Solution: Custom Validation

To achieve mutual exclusivity, you can leverage custom validation within the CRD definition. This involves adding a custom validation schema to your CRD, allowing you to define complex validation rules using JSON Schema.

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: storageconfigurations.mydomain.io
spec:
  # ... (Rest of the spec remains the same)
  validation:
    openAPIV3Schema:
      type: object
      properties:
        spec:
          type: object
          properties:
            # ... (Other properties)
            storageType:
              type: string
              enum: ['local', 'cloud', 'network']
            local:
              type: object
              description: Local storage configuration details
              x-kubernetes-preserve-unknown-fields: true
              # Note: This is the key for mutual exclusivity - enable the field only if storageType is 'local'
              x-kubernetes-validations:
                - type: 'pattern'
                  match: '^.*{{content}}#39;
                  when:
                    fieldPath: 'spec.storageType'
                    operator: '=='
                    value: 'local'
            cloud:
              type: object
              description: Cloud storage configuration details
              x-kubernetes-preserve-unknown-fields: true
              # Enable cloud field only if storageType is 'cloud'
              x-kubernetes-validations:
                - type: 'pattern'
                  match: '^.*{{content}}#39;
                  when:
                    fieldPath: 'spec.storageType'
                    operator: '=='
                    value: 'cloud'
            network:
              type: object
              description: Network storage configuration details
              x-kubernetes-preserve-unknown-fields: true
              # Enable network field only if storageType is 'network'
              x-kubernetes-validations:
                - type: 'pattern'
                  match: '^.*{{content}}#39;
                  when:
                    fieldPath: 'spec.storageType'
                    operator: '=='
                    value: 'network'

Explanation:

  1. storageType Field: We introduce a new field storageType which takes values from the enum ['local', 'cloud', 'network'], acting as a selector for the specific storage type.

  2. x-kubernetes-validations: This custom validation extension allows us to define rules for each storage configuration field.

  3. when Condition: Each validation uses a when condition to control when the rule applies based on the value of storageType. The rule is only active when storageType matches the specified value (local, cloud, or network).

  4. x-kubernetes-preserve-unknown-fields: This ensures that any fields within the storage configurations (local, cloud, network) are accepted even if the storageType doesn't match, as long as the corresponding validation is not active.

Benefits:

  • Enforces Mutual Exclusivity: Ensures that only one storage configuration can be specified at a time, preventing conflicting configurations.
  • Clearer Validation: Provides a clear and organized way to define complex validation logic.
  • Improved User Experience: Guides users to specify the correct storage type and avoids unexpected behavior.

Conclusion: Implementing custom validation with x-kubernetes-validations allows you to define intricate validation rules and ensure the integrity of your CRDs. This is particularly useful for managing mutually exclusive optional fields, enabling you to create robust and well-defined custom resources within your Kubernetes environment.