diff --git a/cmd/config_volumes.go b/cmd/config_volumes.go index 58a54a629..f81e27da7 100644 --- a/cmd/config_volumes.go +++ b/cmd/config_volumes.go @@ -210,7 +210,7 @@ func runAddVolumesPrompt(ctx context.Context, f fn.Function) (err error) { case optionSecret: newVolume.Secret = &selectedResource case optionPersistentVolumeClaim: - newVolume.PresistentVolumeClaim = &fn.PersistentVolumeClaim{ClaimName: selectedResource} + newVolume.PresistentVolumeClaim = &fn.PersistentVolumeClaim{ClaimName: &selectedResource} case optionEmptyDir: newVolume.EmptyDir = &fn.EmptyDir{} } diff --git a/pkg/functions/function.go b/pkg/functions/function.go index 1e7bd504b..d3abdad09 100644 --- a/pkg/functions/function.go +++ b/pkg/functions/function.go @@ -529,7 +529,7 @@ func (f Function) ImageName() (image string, err error) { // registry/parent-namespace/namespace ('quay.io/project/alice') provided image = f.Registry + "/" + f.Name } else if len(registryTokens) > 3 { // the name of the image is also provided `quay.io/alice/my.function.name` - return "", fmt.Errorf("registry should be either 'namespace', 'registry/namespace' or 'registry/parent/namespace', the name of the image will be derived from the function name.") + return "", fmt.Errorf("registry should be either 'namespace', 'registry/namespace' or 'registry/parent/namespace', the name of the image will be derived from the function name") } // Explicitly append :latest tag. We expect source control to drive diff --git a/pkg/functions/function_volumes.go b/pkg/functions/function_volumes.go index 3ae030103..b13b9ce28 100644 --- a/pkg/functions/function_volumes.go +++ b/pkg/functions/function_volumes.go @@ -1,11 +1,6 @@ package functions -import ( - "fmt" - - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/resource" -) +import "fmt" type Volume struct { Secret *string `yaml:"secret,omitempty" jsonschema:"oneof_required=secret"` @@ -18,25 +13,30 @@ type Volume struct { type PersistentVolumeClaim struct { // claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - ClaimName string `yaml:"claimName"` + ClaimName *string `yaml:"claimName,omitempty"` // readOnly Will force the ReadOnly setting in VolumeMounts. // Default false. ReadOnly bool `yaml:"readOnly,omitempty"` } +const ( + StorageMediumDefault = "" // use whatever the default is for the node, assume anything we don't explicitly handle is this + StorageMediumMemory = "Memory" // use memory (e.g. tmpfs on linux) +) + type EmptyDir struct { // 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 - Medium corev1.StorageMedium `yaml:"medium,omitempty"` + Medium string `yaml:"medium,omitempty"` // 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: http://kubernetes.io/docs/user-guide/volumes#emptydir - SizeLimit *resource.Quantity `yaml:"sizeLimit,omitempty"` + SizeLimit *string `yaml:"sizeLimit,omitempty"` } func (v Volume) String() string { @@ -46,9 +46,18 @@ func (v Volume) String() string { } else if v.Secret != nil { result = fmt.Sprintf("Secret \"%s\"", *v.Secret) } else if v.PresistentVolumeClaim != nil { - result = fmt.Sprintf("PersistentVolumeClaim \"%s\"", v.PresistentVolumeClaim.ClaimName) + result = "PersistentVolumeClaim" + if v.PresistentVolumeClaim.ClaimName != nil { + result += fmt.Sprintf(" \"%s\"", *v.PresistentVolumeClaim.ClaimName) + } } else if v.EmptyDir != nil { result = "EmptyDir" + if v.EmptyDir.Medium == StorageMediumMemory { + result += " in memory" + } + if v.EmptyDir.SizeLimit != nil { + result += fmt.Sprintf(" with size limit \"%s\"", *v.EmptyDir.SizeLimit) + } } else { result = "No volume type" } @@ -85,11 +94,14 @@ func validateVolumes(volumes []Volume) (errors []string) { if vol.PresistentVolumeClaim != nil { numVolumes++ + if vol.PresistentVolumeClaim.ClaimName == nil { + errors = append(errors, fmt.Sprintf("volume entry #%d (%s) is missing claim name", i, vol)) + } } if vol.EmptyDir != nil { numVolumes++ - if vol.EmptyDir.Medium != corev1.StorageMediumDefault && vol.EmptyDir.Medium != corev1.StorageMediumMemory { + if vol.EmptyDir.Medium != StorageMediumDefault && vol.EmptyDir.Medium != StorageMediumMemory { errors = append(errors, fmt.Sprintf("volume entry #%d (%s) has invalid storage medium (%s)", i, vol, vol.EmptyDir.Medium)) } } diff --git a/pkg/functions/function_volumes_unit_test.go b/pkg/functions/function_volumes_unit_test.go index 03a97f8c1..0373e9340 100644 --- a/pkg/functions/function_volumes_unit_test.go +++ b/pkg/functions/function_volumes_unit_test.go @@ -16,8 +16,9 @@ func Test_validateVolumes(t *testing.T) { secret := "secret" secret2 := "secret2" cm := "configMap" + pvcName := "pvc" pvc := &PersistentVolumeClaim{ - ClaimName: "pvc", + ClaimName: &pvcName, } emptyDir := &EmptyDir{} @@ -192,8 +193,9 @@ func Test_validateVolumesString(t *testing.T) { path := "path" cm := "configMap" + pvcName := "pvc" pvc := &PersistentVolumeClaim{ - ClaimName: "pvc", + ClaimName: &pvcName, } tests := []struct { diff --git a/pkg/functions/invoke.go b/pkg/functions/invoke.go index 0757da910..11cf58f7a 100644 --- a/pkg/functions/invoke.go +++ b/pkg/functions/invoke.go @@ -90,7 +90,7 @@ func invoke(ctx context.Context, c *Client, f Function, target string, m InvokeM body, err = sendEvent(ctx, route, m, c.transport, verbose) return meta, body, err default: - err = fmt.Errorf("format '%v' not supported.", format) + err = fmt.Errorf("format '%v' not supported", format) return } } diff --git a/pkg/knative/deployer.go b/pkg/knative/deployer.go index 04bbfd974..73953657a 100644 --- a/pkg/knative/deployer.go +++ b/pkg/knative/deployer.go @@ -750,34 +750,41 @@ func processVolumes(volumes []fn.Volume, referencedSecrets, referencedConfigMaps } } } else if vol.PresistentVolumeClaim != nil { - volumeName = "pvc-" + vol.PresistentVolumeClaim.ClaimName + volumeName = "pvc-" + *vol.PresistentVolumeClaim.ClaimName if !createdVolumes.Has(volumeName) { newVolumes = append(newVolumes, corev1.Volume{ Name: volumeName, VolumeSource: corev1.VolumeSource{ PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{ - ClaimName: vol.PresistentVolumeClaim.ClaimName, + ClaimName: *vol.PresistentVolumeClaim.ClaimName, ReadOnly: vol.PresistentVolumeClaim.ReadOnly, }, }, }) createdVolumes.Insert(volumeName) - if !referencedPVCs.Has(vol.PresistentVolumeClaim.ClaimName) { - referencedPVCs.Insert(vol.PresistentVolumeClaim.ClaimName) + if !referencedPVCs.Has(*vol.PresistentVolumeClaim.ClaimName) { + referencedPVCs.Insert(*vol.PresistentVolumeClaim.ClaimName) } } } else if vol.EmptyDir != nil { volumeName = "empty-dir-" + rand.String(7) if !createdVolumes.Has(volumeName) { + + sizeLimit, err := resource.ParseQuantity(*vol.EmptyDir.SizeLimit) + + if err != nil { + return nil, nil, fmt.Errorf("invalid quantity for sizeLimit: %s. Error: %s", *vol.EmptyDir.SizeLimit, err) + } + newVolumes = append(newVolumes, corev1.Volume{ Name: volumeName, VolumeSource: corev1.VolumeSource{ EmptyDir: &corev1.EmptyDirVolumeSource{ - Medium: vol.EmptyDir.Medium, - SizeLimit: vol.EmptyDir.SizeLimit, + Medium: corev1.StorageMedium(vol.EmptyDir.Medium), + SizeLimit: &sizeLimit, }, }, }) diff --git a/schema/func_yaml-schema.json b/schema/func_yaml-schema.json index 87d2356b3..2181c8d72 100644 --- a/schema/func_yaml-schema.json +++ b/schema/func_yaml-schema.json @@ -99,8 +99,7 @@ "description": "medium represents what type of storage medium should back this directory.\nThe default is \"\" which means to use the node's default medium.\nMust be an empty string (default) or Memory.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir" }, "sizeLimit": { - "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/Quantity", + "type": "string", "description": "sizeLimit is the total amount of local storage required for this EmptyDir volume.\nThe size limit is also applicable for memory medium.\nThe maximum usage on memory medium EmptyDir would be the minimum value between\nthe SizeLimit specified here and the sum of memory limits of all containers in a pod.\nThe default is nil which means that the limit is undefined.\nMore info: http://kubernetes.io/docs/user-guide/volumes#emptydir" } }, @@ -243,9 +242,6 @@ "type": "object" }, "PersistentVolumeClaim": { - "required": [ - "claimName" - ], "properties": { "claimName": { "type": "string", @@ -259,11 +255,6 @@ "additionalProperties": false, "type": "object" }, - "Quantity": { - "properties": {}, - "additionalProperties": false, - "type": "object" - }, "ResourcesLimitsOptions": { "properties": { "cpu": {