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_path | kubernetes liveness httpGet path |
|
||||||
| kompose.service.healthcheck.liveness.http_get_port | kubernetes liveness httpGet port |
|
| kompose.service.healthcheck.liveness.http_get_port | kubernetes liveness httpGet port |
|
||||||
| kompose.service.healthcheck.liveness.tcp_port | kubernetes liveness tcpSocket port |
|
| kompose.service.healthcheck.liveness.tcp_port | kubernetes liveness tcpSocket port |
|
||||||
| kompose.service.external-traffic-policy | 'cluster', 'local', '' |
|
| kompose.service.external-traffic-policy | 'cluster', 'local', '' | |
|
||||||
| kompose.security-context.fsgroup | kubernetes pod security group fsgroup |
|
| 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.
|
**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:
|
labels:
|
||||||
kompose.security-context.fsgroup: 1001
|
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
|
## 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.
|
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"`
|
MemLimit types.UnitBytes `compose:"mem_limit"`
|
||||||
MemReservation types.UnitBytes `compose:""`
|
MemReservation types.UnitBytes `compose:""`
|
||||||
DeployMode string `compose:""`
|
DeployMode string `compose:""`
|
||||||
|
VolumeMountSubPath string `compose:"kompose.volume.subpath"`
|
||||||
// DeployLabels mapping to kubernetes labels
|
// DeployLabels mapping to kubernetes labels
|
||||||
DeployLabels map[string]string `compose:""`
|
DeployLabels map[string]string `compose:""`
|
||||||
DeployUpdateConfig types.UpdateConfig `compose:""`
|
DeployUpdateConfig types.UpdateConfig `compose:""`
|
||||||
|
|||||||
@ -719,6 +719,8 @@ func parseKomposeLabels(labels map[string]string, serviceConfig *kobject.Service
|
|||||||
serviceConfig.ImagePullSecret = value
|
serviceConfig.ImagePullSecret = value
|
||||||
case LabelImagePullPolicy:
|
case LabelImagePullPolicy:
|
||||||
serviceConfig.ImagePullPolicy = value
|
serviceConfig.ImagePullPolicy = value
|
||||||
|
case LabelContainerVolumeSubpath:
|
||||||
|
serviceConfig.VolumeMountSubPath = value
|
||||||
default:
|
default:
|
||||||
serviceConfig.Labels[key] = value
|
serviceConfig.Labels[key] = value
|
||||||
}
|
}
|
||||||
|
|||||||
@ -81,6 +81,9 @@ const (
|
|||||||
ServiceTypeHeadless = "Headless"
|
ServiceTypeHeadless = "Headless"
|
||||||
// LabelSecurityContextFsGroup defines the pod FsGroup
|
// LabelSecurityContextFsGroup defines the pod FsGroup
|
||||||
LabelSecurityContextFsGroup = "kompose.security-context.fsgroup"
|
LabelSecurityContextFsGroup = "kompose.security-context.fsgroup"
|
||||||
|
|
||||||
|
// LabelContainerVolumeSubpath defines the volume mount subpath inside container
|
||||||
|
LabelContainerVolumeSubpath = "kompose.volume.subpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// load environment variables from compose file
|
// load environment variables from compose file
|
||||||
|
|||||||
@ -887,6 +887,7 @@ func (k *Kubernetes) ConfigVolumes(name string, service kobject.ServiceConfig) (
|
|||||||
var PVCs []*api.PersistentVolumeClaim
|
var PVCs []*api.PersistentVolumeClaim
|
||||||
var cms []*api.ConfigMap
|
var cms []*api.ConfigMap
|
||||||
var volumeName string
|
var volumeName string
|
||||||
|
var subpathName string
|
||||||
|
|
||||||
// Set a var based on if the user wants to use empty volumes
|
// Set a var based on if the user wants to use empty volumes
|
||||||
// as opposed to persistent volumes and volume claims
|
// as opposed to persistent volumes and volume claims
|
||||||
@ -897,6 +898,10 @@ func (k *Kubernetes) ConfigVolumes(name string, service kobject.ServiceConfig) (
|
|||||||
useEmptyVolumes = true
|
useEmptyVolumes = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if subpath, ok := service.Labels["kompose.volume.subpath"]; ok {
|
||||||
|
subpathName = subpath
|
||||||
|
}
|
||||||
|
|
||||||
// Override volume type if specified in service labels.
|
// Override volume type if specified in service labels.
|
||||||
if vt, ok := service.Labels["kompose.volume.type"]; ok {
|
if vt, ok := service.Labels["kompose.volume.type"]; ok {
|
||||||
if _, okk := ValidVolumeSet[vt]; !okk {
|
if _, okk := ValidVolumeSet[vt]; !okk {
|
||||||
@ -993,6 +998,9 @@ func (k *Kubernetes) ConfigVolumes(name string, service kobject.ServiceConfig) (
|
|||||||
PVCs = append(PVCs, createdPVC)
|
PVCs = append(PVCs, createdPVC)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if subpathName != "" {
|
||||||
|
volMount.SubPath = subpathName
|
||||||
|
}
|
||||||
volumeMounts = append(volumeMounts, volMount)
|
volumeMounts = append(volumeMounts, volMount)
|
||||||
|
|
||||||
// create a new volume object using the volsource and add to list
|
// 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 {
|
func equalStringSlice(s1, s2 []string) bool {
|
||||||
if len(s1) != len(s2) {
|
if len(s1) != len(s2) {
|
||||||
return false
|
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_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"
|
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 "$k8s_cmd" "$k8s_output"
|
||||||
|
convert::expect_success_and_warning "$os_cmd" "$os_output"
|
||||||
|
|
||||||
# Test support for compose.yaml file
|
# 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"
|
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_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"
|
k8s_output="$KOMPOSE_ROOT/script/test/fixtures/compose-env-interpolation/output-k8s.yaml"
|
||||||
convert::expect_success "$k8s_cmd" "$k8s_output"
|
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