Skip to content

Commit

Permalink
Add fake filesystem for test to avoid temporal files on the local fil…
Browse files Browse the repository at this point in the history
…esystem
  • Loading branch information
aledbf committed Nov 22, 2017
1 parent 14b5259 commit 18d6573
Show file tree
Hide file tree
Showing 15 changed files with 631 additions and 87 deletions.
9 changes: 7 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,21 @@ jobs:
- go get github.com/golang/lint/golint
- make fmt lint vet
- stage: Coverage
before_script:
# start minikube
- test/e2e/up.sh
script:
- go get github.com/mattn/goveralls
- go get github.com/modocache/gover
- if ! go get github.com/golang/tools/cmd/cover; then go get golang.org/x/tools/cmd/cover;
fi
- if ! go get github.com/golang/tools/cmd/cover; then go get golang.org/x/tools/cmd/cover;fi
- if ! go get github.com/jteeuwen/go-bindata/...; then github.com/jteeuwen/go-bindata/...;fi
- make cover
- stage: e2e
before_script:
- if ! go get github.com/jteeuwen/go-bindata/...; then github.com/jteeuwen/go-bindata/...;fi
- make e2e-image
- test/e2e/up.sh
- test/e2e/wait-for-nginx.sh
script:
- make e2e-test
# split builds to avoid job timeouts
Expand Down
10 changes: 7 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,12 @@ endif
clean:
$(DOCKER) rmi -f $(MULTI_ARCH_IMG):$(TAG) || true

.PHONE: gobindata
gobindata:
go-bindata -o internal/file/bindata.go -prefix="rootfs" -pkg=file -ignore=Dockerfile -ignore=".DS_Store" rootfs/...

.PHONY: build
build: clean
build: clean gobindata
CGO_ENABLED=0 GOOS=${GOOS} GOARCH=${GOARCH} go build -a -installsuffix cgo \
-ldflags "-s -w -X ${PKG}/version.RELEASE=${TAG} -X ${PKG}/version.COMMIT=${COMMIT} -X ${PKG}/version.REPO=${REPO_INFO}" \
-o ${TEMP_DIR}/rootfs/nginx-ingress-controller ${PKG}/cmd/nginx
Expand All @@ -150,7 +154,7 @@ lint:
@go list -f '{{if len .TestGoFiles}}"golint {{.Dir}}/..."{{end}}' $(shell go list ${PKG}/... | grep -v vendor | grep -v '/test/e2e') | xargs -L 1 sh -c

.PHONY: test
test: fmt lint vet
test: fmt lint vet gobindata
@echo "+ $@"
@go test -v -race -tags "$(BUILDTAGS) cgo" $(shell go list ${PKG}/... | grep -v vendor | grep -v '/test/e2e')

Expand All @@ -165,7 +169,7 @@ e2e-test:
@KUBECONFIG=${HOME}/.kube/config INGRESSNGINXCONFIG=${HOME}/.kube/config ./e2e-tests

.PHONY: cover
cover:
cover: gobindata
@echo "+ $@"
@go list -f '{{if len .TestGoFiles}}"go test -coverprofile={{.Dir}}/.coverprofile {{.ImportPath}}"{{end}}' $(shell go list ${PKG}/... | grep -v vendor | grep -v '/test/e2e') | xargs -L 1 sh -c
gover
Expand Down
2 changes: 1 addition & 1 deletion cmd/nginx/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ func main() {

// create the default SSL certificate (dummy)
defCert, defKey := ssl.GetFakeSSLCert()
c, err := ssl.AddOrUpdateCertAndKey(fakeCertificate, defCert, defKey, []byte{}, fs)
c, err := ssl.AddOrUpdateCertAndKey(fakeCertificate, defCert, defKey, []byte{})
if err != nil {
glog.Fatalf("Error generating self signed certificate: %v", err)
}
Expand Down
289 changes: 289 additions & 0 deletions internal/file/bindata.go

Large diffs are not rendered by default.

127 changes: 127 additions & 0 deletions internal/file/filesystem.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package file

import (
"os"
"path/filepath"

"github.com/golang/glog"

"k8s.io/kubernetes/pkg/util/filesystem"
)

// Filesystem is an interface that we can use to mock various filesystem operations
type Filesystem interface {
filesystem.Filesystem
}

// NewLocalFS implements Filesystem using same-named functions from "os" and "io/ioutil".
func NewLocalFS() (Filesystem, error) {
fs := filesystem.DefaultFs{}

err := initialize(false, fs)
if err != nil {
return nil, err
}

return fs, nil
}

// NewFakeFS creates an in-memory filesytem with all the required
// paths used by the ingress controller.
// This allows running test without polluting the local machine.
func NewFakeFS() (Filesystem, error) {
fs := filesystem.NewFakeFs()

err := initialize(true, fs)
if err != nil {
return nil, err
}

return fs, nil
}

// initialize creates the required directory structure and when
// runs as virtual filesystem it copies the local files to it
func initialize(isVirtual bool, fs Filesystem) error {
for _, directory := range directories {
err := fs.MkdirAll(directory, 0655)
if err != nil {
return err
}
}

if !isVirtual {
return nil
}

for _, file := range files {
f, err := fs.Create(file)
if err != nil {
return err
}

_, err = f.Write([]byte(""))
if err != nil {
return err
}

err = f.Close()
if err != nil {
return err
}
}

err := fs.MkdirAll("/proc", 0655)
if err != nil {
return err
}

glog.Info("Restoring generated (go-bindata) assets in virtual filesystem...")
for _, assetName := range AssetNames() {
err := restoreAsset("/", assetName, fs)
if err != nil {
return err
}
}

return nil
}

// restoreAsset restores an asset under the given directory
func restoreAsset(dir, name string, fs Filesystem) error {
data, err := Asset(name)
if err != nil {
return err
}
info, err := AssetInfo(name)
if err != nil {
return err
}
err = fs.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755))
if err != nil {
return err
}

f, err := fs.Create(_filePath(dir, name))
if err != nil {
return err
}

_, err = f.Write(data)
if err != nil {
return err
}

err = f.Close()
if err != nil {
return err
}

//Missing info.Mode()

err = fs.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
if err != nil {
return err
}
return nil
}
37 changes: 37 additions & 0 deletions internal/file/filesystem_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package file

import (
"testing"
)

func TestNewFakeFS(t *testing.T) {
fs, err := NewFakeFS()
if err != nil {
t.Fatalf("unexpected error creating filesystem abstraction: %v", err)
}

if fs == nil {
t.Fatal("expected a filesystem but none returned")
}

_, err = fs.Stat("/etc/nginx/nginx.conf")
if err != nil {
t.Fatalf("unexpected error reading default nginx.conf file: %v", err)
}
}
26 changes: 26 additions & 0 deletions internal/file/structure.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package file

const (
// AuthDirectory default directory used to store files
// to authenticate request
AuthDirectory = "/etc/ingress-controller/auth"

// DefaultSSLDirectory defines the location where the SSL certificates will be generated
// This directory contains all the SSL certificates that are specified in Ingress rules.
// The name of each file is <namespace>-<secret name>.pem. The content is the concatenated
// certificate and key.
DefaultSSLDirectory = "/ingress-controller/ssl"
)

var (
directories = []string{
"/etc/nginx/template",
"/run",
DefaultSSLDirectory,
AuthDirectory,
}

files = []string{
"/run/nginx.pid",
}
)
5 changes: 2 additions & 3 deletions internal/ingress/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ type Configuration struct {

ConfigMapName string
DefaultService string
IngressClass string
Namespace string

Namespace string

ForceNamespaceIsolation bool

Expand All @@ -87,7 +87,6 @@ type Configuration struct {
UDPConfigMapName string

DefaultHealthzURL string
DefaultIngressClass string
DefaultSSLCertificate string

// optional
Expand Down
27 changes: 19 additions & 8 deletions internal/ingress/controller/nginx.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import (
"k8s.io/client-go/util/flowcontrol"
"k8s.io/kubernetes/pkg/util/filesystem"

"k8s.io/ingress-nginx/internal/file"
"k8s.io/ingress-nginx/internal/ingress"
"k8s.io/ingress-nginx/internal/ingress/annotations"
"k8s.io/ingress-nginx/internal/ingress/annotations/class"
Expand All @@ -57,6 +58,7 @@ import (
"k8s.io/ingress-nginx/internal/net/dns"
"k8s.io/ingress-nginx/internal/net/ssl"
"k8s.io/ingress-nginx/internal/task"
"k8s.io/ingress-nginx/internal/watch"
)

type statusModule string
Expand All @@ -77,7 +79,7 @@ var (
// NewNGINXController creates a new NGINX Ingress controller.
// If the environment variable NGINX_BINARY exists it will be used
// as source for nginx commands
func NewNGINXController(config *Configuration) *NGINXController {
func NewNGINXController(config *Configuration, fs file.Filesystem) *NGINXController {
ngx := os.Getenv("NGINX_BINARY")
if ngx == "" {
ngx = nginxBinary
Expand Down Expand Up @@ -114,12 +116,12 @@ func NewNGINXController(config *Configuration) *NGINXController {
stopCh: make(chan struct{}),
stopLock: &sync.Mutex{},

fileSystem: filesystem.DefaultFs{},
fileSystem: fs,
}

n.listers, n.controllers = n.createListers(n.stopCh)

n.stats = newStatsCollector(config.Namespace, config.IngressClass, n.binary, n.cfg.ListenPorts.Status)
n.stats = newStatsCollector(config.Namespace, class.IngressClass, n.binary, n.cfg.ListenPorts.Status)

n.syncQueue = task.NewTaskQueue(n.syncIngress)

Expand All @@ -131,8 +133,8 @@ func NewNGINXController(config *Configuration) *NGINXController {
PublishService: config.PublishService,
IngressLister: n.listers.Ingress,
ElectionID: config.ElectionID,
IngressClass: config.IngressClass,
DefaultIngressClass: config.DefaultIngressClass,
IngressClass: class.IngressClass,
DefaultIngressClass: class.DefaultClass,
UpdateStatusOnShutdown: config.UpdateStatusOnShutdown,
UseNodeInternalIP: config.UseNodeInternalIP,
})
Expand All @@ -142,7 +144,7 @@ func NewNGINXController(config *Configuration) *NGINXController {

var onChange func()
onChange = func() {
template, err := ngx_template.NewTemplate(tmplPath, onChange)
template, err := ngx_template.NewTemplate(tmplPath, fs)
if err != nil {
// this error is different from the rest because it must be clear why nginx is not working
glog.Errorf(`
Expand All @@ -153,19 +155,28 @@ Error loading new template : %v
return
}

n.t.Close()
n.t = template
glog.Info("new NGINX template loaded")
n.SetForceReload(true)
}

ngxTpl, err := ngx_template.NewTemplate(tmplPath, onChange)
ngxTpl, err := ngx_template.NewTemplate(tmplPath, fs)
if err != nil {
glog.Fatalf("invalid NGINX template: %v", err)
}

n.t = ngxTpl

// TODO: refactor
if _, ok := fs.(filesystem.DefaultFs); !ok {
watch.NewDummyFileWatcher(tmplPath, onChange)
} else {
_, err = watch.NewFileWatcher(tmplPath, onChange)
if err != nil {
glog.Fatalf("unexpected error watching template %v: %v", tmplPath, err)
}
}

return n
}

Expand Down
Loading

0 comments on commit 18d6573

Please sign in to comment.