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

feat(import): copy folder contents #453

Merged
merged 2 commits into from
Nov 6, 2023
Merged

Conversation

rchincha
Copy link
Contributor

@rchincha rchincha commented Apr 3, 2023

What type of PR is this?

Which issue does this PR fix:

What does this PR do / Why do we need it:

If an issue # is not available please add repro steps and logs showing the issue:

Testing done on this change:

Automation added to e2e:

Will this break upgrades or downgrades?

Does this PR introduce any user-facing change?:


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@rchincha
Copy link
Contributor Author

rchincha commented Apr 3, 2023

layer1:
  from:
    type: docker
    url: docker://ubuntu:latest
  import:
    - path: folder1/
      dest: /
  run: |
    ls /

^ at least this works with this PR.

Evaluating what changes will be needed.

pkg/stacker/import.go Outdated Show resolved Hide resolved
Copy link
Contributor

@andaaron andaaron left a comment

Choose a reason for hiding this comment

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

LGTM

- path: stacker://fourth/folder4/subfolder5/
dest: /folder6/
- path: stacker://fourth/folder4/
dest: /folder7/
Copy link
Contributor

Choose a reason for hiding this comment

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

You are not testing an import of a 'stacker://' path without a trailing /.

You should add an import of:

 - path: stacker://fourth/folder4
   dest: /folder8

And then a test of

  [ -d /folder8/folder4 ]

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The issue is if folder8 is present then [ -d /folder8/folder4 ] will evaluate to true else false. But let me add this test and see what happens.

Copy link
Contributor

@smoser smoser Apr 19, 2023

Choose a reason for hiding this comment

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

oh, yuck.

i think that 'target' (the full path to the imported thing) should be fully determined by the 'dest', and not dependent on either the 'path' or the contents of the filesystem to which it is being imported. At worst, target should be determined by 'path' and 'dest', rather than 'path', 'dest' and 'target-filesystem'.

that just seems the least surprising behavior to me.

Copy link
Contributor Author

@rchincha rchincha Apr 19, 2023

Choose a reason for hiding this comment

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

The added test failed. The trailing slash determines what the behavior is - a trailing slash means contents, else the folder itself, applies for path and dest independently

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed the test.

Copy link
Contributor

Choose a reason for hiding this comment

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

a trailing slash means contents, else the folder itself,

that part makes sense.

applies for path and dest independently

that I don't understand.

Copy link
Contributor

@smoser smoser left a comment

Choose a reason for hiding this comment

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

As I understand from reading, a trailing '/' on a path that is a directory means that the contents of the provided path should be placed at 'dest', rather than inside of dest as 'dest/$(basename $path)'.

In #455 I suggested a different set of rules / behavior.

I think we should just not bother with the 'basename' behavior. It makes things much more clear.

The other behavior I think we should iron out is what happens when the 'dest' exists? Does it replace it or "fill" it?

@rchincha
Copy link
Contributor Author

rchincha commented Apr 28, 2023

Documenting docker behavior

https://docs.docker.com/engine/reference/builder/#add

Looks like source's file mode is detected at build time from the filesystem and the dest file mode is inferred from trailing slash (and hence copying file to dir is an error, etc)

[Source folder1 is a dir, Destination /folder1 doesn't exist]

  1. COPY folder1 /folder1
  • creates /folder1 and copies contents on folder1 -> /folder1
  1. COPY folder1/ /folder1
  • same as 1.
  1. COPY folder1 /folder1/
  • same as 1.
  1. COPY folder1/ /folder1/
  • same as 1.

[Source folder1 is a dir, Destination /folder1 already exists]

Same as above

[Source file1, Destination /file1 doesn't exist]

  1. COPY file1 /file1
  • creates a /file1 and copies file1 -> /file1
  1. COPY file1/ /file1
  • same as 1, although there is a trailing slash in source. So it is detecting mode type.
  1. COPY file1 /file1/
  • creates a /file1 folder and copies file1 -> /file1/file1
  1. COPY /file1/ /file1/
  • Same as 3.

[Source file1, Destination /file1 already exists]

  1. COPY file1 /file1
  • copies file1 -> file1
  1. COPY file1/ /file1
  • same as 1.
  1. COPY file1 /file1/
  • error since it expects file1/ to be a dir but we created it as a file first.
  1. COPY file1/ /file1/
  • same as 3

@smoser
Copy link
Contributor

smoser commented Apr 28, 2023

ADD definitely looks like a bunch of iterative behaviors. complete with behavior like:

If is a local tar archive in a recognized compression format (identity, gzip, bzip2 or xz) then it is unpacked as a directory.

Also, ADD seems to indicate add not "merge", and I really could be missing something in the long description of ADD's behavior, but I don't see what happens if I ADD directory 'foo' to /etc which already has 'foo'. Do the contents get merged somehow? As I can tell, that is "union" and I only see that term used wrt tar.

if you want to use that as your reference of something to implement, and then attempt to keep your implementation bug-for-bug in sync with docker's then I guess its fine. I just think that it is more complex than required.

@rchincha
Copy link
Contributor Author

rchincha commented Apr 28, 2023

ADD definitely looks like a bunch of iterative behaviors. complete with behavior like:

If is a local tar archive in a recognized compression format (identity, gzip, bzip2 or xz) then it is unpacked as a directory.

Also, ADD seems to indicate add not "merge", and I really could be missing something in the long description of ADD's behavior, but I don't see what happens if I ADD directory 'foo' to /etc which already has 'foo'. Do the contents get merged somehow? As I can tell, that is "union" and I only see that term used wrt tar.

if you want to use that as your reference of something to implement, and then attempt to keep your implementation bug-for-bug in sync with docker's then I guess its fine. I just think that it is more complex than required.

Not yet sure what stacker does in all these scenarios to compare/contrast yet.

Not one-on-one, but we are constrained by

  1. stacker cannot deviate too much from docker behavior, but it may not have to
  2. stacker imports (and copies) are set up as overlay-dirs, so filesystem grok'ing inside a container actually
  3. Also arguing for predictable behavior/rules just looking at stackerfile itself

@rchincha
Copy link
Contributor Author

but I don't see what happens if I ADD directory 'foo' to /etc which already has 'foo'. Do the contents get merged somehow? As I can tell, that is "union" and I only see that term used wrt tar.

It is a union. If the entry exists in the destination, it gets overwritten.

@codecov
Copy link

codecov bot commented Oct 10, 2023

Codecov Report

Merging #453 (91ed8ea) into main (c9428a0) will decrease coverage by 0.27%.
Report is 1 commits behind head on main.
The diff coverage is 0.00%.

@@            Coverage Diff             @@
##             main     #453      +/-   ##
==========================================
- Coverage   13.32%   13.05%   -0.27%     
==========================================
  Files          40       40              
  Lines        5863     5982     +119     
==========================================
  Hits          781      781              
- Misses       4954     5073     +119     
  Partials      128      128              
Files Coverage Δ
pkg/types/layer.go 50.27% <0.00%> (-0.42%) ⬇️
pkg/stacker/grab.go 0.00% <0.00%> (ø)
pkg/overlay/overlay-dirs.go 0.00% <0.00%> (ø)
pkg/stacker/import.go 0.00% <0.00%> (ø)

... and 1 file with indirect coverage changes

📣 Codecov offers a browser extension for seamless coverage viewing on GitHub. Try it in Chrome or Firefox today!

Copy link
Contributor

@smoser smoser left a comment

Choose a reason for hiding this comment

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

I would like to see some tests that cover 'overlay/existing' behavior.

build:
  from:
    type: oci
    url: $CENTOS_OCI
  run: |
    mkdir /output/
    echo "my-ls" > /output/ls
    touch /output/whizbang

assemble:
  from:
    type: oci
    url: $CENTOS_OCI
  import:
   - path: stacker://build/output/
     dest: /usr/
  run: |
    # existing file in /usr/bin should still be there
    [ -f /usr/bin/env ]

    # 'ls' should be updated.
    read line < /usr/bin/ls

    # whizbang should be present
    [ -f /usr/bin/whizbang ]

if idest == "" || source[len(source)-1:] != "/" {
err = c.Execute(append(bcmd, "cp", source, "/stacker/"+path.Base(source)), nil)
} else {
err = c.Execute(append(bcmd, "cp", source, "/stacker/"), nil)
Copy link
Contributor

Choose a reason for hiding this comment

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

it looks like you're not using 'idest' here at all.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

line #35
if idest == ""

@@ -48,7 +48,6 @@ EOF
}

@test "alpine" {
skip_slow_test
Copy link
Contributor

Choose a reason for hiding this comment

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

was this set of changes intentional?

Copy link
Contributor

Choose a reason for hiding this comment

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

was this set of changes intentional?

I see that this is part of "test - remove commit", so maybe remove that commit?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will do. Once I am convinced that stacker convert tests are not broken with these changes.

tag: first
run: |
mkdir -p /folder1
touch /folder1/file1
Copy link
Contributor

Choose a reason for hiding this comment

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

what does this do?
'second' comes from 'first', which has /folder1, so why create it (with mkdir) and then touch '/folder1/file1' which already exists. is that supposed to force a copy-up?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yup.

test/import.bats Show resolved Hide resolved
  import:
    - path: folder1/
      dest: /

vs

  import:
    - path: folder1
      dest: /

The former will copy the contents of folder1/ at / and the latter will
make and copy a /folder1 at /

Signed-off-by: Ramkumar Chinchani <rchincha@cisco.com>
import:
    - path: folder1
    dest: /folder2

will cause contents of folder1 to show up as and under /folder2

Signed-off-by: Ramkumar Chinchani <rchincha@cisco.com>
- path: folder1
dest: /folder2
run: |
[ -f /folder2/file1 ]
Copy link
Contributor

Choose a reason for hiding this comment

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

This is unfortunate. Using rsync semantics:

serge@jerom ~/delme$ mkdir folder1
serge@jerom ~/delme$ touch folder1/file1
serge@jerom ~/delme$ rsync -va folder1 folder2
sending incremental file list
created directory folder2
folder1/
folder1/file1

sent 138 bytes  received 69 bytes  414.00 bytes/sec
total size is 0  speedup is 0.00
serge@jerom ~/delme$ ls folder2
folder1

So let's make sure to have a very clear documentation for these semantics. Right now this testcase appears to be the clearest documentation.

Copy link
Contributor

Choose a reason for hiding this comment

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

Mind you I think I like the behavior you have here better. I'm surprised by what rsync is doing.

So I'm not asking you to change it. Just document it :)

@rchincha rchincha merged commit 533c4a6 into project-stacker:main Nov 6, 2023
7 of 9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants