Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
24664f1
HTTPS Termination
Jul 6, 2022
e33be3a
Add nolint for test certs
Jul 12, 2022
514c63f
Another nolint
Jul 12, 2022
79b1daa
Last nolint
Jul 12, 2022
23f91c8
Lint warning fixes
Jul 12, 2022
62fdc19
Add event loop config object
Jul 14, 2022
365abb3
Const block
Jul 14, 2022
209288d
Add listener file to state package
Jul 14, 2022
fa85921
Fix secret filepath
Jul 14, 2022
8da6df2
Remove ignored namespaces
Jul 14, 2022
374a6ec
Fix len comparison
Jul 14, 2022
d4bcc0a
Indent if/else/end block in template
Jul 14, 2022
e8a5194
rules -> rulesPerHost
Jul 14, 2022
643129b
secretCache -> secretStore
Jul 14, 2022
1f1bdbf
SecretMemoryManager -> SecretDiskMemoryManager
Jul 14, 2022
ed16702
store -> request
Jul 14, 2022
5a9c672
Do not use default server secret
Jul 14, 2022
57a81dd
Fix test httproute names
Jul 18, 2022
64b8222
Don't configure invalid listeners
Jul 18, 2022
4b6b9ad
collision -> collisions
Jul 18, 2022
bfb6c7b
validateHTTPSListener
Jul 18, 2022
8bfd551
Fix up secrets tests and rename WriteAllStoredSecrets to WriteAllRequ…
Jul 18, 2022
7c34024
Generate default http server
Jul 18, 2022
445974e
HTTPServer -> VirtualServer and HTTPSServers -> SSLServers
Jul 18, 2022
3d1d472
Fix missing semicolon
Jul 19, 2022
84adfd0
Change ns of gateway in example
Jul 19, 2022
623f125
Add gateways to each example
Jul 19, 2022
f2b6cbe
Standardize on implementation package and add test suite files
Jul 19, 2022
1405fc0
Fix linting error
Jul 19, 2022
97a4921
Fix some typos
Jul 19, 2022
02fde36
Add FileManager interface to unit test file i/o
Jul 21, 2022
6f8a3dc
Move listener tests into listener_test.go
Jul 21, 2022
a8e4a54
Remove namespace from example resources
Jul 21, 2022
08a84db
Update capacity
Jul 21, 2022
d05d2c1
Add fixme
Jul 21, 2022
67958f6
Add doc string
Jul 21, 2022
2909f0e
Fix typo
Jul 21, 2022
9eb07ec
Add fixme for concurrency question
Jul 21, 2022
37571b6
Move file i/o tests under secret disk memory manager describe
Jul 25, 2022
5070b28
Use impl in tests
Jul 25, 2022
57472ba
Rewrite error tests as table
Jul 25, 2022
530249e
Fix template spacing
Jul 27, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions internal/state/file_manager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package state

import (
"io/fs"
"io/ioutil"
"os"
)

type stdLibFileManager struct{}

func newStdLibFileManager() *stdLibFileManager {
return &stdLibFileManager{}
}

func (s *stdLibFileManager) ReadDir(dirname string) ([]fs.FileInfo, error) {
return ioutil.ReadDir(dirname)
}

func (s *stdLibFileManager) Remove(name string) error {
return os.Remove(name)
}

func (s *stdLibFileManager) Write(file *os.File, contents []byte) error {
_, err := file.Write(contents)

return err
}

func (s *stdLibFileManager) Create(name string) (*os.File, error) {
return os.Create(name)
}

func (s *stdLibFileManager) Chmod(file *os.File, mode os.FileMode) error {
return file.Chmod(mode)
}
53 changes: 44 additions & 9 deletions internal/state/secrets.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"bytes"
"crypto/tls"
"fmt"
"io/ioutil"
"io/fs"
"os"
"path"

Expand All @@ -14,6 +14,8 @@ import (

//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . SecretStore
//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . SecretDiskMemoryManager
//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . FileManager
//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 io/fs.FileInfo

// tlsSecretFileMode defines the default file mode for files with TLS Secrets.
const tlsSecretFileMode = 0o600
Expand Down Expand Up @@ -72,9 +74,25 @@ type SecretDiskMemoryManager interface {
WriteAllRequestedSecrets() error
}

// FileManager is an interface that exposes File I/O operations.
// Used for unit testing.
type FileManager interface {
// ReadDir returns the file info for the directory.
ReadDir(dirname string) ([]fs.FileInfo, error)
// Remove file with given name.
Remove(name string) error
// Create file at the provided filepath.
Create(name string) (*os.File, error)
// Chmod sets the mode of the file.
Chmod(file *os.File, mode os.FileMode) error
// Write writes contents to the file.
Write(file *os.File, contents []byte) error
}

type SecretDiskMemoryManagerImpl struct {
requestedSecrets map[types.NamespacedName]requestedSecret
secretStore SecretStore
fileManager FileManager
secretDirectory string
}

Expand All @@ -83,12 +101,30 @@ type requestedSecret struct {
path string
}

func NewSecretDiskMemoryManager(secretDirectory string, secretStore SecretStore) *SecretDiskMemoryManagerImpl {
return &SecretDiskMemoryManagerImpl{
// SecretDiskMemoryManagerOption is a function that modifies the configuration of the SecretDiskMemoryManager.
type SecretDiskMemoryManagerOption func(*SecretDiskMemoryManagerImpl)

// WithSecretFileManager sets the file manager of the SecretDiskMemoryManager.
// Used to inject a fake fileManager for unit tests.
func WithSecretFileManager(fileManager FileManager) SecretDiskMemoryManagerOption {
return func(mm *SecretDiskMemoryManagerImpl) {
mm.fileManager = fileManager
}
}

func NewSecretDiskMemoryManager(secretDirectory string, secretStore SecretStore, options ...SecretDiskMemoryManagerOption) *SecretDiskMemoryManagerImpl {
sm := &SecretDiskMemoryManagerImpl{
requestedSecrets: make(map[types.NamespacedName]requestedSecret),
secretStore: secretStore,
secretDirectory: secretDirectory,
fileManager: newStdLibFileManager(),
}

for _, o := range options {
o(sm)
}

return sm
}

func (s *SecretDiskMemoryManagerImpl) Request(nsname types.NamespacedName) (string, error) {
Expand All @@ -113,37 +149,36 @@ func (s *SecretDiskMemoryManagerImpl) Request(nsname types.NamespacedName) (stri

func (s *SecretDiskMemoryManagerImpl) WriteAllRequestedSecrets() error {
// Remove all existing secrets from secrets directory
dir, err := ioutil.ReadDir(s.secretDirectory)
dir, err := s.fileManager.ReadDir(s.secretDirectory)
if err != nil {
return fmt.Errorf("failed to remove all secrets from %s: %w", s.secretDirectory, err)
}

for _, d := range dir {
filepath := path.Join(s.secretDirectory, d.Name())
if err := os.Remove(filepath); err != nil {
if err := s.fileManager.Remove(filepath); err != nil {
return fmt.Errorf("failed to remove secret %s: %w", filepath, err)
}
}

// Write all secrets to secrets directory
for nsname, ss := range s.requestedSecrets {

file, err := os.Create(ss.path)
file, err := s.fileManager.Create(ss.path)
if err != nil {
return fmt.Errorf("failed to create file %s for secret %s: %w", ss.path, nsname, err)
}

if err = file.Chmod(tlsSecretFileMode); err != nil {
if err = s.fileManager.Chmod(file, tlsSecretFileMode); err != nil {
return fmt.Errorf("failed to change mode of file %s for secret %s: %w", ss.path, nsname, err)
}

contents := generateCertAndKeyFileContent(ss.secret)

_, err = file.Write(contents)
err = s.fileManager.Write(file, contents)
if err != nil {
return fmt.Errorf("failed to write secret %s to file %s: %w", nsname, ss.path, err)
}

}

// reset stored secrets
Expand Down
70 changes: 69 additions & 1 deletion internal/state/secrets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
package state_test

import (
"errors"
"io/fs"
"io/ioutil"
"os"
"path"
Expand Down Expand Up @@ -257,7 +259,6 @@ var _ = Describe("SecretStore", func() {
validToInvalidSecret.Data[apiv1.TLSCertKey] = invalidCert

})

Describe("handles CRUD events on secrets", Ordered, func() {
testUpsert := func(s *apiv1.Secret, valid bool) {
store.Upsert(s)
Expand Down Expand Up @@ -330,4 +331,71 @@ var _ = Describe("SecretStore", func() {
store.Delete(nsname)
})
})
Describe("File Management Error Cases", func() {
var (
fakeFileManager *statefakes.FakeFileManager
fakeStore *statefakes.FakeSecretStore
fakeFileInfoSlice []fs.FileInfo
memMgr state.SecretDiskMemoryManager
)

BeforeEach(OncePerOrdered, func() {
fakeFileManager = &statefakes.FakeFileManager{}
fakeStore = &statefakes.FakeSecretStore{}
fakeFileInfoSlice = []fs.FileInfo{&statefakes.FakeFileInfo{}}
memMgr = state.NewSecretDiskMemoryManager("", fakeStore, state.WithSecretFileManager(fakeFileManager))

// populate a requested secret
fakeStore.GetReturns(&state.Secret{Secret: secret1, Valid: true})
_, err := memMgr.Request(types.NamespacedName{Namespace: secret1.Namespace, Name: secret1.Name})
Expect(err).ToNot(HaveOccurred())
})

Describe("Write all requested secrets", Ordered, func() {
It("returns an error when secret directory cannot be read from", func() {
errString := "read dir error"
fakeFileManager.ReadDirReturns(nil, errors.New(errString))

err := memMgr.WriteAllRequestedSecrets()
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring(errString))
})
It("returns an error when a file cannot be removed from the secrets directory", func() {
errString := "remove error"
fakeFileManager.ReadDirReturns(fakeFileInfoSlice, nil)
fakeFileManager.RemoveReturns(errors.New(errString))

err := memMgr.WriteAllRequestedSecrets()
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring(errString))
})
It("returns an error when file cannot be created", func() {
errString := "create error"
fakeFileManager.RemoveReturns(nil)
fakeFileManager.CreateReturns(nil, errors.New(errString))

err := memMgr.WriteAllRequestedSecrets()
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring(errString))
})
It("returns an error when it cannot change the mode of the file", func() {
errStr := "chmod error"
fakeFileManager.CreateReturns(&os.File{}, nil)
fakeFileManager.ChmodReturns(errors.New(errStr))

err := memMgr.WriteAllRequestedSecrets()
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring(errStr))
})
It("returns an error when file cannot be written to", func() {
errString := "write error"
fakeFileManager.ChmodReturns(nil)
fakeFileManager.WriteReturns(errors.New(errString))

err := memMgr.WriteAllRequestedSecrets()
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring(errString))
})
})
})
})
Loading