Support CNI 1.0.0

Fix #792
This commit is contained in:
Tomofumi Hayashi
2022-03-02 01:55:23 +09:00
parent ecc98be9c6
commit 93ec0c121e
835 changed files with 80172 additions and 36848 deletions

2
vendor/k8s.io/klog/v2/OWNERS generated vendored
View File

@@ -15,5 +15,5 @@ approvers:
- tallclair
- piosz
- brancz
- DirectXMan12
- lavalamp
- serathius

2
vendor/k8s.io/klog/v2/go.mod generated vendored
View File

@@ -2,4 +2,4 @@ module k8s.io/klog/v2
go 1.13
require github.com/go-logr/logr v0.2.0
require github.com/go-logr/logr v1.2.0

4
vendor/k8s.io/klog/v2/go.sum generated vendored
View File

@@ -1,2 +1,2 @@
github.com/go-logr/logr v0.2.0 h1:QvGt2nLcHH0WK9orKa+ppBPAxREcH364nPUedEpK0TY=
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE=
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=

307
vendor/k8s.io/klog/v2/klog.go generated vendored
View File

@@ -81,6 +81,7 @@ import (
"math"
"os"
"path/filepath"
"reflect"
"runtime"
"strconv"
"strings"
@@ -283,6 +284,7 @@ func (m *moduleSpec) Get() interface{} {
var errVmoduleSyntax = errors.New("syntax error: expect comma-separated list of filename=N")
// Set will sets module value
// Syntax: -vmodule=recordio=2,file=1,gfs*=3
func (m *moduleSpec) Set(value string) error {
var filter []modulePat
@@ -361,6 +363,7 @@ func (t *traceLocation) Get() interface{} {
var errTraceSyntax = errors.New("syntax error: expect file.go:234")
// Set will sets backtrace value
// Syntax: -log_backtrace_at=gopherflakes.go:234
// Note that unlike vmodule the file extension is included here.
func (t *traceLocation) Set(value string) error {
@@ -433,7 +436,7 @@ func InitFlags(flagset *flag.FlagSet) {
flagset.Var(&logging.verbosity, "v", "number for the log level verbosity")
flagset.BoolVar(&logging.addDirHeader, "add_dir_header", logging.addDirHeader, "If true, adds the file directory to the header of the log messages")
flagset.BoolVar(&logging.skipHeaders, "skip_headers", logging.skipHeaders, "If true, avoid header prefixes in the log messages")
flagset.BoolVar(&logging.oneOutput, "one_output", logging.oneOutput, "If true, only write logs to their native severity level (vs also writing to each lower severity level")
flagset.BoolVar(&logging.oneOutput, "one_output", logging.oneOutput, "If true, only write logs to their native severity level (vs also writing to each lower severity level)")
flagset.BoolVar(&logging.skipLogHeaders, "skip_log_headers", logging.skipLogHeaders, "If true, avoid headers when opening log files")
flagset.Var(&logging.stderrThreshold, "stderrthreshold", "logs at or above this threshold go to stderr")
flagset.Var(&logging.vmodule, "vmodule", "comma-separated list of pattern=N settings for file-filtered logging")
@@ -506,7 +509,7 @@ type loggingT struct {
addDirHeader bool
// If set, all output will be redirected unconditionally to the provided logr.Logger
logr logr.Logger
logr *logr.Logger
// If true, messages will not be propagated to lower severity log levels
oneOutput bool
@@ -695,11 +698,11 @@ func (buf *buffer) someDigits(i, d int) int {
return copy(buf.tmp[i:], buf.tmp[j:])
}
func (l *loggingT) println(s severity, logr logr.Logger, filter LogFilter, args ...interface{}) {
func (l *loggingT) println(s severity, logger *logr.Logger, filter LogFilter, args ...interface{}) {
buf, file, line := l.header(s, 0)
// if logr is set, we clear the generated header as we rely on the backing
// logr implementation to print headers
if logr != nil {
// if logger is set, we clear the generated header as we rely on the backing
// logger implementation to print headers
if logger != nil {
l.putBuffer(buf)
buf = l.getBuffer()
}
@@ -707,18 +710,18 @@ func (l *loggingT) println(s severity, logr logr.Logger, filter LogFilter, args
args = filter.Filter(args)
}
fmt.Fprintln(buf, args...)
l.output(s, logr, buf, file, line, false)
l.output(s, logger, buf, 0 /* depth */, file, line, false)
}
func (l *loggingT) print(s severity, logr logr.Logger, filter LogFilter, args ...interface{}) {
l.printDepth(s, logr, filter, 1, args...)
func (l *loggingT) print(s severity, logger *logr.Logger, filter LogFilter, args ...interface{}) {
l.printDepth(s, logger, filter, 1, args...)
}
func (l *loggingT) printDepth(s severity, logr logr.Logger, filter LogFilter, depth int, args ...interface{}) {
func (l *loggingT) printDepth(s severity, logger *logr.Logger, filter LogFilter, depth int, args ...interface{}) {
buf, file, line := l.header(s, depth)
// if logr is set, we clear the generated header as we rely on the backing
// logr implementation to print headers
if logr != nil {
if logger != nil {
l.putBuffer(buf)
buf = l.getBuffer()
}
@@ -729,14 +732,14 @@ func (l *loggingT) printDepth(s severity, logr logr.Logger, filter LogFilter, de
if buf.Bytes()[buf.Len()-1] != '\n' {
buf.WriteByte('\n')
}
l.output(s, logr, buf, file, line, false)
l.output(s, logger, buf, depth, file, line, false)
}
func (l *loggingT) printf(s severity, logr logr.Logger, filter LogFilter, format string, args ...interface{}) {
func (l *loggingT) printf(s severity, logger *logr.Logger, filter LogFilter, format string, args ...interface{}) {
buf, file, line := l.header(s, 0)
// if logr is set, we clear the generated header as we rely on the backing
// logr implementation to print headers
if logr != nil {
if logger != nil {
l.putBuffer(buf)
buf = l.getBuffer()
}
@@ -747,17 +750,17 @@ func (l *loggingT) printf(s severity, logr logr.Logger, filter LogFilter, format
if buf.Bytes()[buf.Len()-1] != '\n' {
buf.WriteByte('\n')
}
l.output(s, logr, buf, file, line, false)
l.output(s, logger, buf, 0 /* depth */, file, line, false)
}
// printWithFileLine behaves like print but uses the provided file and line number. If
// alsoLogToStderr is true, the log message always appears on standard error; it
// will also appear in the log file unless --logtostderr is set.
func (l *loggingT) printWithFileLine(s severity, logr logr.Logger, filter LogFilter, file string, line int, alsoToStderr bool, args ...interface{}) {
func (l *loggingT) printWithFileLine(s severity, logger *logr.Logger, filter LogFilter, file string, line int, alsoToStderr bool, args ...interface{}) {
buf := l.formatHeader(s, file, line)
// if logr is set, we clear the generated header as we rely on the backing
// logr implementation to print headers
if logr != nil {
if logger != nil {
l.putBuffer(buf)
buf = l.getBuffer()
}
@@ -768,50 +771,49 @@ func (l *loggingT) printWithFileLine(s severity, logr logr.Logger, filter LogFil
if buf.Bytes()[buf.Len()-1] != '\n' {
buf.WriteByte('\n')
}
l.output(s, logr, buf, file, line, alsoToStderr)
l.output(s, logger, buf, 2 /* depth */, file, line, alsoToStderr)
}
// if loggr is specified, will call loggr.Error, otherwise output with logging module.
func (l *loggingT) errorS(err error, loggr logr.Logger, filter LogFilter, msg string, keysAndValues ...interface{}) {
func (l *loggingT) errorS(err error, logger *logr.Logger, filter LogFilter, depth int, msg string, keysAndValues ...interface{}) {
if filter != nil {
msg, keysAndValues = filter.FilterS(msg, keysAndValues)
}
if loggr != nil {
loggr.Error(err, msg, keysAndValues...)
if logger != nil {
logger.WithCallDepth(depth+2).Error(err, msg, keysAndValues...)
return
}
l.printS(err, msg, keysAndValues...)
l.printS(err, errorLog, depth+1, msg, keysAndValues...)
}
// if loggr is specified, will call loggr.Info, otherwise output with logging module.
func (l *loggingT) infoS(loggr logr.Logger, filter LogFilter, msg string, keysAndValues ...interface{}) {
func (l *loggingT) infoS(logger *logr.Logger, filter LogFilter, depth int, msg string, keysAndValues ...interface{}) {
if filter != nil {
msg, keysAndValues = filter.FilterS(msg, keysAndValues)
}
if loggr != nil {
loggr.Info(msg, keysAndValues...)
if logger != nil {
logger.WithCallDepth(depth+2).Info(msg, keysAndValues...)
return
}
l.printS(nil, msg, keysAndValues...)
l.printS(nil, infoLog, depth+1, msg, keysAndValues...)
}
// printS is called from infoS and errorS if loggr is not specified.
// if err arguments is specified, will output to errorLog severity
func (l *loggingT) printS(err error, msg string, keysAndValues ...interface{}) {
b := &bytes.Buffer{}
b.WriteString(fmt.Sprintf("%q", msg))
// set log severity by s
func (l *loggingT) printS(err error, s severity, depth int, msg string, keysAndValues ...interface{}) {
// Only create a new buffer if we don't have one cached.
b := l.getBuffer()
// The message is always quoted, even if it contains line breaks.
// If developers want multi-line output, they should use a small, fixed
// message and put the multi-line output into a value.
b.WriteString(strconv.Quote(msg))
if err != nil {
b.WriteByte(' ')
b.WriteString(fmt.Sprintf("err=%q", err.Error()))
kvListFormat(&b.Buffer, "err", err)
}
kvListFormat(b, keysAndValues...)
var s severity
if err == nil {
s = infoLog
} else {
s = errorLog
}
l.printDepth(s, logging.logr, nil, 2, b)
kvListFormat(&b.Buffer, keysAndValues...)
l.printDepth(s, logging.logr, nil, depth+1, &b.Buffer)
// Make the buffer available for reuse.
l.putBuffer(b)
}
const missingValue = "(MISSING)"
@@ -826,17 +828,106 @@ func kvListFormat(b *bytes.Buffer, keysAndValues ...interface{}) {
v = missingValue
}
b.WriteByte(' ')
switch v.(type) {
case string, error:
b.WriteString(fmt.Sprintf("%s=%q", k, v))
default:
if _, ok := v.(fmt.Stringer); ok {
b.WriteString(fmt.Sprintf("%s=%q", k, v))
} else {
b.WriteString(fmt.Sprintf("%s=%+v", k, v))
}
// Keys are assumed to be well-formed according to
// https://github.com/kubernetes/community/blob/master/contributors/devel/sig-instrumentation/migration-to-structured-logging.md#name-arguments
// for the sake of performance. Keys with spaces,
// special characters, etc. will break parsing.
if k, ok := k.(string); ok {
// Avoid one allocation when the key is a string, which
// normally it should be.
b.WriteString(k)
} else {
b.WriteString(fmt.Sprintf("%s", k))
}
// The type checks are sorted so that more frequently used ones
// come first because that is then faster in the common
// cases. In Kubernetes, ObjectRef (a Stringer) is more common
// than plain strings
// (https://github.com/kubernetes/kubernetes/pull/106594#issuecomment-975526235).
switch v := v.(type) {
case fmt.Stringer:
writeStringValue(b, true, stringerToString(v))
case string:
writeStringValue(b, true, v)
case error:
writeStringValue(b, true, v.Error())
case []byte:
// In https://github.com/kubernetes/klog/pull/237 it was decided
// to format byte slices with "%+q". The advantages of that are:
// - readable output if the bytes happen to be printable
// - non-printable bytes get represented as unicode escape
// sequences (\uxxxx)
//
// The downsides are that we cannot use the faster
// strconv.Quote here and that multi-line output is not
// supported. If developers know that a byte array is
// printable and they want multi-line output, they can
// convert the value to string before logging it.
b.WriteByte('=')
b.WriteString(fmt.Sprintf("%+q", v))
default:
writeStringValue(b, false, fmt.Sprintf("%+v", v))
}
}
}
func stringerToString(s fmt.Stringer) (ret string) {
defer func() {
if err := recover(); err != nil {
ret = "nil"
}
}()
ret = s.String()
return
}
func writeStringValue(b *bytes.Buffer, quote bool, v string) {
data := []byte(v)
index := bytes.IndexByte(data, '\n')
if index == -1 {
b.WriteByte('=')
if quote {
// Simple string, quote quotation marks and non-printable characters.
b.WriteString(strconv.Quote(v))
return
}
// Non-string with no line breaks.
b.WriteString(v)
return
}
// Complex multi-line string, show as-is with indention like this:
// I... "hello world" key=<
// <tab>line 1
// <tab>line 2
// >
//
// Tabs indent the lines of the value while the end of string delimiter
// is indented with a space. That has two purposes:
// - visual difference between the two for a human reader because indention
// will be different
// - no ambiguity when some value line starts with the end delimiter
//
// One downside is that the output cannot distinguish between strings that
// end with a line break and those that don't because the end delimiter
// will always be on the next line.
b.WriteString("=<\n")
for index != -1 {
b.WriteByte('\t')
b.Write(data[0 : index+1])
data = data[index+1:]
index = bytes.IndexByte(data, '\n')
}
if len(data) == 0 {
// String ended with line break, don't add another.
b.WriteString(" >")
} else {
// No line break at end of last line, write rest of string and
// add one.
b.WriteByte('\t')
b.Write(data)
b.WriteString("\n >")
}
}
@@ -860,13 +951,26 @@ func (rb *redirectBuffer) Write(bytes []byte) (n int, err error) {
// SetLogger will set the backing logr implementation for klog.
// If set, all log lines will be suppressed from the regular Output, and
// redirected to the logr implementation.
// All log lines include the 'severity', 'file' and 'line' values attached as
// structured logging values.
// Use as:
// ...
// klog.SetLogger(zapr.NewLogger(zapLog))
//
// To remove a backing logr implemention, use ClearLogger. Setting an
// empty logger with SetLogger(logr.Logger{}) does not work.
func SetLogger(logr logr.Logger) {
logging.logr = logr
logging.mu.Lock()
defer logging.mu.Unlock()
logging.logr = &logr
}
// ClearLogger removes a backing logr implementation if one was set earlier
// with SetLogger.
func ClearLogger() {
logging.mu.Lock()
defer logging.mu.Unlock()
logging.logr = nil
}
// SetOutput sets the output destination for all severities
@@ -904,8 +1008,16 @@ func LogToStderr(stderr bool) {
}
// output writes the data to the log files and releases the buffer.
func (l *loggingT) output(s severity, log logr.Logger, buf *buffer, file string, line int, alsoToStderr bool) {
func (l *loggingT) output(s severity, log *logr.Logger, buf *buffer, depth int, file string, line int, alsoToStderr bool) {
var isLocked = true
l.mu.Lock()
defer func() {
if isLocked {
// Unlock before returning in case that it wasn't done already.
l.mu.Unlock()
}
}()
if l.traceLocation.isSet() {
if l.traceLocation.match(file, line) {
buf.Write(stacks(false))
@@ -916,9 +1028,9 @@ func (l *loggingT) output(s severity, log logr.Logger, buf *buffer, file string,
// TODO: set 'severity' and caller information as structured log info
// keysAndValues := []interface{}{"severity", severityName[s], "file", file, "line", line}
if s == errorLog {
l.logr.Error(nil, string(data))
l.logr.WithCallDepth(depth+3).Error(nil, string(data))
} else {
log.Info(string(data))
log.WithCallDepth(depth + 3).Info(string(data))
}
} else if l.toStderr {
os.Stderr.Write(data)
@@ -968,6 +1080,7 @@ func (l *loggingT) output(s severity, log logr.Logger, buf *buffer, file string,
// If we got here via Exit rather than Fatal, print no stacks.
if atomic.LoadUint32(&fatalNoStacks) > 0 {
l.mu.Unlock()
isLocked = false
timeoutFlush(10 * time.Second)
os.Exit(1)
}
@@ -985,11 +1098,12 @@ func (l *loggingT) output(s severity, log logr.Logger, buf *buffer, file string,
}
}
l.mu.Unlock()
isLocked = false
timeoutFlush(10 * time.Second)
os.Exit(255) // C++ uses -1, which is silly because it's anded with 255 anyway.
os.Exit(255) // C++ uses -1, which is silly because it's anded(&) with 255 anyway.
}
l.putBuffer(buf)
l.mu.Unlock()
if stats := severityStats[s]; stats != nil {
atomic.AddInt64(&stats.lines, 1)
atomic.AddInt64(&stats.bytes, int64(len(data)))
@@ -1269,7 +1383,7 @@ func (l *loggingT) setV(pc uintptr) Level {
// See the documentation of V for more information.
type Verbose struct {
enabled bool
logr logr.Logger
logr *logr.Logger
filter LogFilter
}
@@ -1277,7 +1391,8 @@ func newVerbose(level Level, b bool) Verbose {
if logging.logr == nil {
return Verbose{b, nil, logging.filter}
}
return Verbose{b, logging.logr.V(int(level)), logging.filter}
v := logging.logr.V(int(level))
return Verbose{b, &v, logging.filter}
}
// V reports whether verbosity at the call site is at least the requested level.
@@ -1315,9 +1430,14 @@ func V(level Level) Verbose {
if runtime.Callers(2, logging.pcs[:]) == 0 {
return newVerbose(level, false)
}
v, ok := logging.vmap[logging.pcs[0]]
// runtime.Callers returns "return PCs", but we want
// to look up the symbolic information for the call,
// so subtract 1 from the PC. runtime.CallersFrames
// would be cleaner, but allocates.
pc := logging.pcs[0] - 1
v, ok := logging.vmap[pc]
if !ok {
v = logging.setV(logging.pcs[0])
v = logging.setV(pc)
}
return newVerbose(level, v >= level)
}
@@ -1359,14 +1479,28 @@ func (v Verbose) Infof(format string, args ...interface{}) {
// See the documentation of V for usage.
func (v Verbose) InfoS(msg string, keysAndValues ...interface{}) {
if v.enabled {
logging.infoS(v.logr, v.filter, msg, keysAndValues...)
logging.infoS(v.logr, v.filter, 0, msg, keysAndValues...)
}
}
// InfoSDepth acts as InfoS but uses depth to determine which call frame to log.
// InfoSDepth(0, "msg") is the same as InfoS("msg").
func InfoSDepth(depth int, msg string, keysAndValues ...interface{}) {
logging.infoS(logging.logr, logging.filter, depth, msg, keysAndValues...)
}
// InfoSDepth is equivalent to the global InfoSDepth function, guarded by the value of v.
// See the documentation of V for usage.
func (v Verbose) InfoSDepth(depth int, msg string, keysAndValues ...interface{}) {
if v.enabled {
logging.infoS(v.logr, v.filter, depth, msg, keysAndValues...)
}
}
// Deprecated: Use ErrorS instead.
func (v Verbose) Error(err error, msg string, args ...interface{}) {
if v.enabled {
logging.errorS(err, v.logr, v.filter, msg, args...)
logging.errorS(err, v.logr, v.filter, 0, msg, args...)
}
}
@@ -1374,7 +1508,7 @@ func (v Verbose) Error(err error, msg string, args ...interface{}) {
// See the documentation of V for usage.
func (v Verbose) ErrorS(err error, msg string, keysAndValues ...interface{}) {
if v.enabled {
logging.errorS(err, v.logr, v.filter, msg, keysAndValues...)
logging.errorS(err, v.logr, v.filter, 0, msg, keysAndValues...)
}
}
@@ -1411,7 +1545,7 @@ func Infof(format string, args ...interface{}) {
// output:
// >> I1025 00:15:15.525108 1 controller_utils.go:116] "Pod status updated" pod="kubedns" status="ready"
func InfoS(msg string, keysAndValues ...interface{}) {
logging.infoS(logging.logr, logging.filter, msg, keysAndValues...)
logging.infoS(logging.logr, logging.filter, 0, msg, keysAndValues...)
}
// Warning logs to the WARNING and INFO logs.
@@ -1472,7 +1606,13 @@ func Errorf(format string, args ...interface{}) {
// output:
// >> E1025 00:15:15.525108 1 controller_utils.go:114] "Failed to update pod status" err="timeout"
func ErrorS(err error, msg string, keysAndValues ...interface{}) {
logging.errorS(err, logging.logr, logging.filter, msg, keysAndValues...)
logging.errorS(err, logging.logr, logging.filter, 0, msg, keysAndValues...)
}
// ErrorSDepth acts as ErrorS but uses depth to determine which call frame to log.
// ErrorSDepth(0, "msg") is the same as ErrorS("msg").
func ErrorSDepth(depth int, err error, msg string, keysAndValues ...interface{}) {
logging.errorS(err, logging.logr, logging.filter, depth, msg, keysAndValues...)
}
// Fatal logs to the FATAL, ERROR, WARNING, and INFO logs,
@@ -1561,6 +1701,15 @@ func (ref ObjectRef) String() string {
return ref.Name
}
// MarshalLog ensures that loggers with support for structured output will log
// as a struct by removing the String method via a custom type.
func (ref ObjectRef) MarshalLog() interface{} {
type or ObjectRef
return or(ref)
}
var _ logr.Marshaler = ObjectRef{}
// KMetadata is a subset of the kubernetes k8s.io/apimachinery/pkg/apis/meta/v1.Object interface
// this interface may expand in the future, but will always be a subset of the
// kubernetes k8s.io/apimachinery/pkg/apis/meta/v1.Object interface
@@ -1571,6 +1720,13 @@ type KMetadata interface {
// KObj returns ObjectRef from ObjectMeta
func KObj(obj KMetadata) ObjectRef {
if obj == nil {
return ObjectRef{}
}
if val := reflect.ValueOf(obj); val.Kind() == reflect.Ptr && val.IsNil() {
return ObjectRef{}
}
return ObjectRef{
Name: obj.GetName(),
Namespace: obj.GetNamespace(),
@@ -1584,3 +1740,20 @@ func KRef(namespace, name string) ObjectRef {
Namespace: namespace,
}
}
// KObjs returns slice of ObjectRef from an slice of ObjectMeta
func KObjs(arg interface{}) []ObjectRef {
s := reflect.ValueOf(arg)
if s.Kind() != reflect.Slice {
return nil
}
objectRefs := make([]ObjectRef, 0, s.Len())
for i := 0; i < s.Len(); i++ {
if v, ok := s.Index(i).Interface().(KMetadata); ok {
objectRefs = append(objectRefs, KObj(v))
} else {
return nil
}
}
return objectRefs
}

34
vendor/k8s.io/klog/v2/klog_file.go generated vendored
View File

@@ -22,9 +22,7 @@ import (
"errors"
"fmt"
"os"
"os/user"
"path/filepath"
"runtime"
"strings"
"sync"
"time"
@@ -57,38 +55,6 @@ func init() {
}
}
func getUserName() string {
userNameOnce.Do(func() {
// On Windows, the Go 'user' package requires netapi32.dll.
// This affects Windows Nano Server:
// https://github.com/golang/go/issues/21867
// Fallback to using environment variables.
if runtime.GOOS == "windows" {
u := os.Getenv("USERNAME")
if len(u) == 0 {
return
}
// Sanitize the USERNAME since it may contain filepath separators.
u = strings.Replace(u, `\`, "_", -1)
// user.Current().Username normally produces something like 'USERDOMAIN\USERNAME'
d := os.Getenv("USERDOMAIN")
if len(d) != 0 {
userName = d + "_" + u
} else {
userName = u
}
} else {
current, err := user.Current()
if err == nil {
userName = current.Username
}
}
})
return userName
}
// shortHostname returns its argument, truncating at the first period.
// For instance, given "www.google.com" it returns "www".
func shortHostname(hostname string) string {

19
vendor/k8s.io/klog/v2/klog_file_others.go generated vendored Normal file
View File

@@ -0,0 +1,19 @@
//go:build !windows
// +build !windows
package klog
import (
"os/user"
)
func getUserName() string {
userNameOnce.Do(func() {
current, err := user.Current()
if err == nil {
userName = current.Username
}
})
return userName
}

34
vendor/k8s.io/klog/v2/klog_file_windows.go generated vendored Normal file
View File

@@ -0,0 +1,34 @@
//go:build windows
// +build windows
package klog
import (
"os"
"strings"
)
func getUserName() string {
userNameOnce.Do(func() {
// On Windows, the Go 'user' package requires netapi32.dll.
// This affects Windows Nano Server:
// https://github.com/golang/go/issues/21867
// Fallback to using environment variables.
u := os.Getenv("USERNAME")
if len(u) == 0 {
return
}
// Sanitize the USERNAME since it may contain filepath separators.
u = strings.Replace(u, `\`, "_", -1)
// user.Current().Username normally produces something like 'USERDOMAIN\USERNAME'
d := os.Getenv("USERDOMAIN")
if len(d) != 0 {
userName = d + "_" + u
} else {
userName = u
}
})
return userName
}