Merge pull request #2312 from prachirp/volume

Support mounting volumes to containers
This commit is contained in:
Kubernetes Prow Robot
2020-04-02 14:13:04 -07:00
committed by GitHub
7 changed files with 159 additions and 18 deletions

View File

@@ -11,6 +11,7 @@ import (
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/kio/filters"
"sigs.k8s.io/kustomize/kyaml/runfn"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
@@ -54,6 +55,9 @@ func GetRunFnRunner(name string) *RunFnRunner {
&r.Network, "network", false, "enable network access for functions that declare it")
r.Command.Flags().StringVar(
&r.NetworkName, "network-name", "bridge", "the docker network to run the container in")
r.Command.Flags().StringArrayVar(
&r.Mounts, "mount", []string{},
"a list of storage options read from the filesystem")
return r
}
@@ -75,6 +79,7 @@ type RunFnRunner struct {
RunFns runfn.RunFns
Network bool
NetworkName string
Mounts []string
}
func (r *RunFnRunner) runE(c *cobra.Command, args []string) error {
@@ -199,6 +204,14 @@ data: {}
return []*yaml.RNode{rc}, nil
}
func toStorageMounts(mounts []string) []filters.StorageMount {
var sms []filters.StorageMount
for _, mount := range mounts {
sms = append(sms, filters.StringToStorageMount(mount))
}
return sms
}
func (r *RunFnRunner) preRunE(c *cobra.Command, args []string) error {
if r.EnableStar != (r.StarPath != "") {
return errors.Errorf("must specify --star-path with --enable-star")
@@ -240,6 +253,9 @@ func (r *RunFnRunner) preRunE(c *cobra.Command, args []string) error {
path = args[0]
}
// parse mounts to set storageMounts
storageMounts := toStorageMounts(r.Mounts)
r.RunFns = runfn.RunFns{
FunctionPaths: r.FnPaths,
GlobalScope: r.GlobalScope,
@@ -250,6 +266,7 @@ func (r *RunFnRunner) preRunE(c *cobra.Command, args []string) error {
Network: r.Network,
NetworkName: r.NetworkName,
EnableStarlark: r.EnableStar,
StorageMounts: storageMounts,
}
// don't consider args for the function

View File

@@ -27,6 +27,7 @@ func TestRunFnCommand_preRunE(t *testing.T) {
functionPaths []string
network bool
networkName string
mount []string
}{
{
name: "config map",
@@ -213,6 +214,26 @@ metadata:
data: {g: h, i: j=k}
kind: Foo
apiVersion: v1
`,
},
{
name: "custom kind with storage mounts",
args: []string{
"run", "dir", "--mount", "type=bind,src=/mount/path,dst=/local/",
"--mount", "type=volume,src=myvol,dst=/local/",
"--mount", "type=tmpfs,dst=/local/",
"--image", "foo:bar", "--", "Foo", "g=h", "i=j=k"},
path: "dir",
mount: []string{"type=bind,src=/mount/path,dst=/local/", "type=volume,src=myvol,dst=/local/", "type=tmpfs,dst=/local/"},
expected: `
metadata:
name: function-input
annotations:
config.kubernetes.io/function: |
container: {image: 'foo:bar'}
data: {g: h, i: j=k}
kind: Foo
apiVersion: v1
`,
},
{
@@ -303,6 +324,10 @@ apiVersion: v1
t.FailNow()
}
if !assert.Equal(t, toStorageMounts(tt.mount), r.RunFns.StorageMounts) {
t.FailNow()
}
// check if Functions were set
if tt.expected != "" {
if !assert.Len(t, r.RunFns.Functions, 1) {

View File

@@ -12,8 +12,7 @@ spec:
strict: true
ignoreMissingSchemas: true
# TODO: Remove these once function container network/volumes features are
# stabilized.
# TODO: Update this to use network/volumes features.
# Relevant issues:
# - https://github.com/kubernetes-sigs/kustomize/issues/1901
# - https://github.com/kubernetes-sigs/kustomize/issues/1902

View File

@@ -135,7 +135,7 @@ type ContainerFilter struct {
Network string `yaml:"network,omitempty"`
// StorageMounts is a list of storage options that the container will have mounted.
StorageMounts []StorageMount
StorageMounts []StorageMount `yaml:"mounts,omitempty"`
// Config is the API configuration for the container and passed through the
// API_CONFIG env var to the container.
@@ -156,25 +156,31 @@ func (c ContainerFilter) String() string {
return c.Image
}
// StorageMount represents a container's mounted storage option(s)
type StorageMount struct {
// Type of mount e.g. bind mount, local volume, etc.
MountType string
// Source for the storage to be mounted.
// For named volumes, this is the name of the volume.
// For anonymous volumes, this field is omitted (empty string).
// For bind mounts, this is the path to the file or directory on the host.
Src string
// The path where the file or directory is mounted in the container.
DstPath string
}
func (s *StorageMount) String() string {
return fmt.Sprintf("type=%s,src=%s,dst=%s:ro", s.MountType, s.Src, s.DstPath)
}
func StringToStorageMount(s string) StorageMount {
m := make(map[string]string)
options := strings.Split(s, ",")
for _, option := range options {
keyVal := strings.SplitN(option, "=", 2)
m[keyVal[0]] = keyVal[1]
}
var sm StorageMount
for key, value := range m {
switch {
case key == "type":
sm.MountType = value
case key == "src":
sm.Src = value
case key == "dst":
sm.DstPath = value
}
}
return sm
}
// functionsDirectoryName is keyword directory name for functions scoped 1 directory higher
const functionsDirectoryName = "functions"

View File

@@ -334,6 +334,68 @@ container:
image: foo:v1.0.0`,
},
{
name: "storage mounts json style",
resource: `
apiVersion: v1beta1
kind: Example
metadata:
annotations:
config.kubernetes.io/function: |-
container:
image: foo:v1.0.0
mounts: [ {type: bind, src: /mount/path, dst: /local/}, {src: myvol, dst: /local/, type: volume}, {dst: /local/, type: tmpfs} ]
`,
expectedFn: `
container:
image: foo:v1.0.0
mounts:
- type: bind
src: /mount/path
dst: /local/
- type: volume
src: myvol
dst: /local/
- type: tmpfs
dst: /local/
`,
},
{
name: "storage mounts yaml style",
resource: `
apiVersion: v1beta1
kind: Example
metadata:
annotations:
config.kubernetes.io/function: |-
container:
image: foo:v1.0.0
mounts:
- src: /mount/path
type: bind
dst: /local/
- dst: /local/
src: myvol
type: volume
- type: tmpfs
dst: /local/
`,
expectedFn: `
container:
image: foo:v1.0.0
mounts:
- type: bind
src: /mount/path
dst: /local/
- type: volume
src: myvol
dst: /local/
- type: tmpfs
dst: /local/
`,
},
{
name: "network",
resource: `

View File

@@ -28,6 +28,9 @@ type FunctionSpec struct {
// Starlark is the spec for running a function as a starlark script
Starlark StarlarkSpec `json:"starlark,omitempty" yaml:"starlark,omitempty"`
// Mounts are the storage or directories to mount into the container
StorageMounts []StorageMount `json:"mounts,omitempty" yaml:"mounts,omitempty"`
}
// ContainerSpec defines a spec for running a function as a container
@@ -37,6 +40,9 @@ type ContainerSpec struct {
// Network defines network specific configuration
Network ContainerNetwork `json:"network,omitempty" yaml:"network,omitempty"`
// Mounts are the storage or directories to mount into the container
StorageMounts []StorageMount `json:"mounts,omitempty" yaml:"mounts,omitempty"`
}
// ContainerNetwork
@@ -53,6 +59,21 @@ type StarlarkSpec struct {
Path string `json:"path,omitempty" yaml:"path,omitempty"`
}
// StorageMount represents a container's mounted storage option(s)
type StorageMount struct {
// Type of mount e.g. bind mount, local volume, etc.
MountType string `json:"type,omitempty" yaml:"type,omitempty"`
// Source for the storage to be mounted.
// For named volumes, this is the name of the volume.
// For anonymous volumes, this field is omitted (empty string).
// For bind mounts, this is the path to the file or directory on the host.
Src string `json:"src,omitempty" yaml:"src,omitempty"`
// The path where the file or directory is mounted in the container.
DstPath string `json:"dst,omitempty" yaml:"dst,omitempty"`
}
// GetFunctionSpec returns the FunctionSpec for a resource. Returns
// nil if the resource does not have a FunctionSpec.
//
@@ -68,6 +89,7 @@ func GetFunctionSpec(n *yaml.RNode) *FunctionSpec {
path := meta.Annotations[kioutil.PathAnnotation]
if fn := getFunctionSpecFromAnnotation(n, meta); fn != nil {
fn.Network = ""
fn.StorageMounts = []StorageMount{}
fn.Path = path
return fn
}

View File

@@ -140,6 +140,16 @@ func TestRunFns_Execute__initDefault(t *testing.T) {
FunctionPaths: []string{"foo"},
},
},
{
name: "explicit directories in mounts",
instance: RunFns{StorageMounts: []filters.StorageMount{{MountType: "volume", Src: "myvol", DstPath: "/local/"}}},
expected: RunFns{
Output: os.Stdout,
Input: os.Stdin,
NoFunctionsFromInput: getFalse(),
StorageMounts: []filters.StorageMount{{MountType: "volume", Src: "myvol", DstPath: "/local/"}},
},
},
}
for i := range tests {
tt := tests[i]