taleintervenor dfaef9d393 syscontainer-tools: update license to Mulan PSL v2
reason: update license to Mulan PSL v2

Signed-off-by: taleintervenor <taleintervenor@aliyun.com>
2020-04-27 14:54:17 +08:00

187 lines
5.1 KiB
Go

// Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. All rights reserved.
// syscontainer-tools is licensed under the Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
// http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
// PURPOSE.
// See the Mulan PSL v2 for more details.
// Description: common utils
// Author: zhangwei
// Create: 2018-01-18
package utils
import (
"crypto/rand"
"encoding/hex"
"fmt"
"io"
"log"
"log/syslog"
"os"
"path/filepath"
"strings"
"syscall"
"time"
libctr_utils "github.com/opencontainers/runc/libcontainer/utils"
"github.com/sirupsen/logrus"
)
// SyslogHook to send logs via syslog.
type syslogHook struct {
logger *log.Logger
}
// Creates a hook to be added to an instance of logger. This is called with
// `hook, err := newSyslogHook("default", "udp", "localhost:514", syslog.LOG_DEBUG, "")`
// `if err == nil { log.Hooks.Add(hook) }`
func newSyslogHook(network, raddr string, priority syslog.Priority, tag string) (*syslogHook, error) {
var logger *log.Logger
var err error
if network == "default" {
logger, err = syslog.NewLogger(priority, log.Lshortfile)
if err != nil {
return nil, err
}
logger.SetPrefix(tag)
} else {
w, err := syslog.Dial(network, raddr, priority, "")
if err != nil {
return nil, err
}
logger = log.New(w, tag, log.Lshortfile)
}
return &syslogHook{logger}, err
}
func (hook *syslogHook) Fire(entry *logrus.Entry) error {
line, err := entry.String()
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err)
return err
}
if err := hook.logger.Output(8, line); err != nil {
logrus.Errorf("hook.logger.Output err: %s", err)
}
return nil
}
func (hook *syslogHook) Levels() []logrus.Level {
return logrus.AllLevels
}
const (
syslogUDPPrefix = "udp://"
syslogTCPPrefix = "tcp://"
syslogUnixSock = "unix://"
syslogDefaultUDPService = "localhost:541"
syslogDefaultTCPService = "localhost:541"
)
// SyslogService is a structure which records the syslog service type and serivce address.
type SyslogService struct {
Type string
Addr string
}
// ParseSyslogService parses syslog service from input string
func ParseSyslogService(service string) (*SyslogService, error) {
var serviceType, serviceAddr string
if service == "" {
serviceType = "default"
serviceAddr = ""
} else if strings.HasPrefix(service, syslogUDPPrefix) {
serviceType = "udp"
serviceAddr := service[len(syslogUDPPrefix):]
if serviceAddr == "" {
serviceAddr = syslogDefaultUDPService
}
} else if strings.HasPrefix(service, syslogTCPPrefix) {
serviceType = "tcp"
serviceAddr = service[len(syslogTCPPrefix):]
if serviceAddr == "" {
serviceAddr = syslogDefaultTCPService
}
} else if strings.HasPrefix(service, syslogUnixSock) {
// syslog package will use empty string as network,
// and syslog will lookup the unix socket on host, we do not care.
serviceType = ""
serviceAddr = service[len(syslogUnixSock):]
} else {
return nil, fmt.Errorf("Unspported syslog network: %s", service)
}
serv := &SyslogService{
Type: serviceType,
Addr: serviceAddr,
}
return serv, nil
}
// HookSyslog will hook syslog service to logrus
// syslog supports 4 kinds of service:
// 1. default socket: ""
// 2. unix socket: "unix:///dev/log"
// 3. udp port: "udp://localhost:541"
// 4. tcp port: "tcp://localhost:541"
// by default, if we output to local syslog, use default will be fine.
// syslog Tag:
// syslog will use tag to separate the output stream.
func HookSyslog(service, tag string) error {
serv, err := ParseSyslogService(service)
if err != nil {
return err
}
hook, err := newSyslogHook(serv.Type, serv.Addr, syslog.LOG_INFO|syslog.LOG_USER, tag)
if err != nil {
return fmt.Errorf("Unable to connect to syslog daemon")
}
logrus.AddHook(hook)
return nil
}
// NewPipe creates a pair of new socket pipe.
func NewPipe() (parent, child *os.File, err error) {
fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM|syscall.SOCK_CLOEXEC, 0)
if err != nil {
return nil, nil, err
}
return os.NewFile(uintptr(fds[1]), "parent"), os.NewFile(uintptr(fds[0]), "child"), nil
}
// WriteJSON write json data to io stream
func WriteJSON(w io.Writer, v interface{}) error {
return libctr_utils.WriteJSON(w, v)
}
// RandomID returns a 8-bit ramdon string which read from rand.Reader first,
// and if failed, will use time stamp as random id
func RandomID() string {
id := make([]byte, 32)
if _, err := io.ReadFull(rand.Reader, id); err != nil {
cur := time.Now()
return fmt.Sprint(cur.UnixNano())
}
return hex.EncodeToString(id)[:8]
}
// RandomFile will find a non-existing file in given folder.
func RandomFile(folder string) string {
path := ""
for {
id := RandomID()
path = filepath.Join(folder, id)
if _, err := os.Stat(path); os.IsNotExist(err) {
break
}
}
return path
}