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

Update OSFileWatcher to support symlinks #6172

Merged
merged 1 commit into from
Sep 18, 2020

Conversation

timmysilv
Copy link
Contributor

This PR modifies the wrapper around fsnotify's file Watcher to watch symlinks in a custom manner such that if the symlink itself triggers an event and the target has been updated since the last event, the event should be called.

What this PR does / why we need it:

This PR is needed because fsnotify auto-resolves symlinks internally. fsnotify/fsnotify#199 provides a little bit of context on their internals/decisions. The problem that results from this is that any watcher on a file which is a kubernetes secret will not detect updates, due to the symlink nature of them. Here's a glimpse of an example directory:

bash-5.0$ pwd
/run/secrets/webhook-certs
bash-5.0$ ls -l
total 0
lrwxrwxrwx    1 root     root            13 Sep  8 20:00 ca.crt -> ..data/ca.crt
lrwxrwxrwx    1 root     root            14 Sep  8 20:00 tls.crt -> ..data/tls.crt
lrwxrwxrwx    1 root     root            14 Sep  8 20:00 tls.key -> ..data/tls.key
bash-5.0$ ls -l ..data
lrwxrwxrwx    1 root     root            31 Sep  8 20:36 ..data -> ..2020_09_08_20_36_52.438041338

This change will allow for libraries that auto-update secrets (such as cert-manager for webhook server certs in the above example) to work without interference.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

How Has This Been Tested?

  • Added a unit test case that creates a symlink to file A, creates file B, deletes and replaces the symlink to point to file B instead, and ensures that the watcher raises the expected events.
  • Ran locally using the kind deploy manifest, deleted and recreated the ingress-validation-admission secret and confirmed that the validation webhook server reloaded the TLS files as expected.

Checklist:

  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I've read the CONTRIBUTION guide
  • I have added tests to cover my changes.
  • All new and existing tests passed.

@k8s-ci-robot
Copy link
Contributor

Thanks for your pull request. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

📝 Please follow instructions at https://git.k8s.io/community/CLA.md#the-contributor-license-agreement to sign the CLA.

It may take a couple minutes for the CLA signature to be fully registered; after that, please reply here with a new comment and we'll verify. Thanks.


Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here.

@k8s-ci-robot k8s-ci-robot added cncf-cla: no Indicates the PR's author has not signed the CNCF CLA. needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. labels Sep 15, 2020
@k8s-ci-robot
Copy link
Contributor

Hi @timmysilv. Thanks for your PR.

I'm waiting for a kubernetes member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@k8s-ci-robot k8s-ci-robot added the size/M Denotes a PR that changes 30-99 lines, ignoring generated files. label Sep 15, 2020
@aledbf
Copy link
Member

aledbf commented Sep 15, 2020

/ok-to-test

@k8s-ci-robot k8s-ci-robot added ok-to-test Indicates a non-member PR verified by an org member that is safe to test. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. and removed needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. cncf-cla: no Indicates the PR's author has not signed the CNCF CLA. labels Sep 15, 2020
@aledbf
Copy link
Member

aledbf commented Sep 15, 2020

/retest

@ElvinEfendi
Copy link
Member

The new test being introduced passes without the patch:

> ingress-nginx (master)$ ./build/run-in-docker.sh go test -v ./internal/watch/...
go: downloading github.com/fsnotify/fsnotify v1.4.9
go: downloading golang.org/x/sys v0.0.0-20200803210538-64077c9b5642
go: downloading k8s.io/klog/v2 v2.2.0
go: downloading github.com/pkg/errors v0.9.1
go: downloading github.com/go-logr/logr v0.2.0
=== RUN   TestFileWatcher
--- PASS: TestFileWatcher (0.51s)
=== RUN   TestFileWatcherWithSymlink
--- PASS: TestFileWatcherWithSymlink (0.03s)
PASS
ok  	k8s.io/ingress-nginx/internal/watch	(cached)

Can you fix that first? The test should simulate the bug this PR is fixing.

@timmysilv
Copy link
Contributor Author

Fixed the test to drill a little deeper, the same way k8s does with secrets. Thanks for catching that - maybe I should start writing tests before writing patches 🤔


if targetName != target1.Name() {
t.Fatalf("expected symlink to point to %v, not %v", target1.Name(), targetName)
}
Copy link
Member

Choose a reason for hiding this comment

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

I'd move this assertion right below line 96. By reading the code I thought this assertion somehow depends on what is happening between line 97 and 113, but seems like they are unrelated.

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 put it here because I wanted to wait until everything was set up (including the fileWatcher itself) to assert this, but I'm fine to move it to line 97. I should hope the creation of the watcher doesn't do anything weird :)

} else if finfo.Mode()&os.ModeSymlink != 0 {
if currentRealFile, err := filepath.EvalSymlinks(f.file); err == nil &&
currentRealFile != realFile {
f.onEvent()
Copy link
Member

@ElvinEfendi ElvinEfendi Sep 17, 2020

Choose a reason for hiding this comment

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

Do you not have to condition this on strings.HasSuffix(event.Name, file)? Why?

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 FileWatcher watches the entire directory (that's not new behaviour). Using the example in the PR description, the watcher will watch $dir/ca.crt, which is a symlink to $dir/..data/ca.crt, which is a symlink to $dir/..<dated_dir>/ca.crt. The CREATE event in $dir is not for a file called ca.crt (which would have the correct suffix), but for a directory called ..data which symlinks to the dated directory. However, the watcher should detect that the top-level symlink ($dir/ca.crt) now points to a different file, and trigger an event.
tl;dr when any file is created in the directory being watched, this FileWatcher should confirm if the symlink it was told to monitor has been updated somewhere within the directory (maybe deeper than 1 level).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

More details: this comment shows the internal order of events.

@ElvinEfendi
Copy link
Member

/test pull-ingress-nginx-test

@ElvinEfendi
Copy link
Member

/lgtm

@aledbf can you also take a look?

@k8s-ci-robot k8s-ci-robot added lgtm "Looks good to me", indicates that a PR is ready to be merged. approved Indicates a PR has been approved by an approver from all required OWNERS files. labels Sep 18, 2020
@ElvinEfendi
Copy link
Member

/hold until the second review

@k8s-ci-robot k8s-ci-robot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Sep 18, 2020
@aledbf
Copy link
Member

aledbf commented Sep 18, 2020

/lgtm
/hold cancel

@k8s-ci-robot k8s-ci-robot removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Sep 18, 2020
@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: aledbf, ElvinEfendi, timmysilv

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

@k8s-ci-robot k8s-ci-robot merged commit a6994be into kubernetes:master Sep 18, 2020
safanaj added a commit to safanaj/ingress-nginx that referenced this pull request Nov 15, 2020
This is cherry-picked from PR: kubernetes#6172 , to backport the feature to
auto-reload certs on k8s secrets changes to 0.35.0 , upstream merged
thin in 0.40.0.
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. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. lgtm "Looks good to me", indicates that a PR is ready to be merged. ok-to-test Indicates a non-member PR verified by an org member that is safe to test. size/M Denotes a PR that changes 30-99 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants