VMware vSphere Integrated Containers provider (#206)

* Add Virtual Kubelet provider for VIC

Initial virtual kubelet provider for VMware VIC.  This provider currently
handles creating and starting of a pod VM via the VIC portlayer and persona
server.  Image store handling via the VIC persona server.  This provider
currently requires the feature/wolfpack branch of VIC.

* Added pod stop and delete.  Also added node capacity.

Added the ability to stop and delete pod VMs via VIC.  Also retrieve
node capacity information from the VCH.

* Cleanup and readme file

Some file clean up and added a Readme.md markdown file for the VIC
provider.

* Cleaned up errors, added function comments, moved operation code

1. Cleaned up error handling.  Set standard for creating errors.
2. Added method prototype comments for all interface functions.
3. Moved PodCreator, PodStarter, PodStopper, and PodDeleter to a new folder.

* Add mocking code and unit tests for podcache, podcreator, and podstarter

Used the unit test framework used in VIC to handle assertions in the provider's
unit test.  Mocking code generated using OSS project mockery, which is compatible
with the testify assertion framework.

* Vendored packages for the VIC provider

Requires feature/wolfpack branch of VIC and a few specific commit sha of
projects used within VIC.

* Implementation of POD Stopper and Deleter unit tests (#4)

* Updated files for initial PR
This commit is contained in:
Loc Nguyen
2018-06-04 15:41:32 -07:00
committed by Ria Bhatia
parent 98a111e8b7
commit 513cebe7b7
6296 changed files with 1123685 additions and 8 deletions

101
vendor/github.com/vmware/vic/pkg/log/log.go generated vendored Normal file
View File

@@ -0,0 +1,101 @@
// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// 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 log
import (
"sync"
"github.com/Sirupsen/logrus"
"github.com/vmware/vic/pkg/log/syslog"
)
type LoggingConfig struct {
Formatter logrus.Formatter
Level logrus.Level
Syslog *SyslogConfig
}
type SyslogConfig struct {
Network string
RAddr string
Tag string
Priority syslog.Priority
}
var initializer struct {
once sync.Once
err error
}
func NewLoggingConfig() *LoggingConfig {
return &LoggingConfig{
Formatter: NewTextFormatter(),
Level: logrus.InfoLevel,
}
}
func Init(cfg *LoggingConfig) error {
initializer.once.Do(
func() {
var err error
logger := logrus.StandardLogger()
f := logger.Formatter
l := logger.Level
defer func() {
initializer.err = err
if err != nil {
// revert
logrus.SetFormatter(f)
logrus.SetLevel(l)
}
}()
logrus.SetFormatter(cfg.Formatter)
logrus.SetLevel(cfg.Level)
logrus.Debugf("log cfg: %+v", *cfg)
hook, err := CreateSyslogHook(cfg)
if err == nil && hook != nil {
logrus.AddHook(hook)
}
})
return initializer.err
}
func CreateSyslogHook(cfg *LoggingConfig) (logrus.Hook, error) {
if cfg.Syslog == nil {
return nil, nil
}
hook, err := syslog.NewHook(
cfg.Syslog.Network,
cfg.Syslog.RAddr,
cfg.Syslog.Priority,
cfg.Syslog.Tag,
)
if err != nil {
// not a fatal error, so just log a warning
logrus.Warnf("error trying to initialize syslog: %s", err)
}
return hook, err
}
func (l *LoggingConfig) SetLogLevel(level uint8) {
l.Level = logrus.Level(level)
}

23
vendor/github.com/vmware/vic/pkg/log/syslog/dialer.go generated vendored Normal file
View File

@@ -0,0 +1,23 @@
// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// 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 syslog
import "time"
const defaultDialTimeout = 1 * time.Minute
type dialer interface {
dial() (Writer, error)
}

View File

@@ -0,0 +1,64 @@
// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// 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 syslog
import (
"fmt"
"net"
"os"
"time"
)
type formatter interface {
Format(p Priority, ts time.Time, hostname, tag, msg string) string
}
type localFormatter struct{}
func (l *localFormatter) Format(p Priority, ts time.Time, _, tag, msg string) string {
return fmt.Sprintf("<%d>%s %s[%d]: %s", p, ts.Format(time.Stamp), tag, os.Getpid(), msg)
}
type rfc3164Formatter struct{}
func (c *rfc3164Formatter) Format(p Priority, ts time.Time, hostname, tag, msg string) string {
return fmt.Sprintf("<%d>%s %s %s[%d]: %s", p, ts.Format(time.RFC3339), hostname, tag, os.Getpid(), msg)
}
type netDialer interface {
dial() (net.Conn, error)
}
type defaultNetDialer struct {
network, address string
}
func (d *defaultNetDialer) dial() (net.Conn, error) {
Logger.Infof("trying to connect to %s://%s", d.network, d.address)
return net.DialTimeout(d.network, d.address, defaultDialTimeout)
}
func newFormatter(network string, f Format) formatter {
if network == "" {
return &localFormatter{}
}
switch f {
case RFC3164:
return &rfc3164Formatter{}
}
return nil
}

View File

@@ -0,0 +1,56 @@
// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// 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 syslog
import (
"fmt"
"os"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestNewFormatter(t *testing.T) {
f := newFormatter("", RFC3164)
assert.IsType(t, &localFormatter{}, f)
f = newFormatter("tcp", RFC3164)
assert.IsType(t, &rfc3164Formatter{}, f)
f = newFormatter("tcp", 123)
assert.Nil(t, f)
}
func TestFormatterFormats(t *testing.T) {
var tests = []struct {
format string
tsLayout string
local bool
f formatter
}{
{"<%d>%s %s[%d]: %s", time.Stamp, true, &localFormatter{}},
{"<%d>%s %s %s[%d]: %s", time.RFC3339, false, &rfc3164Formatter{}},
}
for _, te := range tests {
ts := time.Now()
if te.local {
assert.Equal(t, fmt.Sprintf(te.format, priority, ts.Format(te.tsLayout), tag, os.Getpid(), "foo"), te.f.Format(priority, ts, "host", tag, "foo"))
} else {
assert.Equal(t, fmt.Sprintf(te.format, priority, ts.Format(te.tsLayout), "host", tag, os.Getpid(), "foo"), te.f.Format(priority, ts, "host", tag, "foo"))
}
}
}

71
vendor/github.com/vmware/vic/pkg/log/syslog/hook.go generated vendored Normal file
View File

@@ -0,0 +1,71 @@
// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// 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 syslog
import "github.com/Sirupsen/logrus"
type Hook struct {
writer Writer
}
func NewHook(network, raddr string, priority Priority, tag string) (*Hook, error) {
return newHook(&defaultDialer{
network: network,
raddr: raddr,
priority: priority,
tag: tag,
})
}
func newHook(d dialer) (*Hook, error) {
hook := &Hook{}
var err error
hook.writer, err = d.dial()
if err != nil {
return nil, err
}
return hook, nil
}
func (hook *Hook) Fire(entry *logrus.Entry) error {
return hook.writeEntry(entry)
}
func (hook *Hook) Levels() []logrus.Level {
return logrus.AllLevels
}
func (hook *Hook) writeEntry(entry *logrus.Entry) error {
// just use the message since the timestamp
// is added by the syslog package
line := entry.Message
switch entry.Level {
case logrus.PanicLevel, logrus.FatalLevel:
return hook.writer.Crit(line)
case logrus.ErrorLevel:
return hook.writer.Err(line)
case logrus.WarnLevel:
return hook.writer.Warning(line)
case logrus.InfoLevel:
return hook.writer.Info(line)
case logrus.DebugLevel:
return hook.writer.Debug(line)
}
return nil
}

View File

@@ -0,0 +1,126 @@
// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// 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 syslog
import (
"testing"
"time"
"github.com/Sirupsen/logrus"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
func TestNewSyslogHook(t *testing.T) {
// error case
d := &mockDialer{}
d.On("dial").Return(nil, assert.AnError)
h, err := newHook(d)
assert.Nil(t, h)
assert.Error(t, err)
assert.EqualError(t, err, assert.AnError.Error())
d.AssertCalled(t, "dial")
d.AssertNumberOfCalls(t, "dial", 1)
// no error
d = &mockDialer{}
w := &MockWriter{}
d.On("dial").Return(w, nil)
h, err = newHook(d)
assert.NotNil(t, h)
assert.NoError(t, err)
assert.Equal(t, w, h.writer)
d.AssertCalled(t, "dial")
d.AssertNumberOfCalls(t, "dial", 1)
}
func TestLevels(t *testing.T) {
m := &MockWriter{}
d := &mockDialer{}
d.On("dial").Return(m, nil)
h, err := newHook(d)
assert.NotNil(t, h)
assert.NoError(t, err)
m.On("Crit", mock.Anything).Return(nil)
m.On("Err", mock.Anything).Return(nil)
m.On("Warning", mock.Anything).Return(nil)
m.On("Debug", mock.Anything).Return(nil)
m.On("Info", mock.Anything).Return(nil)
var tests = []struct {
entry *logrus.Entry
f string
}{
{
entry: &logrus.Entry{Message: "panic", Level: logrus.PanicLevel},
f: "Crit",
},
{
entry: &logrus.Entry{Message: "fatal", Level: logrus.FatalLevel},
f: "Crit",
},
{
entry: &logrus.Entry{Message: "error", Level: logrus.ErrorLevel},
f: "Err",
},
{
entry: &logrus.Entry{Message: "warn", Level: logrus.WarnLevel},
f: "Warning",
},
{
entry: &logrus.Entry{Message: "info", Level: logrus.InfoLevel},
f: "Info",
},
{
entry: &logrus.Entry{Message: "debug", Level: logrus.DebugLevel},
f: "Debug",
},
}
calls := make(map[string]int)
for _, te := range tests {
calls[te.f] = 0
}
for _, te := range tests {
assert.NoError(t, h.writeEntry(te.entry))
calls[te.f]++
m.AssertCalled(t, te.f, te.entry.Message)
m.AssertNumberOfCalls(t, te.f, calls[te.f])
}
}
func TestConnect(t *testing.T) {
// attempt a connection to a server that
// does not exist
h, err := NewHook(
"tcp",
"foo:514",
Info,
"test",
)
assert.NoError(t, err)
assert.NotNil(t, h)
h.Fire(&logrus.Entry{
Message: "foo",
Level: logrus.InfoLevel,
})
<-time.After(5 * time.Second)
}

View File

@@ -0,0 +1,55 @@
// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// 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 syslog
import (
"net"
mock "github.com/stretchr/testify/mock"
)
// MockAddr is an autogenerated mock type for the Addr type
type MockAddr struct {
mock.Mock
}
// Network provides a mock function with given fields:
func (_m *MockAddr) Network() string {
ret := _m.Called()
var r0 string
if rf, ok := ret.Get(0).(func() string); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(string)
}
return r0
}
// String provides a mock function with given fields:
func (_m *MockAddr) String() string {
ret := _m.Called()
var r0 string
if rf, ok := ret.Get(0).(func() string); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(string)
}
return r0
}
var _ net.Addr = (*MockAddr)(nil)

View File

@@ -0,0 +1,46 @@
// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// 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 syslog
import mock "github.com/stretchr/testify/mock"
// mockDialer is an autogenerated mock type for the dialer type
type mockDialer struct {
mock.Mock
}
// dial provides a mock function with given fields:
func (_m *mockDialer) dial() (Writer, error) {
ret := _m.Called()
var r0 Writer
if rf, ok := ret.Get(0).(func() Writer); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(Writer)
}
}
var r1 error
if rf, ok := ret.Get(1).(func() error); ok {
r1 = rf()
} else {
r1 = ret.Error(1)
}
return r0, r1
}
var _ dialer = (*mockDialer)(nil)

View File

@@ -0,0 +1,38 @@
// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// 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 syslog
import mock "github.com/stretchr/testify/mock"
import time "time"
// mockFormatter is an autogenerated mock type for the formatter type
type mockFormatter struct {
mock.Mock
}
// Format provides a mock function with given fields: p, ts, hostname, tag, msg
func (_m *mockFormatter) Format(p Priority, ts time.Time, hostname string, tag string, msg string) string {
ret := _m.Called(p, ts, hostname, tag, msg)
var r0 string
if rf, ok := ret.Get(0).(func(Priority, time.Time, string, string, string) string); ok {
r0 = rf(p, ts, hostname, tag, msg)
} else {
r0 = ret.Get(0).(string)
}
return r0
}
var _ formatter = (*mockFormatter)(nil)

View File

@@ -0,0 +1,155 @@
// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// 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 syslog
import mock "github.com/stretchr/testify/mock"
import net "net"
import time "time"
// MockConn is an autogenerated mock type for the Conn type
type MockNetConn struct {
mock.Mock
}
// Close provides a mock function with given fields:
func (_m *MockNetConn) Close() error {
ret := _m.Called()
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
} else {
r0 = ret.Error(0)
}
return r0
}
// LocalAddr provides a mock function with given fields:
func (_m *MockNetConn) LocalAddr() net.Addr {
ret := _m.Called()
var r0 net.Addr
if rf, ok := ret.Get(0).(func() net.Addr); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(net.Addr)
}
}
return r0
}
// Read provides a mock function with given fields: b
func (_m *MockNetConn) Read(b []byte) (int, error) {
ret := _m.Called(b)
var r0 int
if rf, ok := ret.Get(0).(func([]byte) int); ok {
r0 = rf(b)
} else {
r0 = ret.Get(0).(int)
}
var r1 error
if rf, ok := ret.Get(1).(func([]byte) error); ok {
r1 = rf(b)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// RemoteAddr provides a mock function with given fields:
func (_m *MockNetConn) RemoteAddr() net.Addr {
ret := _m.Called()
var r0 net.Addr
if rf, ok := ret.Get(0).(func() net.Addr); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(net.Addr)
}
}
return r0
}
// SetDeadline provides a mock function with given fields: t
func (_m *MockNetConn) SetDeadline(t time.Time) error {
ret := _m.Called(t)
var r0 error
if rf, ok := ret.Get(0).(func(time.Time) error); ok {
r0 = rf(t)
} else {
r0 = ret.Error(0)
}
return r0
}
// SetReadDeadline provides a mock function with given fields: t
func (_m *MockNetConn) SetReadDeadline(t time.Time) error {
ret := _m.Called(t)
var r0 error
if rf, ok := ret.Get(0).(func(time.Time) error); ok {
r0 = rf(t)
} else {
r0 = ret.Error(0)
}
return r0
}
// SetWriteDeadline provides a mock function with given fields: t
func (_m *MockNetConn) SetWriteDeadline(t time.Time) error {
ret := _m.Called(t)
var r0 error
if rf, ok := ret.Get(0).(func(time.Time) error); ok {
r0 = rf(t)
} else {
r0 = ret.Error(0)
}
return r0
}
// Write provides a mock function with given fields: b
func (_m *MockNetConn) Write(b []byte) (int, error) {
ret := _m.Called(b)
var r0 int
if rf, ok := ret.Get(0).(func([]byte) int); ok {
r0 = rf(b)
} else {
r0 = ret.Get(0).(int)
}
var r1 error
if rf, ok := ret.Get(1).(func([]byte) error); ok {
r1 = rf(b)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
var _ net.Conn = (*MockNetConn)(nil)

View File

@@ -0,0 +1,47 @@
// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// 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 syslog
import mock "github.com/stretchr/testify/mock"
import net "net"
// mockNetDialer is an autogenerated mock type for the netDialer type
type mockNetDialer struct {
mock.Mock
}
// dial provides a mock function with given fields:
func (_m *mockNetDialer) dial() (net.Conn, error) {
ret := _m.Called()
var r0 net.Conn
if rf, ok := ret.Get(0).(func() net.Conn); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(net.Conn)
}
}
var r1 error
if rf, ok := ret.Get(1).(func() error); ok {
r1 = rf()
} else {
r1 = ret.Error(1)
}
return r0, r1
}
var _ netDialer = (*mockNetDialer)(nil)

View File

@@ -0,0 +1,174 @@
// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// 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 syslog
import mock "github.com/stretchr/testify/mock"
// MockWriter is an autogenerated mock type for the Writer type
type MockWriter struct {
mock.Mock
}
// Close provides a mock function with given fields:
func (_m *MockWriter) Close() error {
ret := _m.Called()
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
} else {
r0 = ret.Error(0)
}
return r0
}
// Crit provides a mock function with given fields: _a0
func (_m *MockWriter) Crit(_a0 string) error {
ret := _m.Called(_a0)
var r0 error
if rf, ok := ret.Get(0).(func(string) error); ok {
r0 = rf(_a0)
} else {
r0 = ret.Error(0)
}
return r0
}
// Debug provides a mock function with given fields: _a0
func (_m *MockWriter) Debug(_a0 string) error {
ret := _m.Called(_a0)
var r0 error
if rf, ok := ret.Get(0).(func(string) error); ok {
r0 = rf(_a0)
} else {
r0 = ret.Error(0)
}
return r0
}
// Emerg provides a mock function with given fields: _a0
func (_m *MockWriter) Emerg(_a0 string) error {
ret := _m.Called(_a0)
var r0 error
if rf, ok := ret.Get(0).(func(string) error); ok {
r0 = rf(_a0)
} else {
r0 = ret.Error(0)
}
return r0
}
// Err provides a mock function with given fields: _a0
func (_m *MockWriter) Err(_a0 string) error {
ret := _m.Called(_a0)
var r0 error
if rf, ok := ret.Get(0).(func(string) error); ok {
r0 = rf(_a0)
} else {
r0 = ret.Error(0)
}
return r0
}
// Info provides a mock function with given fields: _a0
func (_m *MockWriter) Info(_a0 string) error {
ret := _m.Called(_a0)
var r0 error
if rf, ok := ret.Get(0).(func(string) error); ok {
r0 = rf(_a0)
} else {
r0 = ret.Error(0)
}
return r0
}
// Warning provides a mock function with given fields: _a0
func (_m *MockWriter) Warning(_a0 string) error {
ret := _m.Called(_a0)
var r0 error
if rf, ok := ret.Get(0).(func(string) error); ok {
r0 = rf(_a0)
} else {
r0 = ret.Error(0)
}
return r0
}
// WithPriority provides a mock function with given fields: priority
func (_m *MockWriter) WithPriority(priority Priority) Writer {
ret := _m.Called(priority)
var r0 Writer
if rf, ok := ret.Get(0).(func(Priority) Writer); ok {
r0 = rf(priority)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(Writer)
}
}
return r0
}
// WithTag provides a mock function with given fields: tag
func (_m *MockWriter) WithTag(tag string) Writer {
ret := _m.Called(tag)
var r0 Writer
if rf, ok := ret.Get(0).(func(string) Writer); ok {
r0 = rf(tag)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(Writer)
}
}
return r0
}
// Write provides a mock function with given fields: p
func (_m *MockWriter) Write(p []byte) (int, error) {
ret := _m.Called(p)
var r0 int
if rf, ok := ret.Get(0).(func([]byte) int); ok {
r0 = rf(p)
} else {
r0 = ret.Get(0).(int)
}
var r1 error
if rf, ok := ret.Get(1).(func([]byte) error); ok {
r1 = rf(p)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
var _ Writer = (*MockWriter)(nil)

156
vendor/github.com/vmware/vic/pkg/log/syslog/syslog.go generated vendored Normal file
View File

@@ -0,0 +1,156 @@
// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// 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 syslog
import (
"errors"
"os"
"path/filepath"
"github.com/Sirupsen/logrus"
)
// Priority is a combination of the syslog facility and
// severity. For example, Alert | Ftp sends an alert severity
// message from the FTP facility. The default severity is Emerg;
// the default facility is Kern.
type Priority int
const severityMask = 0x07
const facilityMask = 0xf8
// maxLogBuffer was set to 100 but debug logging of config overflows that easily so pushing it up
const maxLogBuffer = 500
const (
// Severity.
// From /usr/include/sys/syslog.h.
// These are the same on Linux, BSD, and OS X.
Emerg Priority = iota // LOG_EMERG
Alert // LOG_ALERT
Crit // LOG_CRIT
Err // LOG_ERR
Warning // LOG_WARNING
Notice // LOG_NOTICE
Info // LOG_INFO
Debug // LOG_DEBUG
)
const (
// Facility.
// From /usr/include/sys/syslog.h.
// These are the same up to LOG_FTP on Linux, BSD, and OS X.
Kern Priority = iota << 3 // LOG_KERN
User // LOG_USER
Mail // LOG_MAIL
Daemon // LOG_DAEMON
Auth // LOG_AUTH
Syslog // LOG_SYSLOG
Lpr // LOG_LPR
News // LOG_NEWS
Uucp // LOG_UUCP
Cron // LOG_CRON
Authpriv // LOG_AUTHPRIV
Ftp // LOG_FTP
_ // unused
_ // unused
_ // unused
_ // unused
Local0 // LOG_LOCAL0
Local1 // LOG_LOCAL1
Local2 // LOG_LOCAL2
Local3 // LOG_LOCAL3
Local4 // LOG_LOCAL4
Local5 // LOG_LOCAL5
Local6 // LOG_LOCAL6
Local7 // LOG_LOCAL7
)
// New establishes a new connection to the system log daemon. Each
// write to the returned writer sends a log message with the given
// priority and prefix.
func New(priority Priority, tag string) (Writer, error) {
return Dial("", "", priority, tag)
}
// Dial establishes a connection to a log daemon by connecting to
// address raddr on the specified network. Each write to the returned
// writer sends a log message with the given facility, severity and
// tag.
// If network is empty, Dial will connect to the local syslog server.
func Dial(network, raddr string, priority Priority, tag string) (Writer, error) {
d := &defaultDialer{
network: network,
raddr: raddr,
tag: tag,
priority: priority,
}
return d.dial()
}
type defaultDialer struct {
network, raddr, tag string
priority Priority
}
func validPriority(priority Priority) bool {
return priority >= 0 && priority <= Local7|Debug
}
func (d *defaultDialer) dial() (Writer, error) {
if !validPriority(d.priority) {
return nil, errors.New("log/syslog: invalid priority")
}
tag := MakeTag("", d.tag)
// #nosec: Errors unhandled.
hostname, _ := os.Hostname()
w := newWriter(d.priority, tag, hostname, newNetDialer(d.network, d.raddr), newFormatter(d.network, RFC3164))
go w.run()
return w, nil
}
const sep = "/"
// MakeTag returns prfeix + sep + proc if prefix is not empty.
// If proc is empty, proc is set to filepath.Base(os.Args[0]).
// If prefix is empty, MakeTag returns proc.
func MakeTag(prefix, proc string) string {
if len(proc) == 0 {
proc = filepath.Base(os.Args[0])
}
if len(prefix) > 0 {
return prefix + sep + proc
}
return proc
}
// Logger is the logger object used by the package
var Logger = logrus.New()
// Format is the syslog format, e.g. RFC 3164
type Format int
const (
RFC3164 Format = iota
)

View File

@@ -0,0 +1,80 @@
// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// 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 syslog
import (
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
)
var (
network = "tcp"
raddr = "localhost:514"
tag = "test"
priority = Info | Daemon
)
func TestMakeTag(t *testing.T) {
p := filepath.Base(os.Args[0])
var tests = []struct {
prefix string
proc string
out string
}{
{
prefix: "",
proc: "",
out: p,
},
{
prefix: "",
proc: "foo",
out: "foo",
},
{
prefix: "foo",
proc: "",
out: "foo" + sep + p,
},
{
prefix: "bar",
proc: "foo",
out: "bar" + sep + "foo",
},
}
for _, te := range tests {
out := MakeTag(te.prefix, te.proc)
assert.Equal(t, te.out, out)
}
}
func TestDefaultDialerBadPriority(t *testing.T) {
d := &defaultDialer{
priority: -1,
}
w, err := d.dial()
assert.Nil(t, w)
assert.Error(t, err)
d.priority = (Local7 | Debug) + 1
w, err = d.dial()
assert.Nil(t, w)
assert.Error(t, err)
}

View File

@@ -0,0 +1,53 @@
// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// 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.
// +build !windows,!nacl,!plan9
package syslog
import (
"errors"
"net"
)
type unixSyslogDialer struct{}
// unixSyslog opens a connection to the syslog daemon running on the
// local machine using a Unix domain socket.
func (u *unixSyslogDialer) dial() (net.Conn, error) {
logTypes := []string{"unixgram", "unix"}
logPaths := []string{"/dev/log", "/var/run/syslog", "/var/run/log"}
for _, network := range logTypes {
for _, path := range logPaths {
conn, err := net.Dial(network, path)
if err != nil {
continue
} else {
return conn, nil
}
}
}
return nil, errors.New("Unix syslog delivery error")
}
func newNetDialer(network, address string) netDialer {
if network == "" {
return &unixSyslogDialer{}
}
return &defaultNetDialer{
network: network,
address: address,
}
}

View File

@@ -0,0 +1,26 @@
// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// 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.
// +build !windows,!nacl,!plan9
package syslog
import "testing"
import "github.com/stretchr/testify/assert"
func TestNewNetDialer(t *testing.T) {
d := newNetDialer("", "")
assert.IsType(t, &unixSyslogDialer{}, d)
}

View File

@@ -0,0 +1,22 @@
// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// 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 syslog
func newNetDialer(network, address string) netDialer {
return &defaultNetDialer{
network: network,
address: address,
}
}

View File

@@ -0,0 +1,25 @@
// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// 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.
// +build windows
package syslog
import "testing"
import "github.com/stretchr/testify/assert"
func TestNewNetDialer(t *testing.T) {
d := newNetDialer("tcp", "foo")
assert.IsType(t, &defaultDialer{}, d)
}

270
vendor/github.com/vmware/vic/pkg/log/syslog/writer.go generated vendored Normal file
View File

@@ -0,0 +1,270 @@
// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// 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 syslog
import (
"errors"
"io"
"net"
"strings"
"sync"
"time"
)
type Writer interface {
io.WriteCloser
Emerg(string) error
Crit(string) error
Err(string) error
Warning(string) error
Info(string) error
Debug(string) error
WithTag(tag string) Writer
WithPriority(priority Priority) Writer
}
type writer struct {
priority Priority
tag string
hostname string
msgs chan *msg
once sync.Once
done, running chan struct{}
dialer netDialer
conn net.Conn
formatter formatter
parent *writer
}
type msg struct {
p Priority
tag string
msg string
}
func newWriter(priority Priority, tag, hostname string, dialer netDialer, f formatter) *writer {
return &writer{
priority: priority,
tag: tag,
hostname: hostname,
dialer: dialer,
msgs: make(chan *msg, maxLogBuffer),
done: make(chan struct{}),
running: make(chan struct{}),
formatter: f,
}
}
// connect makes a connection to the syslog server.
// It must be called with w.mu held.
func (w *writer) connect() (err error) {
if w.conn != nil {
// ignore err from close, it makes sense to continue anyway
w.conn.Close()
w.conn = nil
}
Logger.Infof("trying to connect to syslog server")
w.conn, err = w.dialer.dial()
if err == nil {
Logger.Info("successfully connected to syslog server")
if w.hostname == "" {
// #nosec: Errors unhandled.
w.hostname, _, _ = net.SplitHostPort(w.conn.LocalAddr().String())
}
}
return
}
// Write sends a log message to the syslog daemon.
func (w *writer) Write(b []byte) (int, error) {
w.queueWrite(w.priority, w.tag, string(b))
return len(b), nil
}
// Close closes a connection to the syslog daemon.
func (w *writer) Close() error {
for w.parent != nil {
w = w.parent
}
w.once.Do(func() {
close(w.msgs)
select {
case <-w.running:
<-w.done
}
})
return nil
}
// Emerg logs a message with severity Emerg, ignoring the severity
// passed to New.
func (w *writer) Emerg(m string) error {
return w.queueWrite(Emerg, w.tag, m)
}
// Alert logs a message with severity Alert, ignoring the severity
// passed to New.
func (w *writer) Alert(m string) error {
return w.queueWrite(Alert, w.tag, m)
}
// Crit logs a message with severity Crit, ignoring the severity
// passed to New.
func (w *writer) Crit(m string) error {
return w.queueWrite(Crit, w.tag, m)
}
// Err logs a message with severity Err, ignoring the severity
// passed to New.
func (w *writer) Err(m string) error {
return w.queueWrite(Err, w.tag, m)
}
// Warning logs a message with severity Warning, ignoring the
// severity passed to New.
func (w *writer) Warning(m string) error {
return w.queueWrite(Warning, w.tag, m)
}
// Notice logs a message with severity Notice, ignoring the
// severity passed to New.
func (w *writer) Notice(m string) error {
return w.queueWrite(Notice, w.tag, m)
}
// Info logs a message with severity Info, ignoring the severity
// passed to New.
func (w *writer) Info(m string) error {
return w.queueWrite(Info, w.tag, m)
}
// Debug logs a message with severity Debug, ignoring the severity
// passed to New.
func (w *writer) Debug(m string) error {
return w.queueWrite(Debug, w.tag, m)
}
func (w *writer) queueWrite(p Priority, tag, s string) error {
for w.parent != nil {
w = w.parent
}
select {
case w.msgs <- &msg{p: p, tag: tag, msg: s}:
default:
return errors.New("queue full or writer closed")
}
return nil
}
func (w *writer) writeAndRetry(p Priority, tag, s string) (int, error) {
if len(s) == 0 {
return 0, nil
}
pr := (w.priority & facilityMask) | (p & severityMask)
if w.conn != nil {
n, err := w.write(pr, tag, s)
if err == nil {
return n, err
}
Logger.Errorf("syslog write failed: %s", err)
}
if err := w.connect(); err != nil {
return 0, err
}
return w.write(pr, tag, s)
}
// write generates and writes a syslog formatted string. The
// format is as follows: <PRI>TIMESTAMP HOSTNAME TAG[PID]: MSG
func (w *writer) write(p Priority, tag, msg string) (int, error) {
s := w.formatter.Format(p, time.Now(), w.hostname, tag, msg)
// ensure it ends in a \n
if !strings.HasSuffix(s, "\n") {
s = s + "\n"
}
_, err := w.conn.Write([]byte(s))
if err != nil {
return 0, err
}
// return len(msg), since we want to behave as an io.Writer
return len(msg), nil
}
func (w *writer) WithTag(tag string) Writer {
return &writer{
hostname: w.hostname,
tag: tag,
priority: w.priority,
parent: w,
}
}
func (w *writer) WithPriority(priority Priority) Writer {
if !validPriority(priority) {
return nil
}
return &writer{
hostname: w.hostname,
tag: w.tag,
priority: priority,
parent: w,
}
}
func (w *writer) run() {
Logger.Infof("run()")
defer func() {
Logger.Infof("exiting syslog writer loop")
if w.conn != nil {
w.conn.Close()
}
close(w.done)
}()
if err := w.connect(); err != nil {
switch err.(type) {
case *net.ParseError, *net.AddrError:
Logger.Errorf("could not connect to syslog server (will not try again): %s", err)
return
}
Logger.Errorf("error connecting to syslog server: %s", err)
}
close(w.running)
for m := range w.msgs {
for _, s := range strings.SplitAfter(m.msg, "\n") {
if _, err := w.writeAndRetry(m.p, m.tag, s); err != nil {
Logger.Errorf("could not write syslog message: %s", err)
}
}
}
}

View File

@@ -0,0 +1,278 @@
// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// 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 syslog
import (
"fmt"
"net"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
func TestWriterReconnect(t *testing.T) {
dn := &mockNetDialer{}
dn.On("dial").Return(nil, assert.AnError)
w := newWriter(priority, tag, "", dn, nil)
go w.run()
<-w.running
calls := []func(string) error{
w.Emerg,
w.Crit,
w.Err,
w.Warning,
w.Info,
w.Debug,
}
for _, f := range calls {
err := f("test")
assert.NoError(t, err)
}
w.Close()
dn.AssertNumberOfCalls(t, "dial", 1+len(calls))
}
func TestWriterWrite(t *testing.T) {
msg := "foo"
f := &mockFormatter{}
f.On("Format", priority, mock.Anything, "host", tag, msg).Return("test")
a := &MockAddr{}
a.On("String").Return("host:123")
c := &MockNetConn{}
c.On("LocalAddr").Return(a)
c.On("Write", []byte("test\n")).Return(len(msg), nil)
c.On("Close").Return(nil)
dn := &mockNetDialer{}
dn.On("dial").Return(c, nil)
w := newWriter(priority, tag, "", dn, f)
n, err := w.Write([]byte(msg))
assert.NoError(t, err)
assert.Equal(t, len(msg), n)
go w.run()
<-w.running
w.Close()
c.AssertExpectations(t)
dn.AssertNumberOfCalls(t, "dial", 1)
}
func TestMaxLogBuffer(t *testing.T) {
f := &mockFormatter{}
dn := &mockNetDialer{}
c := &MockNetConn{}
a := &MockAddr{}
a.On("String").Return("foo")
c.On("LocalAddr").Return(a)
c.On("Close").Return(nil)
dn.On("dial").Return(c, nil)
w := newWriter(priority, tag, "", dn, f)
for i := 0; i < maxLogBuffer+1; i++ {
msg := fmt.Sprintf("%d", i)
f.On("Format", priority, mock.Anything, "", tag, msg).Return(msg)
c.On("Write", []byte(msg+"\n")).Return(len(msg), nil)
w.Write([]byte(msg))
}
go w.run()
<-w.running
w.Close()
for i := 0; i < maxLogBuffer; i++ {
if !f.AssertCalled(t, "Format", priority, mock.Anything, "", tag, fmt.Sprintf("%d", i)) ||
!c.AssertCalled(t, "Write", []byte(fmt.Sprintf("%d\n", i))) {
}
}
f.AssertNumberOfCalls(t, "Format", maxLogBuffer)
f.AssertNotCalled(t, "Format", priority, mock.Anything, "", tag, fmt.Sprintf("%d", maxLogBuffer))
}
func TestWriterReconnectWrite(t *testing.T) {
dn := &mockNetDialer{}
c := &MockNetConn{}
a := &MockAddr{}
a.On("String").Return("addr:123")
c.On("LocalAddr").Return(a)
c.On("Close").Return(nil)
dn.On("dial").Return(nil, assert.AnError)
f := &mockFormatter{}
w := newWriter(priority, tag, "", dn, f)
go w.run()
<-w.running
dn.AssertNumberOfCalls(t, "dial", 1)
dn = &mockNetDialer{}
dn.On("dial").Return(c, nil)
w.dialer = dn
f.On("Format", priority, mock.Anything, "addr", tag, "test").Return("test")
c.On("Write", []byte("test\n")).Return(len("test"), nil)
w.Write([]byte("test"))
w.Close()
dn.AssertNumberOfCalls(t, "dial", 1)
c.AssertNumberOfCalls(t, "Write", 1) // 1 call to writer.write
f.AssertNumberOfCalls(t, "Format", 1)
}
func TestWriterReconnectWriteError(t *testing.T) {
dn := &mockNetDialer{}
c := &MockNetConn{}
a := &MockAddr{}
a.On("String").Return("addr:123")
c.On("LocalAddr").Return(a)
c.On("Close").Return(nil)
dn.On("dial").Return(c, nil)
f := &mockFormatter{}
w := newWriter(priority, tag, "", dn, f)
go w.run()
<-w.running
dn.AssertNumberOfCalls(t, "dial", 1)
f.On("Format", priority, mock.Anything, "addr", tag, "test").Return("test")
c.On("Write", []byte("test\n")).Return(0, assert.AnError)
w.Write([]byte("test"))
w.Close()
f.AssertExpectations(t)
c.AssertExpectations(t)
}
func TestWriterWithTag(t *testing.T) {
f := &mockFormatter{}
f.On("Format", priority, mock.Anything, "addr", "child", "child").Return("child")
f.On("Format", priority, mock.Anything, "addr", "gchild", "gchild").Return("gchild")
dn := &mockNetDialer{}
c := &MockNetConn{}
a := &MockAddr{}
a.On("String").Return("addr:123")
c.On("LocalAddr").Return(a)
c.On("Close").Return(nil)
c.On("Write", []byte("child\n")).Return(len("child"), nil)
c.On("Write", []byte("gchild\n")).Return(len("gchild"), nil)
dn.On("dial").Return(c, nil)
w := newWriter(priority, tag, "", dn, f)
child := w.WithTag("child")
child.Write([]byte("child"))
gchild := child.WithTag("gchild")
gchild.Write([]byte("gchild"))
go w.run()
<-w.running
child.Close()
gchild.Close()
select {
case <-w.done:
default:
assert.FailNow(t, "parent writer is not closed by child Close call")
}
f.AssertExpectations(t)
c.AssertExpectations(t)
}
func TestWriterWithPriority(t *testing.T) {
f := &mockFormatter{}
f.On("Format", Err|Daemon, mock.Anything, "addr", tag, "err").Return("err")
f.On("Format", Debug|Daemon, mock.Anything, "addr", tag, "debug").Return("debug")
dn := &mockNetDialer{}
c := &MockNetConn{}
a := &MockAddr{}
a.On("String").Return("addr:123")
c.On("LocalAddr").Return(a)
c.On("Close").Return(nil)
c.On("Write", []byte("err\n")).Return(len("err"), nil)
c.On("Write", []byte("debug\n")).Return(len("debug"), nil)
dn.On("dial").Return(c, nil)
w := newWriter(priority, tag, "", dn, f)
errw := w.WithPriority(Err | Daemon)
errw.Write([]byte("err"))
debugw := errw.WithPriority(Debug | Daemon)
debugw.Write([]byte("debug"))
go w.run()
<-w.running
errw.Close()
select {
case <-w.done:
default:
assert.FailNow(t, "parent writer is not closed by child Close call")
}
f.AssertExpectations(t)
c.AssertExpectations(t)
}
func TestWriterInitialConnectError(t *testing.T) {
var tests = []error{
&net.ParseError{},
&net.AddrError{},
}
for _, e := range tests {
dn := &mockNetDialer{}
dn.On("dial").Return(nil, e)
w := newWriter(priority, tag, "", dn, &mockFormatter{})
w.run()
select {
case <-w.running:
assert.FailNow(t, "writer should not run when connect() fails initially")
default:
}
}
}

63
vendor/github.com/vmware/vic/pkg/log/text_formatter.go generated vendored Normal file
View File

@@ -0,0 +1,63 @@
// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// 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 log
import "github.com/Sirupsen/logrus"
// level strings padded to match the length of the longest level,
// which is "UNKNOWN" currently. Indexed according to levels in
// logrus, e.g. levelStrs[logrus.InfoLevel] == "INFO ".
var levelStrs = []string{
"PANIC",
"FATAL",
"ERROR",
"WARN ",
"INFO ",
"DEBUG",
}
const unknownLevel = "UNKWN"
type TextFormatter struct {
// TimestampFormat is the format used to print the timestamp. By default
// an RFC3339 timestamp is used.
TimestampFormat string
}
// NewTextFormatter returns a text formatter
func NewTextFormatter() *TextFormatter {
return &TextFormatter{
TimestampFormat: "Jan _2 2006 15:04:05.000Z07:00",
}
}
func levelToString(level logrus.Level) string {
if level <= logrus.DebugLevel {
return levelStrs[level]
}
return unknownLevel
}
func (f *TextFormatter) Format(entry *logrus.Entry) ([]byte, error) {
t := f.timeStamp(entry)
l := levelToString(entry.Level)
return []byte(t + " " + l + " " + entry.Message + "\n"), nil
}
func (f *TextFormatter) timeStamp(entry *logrus.Entry) string {
return entry.Time.Format(f.TimestampFormat)
}

View File

@@ -0,0 +1,136 @@
// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// 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 log
import (
"bufio"
"fmt"
"strings"
"testing"
"time"
"github.com/Sirupsen/logrus"
"github.com/stretchr/testify/assert"
)
func BenchmarkFormatNonEmpty(b *testing.B) {
f := NewTextFormatter()
e := &logrus.Entry{
Time: time.Now(),
Level: logrus.InfoLevel,
Message: "the quick brown fox jumps over the lazy dog",
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
f.Format(e)
}
}
func BenchmarkFormatEmpty(b *testing.B) {
f := NewTextFormatter()
e := &logrus.Entry{
Time: time.Now(),
Level: logrus.InfoLevel,
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
f.Format(e)
}
}
func TestFormatEmpty(t *testing.T) {
ti := time.Now()
e := &logrus.Entry{Time: ti, Level: logrus.InfoLevel}
f := NewTextFormatter()
b, err := f.Format(e)
assert.NoError(t, err)
assert.Equal(t, fmt.Sprintf("%s %s \n", ti.Format(f.TimestampFormat), levelToString(e.Level)), string(b))
}
func TestFormatNonEmpty(t *testing.T) {
ti := time.Now()
m := "foo bar baz"
e := &logrus.Entry{Time: ti, Level: logrus.InfoLevel, Message: m}
f := NewTextFormatter()
b, err := f.Format(e)
assert.NoError(t, err)
assert.Equal(t, fmt.Sprintf("%s %s %s\n", ti.Format(f.TimestampFormat), levelToString(e.Level), m), string(b))
// test with multiple lines
pre := fmt.Sprintf("%s %s ", ti.Format(f.TimestampFormat), levelToString(e.Level))
var tests = []struct {
in string
out []string
}{
{
"foo",
[]string{
pre + "foo",
},
},
{
"\n",
[]string{
pre,
"",
},
},
{
"foo\n",
[]string{
pre + "foo",
"",
},
},
{
"\nfoo\n",
[]string{
pre + "",
"foo",
"",
},
},
{
"foo\n",
[]string{
pre + "foo",
"",
},
},
{
"foo \nbar\n baz ",
[]string{
pre + "foo ",
"bar",
" baz ",
},
},
}
for idx, te := range tests {
e.Message = te.in
b, err = f.Format(e)
assert.NoError(t, err)
s := bufio.NewScanner(strings.NewReader(string(b)))
i := 0
for s.Scan() {
assert.True(t, i < len(te.out), "case %d", idx)
assert.Equal(t, te.out[i], s.Text(), "case %d", idx)
i++
}
}
}