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

Docker Devfile Component Sync and Execution #2922

Merged
merged 17 commits into from
Apr 27, 2020

Conversation

maysunfaisal
Copy link
Contributor

@maysunfaisal maysunfaisal commented Apr 18, 2020

What type of PR is this?
/kind feature

What does does this PR do / why we need it:
This PR adds functionality to sync project and exec devfile commands for the docker component.

Specifically, this PR:

  • syncs the project to the project volume /projects for components that has mount sources true
  • integrates the docker exec client API for devfile command execution
  • refactors sync and exec code logic for its consumers
  • integration tests
  • unit tests

Which issue(s) this PR fixes:

#2717

How to test changes / Special notes to the reviewer:
odo preference set pushtarget docker
odo create <component>
odo push

@openshift-ci-robot openshift-ci-robot added do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. Required by Prow. kind/feature Categorizes issue as a feature request. For PRs, that means that the PR is the implementation labels Apr 18, 2020
Copy link
Member

@johnmcollier johnmcollier left a comment

Choose a reason for hiding this comment

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

Overall changes look good, left some preliminary comments based on your WIP changes for sync, I'll re-review once exec is in too.

Will you be adding unit tests to this PR?

@@ -83,3 +87,80 @@ func (dc *Client) GetContainerConfig(containerID string) (*container.Config, err

return containerJSON.Config, nil
}

//ExecCMDInContainer executes
func (dc *Client) ExecCMDInContainer(podName string, containerID string, cmd []string, stdout io.Writer, stderr io.Writer, stdin io.Reader, tty bool) error {
Copy link
Member

@johnmcollier johnmcollier Apr 20, 2020

Choose a reason for hiding this comment

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

I understand why podName string is an arg here (because of the SyncClient interface), but...

We should consider changing the SyncClient interface to take a function like ExecCMDInComponent instead of ExecCMDinContainer, then the client's function (either local or Kube) determines the container (local) or Pod (kube) that needs to be exec'd into. That way we don't need to pass in a (blank) pod name in the Docker client code.

What do you 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.

addressed in 162657e

AttachStdout: stdout != nil,
AttachStderr: stderr != nil,
Cmd: cmd,
// WorkingDir: "/tmp",
Copy link
Member

Choose a reason for hiding this comment

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

Can this commented out param be removed?

if err != nil {
return err
}
}
}
} else {
return recursiveTar(filepath.Dir(srcPath), filepath.Base(srcPath), filepath.Dir(destPath), filepath.Base(destPath), tarWriter, globExps)
return recursiveTar(filepath.Dir(srcPath), filepath.Base(srcPath), filepath.Dir(destPath), "", tarWriter, globExps)
Copy link
Member

Choose a reason for hiding this comment

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

Why did you change the param for destFile from filepath.Base(destPath) to ""?

Copy link
Contributor Author

@maysunfaisal maysunfaisal Apr 21, 2020

Choose a reason for hiding this comment

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

So odo 1 currently tar'd local projects files on your laptop/workspace to /projects in the container, but it did in a way that the archvie had a top level dir. For example, if your local laptop current dir was someproject where you ran odo push, then tar would create someproject/<files> and did a tar extract with command cmdArr := []string{"tar", "xf", "-", "-C", targetPath, "--strip", "1"} where strip was basically stripping this top level dir created during tar, so that inside the container, files would be in /projects

This was fine with kube exec api, but docker client api CopyToContainer does not handle this. The files are copied to /projects/someproject/<files> and would need to execute another command to handle this.

So instead of creating the destination tar in filepath.Base(destPath), we just do not specify a dir, and pass in "" for this reason and tar extract command has been updated to remove the strip option in kclient/occlient implementation

)

// New instantiantes a component adapter
func New(adapterContext common.AdapterContext, client SyncClient) Adapter {
Copy link
Member

Choose a reason for hiding this comment

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

What's the benefit of an adapter here over just adding functions to a SyncClient instance?

I'm fine with either approach here, just curious.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just thought it was cleaner, but yeah i can remove the adapter and perhaps make them functions like the other packages

if !podChanged && !parameters.ForceBuild && len(parameters.WatchFiles) == 0 && len(parameters.WatchDeletedFiles) == 0 {
absIgnoreRules := util.GetAbsGlobExps(parameters.Path, parameters.IgnoredFiles)

spinner := log.NewStatus(log.GetStdout())
Copy link
Member

Choose a reason for hiding this comment

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

Can you use log.Spinner() for the spinner here? To be consistent with the rest of odo. And pair that with a defer s.End(false)

// GetSupervisordVolumeLabels returns the label selectors used to retrieve the supervisord volume
func GetSupervisordVolumeLabels() map[string]string {
supervisordLabels := map[string]string{
"name": adaptersCommon.SupervisordVolumeName,
Copy link
Member

Choose a reason for hiding this comment

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

Since there be multiple versions of supervisord, could we make one of the labels the version of supervisord? So that old versions of the supervisord volume aren't accidentally used by odo

adaptersCommon.SupervisordMountPath,
}

s := log.Spinner("Pulling image " + image)
Copy link
Member

Choose a reason for hiding this comment

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

Maybe put this log behind a glog.v(3)? Don't think the user needs to see it by default

)
// Get a sync adapter. Check if project files have changed and sync accordingly
syncAdapter := sync.New(a.AdapterContext, &a.Client)
err = syncAdapter.CheckProjectFiles(parameters, pod.GetName(), containerName, podChanged, componentExists)
Copy link
Member

Choose a reason for hiding this comment

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

Can we change the name of CheckProjectFiles to be something more clear? Something like SyncFiles?

@maysunfaisal maysunfaisal marked this pull request as ready for review April 21, 2020 19:15
@maysunfaisal maysunfaisal changed the title {WIP} Docker Devfile Component Sync and Execution Docker Devfile Component Sync and Execution Apr 21, 2020
@openshift-ci-robot openshift-ci-robot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. Required by Prow. label Apr 21, 2020
@maysunfaisal maysunfaisal force-pushed the 2717-1 branch 2 times, most recently from 4a9f018 to 2aed578 Compare April 21, 2020 23:41
// if there are two commands, it is the optional build command and the mandatory run command, set buildRequired to true
buildRequired = true
} else {
return false, fmt.Errorf("error executing devfile commands - there should be at least 1 command or at most 2 commands, currently there are %v commands", len(pushDevfileCommands))
Copy link
Member

Choose a reason for hiding this comment

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

Will this error cause issues when we need to add support devfile init commands (or other commads) later for Docker? Would it be better to just set buildRequired = true if len(pushDevfileCommands) >= 2?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

dev init PR changed the logic, which i think is better(glancing at it). That will replace this..

@@ -36,6 +68,29 @@ func (a Adapter) Push(parameters common.PushParameters) (err error) {
return errors.Wrap(err, "unable to create or update component")
}

containers := utils.GetComponentContainers(a.Client, a.ComponentName)
// Find at least one pod with the source volume mounted, error out if none can be found
Copy link
Member

Choose a reason for hiding this comment

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

Change pod to container 😉

// Find at least one pod with the source volume mounted, error out if none can be found
containerID, err := getFirstContainerWithSourceVolume(containers)
if err != nil {
return errors.Wrapf(err, "error while retrieving container for component: %s", a.ComponentName)
Copy link
Member

Choose a reason for hiding this comment

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

Can you change the error message to be a little more clear that we couldn't find any volume that had the source volume mounted on it?

syncAdapter := sync.New(a.AdapterContext, &a.Client)
// podName is set to empty string on docker
// podChanged is set to false, since docker volume is always present even if container goes down
isPushRequired, err := syncAdapter.SyncFiles(parameters, "", containerID, false, componentExists)
Copy link
Member

Choose a reason for hiding this comment

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

SyncFiles takes in a number of params, could we merge them into a single struct like we did for the push params? Then we wouldn't have to explicitly set an empty podName for Docker. Thoughts?

Copy link
Member

Choose a reason for hiding this comment

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

Can you change isPushRequired to something else, since part of what SyncDoes is push the changes to the running container. Maybe something like buildRequired or execRequired?

common.AdapterContext
}

// SyncFiles checks whether files have changed in a project
Copy link
Member

Choose a reason for hiding this comment

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

The function description should be updated, as it doesn't just check if the files changed:

  • If files are passed in from watch, it syncs those files directly
  • Otherwise, it determines which files changed and then syncs them to the conainer

return supervisordLabels
}

// CreateAndInitSupervisordVolume creates the supervisord volume and initializes it with odo init
Copy link
Member

Choose a reason for hiding this comment

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

What do you mean by initializes it with odo init?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated to say supervisord bootstrap, i meant odo init repo earlier

}

var s *log.Status
if log.IsDebug() {
Copy link
Member

Choose a reason for hiding this comment

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

As an alternative, we can do if glog.V(4) { so that it shows up properly when users do odo push --v <level> (see https://github.com/openshift/odo/blob/master/pkg/lclient/images.go#L24)

Copy link
Contributor Author

@maysunfaisal maysunfaisal Apr 22, 2020

Choose a reason for hiding this comment

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

Hmm, think will stick with log.IsDebug() since it returns true for any -v > 0, then its not just bounded by -v 4

And we also use log.IsDebug() for showing build output from build command

Copy link
Member

Choose a reason for hiding this comment

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

Fair enough, works for me.

AddVolumeToComp(supervisordVolumeName, adaptersCommon.SupervisordMountPath, &hostConfig)

// Create the docker container
if log.IsDebug() {
Copy link
Member

Choose a reason for hiding this comment

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

See my other comment about using if glog.V(4)

err = a.execDevfile(pushDevfileCommands, componentExists, parameters.Show, pod.GetName(), pod.Spec.Containers)
if err != nil {
return err
if isPushRequired {
Copy link
Member

Choose a reason for hiding this comment

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

See other comment about renaming isPushRequired


err := ExecuteCommand(client, podName, containerName, cmdArr, show)
if err != nil {
s.End(false)
Copy link
Member

Choose a reason for hiding this comment

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

Because of the defer s.End(false), we don't need the s.End(false) here.

@kadel
Copy link
Member

kadel commented Apr 22, 2020

/refresh

@cdrage
Copy link
Member

cdrage commented Apr 22, 2020

@maysunfaisal Need to rebase / resolve conflicts. Looks like a lot of code I was going to review is either going to be overridden or changed due to the conflicts.

@maysunfaisal
Copy link
Contributor Author

@cdrage it would be nice if you could look at the sync code changes, they have changed a teeny bit and they dont have merge conflicts. This affects occlient, kclient and lcient - See review discussion - #2922 (comment)

@kadel
Copy link
Member

kadel commented Apr 23, 2020

/retest

@cdrage
Copy link
Member

cdrage commented Apr 23, 2020

@cdrage it would be nice if you could look at the sync code changes, they have changed a teeny bit and they dont have merge conflicts. This affects occlient, kclient and lcient - See review discussion - #2922 (comment)

There's still conflicts :( I don't think you pushed the changes?

@kadel
Copy link
Member

kadel commented Apr 23, 2020

I don't see any integrations test that would verify that the commands were actually executed, and the application was build and started :-/

@maysunfaisal
Copy link
Contributor Author

@cdage it was because the delete PR went in early this morning, was rebased with master until then!

@kadel I am working on the tests today since we didnt cut a driver yesterday

@kadel
Copy link
Member

kadel commented Apr 23, 2020

/approve

@openshift-ci-robot
Copy link
Collaborator

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: kadel

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci-robot openshift-ci-robot added approved Indicates a PR has been approved by an approver from all required OWNERS files. Required by Prow. needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. Required by Prow. labels Apr 23, 2020
@openshift-ci-robot openshift-ci-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. Required by Prow. label Apr 24, 2020
@openshift-bot
Copy link

/retest

Please review the full test history for this PR and help us cut down flakes.

@openshift-ci-robot openshift-ci-robot removed the lgtm Indicates that a PR is ready to be merged. Required by Prow. label Apr 27, 2020
Signed-off-by: Maysun J Faisal <maysun.j.faisal@ibm.com>
Signed-off-by: Maysun J Faisal <maysun.j.faisal@ibm.com>
Signed-off-by: Maysun J Faisal <maysun.j.faisal@ibm.com>
Signed-off-by: Maysun J Faisal <maysun.j.faisal@ibm.com>
Signed-off-by: Maysun J Faisal <maysun.j.faisal@ibm.com>
Signed-off-by: Maysun J Faisal <maysun.j.faisal@ibm.com>
Signed-off-by: Maysun J Faisal <maysun.j.faisal@ibm.com>
Signed-off-by: Maysun J Faisal <maysun.j.faisal@ibm.com>
Signed-off-by: Maysun J Faisal <maysun.j.faisal@ibm.com>
Signed-off-by: Maysun J Faisal <maysun.j.faisal@ibm.com>
Signed-off-by: Maysun J Faisal <maysun.j.faisal@ibm.com>
Signed-off-by: Maysun J Faisal <maysun.j.faisal@ibm.com>
Signed-off-by: Maysun J Faisal <maysun.j.faisal@ibm.com>
Signed-off-by: Maysun J Faisal <maysun.j.faisal@ibm.com>
Signed-off-by: Maysun J Faisal <maysun.j.faisal@ibm.com>
Signed-off-by: Maysun J Faisal <maysun.j.faisal@ibm.com>
Signed-off-by: Maysun J Faisal <maysun.j.faisal@ibm.com>
@cdrage
Copy link
Member

cdrage commented Apr 27, 2020

/lgtm

@openshift-ci-robot openshift-ci-robot added the lgtm Indicates that a PR is ready to be merged. Required by Prow. label Apr 27, 2020
@cdrage
Copy link
Member

cdrage commented Apr 27, 2020

/retest

@cdrage
Copy link
Member

cdrage commented Apr 27, 2020

Tests all pass but we're waiting for benchmarks to complete. So merging manually.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. Required by Prow. kind/feature Categorizes issue as a feature request. For PRs, that means that the PR is the implementation lgtm Indicates that a PR is ready to be merged. Required by Prow.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants