diff --git a/docs/user-guide.md b/docs/user-guide.md index fd397098..3ff992b2 100755 --- a/docs/user-guide.md +++ b/docs/user-guide.md @@ -163,6 +163,7 @@ The currently supported options are: | kompose.service.nodeport.port | port value (string) | | kompose.service.expose.tls-secret | secret name | | kompose.volume.size | kubernetes supported volume size | +| kompose.volume.storage-class-name | kubernetes supported volume storageClassName | | kompose.controller.type | deployment / daemonset / replicationcontroller | | kompose.image-pull-policy | kubernetes pods imagePullPolicy | | kompose.image-pull-secret | kubernetes secret name for imagePullSecrets | @@ -286,6 +287,21 @@ services: - db-data:/var/lib/postgresql/data ``` +- `kompose.volume.storage-class-name` defines the requests storage's class name in the PersistentVolumeClaim. + +For example: + +```yaml +version: '3' +services: + db: + image: postgres:10.1 + labels: + kompose.volume.storage-class-name: custom-storage-class-name + volumes: + - db-data:/var/lib/postgresql/data +``` + - `kompose.controller.type` defines which controller type should convert for this service For example: diff --git a/pkg/transformer/kubernetes/kubernetes.go b/pkg/transformer/kubernetes/kubernetes.go index 61f928e0..e7bf98cd 100644 --- a/pkg/transformer/kubernetes/kubernetes.go +++ b/pkg/transformer/kubernetes/kubernetes.go @@ -498,7 +498,7 @@ func (k *Kubernetes) CreateSecrets(komposeObject kobject.KomposeObject) ([]*api. } // CreatePVC initializes PersistentVolumeClaim -func (k *Kubernetes) CreatePVC(name string, mode string, size string, selectorValue string) (*api.PersistentVolumeClaim, error) { +func (k *Kubernetes) CreatePVC(name string, mode string, size string, selectorValue string, storageClassName string) (*api.PersistentVolumeClaim, error) { volSize, err := resource.ParseQuantity(size) if err != nil { return nil, errors.Wrap(err, "resource.ParseQuantity failed, Error parsing size") @@ -533,6 +533,11 @@ func (k *Kubernetes) CreatePVC(name string, mode string, size string, selectorVa } else { pvc.Spec.AccessModes = []api.PersistentVolumeAccessMode{api.ReadWriteOnce} } + + if len(storageClassName) > 0 { + pvc.Spec.StorageClassName = &storageClassName + } + return pvc, nil } @@ -844,6 +849,7 @@ func (k *Kubernetes) ConfigVolumes(name string, service kobject.ServiceConfig) ( } else { volsource = k.ConfigPVCVolumeSource(volumeName, readonly) if volume.VFrom == "" { + var storageClassName string defaultSize := PVCRequestSize if k.Opt.PVCRequestSize != "" { defaultSize = k.Opt.PVCRequestSize @@ -854,11 +860,13 @@ func (k *Kubernetes) ConfigVolumes(name string, service kobject.ServiceConfig) ( for key, value := range service.Labels { if key == "kompose.volume.size" { defaultSize = value + } else if key == "kompose.volume.storage-class-name" { + storageClassName = value } } } - createdPVC, err := k.CreatePVC(volumeName, volume.Mode, defaultSize, volume.SelectorValue) + createdPVC, err := k.CreatePVC(volumeName, volume.Mode, defaultSize, volume.SelectorValue, storageClassName) if err != nil { return nil, nil, nil, nil, errors.Wrap(err, "k.CreatePVC failed") diff --git a/pkg/transformer/kubernetes/kubernetes_test.go b/pkg/transformer/kubernetes/kubernetes_test.go index 0f2045ef..2e4dd520 100644 --- a/pkg/transformer/kubernetes/kubernetes_test.go +++ b/pkg/transformer/kubernetes/kubernetes_test.go @@ -697,3 +697,15 @@ func TestServiceAccountNameOnMultipleContainers(t *testing.T) { } } } + +func TestCreatePVC(t *testing.T) { + storageClassName := "custom-storage-class-name" + k := Kubernetes{} + result, err := k.CreatePVC("", "", PVCRequestSize, "", storageClassName) + if err != nil { + t.Error(errors.Wrap(err, "k.CreatePVC failed")) + } + if *result.Spec.StorageClassName != storageClassName { + t.Errorf("Expected %s returned, got %s", storageClassName, *result.Spec.StorageClassName) + } +} diff --git a/script/test/cmd/tests_new.sh b/script/test/cmd/tests_new.sh index 912a9814..0943a1bf 100755 --- a/script/test/cmd/tests_new.sh +++ b/script/test/cmd/tests_new.sh @@ -102,3 +102,7 @@ convert::check_artifacts_generated "kompose --build local -f $relative_path conv # Should warn when push image disabled cmd="kompose -f $KOMPOSE_ROOT/script/test/fixtures/buildconfig/docker-compose-build-no-image.yml -o $TEMP_DIR/output_file convert --build=local --push-image-registry=whatever" convert::expect_warning "$cmd" "Push image registry 'whatever' is specified but push image is disabled, skipping pushing to repository" + +#TEST the kompose.volume.storage-class-name label +convert::check_artifacts_generated "kompose -f $KOMPOSE_ROOT/script/test/fixtures/storage-class-name/docker-compose.yml convert -o $TEMP_DIR/output-k8s.json -j" "$TEMP_DIR/output-k8s.json" +convert::check_artifacts_generated "kompose --provider=openshift -f $KOMPOSE_ROOT/script/test/fixtures/storage-class-name/docker-compose.yml convert -o $TEMP_DIR/output-os.json -j" "$TEMP_DIR/output-os.json" diff --git a/script/test/fixtures/storage-class-name/docker-compose.yml b/script/test/fixtures/storage-class-name/docker-compose.yml new file mode 100644 index 00000000..acb3afdc --- /dev/null +++ b/script/test/fixtures/storage-class-name/docker-compose.yml @@ -0,0 +1,10 @@ +version: "3" +services: + nginx: + image: nginx + ports: + - "80:80" + labels: + kompose.volume.storage-class-name: custom-storage-class-name + volumes: + - /etc/nginx/nginx.conf diff --git a/script/test/fixtures/storage-class-name/output-k8s.json b/script/test/fixtures/storage-class-name/output-k8s.json new file mode 100644 index 00000000..1a5c01a3 --- /dev/null +++ b/script/test/fixtures/storage-class-name/output-k8s.json @@ -0,0 +1,131 @@ +{ + "kind": "List", + "apiVersion": "v1", + "metadata": {}, + "items": [ + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "nginx", + "creationTimestamp": null, + "labels": { + "io.kompose.service": "nginx" + }, + "annotations": { + "kompose.cmd": "%CMD%", + "kompose.version": "%VERSION%", + "kompose.volume.storage-class-name": "custom-storage-class-name" + } + }, + "spec": { + "ports": [ + { + "name": "80", + "port": 80, + "targetPort": 80 + } + ], + "selector": { + "io.kompose.service": "nginx" + } + }, + "status": { + "loadBalancer": {} + } + }, + { + "kind": "Deployment", + "apiVersion": "apps/v1", + "metadata": { + "name": "nginx", + "creationTimestamp": null, + "labels": { + "io.kompose.service": "nginx" + }, + "annotations": { + "kompose.cmd": "%CMD%", + "kompose.version": "%VERSION%", + "kompose.volume.storage-class-name": "custom-storage-class-name" + } + }, + "spec": { + "replicas": 1, + "selector": { + "matchLabels": { + "io.kompose.service": "nginx" + } + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "io.kompose.service": "nginx" + }, + "annotations": { + "kompose.cmd": "%CMD%", + "kompose.version": "%VERSION%", + "kompose.volume.storage-class-name": "custom-storage-class-name" + } + }, + "spec": { + "volumes": [ + { + "name": "nginx-claim0", + "persistentVolumeClaim": { + "claimName": "nginx-claim0" + } + } + ], + "containers": [ + { + "name": "nginx", + "image": "nginx", + "ports": [ + { + "containerPort": 80 + } + ], + "resources": {}, + "volumeMounts": [ + { + "name": "nginx-claim0", + "mountPath": "/etc/nginx/nginx.conf" + } + ] + } + ], + "restartPolicy": "Always" + } + }, + "strategy": { + "type": "Recreate" + } + }, + "status": {} + }, + { + "kind": "PersistentVolumeClaim", + "apiVersion": "v1", + "metadata": { + "name": "nginx-claim0", + "creationTimestamp": null, + "labels": { + "io.kompose.service": "nginx-claim0" + } + }, + "spec": { + "accessModes": [ + "ReadWriteOnce" + ], + "resources": { + "requests": { + "storage": "100Mi" + } + }, + "storageClassName": "custom-storage-class-name" + }, + "status": {} + } + ] +} diff --git a/script/test/fixtures/storage-class-name/output-os.json b/script/test/fixtures/storage-class-name/output-os.json new file mode 100644 index 00000000..74c61c1a --- /dev/null +++ b/script/test/fixtures/storage-class-name/output-os.json @@ -0,0 +1,181 @@ +{ + "kind": "List", + "apiVersion": "v1", + "metadata": {}, + "items": [ + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "nginx", + "creationTimestamp": null, + "labels": { + "io.kompose.service": "nginx" + }, + "annotations": { + "kompose.volume.storage-class-name": "custom-storage-class-name" + } + }, + "spec": { + "ports": [ + { + "name": "80", + "port": 80, + "targetPort": 80 + } + ], + "selector": { + "io.kompose.service": "nginx" + } + }, + "status": { + "loadBalancer": {} + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "nginx", + "creationTimestamp": null, + "labels": { + "io.kompose.service": "nginx" + }, + "annotations": { + "kompose.volume.storage-class-name": "custom-storage-class-name" + } + }, + "spec": { + "strategy": { + "type": "Recreate", + "resources": {} + }, + "triggers": [ + { + "type": "ConfigChange" + }, + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "nginx" + ], + "from": { + "kind": "ImageStreamTag", + "name": "nginx:latest" + } + } + } + ], + "replicas": 1, + "test": false, + "selector": { + "io.kompose.service": "nginx" + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "io.kompose.service": "nginx" + } + }, + "spec": { + "volumes": [ + { + "name": "nginx-claim0", + "persistentVolumeClaim": { + "claimName": "nginx-claim0" + } + } + ], + "containers": [ + { + "name": "nginx", + "image": " ", + "ports": [ + { + "containerPort": 80 + } + ], + "resources": {}, + "volumeMounts": [ + { + "name": "nginx-claim0", + "mountPath": "/etc/nginx/nginx.conf" + } + ] + } + ], + "restartPolicy": "Always" + } + } + }, + "status": { + "latestVersion": 0, + "observedGeneration": 0, + "replicas": 0, + "updatedReplicas": 0, + "availableReplicas": 0, + "unavailableReplicas": 0 + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "nginx", + "creationTimestamp": null, + "labels": { + "io.kompose.service": "nginx" + } + }, + "spec": { + "lookupPolicy": { + "local": false + }, + "tags": [ + { + "name": "", + "annotations": null, + "from": { + "kind": "DockerImage", + "name": "nginx" + }, + "generation": null, + "importPolicy": {}, + "referencePolicy": { + "type": "" + } + } + ] + }, + "status": { + "dockerImageRepository": "" + } + }, + { + "kind": "PersistentVolumeClaim", + "apiVersion": "v1", + "metadata": { + "name": "nginx-claim0", + "creationTimestamp": null, + "labels": { + "io.kompose.service": "nginx-claim0" + } + }, + "spec": { + "accessModes": [ + "ReadWriteOnce" + ], + "resources": { + "requests": { + "storage": "100Mi" + } + }, + "storageClassName": "custom-storage-class-name" + }, + "status": {} + } + ] +}