Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions api/v1alpha1/applyconfiguration/api/v1alpha1/storagemount.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 14 additions & 3 deletions api/v1alpha1/applyconfiguration/api/v1alpha1/storagesource.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 16 additions & 7 deletions api/v1alpha1/mcpserver_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,16 @@ type Source struct {
}

// StorageType defines the type of storage mount.
// +kubebuilder:validation:Enum=ConfigMap;Secret
// +kubebuilder:validation:Enum=ConfigMap;Secret;EmptyDir
type StorageType string

const (
// StorageTypeConfigMap indicates a ConfigMap volume source.
StorageTypeConfigMap StorageType = "ConfigMap"
// StorageTypeSecret indicates a Secret volume source.
StorageTypeSecret StorageType = "Secret"
// StorageTypeEmptyDir indicates an EmptyDir volume source.
StorageTypeEmptyDir StorageType = "EmptyDir"
)

// MountPermissions defines the access permissions for a volume mount.
Expand All @@ -105,13 +107,14 @@ const (
MountPermissionsRecursiveReadOnly MountPermissions = "RecursiveReadOnly"
)

// StorageSource defines the source of the storage to mount (ConfigMap or Secret).
// StorageSource defines the source of the storage to mount (ConfigMap, Secret, or EmptyDir).
// +kubebuilder:validation:XValidation:rule="self.type == 'ConfigMap' ? has(self.configMap) : !has(self.configMap)",message="configMap must be set when type is ConfigMap and must not be set otherwise"
// +kubebuilder:validation:XValidation:rule="self.type == 'Secret' ? has(self.secret) : !has(self.secret)",message="secret must be set when type is Secret and must not be set otherwise"
// +kubebuilder:validation:XValidation:rule="self.type == 'EmptyDir' ? has(self.emptyDir) : !has(self.emptyDir)",message="emptyDir must be set when type is EmptyDir and must not be set otherwise"
type StorageSource struct {
// Type is a required field that specifies the type of volume source.
// Allowed values are: ConfigMap, Secret.
// This determines which volume source field (configMap or secret) should be configured.
// Allowed values are: ConfigMap, Secret, EmptyDir.
// This determines which volume source field (configMap, secret, or emptyDir) should be configured.
// +kubebuilder:validation:Required
Type StorageType `json:"type,omitempty"`

Expand All @@ -124,11 +127,16 @@ type StorageSource struct {
// Uses native Kubernetes SecretVolumeSource type for full feature parity.
// +optional
Secret *corev1.SecretVolumeSource `json:"secret,omitempty"`

// EmptyDir specifies an EmptyDir volume source (when Type is EmptyDir).
// Uses native Kubernetes EmptyDirVolumeSource type for full feature parity.
// +optional
EmptyDir *corev1.EmptyDirVolumeSource `json:"emptyDir,omitempty"`
}

// StorageMount defines a storage mount combining volume source and mount configuration.
// The Path and Permissions fields apply to all storage types, while Source contains
// the type-specific configuration (ConfigMap or Secret).
// the type-specific configuration (ConfigMap, Secret, or EmptyDir).
type StorageMount struct {
// Path is a required field that specifies where the volume should be mounted in the container.
// Must be an absolute path (starting with /).
Expand All @@ -147,11 +155,12 @@ type StorageMount struct {
// When set to ReadWrite, the mount is read-write.
// When set to RecursiveReadOnly, the mount and all submounts are recursively read-only.
// Defaults to ReadOnly for ConfigMap and Secret mounts.
// For EmptyDir mounts, ReadWrite is more common for writable scratch space.
// +optional
// +kubebuilder:default=ReadOnly
Permissions MountPermissions `json:"permissions,omitempty"`

// Source defines where the storage data comes from (ConfigMap or Secret).
// Source defines where the storage data comes from (ConfigMap, Secret, or EmptyDir).
// +kubebuilder:validation:Required
Source StorageSource `json:"source,omitzero"`
}
Expand Down Expand Up @@ -189,7 +198,7 @@ type ServerConfig struct {
// +optional
EnvFrom []corev1.EnvFromSource `json:"envFrom,omitempty"`

// Storage defines storage mounts for ConfigMaps and Secrets.
// Storage defines storage mounts for ConfigMaps, Secrets, and EmptyDirs.
// Each item uses native Kubernetes volume source types for consistency and feature parity.
// If specified, must contain at least 1 item. Maximum 64 items.
// Each storage mount must have a unique path.
Expand Down
5 changes: 5 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

42 changes: 37 additions & 5 deletions config/crd/bases/mcp.x-k8s.io_mcpservers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -322,15 +322,15 @@ spec:
type: integer
storage:
description: |-
Storage defines storage mounts for ConfigMaps and Secrets.
Storage defines storage mounts for ConfigMaps, Secrets, and EmptyDirs.
Each item uses native Kubernetes volume source types for consistency and feature parity.
If specified, must contain at least 1 item. Maximum 64 items.
Each storage mount must have a unique path.
items:
description: |-
StorageMount defines a storage mount combining volume source and mount configuration.
The Path and Permissions fields apply to all storage types, while Source contains
the type-specific configuration (ConfigMap or Secret).
the type-specific configuration (ConfigMap, Secret, or EmptyDir).
properties:
path:
description: |-
Expand All @@ -356,14 +356,15 @@ spec:
When set to ReadWrite, the mount is read-write.
When set to RecursiveReadOnly, the mount and all submounts are recursively read-only.
Defaults to ReadOnly for ConfigMap and Secret mounts.
For EmptyDir mounts, ReadWrite is more common for writable scratch space.
enum:
- ReadOnly
- ReadWrite
- RecursiveReadOnly
type: string
source:
description: Source defines where the storage data comes
from (ConfigMap or Secret).
from (ConfigMap, Secret, or EmptyDir).
properties:
configMap:
description: |-
Expand Down Expand Up @@ -435,6 +436,32 @@ spec:
type: boolean
type: object
x-kubernetes-map-type: atomic
emptyDir:
description: |-
EmptyDir specifies an EmptyDir volume source (when Type is EmptyDir).
Uses native Kubernetes EmptyDirVolumeSource type for full feature parity.
properties:
medium:
description: |-
medium represents what type of storage medium should back this directory.
The default is "" which means to use the node's default medium.
Must be an empty string (default) or Memory.
More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir
type: string
sizeLimit:
anyOf:
- type: integer
- type: string
description: |-
sizeLimit is the total amount of local storage required for this EmptyDir volume.
The size limit is also applicable for memory medium.
The maximum usage on memory medium EmptyDir would be the minimum value between
the SizeLimit specified here and the sum of memory limits of all containers in a pod.
The default is nil which means that the limit is undefined.
More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
type: object
secret:
description: |-
Secret specifies a Secret volume source (when Type is Secret).
Expand Down Expand Up @@ -503,11 +530,12 @@ spec:
type:
description: |-
Type is a required field that specifies the type of volume source.
Allowed values are: ConfigMap, Secret.
This determines which volume source field (configMap or secret) should be configured.
Allowed values are: ConfigMap, Secret, EmptyDir.
This determines which volume source field (configMap, secret, or emptyDir) should be configured.
enum:
- ConfigMap
- Secret
- EmptyDir
type: string
required:
- type
Expand All @@ -520,6 +548,10 @@ spec:
- message: secret must be set when type is Secret and must
not be set otherwise
rule: 'self.type == ''Secret'' ? has(self.secret) : !has(self.secret)'
- message: emptyDir must be set when type is EmptyDir and
must not be set otherwise
rule: 'self.type == ''EmptyDir'' ? has(self.emptyDir)
: !has(self.emptyDir)'
required:
- path
- source
Expand Down
18 changes: 18 additions & 0 deletions config/samples/mcp_v1alpha1_mcpserver_with_emptydir.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
apiVersion: mcp.x-k8s.io/v1alpha1
kind: MCPServer
metadata:
name: kubernetes-mcp-server
spec:
source:
type: ContainerImage
containerImage:
ref: quay.io/containers/kubernetes_mcp_server:latest
config:
port: 8080
storage:
- path: /tmp
permissions: ReadWrite
source:
type: EmptyDir
emptyDir:
sizeLimit: 100Mi
6 changes: 6 additions & 0 deletions internal/controller/mcpserver_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,12 @@ func (r *MCPServerReconciler) processStorageMounts(
}
}
volume.Secret = storage.Source.Secret
case mcpv1alpha1.StorageTypeEmptyDir:
if storage.Source.EmptyDir == nil {
return nil, nil, fmt.Errorf("emptyDir must be set when type is EmptyDir for storage mount at index %d", i)
}
// No existence validation needed - EmptyDir is created by Kubernetes
volume.EmptyDir = storage.Source.EmptyDir
default:
return nil, nil, fmt.Errorf("unsupported storage type %s at index %d", storage.Source.Type, i)
}
Expand Down
Loading