-
Notifications
You must be signed in to change notification settings - Fork 244
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
File sync for devfiles #2681
File sync for devfiles #2681
Conversation
Signed-off-by: John Collier <John.J.Collier@ibm.com>
Signed-off-by: John Collier <John.J.Collier@ibm.com>
Signed-off-by: John Collier <John.J.Collier@ibm.com>
Signed-off-by: John Collier <John.J.Collier@ibm.com>
Signed-off-by: John Collier <John.J.Collier@ibm.com>
Signed-off-by: John Collier <John.J.Collier@ibm.com>
Signed-off-by: John Collier <John.J.Collier@ibm.com>
Signed-off-by: John Collier <John.J.Collier@ibm.com>
/retest |
1 similar comment
/retest |
Codecov Report
@@ Coverage Diff @@
## master #2681 +/- ##
==========================================
- Coverage 43.92% 43.46% -0.46%
==========================================
Files 86 86
Lines 7757 7907 +150
==========================================
+ Hits 3407 3437 +30
- Misses 4015 4134 +119
- Partials 335 336 +1
Continue to review full report at Codecov.
|
Signed-off-by: John Collier <John.J.Collier@ibm.com>
Signed-off-by: John Collier <John.J.Collier@ibm.com>
Updated to include:
|
/retest |
@@ -98,6 +98,7 @@ jobs: | |||
- travis_wait make test-cmd-app | |||
- travis_wait make test-cmd-push | |||
- travis_wait make test-cmd-project | |||
- travis_wait make test-cmd-devfile-push |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1,
FYI - Travis job runs test on 3.11 cluster
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update the name: field accordingly. For example
name: "watch, storage, app, project, push and devfile push command integration tests"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, updated!
Makefile
Outdated
@@ -190,6 +190,11 @@ test-cmd-pref-config: | |||
test-cmd-push: | |||
ginkgo $(GINKGO_FLAGS) -focus="odo push command tests" tests/integration/ | |||
|
|||
# Run odo push command tests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Run odo push command tests
-> Run odo push devfile command tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, updated!
@@ -98,6 +98,7 @@ jobs: | |||
- travis_wait make test-cmd-app | |||
- travis_wait make test-cmd-push | |||
- travis_wait make test-cmd-project | |||
- travis_wait make test-cmd-devfile-push |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update the name: field accordingly. For example
name: "watch, storage, app, project, push and devfile push command integration tests"
context = helper.CreateNewContext() | ||
currentWorkingDirectory = helper.Getwd() | ||
helper.Chdir(context) | ||
os.Setenv("ODO_EXPERIMENTAL", "true") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do not use it like this because odo test spec (It) runs on two ginkgo test node in parallel, so it may cause race condition. To avoid such situation we have a env variable which can control preference path.
You can use
os.Setenv("GLOBALODOCONFIG", filepath.Join(context, "config.yaml"))
and in the spec i mean in the It block you can update the preference value. For example
helper.CmdShouldPass("odo", "preference", "set", "Experimental", "true")
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was wondering about the tests running in parallel and whether or not that would cause problems, good to know! I'll update my PR to include that.
helper.DeleteProject(project) | ||
helper.DeleteDir(context) | ||
helper.Chdir(currentWorkingDirectory) | ||
os.Unsetenv("ODO_EXPERIMENTAL") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As per https://github.com/openshift/odo/pull/2681/files#r388746348 use os.Unsetenv("GLOBALODOCONFIG")
instead.
output := helper.CmdShouldPass("odo", "push", "--devfile", "devfile.yaml", "--namespace", project) | ||
Expect(output).To(ContainSubstring("✓ Waiting for component to start")) | ||
Expect(output).To(ContainSubstring("✓ Push devfile component")) | ||
Expect(output).To(ContainSubstring("✓ Changes successfully pushed to component")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One assertion that confirms the devfile push is successful would be enough. So Expect(output).To(ContainSubstring("Changes successfully pushed to component"))
would be the proper fit imo. Do not to pass character like ✓
in assert as it may behave differently on terminal like PowerShell.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, right good point.
// This is run after every Spec (It) | ||
var _ = AfterEach(func() { | ||
helper.DeleteProject(project) | ||
helper.DeleteDir(context) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will throw error on windows platform. Rearranging the line with the below one will fix the problem
helper.Chdir(currentWorkingDirectory)
helper.DeleteDir(context)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh, that's a good point about Windows. Updated.
Expect(output).To(ContainSubstring("No file changes detected, skipping build")) | ||
helper.ReplaceString(filepath.Join(context, "server.js"), "node listening on", "UPDATED!") | ||
|
||
helper.CmdShouldPass("odo", "push", "--context", context+"/nodejs-ex", "--namespace", project) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use filepath.Join(context, "nodejs-ex")
instead of context+"/nodejs-ex"
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated, good catch!
Signed-off-by: John Collier <John.J.Collier@ibm.com>
@amitkrout Thanks for reviewing! I've addressed your review comments in a new commit. |
@kadel @rajivnathan The changes to support pushing to
As Rajiv notes, we'll probably need to do some more more work later to properly iron out support for multiple projects, but this is a fine start at the very least. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changes look good and verified that it syncs to the project folder now. Thanks for making the changes! Just one comment left
@@ -246,6 +248,22 @@ func (a Adapter) pushLocal(path string, files []string, delFiles []string, isFor | |||
s := log.Spinner("Syncing files to the component") | |||
defer s.End(false) | |||
|
|||
// If there's only one project defined in the devfile, sync to `/projects/project-name`, otherwise sync to /projects | |||
projects := a.Devfile.Data.GetProjects() | |||
fmt.Println(len(projects)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like an errant println slipped through
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was an errant debugging line that slipped through, removed.
Signed-off-by: John Collier <John.J.Collier@ibm.com>
/lgtm opened #2705 for follow up discussion on how best to handle multiple projects |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/lgtm
} | ||
|
||
// Push syncs source code from the user's disk to the component | ||
func (a Adapter) pushLocal(path string, files []string, delFiles []string, isForcePush bool, globExps []string) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this function is doing alot of things, lets try to extract certain portions to make unit testing better.
two suggestions would be be -
1 - https://github.com/openshift/odo/pull/2681/files#diff-825a1a88d75e789899c58e89a79eb767R254-R264 can be extracted into a function
2 - https://github.com/openshift/odo/pull/2681/files#diff-825a1a88d75e789899c58e89a79eb767R268-R277 can be extracted into a function
Also if the function has more then 5 args please try to create a struct to pass on data or consider moving it as part of the method's struct if it doesn't change through out the lifecycle of the struct.
e.g. path and ignoredFiles fields might not change throughout the life of Adapter
so maybe it can be places as part of the Adapter's struct? - this is just an example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@girishramnani I'm not sure moving those sections into separate functions would make unit testing easier - they both involve exec'ing into an already running container and manipulating the files that exist there, and that can't be mocked with the fake kube client.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should be able to mock it 🤔 ( I think kube/openshift would have a mock clientset for whatever function exec is using ) and it will definitely make unit testing pushLocal easier because when you would write test for pushLocal you would mock the https://github.com/openshift/odo/pull/2681/files#diff-825a1a88d75e789899c58e89a79eb767R254-R264 and https://github.com/openshift/odo/pull/2681/files#diff-825a1a88d75e789899c58e89a79eb767R268-R277 functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think what makes it different is that we're interacting with the kube client differently than we do for other resources. We're interacting directly with the rest client, not calling an existing exec
function, and I think that doesn't work well with the mock Kube client:
req := c.KubeClient.CoreV1().RESTClient().
Post().
Namespace(c.Namespace).
Resource("pods").
Name(podName).
SubResource("exec").
VersionedParams(&podExecOptions, scheme.ParameterCodec)
and
exec, err := remotecommand.NewSPDYExecutor(config, "POST", req.URL())
if err != nil {
return errors.Wrapf(err, "unable execute command via SPDY")
}
// initialize the transport of the standard shell streams
err = exec.Stream(remotecommand.StreamOptions{
Stdin: stdin,
Stdout: stdout,
Stderr: stderr,
Tty: tty,
})
(see https://github.com/openshift/odo/blob/master/pkg/kclient/pods.go#L93)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a compromise, rather than putting those sections with the exec into separate functions, what about moving everything before the exec into their own functions (maybe getCommandToCreateFolder
and getCommandToDelete
)? Then we could still write unit tests.
(Note when moving ExecCMDInContainer
over from occlient, I couldn't find any references in the existing odo code that had unit tests for it, or unit tests for functions that called it, so other parts of odo have had this problem too.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Note when moving
ExecCMDInContainer
over from occlient, I couldn't find any references in the existing odo code that had unit tests for it, or unit tests for functions that called it, so other parts of odo have had this problem too.)
and that is the reason that we should unit test these as we have the opportunity to re-write/replace this functionality
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a compromise, rather than putting those sections with the exec into separate functions, what about moving everything before the exec into their own functions (maybe
getCommandToCreateFolder
andgetCommandToDelete
)? Then we could still write unit tests.
I keep that upto you, I just wanted to break this function down into smaller pieces to make it more unit testable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@girishramnani I'll go with approach for now (and see if there are any other pieces we can break up). I'll also address your comment regarding the number of parameters.
Since unit tests for the ExecCmdInContainer
function will require more work / intevestigation / design, I'll address it as part of #2652 (which is also dealing with unit-testing exec as part of sync)
For the second push, I changed the environment variable in devfile. |
@kadel Yup, looks like it, since changing the environment variable would have restarted the deployment. |
Push command needs to detect this and wait, till the pod is ready again. |
/approve |
[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 |
Signed-off-by: John Collier <John.J.Collier@ibm.com>
Signed-off-by: John Collier <John.J.Collier@ibm.com>
Separated out pushLocal into 3 more functions and added unit tests for them. Going to refactor ExecCMDInContainer in a separate PR to make it:
I'll refactor both ExecCMDInContainer in kclient and occlient (as the syncclient interface requires clients to implement this function) |
Signed-off-by: John Collier <John.J.Collier@ibm.com>
Confirmed with @johnmcollier this sync support do incremental sync to only sync the changed file. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
/retest Please review the full test history for this PR and help us cut down flakes. |
1 similar comment
/retest Please review the full test history for this PR and help us cut down flakes. |
What type of PR is this?
/kind feature
What does does this PR do / why we need it:
This PR implements file syncing for devfile components, using the kubernetes client library. The push code is based on the existing push/sync code used in classic odo, with only a few small tweaks required.
Overall this PR does the following:
It updates the Devfile deployment code to create a shared emptyDir volume (called
odo-projects
) and mount it under/projects
in all of the devfile components that setmountSources: true
Creates a
Push()
function in the devfile adapters to handle file syncing--force
is set), it will sync all of files in the source directory using thesync
packageCreates a
DoesComponentExist()
function in the devfile adaptersutils.ComponentExists
Moved
IsEmpty
into thepkg/utils
package frompkg/component
Tests
Which issue(s) this PR fixes:
Fixes #2473, #2673
How to test changes / Special notes to the reviewer:
make
make test
to verify unit tests passodo push
verify that the deployment starts and files get synced