forked from LaconicNetwork/kompose
feat: support container volume mount subpath (#1628)
* feat: support volumes subpath Signed-off-by: AhmedGrati <ahmedgrati1999@gmail.com> * docs: add the kompose.volume.sub-path label Signed-off-by: AhmedGrati <ahmedgrati1999@gmail.com> * fix: update e2e tests Signed-off-by: AhmedGrati <ahmedgrati1999@gmail.com> --------- Signed-off-by: AhmedGrati <ahmedgrati1999@gmail.com>
This commit is contained in:
parent
d1e32e7d7d
commit
485cd2f163
@ -200,8 +200,9 @@ The currently supported options are:
|
||||
| kompose.service.healthcheck.liveness.http_get_path | kubernetes liveness httpGet path |
|
||||
| kompose.service.healthcheck.liveness.http_get_port | kubernetes liveness httpGet port |
|
||||
| kompose.service.healthcheck.liveness.tcp_port | kubernetes liveness tcpSocket port |
|
||||
| kompose.service.external-traffic-policy | 'cluster', 'local', '' |
|
||||
| kompose.security-context.fsgroup | kubernetes pod security group fsgroup |
|
||||
| kompose.service.external-traffic-policy | 'cluster', 'local', '' | |
|
||||
| kompose.security-context.fsgroup | kubernetes pod security group fsgroup | |
|
||||
| kompose.volume.sub-path | kubernetes volume mount subpath | |
|
||||
|
||||
**Note**: `kompose.service.type` label should be defined with `ports` only (except for headless service), otherwise `kompose` will fail.
|
||||
|
||||
@ -446,6 +447,20 @@ services:
|
||||
labels:
|
||||
kompose.security-context.fsgroup: 1001
|
||||
```
|
||||
|
||||
- `kompose.volume.sub-path` defines Kubernetes Container [VolumeMounts Subpath](https://kubernetes.io/docs/concepts/storage/volumes/#using-subpath).
|
||||
|
||||
For example:
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
pgadmin:
|
||||
image: postgres
|
||||
labels:
|
||||
kompose.volume.sub-path: pg-data
|
||||
```
|
||||
## Restart
|
||||
|
||||
If you want to create normal pods without controller you can use `restart` construct of docker-compose to define that. Follow table below to see what happens on the `restart` value.
|
||||
|
||||
@ -142,6 +142,7 @@ type ServiceConfig struct {
|
||||
MemLimit types.UnitBytes `compose:"mem_limit"`
|
||||
MemReservation types.UnitBytes `compose:""`
|
||||
DeployMode string `compose:""`
|
||||
VolumeMountSubPath string `compose:"kompose.volume.subpath"`
|
||||
// DeployLabels mapping to kubernetes labels
|
||||
DeployLabels map[string]string `compose:""`
|
||||
DeployUpdateConfig types.UpdateConfig `compose:""`
|
||||
|
||||
@ -719,6 +719,8 @@ func parseKomposeLabels(labels map[string]string, serviceConfig *kobject.Service
|
||||
serviceConfig.ImagePullSecret = value
|
||||
case LabelImagePullPolicy:
|
||||
serviceConfig.ImagePullPolicy = value
|
||||
case LabelContainerVolumeSubpath:
|
||||
serviceConfig.VolumeMountSubPath = value
|
||||
default:
|
||||
serviceConfig.Labels[key] = value
|
||||
}
|
||||
|
||||
@ -81,6 +81,9 @@ const (
|
||||
ServiceTypeHeadless = "Headless"
|
||||
// LabelSecurityContextFsGroup defines the pod FsGroup
|
||||
LabelSecurityContextFsGroup = "kompose.security-context.fsgroup"
|
||||
|
||||
// LabelContainerVolumeSubpath defines the volume mount subpath inside container
|
||||
LabelContainerVolumeSubpath = "kompose.volume.subpath"
|
||||
)
|
||||
|
||||
// load environment variables from compose file
|
||||
|
||||
@ -887,6 +887,7 @@ func (k *Kubernetes) ConfigVolumes(name string, service kobject.ServiceConfig) (
|
||||
var PVCs []*api.PersistentVolumeClaim
|
||||
var cms []*api.ConfigMap
|
||||
var volumeName string
|
||||
var subpathName string
|
||||
|
||||
// Set a var based on if the user wants to use empty volumes
|
||||
// as opposed to persistent volumes and volume claims
|
||||
@ -897,6 +898,10 @@ func (k *Kubernetes) ConfigVolumes(name string, service kobject.ServiceConfig) (
|
||||
useEmptyVolumes = true
|
||||
}
|
||||
|
||||
if subpath, ok := service.Labels["kompose.volume.subpath"]; ok {
|
||||
subpathName = subpath
|
||||
}
|
||||
|
||||
// Override volume type if specified in service labels.
|
||||
if vt, ok := service.Labels["kompose.volume.type"]; ok {
|
||||
if _, okk := ValidVolumeSet[vt]; !okk {
|
||||
@ -993,6 +998,9 @@ func (k *Kubernetes) ConfigVolumes(name string, service kobject.ServiceConfig) (
|
||||
PVCs = append(PVCs, createdPVC)
|
||||
}
|
||||
}
|
||||
if subpathName != "" {
|
||||
volMount.SubPath = subpathName
|
||||
}
|
||||
volumeMounts = append(volumeMounts, volMount)
|
||||
|
||||
// create a new volume object using the volsource and add to list
|
||||
|
||||
@ -104,6 +104,13 @@ func newServiceConfigWithExternalTrafficPolicy() kobject.ServiceConfig {
|
||||
}
|
||||
}
|
||||
|
||||
func newServiceConfigWithServiceVolumeMount(volumeMountSubPathValue string) kobject.ServiceConfig {
|
||||
return kobject.ServiceConfig{
|
||||
Name: "app",
|
||||
VolumeMountSubPath: volumeMountSubPathValue,
|
||||
}
|
||||
}
|
||||
|
||||
func equalStringSlice(s1, s2 []string) bool {
|
||||
if len(s1) != len(s2) {
|
||||
return false
|
||||
@ -1023,3 +1030,24 @@ func TestServiceExternalTrafficPolicy(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestVolumeMountSubPath(t *testing.T) {
|
||||
groupName := "pod_group"
|
||||
expectedSubPathValue := "test-subpath"
|
||||
komposeObject := kobject.KomposeObject{
|
||||
ServiceConfigs: map[string]kobject.ServiceConfig{"app": newServiceConfigWithServiceVolumeMount(expectedSubPathValue)},
|
||||
}
|
||||
k := Kubernetes{}
|
||||
objs, err := k.Transform(komposeObject, kobject.ConvertOptions{ServiceGroupMode: groupName})
|
||||
if err != nil {
|
||||
t.Error(errors.Wrap(err, "k.Transform failed"))
|
||||
}
|
||||
for _, obj := range objs {
|
||||
if deployment, ok := obj.(*appsv1.Deployment); ok {
|
||||
volMountSubPath := deployment.Spec.Template.Spec.Containers[0].VolumeMounts[0].SubPath
|
||||
if volMountSubPath != expectedSubPathValue {
|
||||
t.Errorf("Expected VolumeMount Subpath %v, got %v", expectedSubPathValue, volMountSubPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -247,6 +247,7 @@ k8s_output="$KOMPOSE_ROOT/script/test/fixtures/fsgroup/output-k8s.yaml"
|
||||
os_cmd="kompose --provider=openshift -f $KOMPOSE_ROOT/script/test/fixtures/fsgroup/docker-compose.yaml convert --stdout --with-kompose-annotation=false"
|
||||
os_output="$KOMPOSE_ROOT/script/test/fixtures/fsgroup/output-os.yaml"
|
||||
convert::expect_success_and_warning "$k8s_cmd" "$k8s_output"
|
||||
convert::expect_success_and_warning "$os_cmd" "$os_output"
|
||||
|
||||
# Test support for compose.yaml file
|
||||
k8s_cmd="kompose -f $KOMPOSE_ROOT/script/test/fixtures/compose-file-support/docker-compose.yaml convert --stdout --with-kompose-annotation=false"
|
||||
@ -257,3 +258,12 @@ convert::expect_success "$k8s_cmd" "$k8s_output"
|
||||
k8s_cmd="kompose -f $KOMPOSE_ROOT/script/test/fixtures/compose-env-interpolation/docker-compose.yaml convert --stdout --with-kompose-annotation=false"
|
||||
k8s_output="$KOMPOSE_ROOT/script/test/fixtures/compose-env-interpolation/output-k8s.yaml"
|
||||
convert::expect_success "$k8s_cmd" "$k8s_output"
|
||||
convert::expect_success "$os_cmd" "$os_output"
|
||||
|
||||
# Test support for subpath volume
|
||||
k8s_cmd="kompose -f $KOMPOSE_ROOT/script/test/fixtures/vols-subpath/docker-compose.yaml convert --stdout --with-kompose-annotation=false"
|
||||
k8s_output="$KOMPOSE_ROOT/script/test/fixtures/vols-subpath/output-k8s.yaml"
|
||||
os_cmd="kompose --provider=openshift -f $KOMPOSE_ROOT/script/test/fixtures/vols-subpath/docker-compose.yaml convert --stdout --with-kompose-annotation=false"
|
||||
os_output="$KOMPOSE_ROOT/script/test/fixtures/vols-subpath/output-os.yaml"
|
||||
convert::expect_success_and_warning "$k8s_cmd" "$k8s_output"
|
||||
convert::expect_success "$os_cmd" "$os_output"
|
||||
|
||||
15
script/test/fixtures/vols-subpath/docker-compose.yaml
vendored
Normal file
15
script/test/fixtures/vols-subpath/docker-compose.yaml
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
version: '3.8'
|
||||
volumes:
|
||||
postgres-data:
|
||||
|
||||
services:
|
||||
postgres:
|
||||
labels:
|
||||
kompose.volume.subpath: test
|
||||
image: postgres
|
||||
environment:
|
||||
POSTGRES_USER: dumb_postgres_user
|
||||
POSTGRES_PASSWORD: postgres_password
|
||||
POSTGRES_DB: dumb_db
|
||||
volumes:
|
||||
- postgres-data:/var/lib/postgresql/data
|
||||
80
script/test/fixtures/vols-subpath/output-k8s.yaml
vendored
Normal file
80
script/test/fixtures/vols-subpath/output-k8s.yaml
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
annotations:
|
||||
kompose.volume.subpath: test
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
io.kompose.service: postgres
|
||||
name: postgres
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
io.kompose.service: postgres
|
||||
strategy:
|
||||
type: Recreate
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
kompose.volume.subpath: test
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
io.kompose.network/vols-subpath-default: "true"
|
||||
io.kompose.service: postgres
|
||||
spec:
|
||||
containers:
|
||||
- env:
|
||||
- name: POSTGRES_DB
|
||||
value: dumb_db
|
||||
- name: POSTGRES_PASSWORD
|
||||
value: postgres_password
|
||||
- name: POSTGRES_USER
|
||||
value: dumb_postgres_user
|
||||
image: postgres
|
||||
name: postgres
|
||||
resources: {}
|
||||
volumeMounts:
|
||||
- mountPath: /var/lib/postgresql/data
|
||||
name: postgres-data
|
||||
subPath: test
|
||||
restartPolicy: Always
|
||||
volumes:
|
||||
- name: postgres-data
|
||||
persistentVolumeClaim:
|
||||
claimName: postgres-data
|
||||
status: {}
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
io.kompose.service: postgres-data
|
||||
name: postgres-data
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 100Mi
|
||||
status: {}
|
||||
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: vols-subpath-default
|
||||
spec:
|
||||
ingress:
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
io.kompose.network/vols-subpath-default: "true"
|
||||
podSelector:
|
||||
matchLabels:
|
||||
io.kompose.network/vols-subpath-default: "true"
|
||||
|
||||
103
script/test/fixtures/vols-subpath/output-os.yaml
vendored
Normal file
103
script/test/fixtures/vols-subpath/output-os.yaml
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
---
|
||||
apiVersion: apps.openshift.io/v1
|
||||
kind: DeploymentConfig
|
||||
metadata:
|
||||
annotations:
|
||||
kompose.volume.subpath: test
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
io.kompose.service: postgres
|
||||
name: postgres
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
io.kompose.service: postgres
|
||||
strategy:
|
||||
resources: {}
|
||||
type: Recreate
|
||||
template:
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
io.kompose.network/vols-subpath-default: "true"
|
||||
io.kompose.service: postgres
|
||||
spec:
|
||||
containers:
|
||||
- env:
|
||||
- name: POSTGRES_DB
|
||||
value: dumb_db
|
||||
- name: POSTGRES_PASSWORD
|
||||
value: postgres_password
|
||||
- name: POSTGRES_USER
|
||||
value: dumb_postgres_user
|
||||
image: ' '
|
||||
name: postgres
|
||||
resources: {}
|
||||
volumeMounts:
|
||||
- mountPath: /var/lib/postgresql/data
|
||||
name: postgres-data
|
||||
subPath: test
|
||||
restartPolicy: Always
|
||||
volumes:
|
||||
- name: postgres-data
|
||||
persistentVolumeClaim:
|
||||
claimName: postgres-data
|
||||
test: false
|
||||
triggers:
|
||||
- type: ConfigChange
|
||||
- imageChangeParams:
|
||||
automatic: true
|
||||
containerNames:
|
||||
- postgres
|
||||
from:
|
||||
kind: ImageStreamTag
|
||||
name: postgres:latest
|
||||
type: ImageChange
|
||||
status:
|
||||
availableReplicas: 0
|
||||
latestVersion: 0
|
||||
observedGeneration: 0
|
||||
replicas: 0
|
||||
unavailableReplicas: 0
|
||||
updatedReplicas: 0
|
||||
|
||||
---
|
||||
apiVersion: image.openshift.io/v1
|
||||
kind: ImageStream
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
io.kompose.service: postgres
|
||||
name: postgres
|
||||
spec:
|
||||
lookupPolicy:
|
||||
local: false
|
||||
tags:
|
||||
- annotations: null
|
||||
from:
|
||||
kind: DockerImage
|
||||
name: postgres
|
||||
generation: null
|
||||
importPolicy: {}
|
||||
name: latest
|
||||
referencePolicy:
|
||||
type: ""
|
||||
status:
|
||||
dockerImageRepository: ""
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
io.kompose.service: postgres-data
|
||||
name: postgres-data
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 100Mi
|
||||
status: {}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user