Merge pull request #193 from hoegaarden/simplify_dir_handling
Simplify directory handling
This commit is contained in:
commit
a6e056c00e
|
|
@ -34,13 +34,8 @@ type APIServer struct {
|
|||
// See the `SpecialPathFinder` example.
|
||||
ProcessStarter SimpleSessionStarter
|
||||
|
||||
// CertDirManager is responsible to provide a directory where the APIServer can find and store certain
|
||||
// certificates and keys, and to clean up after the APIServer was shut down
|
||||
// If not specified, a empty temporary directory is created and deleted.
|
||||
//
|
||||
// You can customise this if, e.g. you wish to pre-populate the directory with certs & keys from your central
|
||||
// secrets store. See the `CredHubCertDirManager` example.
|
||||
CertDirManager CertDirManager
|
||||
// CertDir is a struct holding a path to a certificate directory and a function to cleanup that directory.
|
||||
CertDir *Directory
|
||||
|
||||
// Etcd is an implementation of a ControlPlaneProcess and is responsible to run Etcd and provide its coordinates.
|
||||
// If not specified, a brand new instance of Etcd is brought up.
|
||||
|
|
@ -59,14 +54,6 @@ type APIServer struct {
|
|||
stdErr *gbytes.Buffer
|
||||
}
|
||||
|
||||
// CertDirManager knows how to manage a certificate directory for an APIServer.
|
||||
type CertDirManager interface {
|
||||
Create() (string, error)
|
||||
Destroy() error
|
||||
}
|
||||
|
||||
//go:generate counterfeiter . CertDirManager
|
||||
|
||||
// URL returns the URL APIServer is listening on. Clients can use this to connect to APIServer.
|
||||
func (s *APIServer) URL() (string, error) {
|
||||
if s.AddressManager == nil {
|
||||
|
|
@ -85,14 +72,12 @@ func (s *APIServer) URL() (string, error) {
|
|||
|
||||
// Start starts the apiserver, waits for it to come up, and returns an error, if occoured.
|
||||
func (s *APIServer) Start() error {
|
||||
s.ensureInitialized()
|
||||
|
||||
port, addr, err := s.AddressManager.Initialize()
|
||||
err := s.ensureInitialized()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
certDir, err := s.CertDirManager.Create()
|
||||
port, addr, err := s.AddressManager.Initialize()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -119,7 +104,7 @@ func (s *APIServer) Start() error {
|
|||
"--bind-address=0.0.0.0",
|
||||
"--storage-backend=etcd3",
|
||||
fmt.Sprintf("--etcd-servers=%s", etcdURLString),
|
||||
fmt.Sprintf("--cert-dir=%s", certDir),
|
||||
fmt.Sprintf("--cert-dir=%s", s.CertDir.Path),
|
||||
fmt.Sprintf("--insecure-port=%d", port),
|
||||
fmt.Sprintf("--insecure-bind-address=%s", addr),
|
||||
}
|
||||
|
|
@ -141,7 +126,7 @@ func (s *APIServer) Start() error {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *APIServer) ensureInitialized() {
|
||||
func (s *APIServer) ensureInitialized() error {
|
||||
if s.Path == "" {
|
||||
s.Path = DefaultBinPathFinder("kube-apiserver")
|
||||
}
|
||||
|
|
@ -153,8 +138,12 @@ func (s *APIServer) ensureInitialized() {
|
|||
return gexec.Start(command, out, err)
|
||||
}
|
||||
}
|
||||
if s.CertDirManager == nil {
|
||||
s.CertDirManager = NewTempDirManager()
|
||||
if s.CertDir == nil {
|
||||
certDir, err := newDirectory()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.CertDir = certDir
|
||||
}
|
||||
if s.Etcd == nil {
|
||||
s.Etcd = &Etcd{}
|
||||
|
|
@ -168,6 +157,8 @@ func (s *APIServer) ensureInitialized() {
|
|||
|
||||
s.stdOut = gbytes.NewBuffer()
|
||||
s.stdErr = gbytes.NewBuffer()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop stops this process gracefully, waits for its termination, and cleans up the cert directory.
|
||||
|
|
@ -191,7 +182,10 @@ func (s *APIServer) Stop() error {
|
|||
return err
|
||||
}
|
||||
|
||||
return s.CertDirManager.Destroy()
|
||||
if s.CertDir.Cleanup == nil {
|
||||
return nil
|
||||
}
|
||||
return s.CertDir.Cleanup()
|
||||
}
|
||||
|
||||
// ExitCode returns the exit code of the process, if it has exited. If it hasn't exited yet, ExitCode returns -1.
|
||||
|
|
|
|||
|
|
@ -20,16 +20,15 @@ import (
|
|||
var _ = Describe("Apiserver", func() {
|
||||
var (
|
||||
fakeSession *testfakes.FakeSimpleSession
|
||||
fakeCertDirManager *testfakes.FakeCertDirManager
|
||||
apiServer *APIServer
|
||||
fakeEtcdProcess *testfakes.FakeControlPlaneProcess
|
||||
fakeAddressManager *testfakes.FakeAddressManager
|
||||
apiServerStopper chan struct{}
|
||||
cleanupCallCount int
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
fakeSession = &testfakes.FakeSimpleSession{}
|
||||
fakeCertDirManager = &testfakes.FakeCertDirManager{}
|
||||
fakeEtcdProcess = &testfakes.FakeControlPlaneProcess{}
|
||||
fakeAddressManager = &testfakes.FakeAddressManager{}
|
||||
|
||||
|
|
@ -42,9 +41,15 @@ var _ = Describe("Apiserver", func() {
|
|||
apiServer = &APIServer{
|
||||
AddressManager: fakeAddressManager,
|
||||
Path: "/some/path/to/apiserver",
|
||||
CertDirManager: fakeCertDirManager,
|
||||
Etcd: fakeEtcdProcess,
|
||||
StopTimeout: 500 * time.Millisecond,
|
||||
CertDir: &Directory{
|
||||
Path: "/some/path/to/certdir",
|
||||
Cleanup: func() error {
|
||||
cleanupCallCount += 1
|
||||
return nil
|
||||
},
|
||||
},
|
||||
Etcd: fakeEtcdProcess,
|
||||
StopTimeout: 500 * time.Millisecond,
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -66,6 +71,7 @@ var _ = Describe("Apiserver", func() {
|
|||
Expect(command.Args).To(ContainElement("--insecure-port=1234"))
|
||||
Expect(command.Args).To(ContainElement("--insecure-bind-address=this.is.the.API.server"))
|
||||
Expect(command.Args).To(ContainElement("--etcd-servers=the etcd url"))
|
||||
Expect(command.Args).To(ContainElement("--cert-dir=/some/path/to/certdir"))
|
||||
Expect(command.Path).To(Equal("/some/path/to/apiserver"))
|
||||
fmt.Fprint(err, "Serving insecurely on this.is.the.API.server:1234")
|
||||
return fakeSession, nil
|
||||
|
|
@ -82,9 +88,6 @@ var _ = Describe("Apiserver", func() {
|
|||
By("...in turn calling the AddressManager")
|
||||
Expect(fakeAddressManager.InitializeCallCount()).To(Equal(1))
|
||||
|
||||
By("...in turn calling the CertDirManager")
|
||||
Expect(fakeCertDirManager.CreateCallCount()).To(Equal(1))
|
||||
|
||||
By("...getting the URL of Etcd")
|
||||
Expect(fakeEtcdProcess.URLCallCount()).To(Equal(1))
|
||||
|
||||
|
|
@ -92,23 +95,21 @@ var _ = Describe("Apiserver", func() {
|
|||
Expect(fakeSession.ExitCodeCallCount()).To(Equal(0))
|
||||
Expect(apiServer).NotTo(gexec.Exit())
|
||||
Expect(fakeSession.ExitCodeCallCount()).To(Equal(1))
|
||||
Expect(fakeCertDirManager.CreateCallCount()).To(Equal(1))
|
||||
|
||||
By("Stopping the API Server")
|
||||
Expect(apiServer.Stop()).To(Succeed())
|
||||
|
||||
Expect(fakeCertDirManager.DestroyCallCount()).To(Equal(1))
|
||||
Expect(cleanupCallCount).To(Equal(1))
|
||||
Expect(fakeEtcdProcess.StopCallCount()).To(Equal(1))
|
||||
Expect(apiServer).To(gexec.Exit(143))
|
||||
Expect(fakeSession.TerminateCallCount()).To(Equal(1))
|
||||
Expect(fakeSession.ExitCodeCallCount()).To(Equal(2))
|
||||
Expect(fakeCertDirManager.DestroyCallCount()).To(Equal(1))
|
||||
})
|
||||
})
|
||||
|
||||
Context("when the certificate directory cannot be destroyed", func() {
|
||||
It("propagates the error", func() {
|
||||
fakeCertDirManager.DestroyReturns(fmt.Errorf("destroy failed"))
|
||||
apiServer.CertDir.Cleanup = func() error { return fmt.Errorf("destroy failed") }
|
||||
fakeAddressManager.InitializeReturns(1234, "this.is.apiserver", nil)
|
||||
apiServer.ProcessStarter = func(Command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
|
||||
fmt.Fprint(err, "Serving insecurely on this.is.apiserver:1234")
|
||||
|
|
@ -121,6 +122,25 @@ var _ = Describe("Apiserver", func() {
|
|||
})
|
||||
})
|
||||
|
||||
Context("when there is on function to cleanup the certificate directory", func() {
|
||||
It("does not panic", func() {
|
||||
apiServer.CertDir.Cleanup = nil
|
||||
fakeAddressManager.InitializeReturns(1234, "this.is.apiserver", nil)
|
||||
apiServer.ProcessStarter = func(Command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
|
||||
fmt.Fprint(err, "Serving insecurely on this.is.apiserver:1234")
|
||||
return fakeSession, nil
|
||||
}
|
||||
|
||||
Expect(apiServer.Start()).To(Succeed())
|
||||
|
||||
var err error
|
||||
Expect(func() {
|
||||
err = apiServer.Stop()
|
||||
}).NotTo(Panic())
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
||||
Context("when etcd cannot be stopped", func() {
|
||||
It("propagates the error", func() {
|
||||
fakeEtcdProcess.StopReturns(fmt.Errorf("stopping etcd failed"))
|
||||
|
|
@ -184,22 +204,6 @@ var _ = Describe("Apiserver", func() {
|
|||
})
|
||||
})
|
||||
|
||||
Context("when the certificate directory cannot be created", func() {
|
||||
It("propagates the error, and does not start any process", func() {
|
||||
fakeCertDirManager.CreateReturnsOnCall(0, "", fmt.Errorf("Error on cert directory creation."))
|
||||
|
||||
apiServer.ProcessStarter = func(Command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
|
||||
Expect(true).To(BeFalse(),
|
||||
"the api server process starter shouldn't be called if creating the cert dir fails")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
err := apiServer.Start()
|
||||
Expect(err).To(MatchError(ContainSubstring("Error on cert directory creation.")))
|
||||
Expect(fakeEtcdProcess.StartCallCount()).To(Equal(0))
|
||||
})
|
||||
})
|
||||
|
||||
Context("when the address manager fails to get a new address", func() {
|
||||
It("propagates the error and does not start any process", func() {
|
||||
fakeAddressManager.InitializeReturns(0, "", fmt.Errorf("some error finding a free port"))
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
package test
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Directory holds a path to a directory and knows how to tear down / cleanup that directory
|
||||
type Directory struct {
|
||||
Path string
|
||||
Cleanup func() error
|
||||
}
|
||||
|
||||
func newDirectory() (*Directory, error) {
|
||||
path, err := ioutil.TempDir("", "k8s_test_framework_")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Directory{
|
||||
Path: path,
|
||||
Cleanup: func() error {
|
||||
return os.RemoveAll(path)
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package test
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("NewCertDir", func() {
|
||||
It("returns a valid CertDir struct", func() {
|
||||
certDir, err := newDirectory()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(certDir.Path).To(BeADirectory())
|
||||
Expect(certDir.Cleanup()).To(Succeed())
|
||||
Expect(certDir.Path).NotTo(BeAnExistingFile())
|
||||
})
|
||||
})
|
||||
|
|
@ -18,7 +18,7 @@ type Etcd struct {
|
|||
AddressManager AddressManager
|
||||
Path string
|
||||
ProcessStarter SimpleSessionStarter
|
||||
DataDirManager DataDirManager
|
||||
DataDir *Directory
|
||||
StopTimeout time.Duration
|
||||
StartTimeout time.Duration
|
||||
session SimpleSession
|
||||
|
|
@ -26,14 +26,6 @@ type Etcd struct {
|
|||
stdErr *gbytes.Buffer
|
||||
}
|
||||
|
||||
// DataDirManager knows how to manage a data directory to be used by Etcd.
|
||||
type DataDirManager interface {
|
||||
Create() (string, error)
|
||||
Destroy() error
|
||||
}
|
||||
|
||||
//go:generate counterfeiter . DataDirManager
|
||||
|
||||
// SimpleSession describes a CLI session. You can get output, the exit code, and you can terminate it.
|
||||
//
|
||||
// It is implemented by *gexec.Session.
|
||||
|
|
@ -67,14 +59,12 @@ func (e *Etcd) URL() (string, error) {
|
|||
|
||||
// Start starts the etcd, waits for it to come up, and returns an error, if occoured.
|
||||
func (e *Etcd) Start() error {
|
||||
e.ensureInitialized()
|
||||
|
||||
port, host, err := e.AddressManager.Initialize()
|
||||
err := e.ensureInitialized()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dataDir, err := e.DataDirManager.Create()
|
||||
port, host, err := e.AddressManager.Initialize()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -85,7 +75,7 @@ func (e *Etcd) Start() error {
|
|||
"--listen-peer-urls=http://localhost:0",
|
||||
fmt.Sprintf("--advertise-client-urls=%s", clientURL),
|
||||
fmt.Sprintf("--listen-client-urls=%s", clientURL),
|
||||
fmt.Sprintf("--data-dir=%s", dataDir),
|
||||
fmt.Sprintf("--data-dir=%s", e.DataDir.Path),
|
||||
}
|
||||
|
||||
detectedStart := e.stdErr.Detect(fmt.Sprintf(
|
||||
|
|
@ -106,7 +96,7 @@ func (e *Etcd) Start() error {
|
|||
}
|
||||
}
|
||||
|
||||
func (e *Etcd) ensureInitialized() {
|
||||
func (e *Etcd) ensureInitialized() error {
|
||||
if e.Path == "" {
|
||||
e.Path = DefaultBinPathFinder("etcd")
|
||||
}
|
||||
|
|
@ -119,8 +109,12 @@ func (e *Etcd) ensureInitialized() {
|
|||
return gexec.Start(command, out, err)
|
||||
}
|
||||
}
|
||||
if e.DataDirManager == nil {
|
||||
e.DataDirManager = NewTempDirManager()
|
||||
if e.DataDir == nil {
|
||||
dataDir, err := newDirectory()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
e.DataDir = dataDir
|
||||
}
|
||||
if e.StopTimeout == 0 {
|
||||
e.StopTimeout = 20 * time.Second
|
||||
|
|
@ -131,6 +125,8 @@ func (e *Etcd) ensureInitialized() {
|
|||
|
||||
e.stdOut = gbytes.NewBuffer()
|
||||
e.stdErr = gbytes.NewBuffer()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop stops this process gracefully, waits for its termination, and cleans up the data directory.
|
||||
|
|
@ -150,7 +146,10 @@ func (e *Etcd) Stop() error {
|
|||
return fmt.Errorf("timeout waiting for etcd to stop")
|
||||
}
|
||||
|
||||
return e.DataDirManager.Destroy()
|
||||
if e.DataDir.Cleanup == nil {
|
||||
return nil
|
||||
}
|
||||
return e.DataDir.Cleanup()
|
||||
}
|
||||
|
||||
// ExitCode returns the exit code of the process, if it has exited. If it hasn't exited yet, ExitCode returns -1.
|
||||
|
|
|
|||
|
|
@ -17,16 +17,15 @@ import (
|
|||
|
||||
var _ = Describe("Etcd", func() {
|
||||
var (
|
||||
fakeSession *testfakes.FakeSimpleSession
|
||||
fakeDataDirManager *testfakes.FakeDataDirManager
|
||||
fakeAddressManager *testfakes.FakeAddressManager
|
||||
etcd *Etcd
|
||||
etcdStopper chan struct{}
|
||||
fakeSession *testfakes.FakeSimpleSession
|
||||
fakeAddressManager *testfakes.FakeAddressManager
|
||||
etcd *Etcd
|
||||
etcdStopper chan struct{}
|
||||
dataDirCleanupCount int
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
fakeSession = &testfakes.FakeSimpleSession{}
|
||||
fakeDataDirManager = &testfakes.FakeDataDirManager{}
|
||||
fakeAddressManager = &testfakes.FakeAddressManager{}
|
||||
|
||||
etcdStopper = make(chan struct{}, 1)
|
||||
|
|
@ -38,8 +37,14 @@ var _ = Describe("Etcd", func() {
|
|||
etcd = &Etcd{
|
||||
AddressManager: fakeAddressManager,
|
||||
Path: "/path/to/some/etcd",
|
||||
DataDirManager: fakeDataDirManager,
|
||||
StopTimeout: 500 * time.Millisecond,
|
||||
DataDir: &Directory{
|
||||
Path: "/path/to/some/etcd",
|
||||
Cleanup: func() error {
|
||||
dataDirCleanupCount += 1
|
||||
return nil
|
||||
},
|
||||
},
|
||||
StopTimeout: 500 * time.Millisecond,
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -70,29 +75,26 @@ var _ = Describe("Etcd", func() {
|
|||
By("...in turn calling using the AddressManager")
|
||||
Expect(fakeAddressManager.InitializeCallCount()).To(Equal(1))
|
||||
|
||||
By("...in turn using the DataDirManager")
|
||||
Expect(fakeDataDirManager.CreateCallCount()).To(Equal(1))
|
||||
|
||||
Eventually(etcd).Should(gbytes.Say("Everything is dandy"))
|
||||
Expect(fakeSession.ExitCodeCallCount()).To(Equal(0))
|
||||
Expect(etcd).NotTo(gexec.Exit())
|
||||
Expect(fakeSession.ExitCodeCallCount()).To(Equal(1))
|
||||
Expect(fakeDataDirManager.CreateCallCount()).To(Equal(1))
|
||||
|
||||
By("Stopping the Etcd Server")
|
||||
Expect(etcd.Stop()).To(Succeed())
|
||||
|
||||
Expect(fakeDataDirManager.DestroyCallCount()).To(Equal(1))
|
||||
Expect(dataDirCleanupCount).To(Equal(1))
|
||||
Expect(etcd).To(gexec.Exit(143))
|
||||
Expect(fakeSession.TerminateCallCount()).To(Equal(1))
|
||||
Expect(fakeSession.ExitCodeCallCount()).To(Equal(2))
|
||||
Expect(fakeDataDirManager.DestroyCallCount()).To(Equal(1))
|
||||
})
|
||||
})
|
||||
|
||||
Context("when the data directory cannot be destroyed", func() {
|
||||
It("propagates the error", func() {
|
||||
fakeDataDirManager.DestroyReturns(fmt.Errorf("destroy failed"))
|
||||
etcd.DataDir.Cleanup = func() error {
|
||||
return fmt.Errorf("destroy failed")
|
||||
}
|
||||
fakeAddressManager.InitializeReturns(1234, "this.is.etcd", nil)
|
||||
etcd.ProcessStarter = func(Command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
|
||||
fmt.Fprint(err, "serving insecure client requests on this.is.etcd:1234")
|
||||
|
|
@ -105,18 +107,22 @@ var _ = Describe("Etcd", func() {
|
|||
})
|
||||
})
|
||||
|
||||
Context("when the data directory cannot be created", func() {
|
||||
It("propagates the error", func() {
|
||||
fakeDataDirManager.CreateReturnsOnCall(0, "", fmt.Errorf("Error on directory creation."))
|
||||
|
||||
Context("when there is no function to cleanup the data directory", func() {
|
||||
It("does not panic", func() {
|
||||
etcd.DataDir.Cleanup = nil
|
||||
fakeAddressManager.InitializeReturns(1234, "this.is.etcd", nil)
|
||||
etcd.ProcessStarter = func(Command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
|
||||
Expect(true).To(BeFalse(),
|
||||
"the etcd process starter shouldn't be called if getting a free port fails")
|
||||
return nil, nil
|
||||
fmt.Fprint(err, "serving insecure client requests on this.is.etcd:1234")
|
||||
return fakeSession, nil
|
||||
}
|
||||
|
||||
err := etcd.Start()
|
||||
Expect(err).To(MatchError(ContainSubstring("Error on directory creation.")))
|
||||
Expect(etcd.Start()).To(Succeed())
|
||||
|
||||
var err error
|
||||
Expect(func() {
|
||||
err = etcd.Stop()
|
||||
}).NotTo(Panic())
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
package test_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
. "k8s.io/kubectl/pkg/framework/test"
|
||||
)
|
||||
|
||||
func ExampleAPIServer_credHubCertDirManager() {
|
||||
apiServer := &APIServer{
|
||||
CertDirManager: NewCredHubCertDirManager(),
|
||||
}
|
||||
fmt.Println(apiServer)
|
||||
}
|
||||
|
||||
func credHubLoader(dir string, prefix string) (string, error) {
|
||||
tempDir, _ := ioutil.TempDir("/var/cache/kube/cert", prefix+"cred-hub-")
|
||||
loadCertsFromCredHub(tempDir)
|
||||
return tempDir, nil
|
||||
}
|
||||
|
||||
func credHubSaver(tempDir string) error {
|
||||
saveCertsToCredHub(tempDir)
|
||||
return os.RemoveAll(tempDir)
|
||||
}
|
||||
|
||||
func NewCredHubCertDirManager() *TempDirManager {
|
||||
return &TempDirManager{
|
||||
Maker: credHubLoader,
|
||||
Remover: credHubSaver,
|
||||
}
|
||||
}
|
||||
|
||||
func loadCertsFromCredHub(dir string) { /* to de implemented */ }
|
||||
func saveCertsToCredHub(dir string) { /* to be implemented */ }
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
package test
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
)
|
||||
|
||||
// TempDirMaker can create directories.
|
||||
//
|
||||
// It is implemented by `ioutil.TempDir`
|
||||
type TempDirMaker func(dir, prefix string) (name string, err error)
|
||||
|
||||
// TempDirRemover can delete directories
|
||||
//
|
||||
// It is implemented by `os.RemoveAll`
|
||||
type TempDirRemover func(dir string) error
|
||||
|
||||
// NewTempDirManager returns a new manager for creation and deleteion of temporary directories.
|
||||
func NewTempDirManager() *TempDirManager {
|
||||
return &TempDirManager{
|
||||
Maker: ioutil.TempDir,
|
||||
Remover: os.RemoveAll,
|
||||
}
|
||||
}
|
||||
|
||||
// TempDirManager knows when to call the directory maker and remover and keeps track of created directories.
|
||||
type TempDirManager struct {
|
||||
Maker TempDirMaker
|
||||
Remover TempDirRemover
|
||||
dir string
|
||||
}
|
||||
|
||||
// Create knows how to create a temporary directory and how to keep track of it.
|
||||
func (t *TempDirManager) Create() (string, error) {
|
||||
if t.dir == "" {
|
||||
dir, err := t.Maker("", "kube-test-framework-")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
t.dir = dir
|
||||
}
|
||||
return t.dir, nil
|
||||
}
|
||||
|
||||
// Destroy knows how to destroy a previously created directory.
|
||||
func (t *TempDirManager) Destroy() error {
|
||||
if t.dir != "" {
|
||||
err := t.Remover(t.dir)
|
||||
t.dir = ""
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,111 +0,0 @@
|
|||
package test_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
. "k8s.io/kubectl/pkg/framework/test"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("TempDirManager", func() {
|
||||
var (
|
||||
manager *TempDirManager
|
||||
removerError error
|
||||
createError error
|
||||
managedDirCount int
|
||||
separateDirCounter int
|
||||
)
|
||||
BeforeEach(func() {
|
||||
managedDirCount = 0
|
||||
separateDirCounter = 0
|
||||
createError = nil
|
||||
removerError = nil
|
||||
manager = NewTempDirManager()
|
||||
manager.Maker = func(dir, prefix string) (string, error) {
|
||||
managedDirCount += 1
|
||||
separateDirCounter += 1
|
||||
return fmt.Sprintf("%d-%s-%s", separateDirCounter, dir, prefix), createError
|
||||
}
|
||||
manager.Remover = func(dir string) error {
|
||||
managedDirCount -= 1
|
||||
return removerError
|
||||
}
|
||||
})
|
||||
|
||||
It("can creates and remove directories", func() {
|
||||
Expect(managedDirCount).To(Equal(0))
|
||||
manager.Create()
|
||||
Expect(managedDirCount).To(Equal(1))
|
||||
manager.Destroy()
|
||||
Expect(managedDirCount).To(Equal(0))
|
||||
})
|
||||
|
||||
Context("when I call Create() multiple times on the same manager", func() {
|
||||
It("returns the same directory every time", func() {
|
||||
var dir1, dir2 string
|
||||
var err error
|
||||
|
||||
Expect(managedDirCount).To(Equal(0))
|
||||
|
||||
dir1, err = manager.Create()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(managedDirCount).To(Equal(1))
|
||||
|
||||
dir2, err = manager.Create()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(managedDirCount).To(Equal(1))
|
||||
Expect(dir1).To(Equal(dir2))
|
||||
})
|
||||
|
||||
It("deletes the managed directory as soon as Destroy() is called even once", func() {
|
||||
var err error
|
||||
|
||||
Expect(managedDirCount).To(Equal(0))
|
||||
|
||||
_, err = manager.Create()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
_, err = manager.Create()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(managedDirCount).To(Equal(1))
|
||||
|
||||
manager.Destroy()
|
||||
Expect(managedDirCount).To(Equal(0))
|
||||
})
|
||||
})
|
||||
|
||||
Context("when I call Destroy() without calling create first", func() {
|
||||
It("does nothing", func() {
|
||||
Expect(managedDirCount).To(Equal(0))
|
||||
manager.Destroy()
|
||||
Expect(managedDirCount).To(Equal(0))
|
||||
})
|
||||
})
|
||||
|
||||
Context("when the remover returns an error", func() {
|
||||
JustBeforeEach(func() {
|
||||
removerError = fmt.Errorf("Error on removing dir")
|
||||
})
|
||||
It("handles that error depending on whether Create() has been called", func() {
|
||||
By("avoiding the error if Create() has not been called")
|
||||
err := manager.Destroy()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("propagating the error if Create() has been called")
|
||||
manager.Create()
|
||||
err = manager.Destroy()
|
||||
Expect(err).To(MatchError("Error on removing dir"))
|
||||
})
|
||||
})
|
||||
|
||||
Context("when the creater returns an error", func() {
|
||||
JustBeforeEach(func() {
|
||||
createError = fmt.Errorf("Error on creating dir")
|
||||
})
|
||||
It("bubbles up the error", func() {
|
||||
_, err := manager.Create()
|
||||
Expect(err).To(MatchError("Error on creating dir"))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -1,140 +0,0 @@
|
|||
// Code generated by counterfeiter. DO NOT EDIT.
|
||||
package testfakes
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
type FakeCertDirManager struct {
|
||||
CreateStub func() (string, error)
|
||||
createMutex sync.RWMutex
|
||||
createArgsForCall []struct{}
|
||||
createReturns struct {
|
||||
result1 string
|
||||
result2 error
|
||||
}
|
||||
createReturnsOnCall map[int]struct {
|
||||
result1 string
|
||||
result2 error
|
||||
}
|
||||
DestroyStub func() error
|
||||
destroyMutex sync.RWMutex
|
||||
destroyArgsForCall []struct{}
|
||||
destroyReturns struct {
|
||||
result1 error
|
||||
}
|
||||
destroyReturnsOnCall map[int]struct {
|
||||
result1 error
|
||||
}
|
||||
invocations map[string][][]interface{}
|
||||
invocationsMutex sync.RWMutex
|
||||
}
|
||||
|
||||
func (fake *FakeCertDirManager) Create() (string, error) {
|
||||
fake.createMutex.Lock()
|
||||
ret, specificReturn := fake.createReturnsOnCall[len(fake.createArgsForCall)]
|
||||
fake.createArgsForCall = append(fake.createArgsForCall, struct{}{})
|
||||
fake.recordInvocation("Create", []interface{}{})
|
||||
fake.createMutex.Unlock()
|
||||
if fake.CreateStub != nil {
|
||||
return fake.CreateStub()
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
return fake.createReturns.result1, fake.createReturns.result2
|
||||
}
|
||||
|
||||
func (fake *FakeCertDirManager) CreateCallCount() int {
|
||||
fake.createMutex.RLock()
|
||||
defer fake.createMutex.RUnlock()
|
||||
return len(fake.createArgsForCall)
|
||||
}
|
||||
|
||||
func (fake *FakeCertDirManager) CreateReturns(result1 string, result2 error) {
|
||||
fake.CreateStub = nil
|
||||
fake.createReturns = struct {
|
||||
result1 string
|
||||
result2 error
|
||||
}{result1, result2}
|
||||
}
|
||||
|
||||
func (fake *FakeCertDirManager) CreateReturnsOnCall(i int, result1 string, result2 error) {
|
||||
fake.CreateStub = nil
|
||||
if fake.createReturnsOnCall == nil {
|
||||
fake.createReturnsOnCall = make(map[int]struct {
|
||||
result1 string
|
||||
result2 error
|
||||
})
|
||||
}
|
||||
fake.createReturnsOnCall[i] = struct {
|
||||
result1 string
|
||||
result2 error
|
||||
}{result1, result2}
|
||||
}
|
||||
|
||||
func (fake *FakeCertDirManager) Destroy() error {
|
||||
fake.destroyMutex.Lock()
|
||||
ret, specificReturn := fake.destroyReturnsOnCall[len(fake.destroyArgsForCall)]
|
||||
fake.destroyArgsForCall = append(fake.destroyArgsForCall, struct{}{})
|
||||
fake.recordInvocation("Destroy", []interface{}{})
|
||||
fake.destroyMutex.Unlock()
|
||||
if fake.DestroyStub != nil {
|
||||
return fake.DestroyStub()
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1
|
||||
}
|
||||
return fake.destroyReturns.result1
|
||||
}
|
||||
|
||||
func (fake *FakeCertDirManager) DestroyCallCount() int {
|
||||
fake.destroyMutex.RLock()
|
||||
defer fake.destroyMutex.RUnlock()
|
||||
return len(fake.destroyArgsForCall)
|
||||
}
|
||||
|
||||
func (fake *FakeCertDirManager) DestroyReturns(result1 error) {
|
||||
fake.DestroyStub = nil
|
||||
fake.destroyReturns = struct {
|
||||
result1 error
|
||||
}{result1}
|
||||
}
|
||||
|
||||
func (fake *FakeCertDirManager) DestroyReturnsOnCall(i int, result1 error) {
|
||||
fake.DestroyStub = nil
|
||||
if fake.destroyReturnsOnCall == nil {
|
||||
fake.destroyReturnsOnCall = make(map[int]struct {
|
||||
result1 error
|
||||
})
|
||||
}
|
||||
fake.destroyReturnsOnCall[i] = struct {
|
||||
result1 error
|
||||
}{result1}
|
||||
}
|
||||
|
||||
func (fake *FakeCertDirManager) Invocations() map[string][][]interface{} {
|
||||
fake.invocationsMutex.RLock()
|
||||
defer fake.invocationsMutex.RUnlock()
|
||||
fake.createMutex.RLock()
|
||||
defer fake.createMutex.RUnlock()
|
||||
fake.destroyMutex.RLock()
|
||||
defer fake.destroyMutex.RUnlock()
|
||||
copiedInvocations := map[string][][]interface{}{}
|
||||
for key, value := range fake.invocations {
|
||||
copiedInvocations[key] = value
|
||||
}
|
||||
return copiedInvocations
|
||||
}
|
||||
|
||||
func (fake *FakeCertDirManager) recordInvocation(key string, args []interface{}) {
|
||||
fake.invocationsMutex.Lock()
|
||||
defer fake.invocationsMutex.Unlock()
|
||||
if fake.invocations == nil {
|
||||
fake.invocations = map[string][][]interface{}{}
|
||||
}
|
||||
if fake.invocations[key] == nil {
|
||||
fake.invocations[key] = [][]interface{}{}
|
||||
}
|
||||
fake.invocations[key] = append(fake.invocations[key], args)
|
||||
}
|
||||
|
|
@ -1,140 +0,0 @@
|
|||
// Code generated by counterfeiter. DO NOT EDIT.
|
||||
package testfakes
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
type FakeDataDirManager struct {
|
||||
CreateStub func() (string, error)
|
||||
createMutex sync.RWMutex
|
||||
createArgsForCall []struct{}
|
||||
createReturns struct {
|
||||
result1 string
|
||||
result2 error
|
||||
}
|
||||
createReturnsOnCall map[int]struct {
|
||||
result1 string
|
||||
result2 error
|
||||
}
|
||||
DestroyStub func() error
|
||||
destroyMutex sync.RWMutex
|
||||
destroyArgsForCall []struct{}
|
||||
destroyReturns struct {
|
||||
result1 error
|
||||
}
|
||||
destroyReturnsOnCall map[int]struct {
|
||||
result1 error
|
||||
}
|
||||
invocations map[string][][]interface{}
|
||||
invocationsMutex sync.RWMutex
|
||||
}
|
||||
|
||||
func (fake *FakeDataDirManager) Create() (string, error) {
|
||||
fake.createMutex.Lock()
|
||||
ret, specificReturn := fake.createReturnsOnCall[len(fake.createArgsForCall)]
|
||||
fake.createArgsForCall = append(fake.createArgsForCall, struct{}{})
|
||||
fake.recordInvocation("Create", []interface{}{})
|
||||
fake.createMutex.Unlock()
|
||||
if fake.CreateStub != nil {
|
||||
return fake.CreateStub()
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
return fake.createReturns.result1, fake.createReturns.result2
|
||||
}
|
||||
|
||||
func (fake *FakeDataDirManager) CreateCallCount() int {
|
||||
fake.createMutex.RLock()
|
||||
defer fake.createMutex.RUnlock()
|
||||
return len(fake.createArgsForCall)
|
||||
}
|
||||
|
||||
func (fake *FakeDataDirManager) CreateReturns(result1 string, result2 error) {
|
||||
fake.CreateStub = nil
|
||||
fake.createReturns = struct {
|
||||
result1 string
|
||||
result2 error
|
||||
}{result1, result2}
|
||||
}
|
||||
|
||||
func (fake *FakeDataDirManager) CreateReturnsOnCall(i int, result1 string, result2 error) {
|
||||
fake.CreateStub = nil
|
||||
if fake.createReturnsOnCall == nil {
|
||||
fake.createReturnsOnCall = make(map[int]struct {
|
||||
result1 string
|
||||
result2 error
|
||||
})
|
||||
}
|
||||
fake.createReturnsOnCall[i] = struct {
|
||||
result1 string
|
||||
result2 error
|
||||
}{result1, result2}
|
||||
}
|
||||
|
||||
func (fake *FakeDataDirManager) Destroy() error {
|
||||
fake.destroyMutex.Lock()
|
||||
ret, specificReturn := fake.destroyReturnsOnCall[len(fake.destroyArgsForCall)]
|
||||
fake.destroyArgsForCall = append(fake.destroyArgsForCall, struct{}{})
|
||||
fake.recordInvocation("Destroy", []interface{}{})
|
||||
fake.destroyMutex.Unlock()
|
||||
if fake.DestroyStub != nil {
|
||||
return fake.DestroyStub()
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1
|
||||
}
|
||||
return fake.destroyReturns.result1
|
||||
}
|
||||
|
||||
func (fake *FakeDataDirManager) DestroyCallCount() int {
|
||||
fake.destroyMutex.RLock()
|
||||
defer fake.destroyMutex.RUnlock()
|
||||
return len(fake.destroyArgsForCall)
|
||||
}
|
||||
|
||||
func (fake *FakeDataDirManager) DestroyReturns(result1 error) {
|
||||
fake.DestroyStub = nil
|
||||
fake.destroyReturns = struct {
|
||||
result1 error
|
||||
}{result1}
|
||||
}
|
||||
|
||||
func (fake *FakeDataDirManager) DestroyReturnsOnCall(i int, result1 error) {
|
||||
fake.DestroyStub = nil
|
||||
if fake.destroyReturnsOnCall == nil {
|
||||
fake.destroyReturnsOnCall = make(map[int]struct {
|
||||
result1 error
|
||||
})
|
||||
}
|
||||
fake.destroyReturnsOnCall[i] = struct {
|
||||
result1 error
|
||||
}{result1}
|
||||
}
|
||||
|
||||
func (fake *FakeDataDirManager) Invocations() map[string][][]interface{} {
|
||||
fake.invocationsMutex.RLock()
|
||||
defer fake.invocationsMutex.RUnlock()
|
||||
fake.createMutex.RLock()
|
||||
defer fake.createMutex.RUnlock()
|
||||
fake.destroyMutex.RLock()
|
||||
defer fake.destroyMutex.RUnlock()
|
||||
copiedInvocations := map[string][][]interface{}{}
|
||||
for key, value := range fake.invocations {
|
||||
copiedInvocations[key] = value
|
||||
}
|
||||
return copiedInvocations
|
||||
}
|
||||
|
||||
func (fake *FakeDataDirManager) recordInvocation(key string, args []interface{}) {
|
||||
fake.invocationsMutex.Lock()
|
||||
defer fake.invocationsMutex.Unlock()
|
||||
if fake.invocations == nil {
|
||||
fake.invocations = map[string][][]interface{}{}
|
||||
}
|
||||
if fake.invocations[key] == nil {
|
||||
fake.invocations[key] = [][]interface{}{}
|
||||
}
|
||||
fake.invocations[key] = append(fake.invocations[key], args)
|
||||
}
|
||||
Loading…
Reference in New Issue