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

Flexvolume dynamic plugin discovery: Prober unit tests and basic e2e test. #51474

Merged
merged 3 commits into from
Sep 3, 2017

Conversation

verult
Copy link
Contributor

@verult verult commented Aug 28, 2017

What this PR does / why we need it: Tests for changes introduced in PR #50031 .
As part of the prober unit test, I mocked filesystem, filesystem watch, and Flexvolume plugin initialization.
Moved the filesystem event goroutine to watcher implementation.

Which issue this PR fixes (optional, in fixes #<issue number>(, fixes #<issue_number>, ...) format, will close that issue when PR gets merged): fixes #51147

Special notes for your reviewer:
First commit contains added functionality of the mock filesystem.
Second commit is the refactor for moving mock filesystem into a common util directory.
Third commit is the unit and e2e tests.

Release note:

NONE

/release-note-none
/sig storage
/assign @saad-ali @liggitt
/cc @mtaufen @chakri-nelluri @wongma7

@k8s-ci-robot k8s-ci-robot added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. sig/storage Categorizes an issue or PR as relevant to SIG Storage. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. labels Aug 28, 2017
@k8s-github-robot k8s-github-robot added the release-note-none Denotes a PR that doesn't merit a release note. label Aug 28, 2017
@verult verult force-pushed the ProberTest branch 3 times, most recently from 6b0f5f4 to 43f9872 Compare August 28, 2017 21:50
Copy link
Contributor

@wongma7 wongma7 left a comment

Choose a reason for hiding this comment

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

e2e test lgtm

@@ -0,0 +1,69 @@
/*
Copyright 2017 The Kubernetes Authors.
Copy link
Contributor

Choose a reason for hiding this comment

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

Move this to util/filesystem?

case err := <-prober.watcher.Errors:
glog.Errorf("Received an error from watcher: %s", err)
}
prober.watcher.Init(func(event fsnotify.Event) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Move this block to initWatcher?

}

// Creates a new filesystem watcher and adds watches for the plugin directory
// and all of its subdirectories.
func (prober *flexVolumeProber) initWatcher() error {
var err error
if prober.watcher, err = fsnotify.NewWatcher(); err != nil {
return fmt.Errorf("Error creating new watcher: %s", err)
if prober.watcher == nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need the nil check? Is initWatcher called more than once?

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 mock watcher is injected by creating an instance of flexVolumeProber with watcher already assigned. The nil check is to make sure the mock is not overridden.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ideally code shouldn't know whether or not it's working with a mock, doing so breaks the abstraction.
Can we always assign the watcher to the flexVolumeProber before we get here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can initialize the watcher in GetDynamicPluginProber() (the prober constructor, essentially), but it would have to handle the possibility of an error somehow. Returning the error from a constructor seems strange, and we shouldn't handle the error here. IMO it's better to call it in Init().

Or, it gets passed into the constructor as a dependency. I don't think the caller should worry about the details of underlying watcher implementation, especially when most of the time it's the default watcher anyway.

From the perspective of this code, it's doing a safety check to make sure watcher is always initialized. There isn't any code that depends on the watcher being a mock or not.

Copy link
Contributor

Choose a reason for hiding this comment

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

It's fine to return an error from the constructor, IMO.

@@ -213,8 +209,8 @@ func (prober *flexVolumeProber) initWatcher() error {

// Creates the plugin directory, if it doesn't already exist.
func (prober *flexVolumeProber) createPluginDir() error {
if _, err := os.Stat(prober.pluginDir); os.IsNotExist(err) {
err := os.MkdirAll(prober.pluginDir, 0755)
if _, err := prober.fs.Stat(prober.pluginDir); os.IsNotExist(err) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Log a warning & event from here that Flex volume plugin directory is not present. This is not supposed to happen.

Copy link
Contributor

Choose a reason for hiding this comment

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

@derekwaynecarr is this an appropriate place for an event or should they just log an error? IIRC events are really more appropriate for alerting on state changes, and it's probably better to just log an error here. Though I suppose you could consider "Recreating" a state change...

"fmt"
"github.com/fsnotify/fsnotify"
"github.com/stretchr/testify/assert"
utilfs "k8s.io/kubernetes/pkg/util/filesystem"
Copy link
Contributor

Choose a reason for hiding this comment

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

Fix package order

}

// Mock filesystem watcher
type mockWatcher struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

Move this to separate file?

Copy link
Contributor

Choose a reason for hiding this comment

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

+1. I'd also rename it to fakeWatcher, which is more conventional in our codebase

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ACK

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Keeping the file inside Flexvolume directory since fakes may look different depending on test.

@@ -21,6 +21,7 @@ import (
"time"

"github.com/spf13/afero"
"path/filepath"
Copy link
Contributor

Choose a reason for hiding this comment

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

Fix package order

@verult
Copy link
Contributor Author

verult commented Aug 29, 2017

fixes #51570

@verult verult force-pushed the ProberTest branch 2 times, most recently from 061138e to 9545c15 Compare August 30, 2017 18:34
func (DefaultFs) ReadFile(filename string) ([]byte, error) {
return ioutil.ReadFile(filename)
}

// TempFile via os.TempFile
// TempFile via ioutil.TempFile
Copy link
Contributor

Choose a reason for hiding this comment

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

thanks!

@@ -62,12 +63,12 @@ func (fs *fakeFs) Chtimes(name string, atime time.Time, mtime time.Time) error {
return fs.a.Fs.Chtimes(name, atime, mtime)
}

// ReadFile via afero.Fs.ReadFile
// ReadFile via afero.ReadFile
Copy link
Contributor

Choose a reason for hiding this comment

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

thanks!

func (fs *fakeFs) ReadFile(filename string) ([]byte, error) {
return fs.a.ReadFile(filename)
}

// TempFile via afero.Fs.TempFile
// TempFile via afero.TempFile
Copy link
Contributor

Choose a reason for hiding this comment

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

thanks!

"github.com/fsnotify/fsnotify"
)

// A callback-based filesystem watcher abstraction for fsnotify.
Copy link
Contributor

Choose a reason for hiding this comment

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

Comment should look like "FSWatcher..."

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ACK

// Add a filesystem path to watch
AddWatch(path string) error
}
type FSEventHandler func(event fsnotify.Event)
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add a godoc comment

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ACK

func TestProberMultipleEvents(t *testing.T) {
// Arrange
_, fs, watcher, prober := initTestEnvironment(t)
for i := 0; i < 5; i++ {
Copy link
Contributor

Choose a reason for hiding this comment

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

put the number of iterations in a variable so you can adjust more easily/calculate the number for your assertions w/o hardcoding

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ACK

}

// Mock filesystem watcher
type mockWatcher struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

+1. I'd also rename it to fakeWatcher, which is more conventional in our codebase

}

// Mock Flexvolume plugin
type mockPluginFactory struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

Rename this to fakePluginFactory and move to a separate file. We typically put the fakes in the same package as the real ones, but in a different file.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ACK

@@ -170,7 +174,7 @@ var _ = SIGDescribe("Flexvolumes [Disruptive] [Feature:FlexVolume]", func() {
driverInstallAs := driver + "-" + suffix

By(fmt.Sprintf("installing flexvolume %s on node %s as %s", path.Join(driverDir, driver), node.Name, driverInstallAs))
installFlex(&node, "k8s", driverInstallAs, path.Join(driverDir, driver))
installFlex(&node, "k8s", driverInstallAs, path.Join(driverDir, driver), true /* restart */)
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure I'm a fan of comments interleaved with code in the same line.

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 comment is mainly to clarify the parameter name, and is used in several places in the code base AFAIK.

driverInstallAs := driver + "-" + suffix

By(fmt.Sprintf("installing flexvolume %s on node %s as %s", path.Join(driverDir, driver), node.Name, driverInstallAs))
installFlex(&node, "k8s", driverInstallAs, path.Join(driverDir, driver), false /* restart */)
Copy link
Contributor

Choose a reason for hiding this comment

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

Again not sure I like the interleaved comments. And this one should probably read "skip restart", in any case.

@verult verult force-pushed the ProberTest branch 3 times, most recently from 952439b to 096f6c7 Compare August 31, 2017 22:40
Copy link
Contributor

@chakri-nelluri chakri-nelluri left a comment

Choose a reason for hiding this comment

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

One minor comment. Other than that looks good.

@@ -0,0 +1,53 @@
/*
Copy link
Contributor

Choose a reason for hiding this comment

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

Move this to util too?

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 decided to leave it in Flexvolume directory because fakes could be different depending on test.

Copy link
Contributor

Choose a reason for hiding this comment

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

ACK

@saad-ali
Copy link
Member

saad-ali commented Sep 1, 2017

/lgtm
/approve

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Sep 1, 2017
@saad-ali
Copy link
Member

saad-ali commented Sep 1, 2017

/test pull-kubernetes-e2e-gce-etcd3

@chakri-nelluri
Copy link
Contributor

Thanks @verult.
/lgtm

@chakri-nelluri
Copy link
Contributor

/approve

1 similar comment
@thockin
Copy link
Member

thockin commented Sep 1, 2017

/approve

@k8s-github-robot
Copy link

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: chakri-nelluri, saad-ali, thockin, verult

Associated issue: 50031

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

Needs approval from an approver in each of these OWNERS Files:

You can indicate your approval by writing /approve in a comment
You can cancel your approval by writing /approve cancel in a comment

@k8s-github-robot k8s-github-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Sep 1, 2017
@abgworrall abgworrall modified the milestone: v1.8 Sep 2, 2017
@k8s-github-robot
Copy link

Automatic merge from submit-queue (batch tested with PRs 51805, 51725, 50925, 51474, 51638)

@k8s-github-robot k8s-github-robot merged commit f07279a into kubernetes:master Sep 3, 2017
@verult verult deleted the ProberTest branch March 24, 2018 01:34
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. release-note-none Denotes a PR that doesn't merit a release note. sig/storage Categorizes an issue or PR as relevant to SIG Storage. size/XL Denotes a PR that changes 500-999 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Flexvolume Dynamic Plugin Discovery Testing
10 participants