Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handling Volume at early stage #626

Merged
merged 1 commit into from
Jul 27, 2017
Merged

Conversation

surajnarwade
Copy link
Contributor

It will resolve #544 as well as refactor volume handling part.

@k8s-ci-robot k8s-ci-robot added the cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. label May 30, 2017
@surajnarwade surajnarwade changed the title Handling Volume at early stage [WIP]Handling Volume at early stage May 30, 2017
@surajnarwade
Copy link
Contributor Author

this PR is still in WIP, so I will add tests later.
@cdrage @kadel @surajssd suggestions needed

@cdrage
Copy link
Member

cdrage commented Jun 13, 2017

@surajnarwade DaemonSet's aren't working. See: https://travis-ci.org/kubernetes-incubator/kompose/jobs/237507721#L398

Please get current tests to pass as well 😄 before we add new tests!

@surajnarwade surajnarwade force-pushed the handle_volume branch 2 times, most recently from a7a045b to ede9e62 Compare June 15, 2017 09:10
@surajssd
Copy link
Member

@surajnarwade please rebase

@surajnarwade surajnarwade force-pushed the handle_volume branch 2 times, most recently from 2695d87 to 56a1d60 Compare June 15, 2017 09:47
@surajnarwade
Copy link
Contributor Author

@surajssd @cdrage done with rebase and tests are green now, needs your review please :)

Copy link
Member

@cdrage cdrage left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple questions:

Do we have tests that already cover volumes (no need to add more unit tests?)

Is it possible copy some of the functionality of: https://github.com/docker/cli/blob/master/cli/compose/types/types.go#L243 in order to better reflect the libraries we're using for parsing? (May be diffifcult since you know.. we use libcompose for parsing v1v2 but docker/cli for v3)

@@ -92,6 +92,7 @@ type ServiceConfig struct {
MemLimit yaml.MemStringorInt `compose:"mem_limit" bundle:""`
TmpFs []string `compose:"tmpfs" bundle:""`
Dockerfile string `compose:"dockerfile" bundle:""`
Vols []Volumes `compose:"" bundle:""`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why Vols not Volumes?

Ideally we try and replicate / go by how they do it in libcompose :) See: https://github.com/docker/libcompose/blob/56b0613aac7d6d524d29dacb6b4221b5e4618d45/config/types.go#L70

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Volumes is already there https://github.com/kubernetes-incubator/kompose/blob/master/pkg/kobject/kobject.go#L70 for libcompose mapping, Vols is new struct for handling volumes.

Copy link
Member

@surajssd surajssd Jun 21, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is not a good idea to have both Volumes and Vols, please remove the []string and rename Vols to Volumes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I mean here is that []Volumes was added to get rid of []string ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

either I can swap names but we can't remove []string

Container string
Mode string
PVCName string
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like how many variables there are. It may be better copying how they do it within Docker/CLI so it's easier for us to be compatible with them. See: https://github.com/docker/cli/blob/master/cli/compose/types/types.go#L243 or perhaps even import and use the type.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cdrage I think this is needed for doing the whole volumesFrom thing reliably, since these will be resolved once to save computation later.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit confusing for me also. Maybe it would be nice to have some comments describing what some of the variables are for.

}

log.Debug("Volume name %s", volumeName)
//POC work ############################
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this comment

}
}
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to refactor this into it's own function (parseV1V2Volumes maybe?)


log.Debug("Volume name %s", volumeName)
//POC work ############################
for _, vol1 := range service.Vols {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please change vol1 variable name to something better, why not volume like before?

@surajnarwade
Copy link
Contributor Author

@cdrage , in order to answer your question regarding copying functionality from docker/cli, it can be used moreover for root level volumes key but not the thing that I am working on.

@cdrage
Copy link
Member

cdrage commented Jun 20, 2017

@surajnarwade I believe that you can use similar type.

See how we "copy" from libcompose in kobject.go in terms of ServiceConfig. This should be the same in terms of Volumes. It makes sense to try to keep the underlying code similar to upstream code.

What do you think @kadel ? Also regarding the many variables (see #626 (diff))

@surajnarwade surajnarwade changed the title [WIP]Handling Volume at early stage Handling Volume at early stage Jun 20, 2017
VFrom string
VolumeName string
Host string
Container string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this container mount Path ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean I am confused on MountPath vs Container ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mountpath can be host:container, hence container is that directory, for example, /abc


func handleVolume(svcName string, komposeObject kobject.KomposeObject) (volume []kobject.Volumes) {

if komposeObject.ServiceConfigs[svcName].VolumesFrom != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please put in lots of comments since it is hard to understand what is happening here

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After certain time even the programmer forgets why s/he wrote a piece of code! :-D

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comments not just here but in other parts of code


if komposeObject.ServiceConfigs[svcName].VolumesFrom != nil {
for _, depVol := range komposeObject.ServiceConfigs[svcName].VolumesFrom {

Copy link
Member

@surajssd surajssd Jun 21, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: s//n/

if komposeObject.ServiceConfigs[svcName].VolumesFrom != nil {
for _, depVol := range komposeObject.ServiceConfigs[svcName].VolumesFrom {

dVols := handleVolume(depVol, komposeObject)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also why this recursive call is made, needs an explanation

cVols = append(cVols, vol)
}
for _, cv := range cVols {
i, dv := getVol(cv, dVols)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit for general practices reason, s/i/ok ?

}
for _, cv := range cVols {
i, dv := getVol(cv, dVols)
if i == true {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also in a conditional where you are using boolean values no need to check it with booleans! essentially I mean s/i == true/i

dv.VFrom = dv.SvcName
volume = append(volume, dv)
}

Copy link
Member

@surajssd surajssd Jun 21, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: s//n/

}

}

Copy link
Member

@surajssd surajssd Jun 21, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: s//n/

MountPath: v,
}
volume = append(volume, vol)

Copy link
Member

@surajssd surajssd Jun 21, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: s//n/

return false
}

func getVol(tofind kobject.Volumes, dVols []kobject.Volumes) (bool, kobject.Volumes) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a generic function that searches array of volumes without any bias on what the array of volumes is so maybe name it better, like s/dVols/vols/

}

func checkvolpresent(tofind kobject.Volumes, cVols []kobject.Volumes) bool {
for _, cv := range cVols {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see a reason to have this function? Because getVol does similar thing but with inverted functionality can we use just one?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but getVol returns with extra Volumes struct

@surajnarwade
Copy link
Contributor Author

@cdrage , added new example

Copy link
Member

@cdrage cdrage left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the most part, this is all just renaming as well as moving things around, rather than refactoring.

Other than my one nitpick, LGTM.

@@ -17,4 +17,4 @@ services:
volumes:
- /www/public
volumes_from:
- web
- web
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added space I think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you've got to do git checkout script/test/fixtures/volume-mounts/volumes-from/docker-compose.yml to revert it back to normal. you've modified something here (newline maybe?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cdrage already resolved that change, so it's outdated now :)

@cdrage
Copy link
Member

cdrage commented Jul 17, 2017

Let's get @kadel 's quick approval then merge.

@cdrage
Copy link
Member

cdrage commented Jul 18, 2017

LGTM!

}

// for current volumes
func checkVolPresent(toFind kobject.Volumes, Vols []kobject.Volumes) bool {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be named checkVolNotPresent?

@kadel
Copy link
Member

kadel commented Jul 19, 2017

It will resolve #544 as well as refactor volume handling part.

this is not resolving #544 is it?
Isn't this meant to be just ground work for resolving #544 in the future?

@surajnarwade
Copy link
Contributor Author

@kadel , it will completely resolve #544

@kadel
Copy link
Member

kadel commented Jul 20, 2017

@kadel , it will completely resolve #544

I've tested that and result is still the same :-(

@surajnarwade
Copy link
Contributor Author

@kadel , problem is occuring due to permissions of volumes in the example mentioned in the issue.

@kadel
Copy link
Member

kadel commented Jul 20, 2017

@kadel , problem is occuring due to permissions of volumes in the example mentioned in the issue.

yeh, but it should work even with permissions.
If volumes are the same, only permissions differ that kompose has to set readOnly for ro volumes. Right now it puts duplicate volume there.

return nil, errors.Wrapf(err, "could not parse volume %q: %v", vn, err)
}
v.SvcName = svcName
v.MountPath = vn
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vn contains full path with permissions. like ./certs:/etc/nginx/certs:ro.
Shouldn't permission be stripped from it before saving it to MountPath?

It might solve problem with duplicate volumes with different permissions #626 (comment)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it can be quickly fixed like this: v.MountPath = fmt.Sprintf("%s:%s", v.Host, v.Container)

This made me realize that we don't even need v.MountPath as it can be always assembled from v.Host + v.Container and if needed v.Mode

@surajnarwade
Copy link
Contributor Author

@kadel , now it works

@kadel
Copy link
Member

kadel commented Jul 24, 2017

@surajnarwade getting closer ;-)

But permissions are still not correct:-(

letsencrypt Deployment has /etc/nginx/certs mounted as readOnly, even if docker-compose says rw

          - mountPath: /etc/nginx/certs
            name: proxy-claim2
            readOnly: true

@cdrage
Copy link
Member

cdrage commented Jul 24, 2017

@kadel Odd that this is not caught in a failing test, did @surajnarwade override it or is there actually no tests written for checking if the readOnly value has been enabled?

@kadel
Copy link
Member

kadel commented Jul 25, 2017

@kadel Odd that this is not caught in a failing test, did @surajnarwade override it or is there actually no tests written for checking if the readOnly value has been enabled?

It looks like there is no test case checking that :-(

There should be a test testing this case: One volume mounted to two different containers, in one container as ro, in other as rw

// for dependent volumes, returns true and the respective volume if mountpath are same
func getVol(toFind kobject.Volumes, Vols []kobject.Volumes) (bool, kobject.Volumes) {
for _, dv := range Vols {
if toFind.MountPath == dv.MountPath && toFind.Mode == dv.Mode {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

toFind.Mode == dv.Mode shouldn't be here. It bring back issue with duplicate volumeMounts

@kadel
Copy link
Member

kadel commented Jul 25, 2017

I've created simple test file:

version: "2"

services:
  foo:
    image: quay.io/tomkral/sleeper
    volumes:
     - ./data:/opt/data:ro
    
  bar:
    image: quay.io/tomkral/sleeper
    volumes_from: 
     - foo
    volumes:
     - ./data:/opt/data:rw

using this I've found weird bug
If I use this docker-compose file I Deploymnet for bar service doesn't have any volumeMounts.

Once I add second volume for bar service:

    volumes:
     - ./data:/opt/data:rw
     - /tmp

generated Deployment suddenly has both volumeMounts

@kadel
Copy link
Member

kadel commented Jul 25, 2017

I think that for this docker-compose

version: "2"

services:
  foo:
    image: quay.io/tomkral/sleeper
    volumes:
     - ./data:/opt/data:ro
    
  bar:
    image: quay.io/tomkral/sleeper
    volumes_from: 
     - foo
    volumes:
     - ./data:/opt/data:rw

correct output should be

apiVersion: v1
items:
- apiVersion: v1
  kind: Service
  metadata:
    creationTimestamp: null
    labels:
      io.kompose.service: bar
    name: bar
  spec:
    clusterIP: None
    ports:
    - name: headless
      port: 55555
      targetPort: 0
    selector:
      io.kompose.service: bar
  status:
    loadBalancer: {}
- apiVersion: v1
  kind: Service
  metadata:
    creationTimestamp: null
    labels:
      io.kompose.service: foo
    name: foo
  spec:
    clusterIP: None
    ports:
    - name: headless
      port: 55555
      targetPort: 0
    selector:
      io.kompose.service: foo
  status:
    loadBalancer: {}
- apiVersion: extensions/v1beta1
  kind: Deployment
  metadata:
    creationTimestamp: null
    labels:
      io.kompose.service: bar
    name: bar
  spec:
    replicas: 1
    strategy:
      type: Recreate
    template:
      metadata:
        creationTimestamp: null
        labels:
          io.kompose.service: bar
      spec:
        containers:
        - image: quay.io/tomkral/sleeper
          name: bar
          resources: {}
          volumeMounts:
          - mountPath: /opt/data
            name: foo-claim0
        restartPolicy: Always
        volumes:
        - name: foo-claim0
          persistentVolumeClaim:
            claimName: foo-claim0
  status: {}
- apiVersion: extensions/v1beta1
  kind: Deployment
  metadata:
    creationTimestamp: null
    labels:
      io.kompose.service: foo
    name: foo
  spec:
    replicas: 1
    strategy:
      type: Recreate
    template:
      metadata:
        creationTimestamp: null
        labels:
          io.kompose.service: foo
      spec:
        containers:
        - image: quay.io/tomkral/sleeper
          name: foo
          resources: {}
          volumeMounts:
          - mountPath: /opt/data
            name: foo-claim0
            readOnly: true
        restartPolicy: Always
        volumes:
        - name: foo-claim0
          persistentVolumeClaim:
            claimName: foo-claim0
            readOnly: true
  status: {}
- apiVersion: v1
  kind: PersistentVolumeClaim
  metadata:
    creationTimestamp: null
    labels:
      io.kompose.service: foo-claim0
    name: foo-claim0
  spec:
    accessModes:
    - ReadWriteOnce
    resources:
      requests:
        storage: 100Mi
  status: {}
kind: List
metadata: {}

To sum this up with the current state of this PR I see two issues.

  1. readOnly flag is set for volumeMount that has explicitly specified rw in docker-compose
  2. missing volume if there is only one volume with volume_from defined

It will resolve kubernetes#544 as well as refactor volume handling part.
@kadel
Copy link
Member

kadel commented Jul 27, 2017

It looks like all the problems were solved in the last update of this PR. 🎉

Grat work @surajnarwade ! 👍

@kadel kadel merged commit 3b2ef30 into kubernetes:master Jul 27, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. review needed
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Fatal error saying "/etc/nginx/certs": must be unique
5 participants