Merge remote-tracking branch 'origin/master' into feature/multus-4.0

This commit is contained in:
Tomofumi Hayashi
2022-04-12 19:19:49 +09:00
14 changed files with 398 additions and 37 deletions

View File

@@ -40,6 +40,10 @@ const (
defaultCniConfigDir = "/etc/cni/net.d"
defaultMultusGlobalNamespaces = ""
defaultMultusLogFile = ""
defaultMultusLogMaxSize = 100 // megabytes
defaultMultusLogMaxAge = 5 // days
defaultMultusLogMaxBackups = 5
defaultMultusLogCompress = true
defaultMultusLogLevel = ""
defaultMultusLogToStdErr = false
defaultMultusMasterCNIFile = ""
@@ -55,6 +59,10 @@ const (
multusConfigFileVarName = "multus-conf-file"
multusGlobalNamespaces = "global-namespaces"
multusLogFile = "multus-log-file"
multusLogMaxSize = "multus-log-max-size"
multusLogMaxAge = "multus-log-max-age"
multusLogMaxBackups = "multus-log-max-backups"
multusLogCompress = "multus-log-compress"
multusLogLevel = "multus-log-level"
multusLogToStdErr = "multus-log-to-stderr"
multusMasterCNIFileVarName = "multus-master-cni-file"
@@ -75,6 +83,10 @@ func main() {
logToStdErr := flag.Bool(multusLogToStdErr, false, "If the multus logs are also to be echoed to stderr.")
logLevel := flag.String(multusLogLevel, "", "One of: debug/verbose/error/panic. Used only with --multus-conf-file=auto.")
logFile := flag.String(multusLogFile, "", "Path where to multus will log. Used only with --multus-conf-file=auto.")
logMaxSize := flag.Int(multusLogMaxSize, defaultMultusLogMaxSize, "the maximum size in megabytes of the log file before it gets rotated")
logMaxAge := flag.Int(multusLogMaxAge, defaultMultusLogMaxAge, "the maximum number of days to retain old log files in their filename")
logMaxBackups := flag.Int(multusLogMaxBackups, defaultMultusLogMaxBackups, "the maximum number of old log files to retain")
logCompress := flag.Bool(multusLogCompress, defaultMultusLogCompress, "compress determines if the rotated log files should be compressed using gzip")
cniVersion := flag.String(multusCNIVersion, "", "Allows you to specify CNI spec version. Used only with --multus-conf-file=auto.")
forceCNIVersion := flag.Bool("force-cni-version", false, "force to use given CNI version. only for kind-e2e testing") // this is only for kind-e2e
readinessIndicator := flag.String(multusReadinessIndicatorFile, "", "Which file should be used as the readiness indicator. Used only with --multus-conf-file=auto.")
@@ -127,6 +139,28 @@ func main() {
configurationOptions, config.WithReadinessFileIndicator(*readinessIndicator))
}
// logOptions
var logOptionFuncs []config.LogOptionFunc
if *logMaxAge != defaultMultusLogMaxAge {
logOptionFuncs = append(logOptionFuncs, config.WithLogMaxAge(logMaxAge))
}
if *logMaxSize != defaultMultusLogMaxSize {
logOptionFuncs = append(logOptionFuncs, config.WithLogMaxSize(logMaxSize))
}
if *logMaxBackups != defaultMultusLogMaxBackups {
logOptionFuncs = append(logOptionFuncs, config.WithLogMaxBackups(logMaxBackups))
}
if *logCompress != defaultMultusLogCompress {
logOptionFuncs = append(logOptionFuncs, config.WithLogCompress(logCompress))
}
if len(logOptionFuncs) > 0 {
logOptions := &config.LogOptions{}
config.MutateLogOptions(logOptions, logOptionFuncs...)
configurationOptions = append(configurationOptions, config.WithLogOptions(logOptions))
}
multusConfig, err := config.NewMultusConfig(multusPluginName, *cniVersion, configurationOptions...)
if err != nil {
_ = logging.Errorf("Failed to create multus config: %v", err)

View File

@@ -14,6 +14,12 @@ Following is the example of multus config file, in `/etc/cni/net.d/`.
"binDir": "/opt/cni/bin",
"logFile": "/var/log/multus.log",
"logLevel": "debug",
"logOptions": {
"maxAge": 5,
"maxSize": 100,
"maxBackups": 5,
"compress": true
},
"capabilities": {
"portMappings": true
},
@@ -44,6 +50,7 @@ Following is the example of multus config file, in `/etc/cni/net.d/`.
* `logToStderr` (bool, optional): Enable or disable logging to `STDERR`. Defaults to true.
* `logFile` (string, optional): file path for log file. multus puts log in given file
* `logLevel` (string, optional): logging level ("debug", "error", "verbose", or "panic")
* `logOptions` (object, optional): logging option, More detailed log configuration
* `namespaceIsolation` (boolean, optional): Enables a security feature where pods are only allowed to access `NetworkAttachmentDefinitions` in the namespace where the pod resides. Defaults to false.
* `capabilities` ({}list, optional): [capabilities](https://github.com/containernetworking/cni/blob/master/CONVENTIONS.md#dynamic-plugin-specific-fields-capabilities--runtime-configuration) supported by at least one of the delegates. (NOTE: Multus only supports portMappings/Bandwidth capability for cluster networks).
* `readinessindicatorfile`: The path to a file whose existence denotes that the default network is ready
@@ -124,6 +131,26 @@ You may configure the logging level by using the `LogLevel` option in your CNI c
"LogLevel": "debug",
```
#### Logging Options
If you want a more detailed configuration of the logging, This includes the following parameters:
* `maxAge` the maximum number of days to retain old log files in their filename
* `maxSize` the maximum size in megabytes of the log file before it gets rotated
* `maxBackups` the maximum number of days to retain old log files in their filename
* `compress` compress determines if the rotated log files should be compressed using gzip
For example in your CNI configuration, you may set:
```
"logOptions": {
"maxAge": 5,
"maxSize": 100,
"maxBackups": 5,
"compress": true
}
```
### Namespace Isolation
The functionality provided by the `namespaceIsolation` configuration option enables a mode where Multus only allows pods to access custom resources (the `NetworkAttachmentDefinitions`) within the namespace where that pod resides. In other words, the `NetworkAttachmentDefinitions` are isolated to usage within the namespace in which they're created.

View File

@@ -5,11 +5,11 @@ if [ ! -d bin ]; then
mkdir bin
fi
curl -Lo ./bin/kind "https://github.com/kubernetes-sigs/kind/releases/download/v0.11.1/kind-$(uname)-amd64"
curl -Lo ./bin/kind "https://github.com/kubernetes-sigs/kind/releases/download/v0.12.0/kind-$(uname)-amd64"
chmod +x ./bin/kind
curl -Lo ./bin/kubectl https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl
chmod +x ./bin/kubectl
curl -Lo ./bin/koko https://github.com/redhat-nfvpe/koko/releases/download/v0.82/koko_0.82_linux_amd64
curl -Lo ./bin/koko https://github.com/redhat-nfvpe/koko/releases/download/v0.83/koko_0.83_linux_amd64
chmod +x ./bin/koko
curl -Lo ./bin/jq https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64
chmod +x ./bin/jq

View File

@@ -7,9 +7,9 @@ metadata:
data:
install_cni.sh: |
cd /tmp
wget https://github.com/containernetworking/plugins/releases/download/v1.1.0/cni-plugins-linux-amd64-v1.1.0.tgz
wget https://github.com/containernetworking/plugins/releases/download/v1.1.1/cni-plugins-linux-amd64-v1.1.1.tgz
cd /host/opt/cni/bin
tar xvfzp /tmp/cni-plugins-linux-amd64-v1.1.0.tgz
tar xvfzp /tmp/cni-plugins-linux-amd64-v1.1.1.tgz
sleep infinite
---
apiVersion: apps/v1

View File

@@ -529,7 +529,7 @@ func getNetDelegate(client *ClientInfo, pod *v1.Pod, netname, confdir, namespace
isNetnamePath := strings.Contains(netname, "/")
// if netname is not directory or file, it must be net-attach-def name or CNI config name
if ! isNetnamePath {
if !isNetnamePath {
// option1) search CRD object for the network
net := &types.NetworkSelectionElement{
Name: netname,

View File

@@ -41,9 +41,42 @@ const (
var loggingStderr bool
var loggingW io.Writer
var loggingLevel Level
var logger *lumberjack.Logger
const defaultTimestampFormat = time.RFC3339
// LogOptions specifies the configuration of the log
type LogOptions struct {
MaxAge *int `json:"maxAge,omitempty"`
MaxSize *int `json:"maxSize,omitempty"`
MaxBackups *int `json:"maxBackups,omitempty"`
Compress *bool `json:"compress,omitempty"`
}
// SetLogOptions set the LoggingOptions of NetConf
func SetLogOptions(options *LogOptions) {
// give some default value
logger.MaxSize = 100
logger.MaxAge = 5
logger.MaxBackups = 5
logger.Compress = true
if options != nil {
if options.MaxAge != nil {
logger.MaxAge = *options.MaxAge
}
if options.MaxSize != nil {
logger.MaxSize = *options.MaxSize
}
if options.MaxBackups != nil {
logger.MaxBackups = *options.MaxBackups
}
if options.Compress != nil {
logger.Compress = *options.Compress
}
}
loggingW = logger
}
func (l Level) String() string {
switch l {
case PanicLevel:
@@ -141,13 +174,8 @@ func SetLogFile(filename string) {
return
}
loggingW = &lumberjack.Logger{
Filename: filename,
MaxSize: 100, // megabytes
MaxBackups: 5,
MaxAge: 5, // days
Compress: true,
}
logger.Filename = filename
loggingW = logger
}
@@ -155,4 +183,5 @@ func init() {
loggingStderr = true
loggingW = nil
loggingLevel = PanicLevel
logger = &lumberjack.Logger{}
}

View File

@@ -15,6 +15,8 @@
package logging
import (
testutils "gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/testing"
"gopkg.in/natefinch/lumberjack.v2"
"testing"
. "github.com/onsi/ginkgo"
@@ -79,4 +81,54 @@ var _ = Describe("logging operations", func() {
currentLevel := loggingLevel
Expect(currentLevel).To(Equal(GetLoggingLevel()))
})
It("Check user settings logOptions for logging", func() {
SetLogFile("/var/log/multus.log")
expectLogger := &lumberjack.Logger{
Filename: "/var/log/multus.log",
MaxAge: 1,
MaxSize: 10,
MaxBackups: 1,
Compress: true,
}
logOptions := &LogOptions{
MaxAge: testutils.Int(1),
MaxSize: testutils.Int(10),
MaxBackups: testutils.Int(1),
Compress: testutils.Bool(true),
}
SetLogOptions(logOptions)
Expect(expectLogger).To(Equal(logger))
})
It("Check user settings logOptions and missing some options", func() {
SetLogFile("/var/log/multus.log")
expectLogger := &lumberjack.Logger{
Filename: "/var/log/multus.log",
MaxAge: 5,
MaxSize: 100,
MaxBackups: 1,
Compress: true,
}
logOptions := &LogOptions{
MaxBackups: testutils.Int(1),
Compress: testutils.Bool(true),
}
SetLogOptions(logOptions)
Expect(expectLogger).To(Equal(logger))
})
It("Check user don't settings logOptions for logging", func() {
SetLogFile("/var/log/multus.log")
logger1 := &lumberjack.Logger{
Filename: "/var/log/multus.log",
MaxAge: 5,
MaxSize: 100,
MaxBackups: 5,
Compress: true,
}
SetLogOptions(nil)
Expect(logger1).To(Equal(logger))
})
})

View File

@@ -199,7 +199,7 @@ func confCheck(rt *libcni.RuntimeConf, rawNetconf []byte, multusNetconf *types.N
err = cniNet.CheckNetwork(context.Background(), conf, rt)
if err != nil {
return logging.Errorf("error in getting result from DelNetwork: %v", err)
return logging.Errorf("error in getting result from CheckNetwork: %v", err)
}
return err

View File

@@ -33,6 +33,9 @@ const (
singleConfigCapabilityKey = "capabilities"
)
// LogOptionFunc mutates the `LoggingOptions` object
type LogOptionFunc func(logOptions *LogOptions)
// Option mutates the `conf` object
type Option func(conf *MultusConf) error
@@ -44,6 +47,7 @@ type MultusConf struct {
LogFile string `json:"logFile,omitempty"`
LogLevel string `json:"logLevel,omitempty"`
LogToStderr bool `json:"logToStderr,omitempty"`
LogOptions *LogOptions `json:"logOptions,omitempty"`
Name string `json:"name"`
ClusterNetwork string `json:"clusterNetwork,omitempty"`
NamespaceIsolation bool `json:"namespaceIsolation,omitempty"`
@@ -53,6 +57,14 @@ type MultusConf struct {
CniDir string `json:"cniDir,omitempty"`
}
// LogOptions specifies the configuration of the log
type LogOptions struct {
MaxAge *int `json:"maxAge,omitempty"`
MaxSize *int `json:"maxSize,omitempty"`
MaxBackups *int `json:"maxBackups,omitempty"`
Compress *bool `json:"compress,omitempty"`
}
// NewMultusConfig creates a basic configuration generator. It can be mutated
// via the `With...` methods.
func NewMultusConfig(pluginName string, cniVersion string, configurationOptions ...Option) (*MultusConf, error) {
@@ -166,6 +178,15 @@ func WithLogFile(logFile string) Option {
}
}
// WithLogOptions mutates the inner state to set the
// LogOptions attribute
func WithLogOptions(logOptions *LogOptions) Option {
return func(conf *MultusConf) error {
conf.LogOptions = logOptions
return nil
}
}
// WithReadinessFileIndicator mutates the inner state to set the
// ReadinessIndicatorFile attribute
func WithReadinessFileIndicator(path string) Option {
@@ -241,6 +262,46 @@ func withCapabilities(cniData interface{}) Option {
}
}
// MutateLogOptions update the LoggingOptions of the MultusConf according
// to the provided configuration `loggingOptions`
func MutateLogOptions(logOption *LogOptions, logOptionFunc ...LogOptionFunc) {
for _, loggingOption := range logOptionFunc {
loggingOption(logOption)
}
}
// WithLogMaxSize mutates the inner state to set the
// logMaxSize attribute
func WithLogMaxSize(maxSize *int) LogOptionFunc {
return func(logOptions *LogOptions) {
logOptions.MaxSize = maxSize
}
}
// WithLogMaxAge mutates the inner state to set the
// logMaxAge attribute
func WithLogMaxAge(maxAge *int) LogOptionFunc {
return func(logOptions *LogOptions) {
logOptions.MaxAge = maxAge
}
}
// WithLogMaxBackups mutates the inner state to set the
// logMaxBackups attribute
func WithLogMaxBackups(maxBackups *int) LogOptionFunc {
return func(logOptions *LogOptions) {
logOptions.MaxBackups = maxBackups
}
}
// WithLogCompress mutates the inner state to set the
// logCompress attribute
func WithLogCompress(compress *bool) LogOptionFunc {
return func(logOptions *LogOptions) {
logOptions.Compress = compress
}
}
func extractCapabilities(capabilitiesInterface interface{}) []string {
capabilitiesMap, ok := capabilitiesInterface.(map[string]interface{})
if !ok {

View File

@@ -22,6 +22,8 @@ import (
"os"
"testing"
testutils "gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
@@ -146,6 +148,122 @@ var _ = Describe("Configuration Generator", func() {
Expect(multusConfig.Generate()).Should(MatchJSON(expectedResult))
})
It("multus config with logging options configuration", func() {
multusConfig, err := newMultusConfigWithDelegates(
primaryCNIName,
cniVersion,
primaryCNIFile,
WithLogOptions(&LogOptions{
MaxAge: testutils.Int(5),
MaxSize: testutils.Int(100),
MaxBackups: testutils.Int(5),
Compress: testutils.Bool(true),
}))
Expect(err).NotTo(HaveOccurred())
expectedResult := fmt.Sprintf(`
{
"cniVersion":"0.4.0",
"clusterNetwork":"%s",
"name":"multus-cni-network",
"logOptions": {
"maxAge": 5,
"maxSize": 100,
"maxBackups": 5,
"compress": true
},
"type":"myCNI"
}`, primaryCNIFile)
Expect(multusConfig.Generate()).Should(MatchJSON(expectedResult))
})
It("multus config with logging options with max age", func() {
logOption := &LogOptions{}
MutateLogOptions(logOption, WithLogMaxAge(testutils.Int(5)))
multusConfig, err := newMultusConfigWithDelegates(
primaryCNIName,
cniVersion,
primaryCNIFile,
WithLogOptions(logOption))
Expect(err).NotTo(HaveOccurred())
expectedResult := fmt.Sprintf(`
{
"cniVersion":"0.4.0",
"clusterNetwork":"%s",
"name":"multus-cni-network",
"logOptions": {
"maxAge": 5
},
"type":"myCNI"
}`, primaryCNIFile)
Expect(multusConfig.Generate()).Should(MatchJSON(expectedResult))
})
It("multus config with logging options with max size", func() {
logOption := &LogOptions{}
MutateLogOptions(logOption, WithLogMaxSize(testutils.Int(100)))
multusConfig, err := newMultusConfigWithDelegates(
primaryCNIName,
cniVersion,
primaryCNIFile,
WithLogOptions(logOption))
Expect(err).NotTo(HaveOccurred())
expectedResult := fmt.Sprintf(`
{
"cniVersion":"0.4.0",
"clusterNetwork":"%s",
"name":"multus-cni-network",
"logOptions": {
"maxSize": 100
},
"type":"myCNI"
}`, primaryCNIFile)
Expect(multusConfig.Generate()).Should(MatchJSON(expectedResult))
})
It("multus config with logging options with log max backups", func() {
logOption := &LogOptions{}
MutateLogOptions(logOption, WithLogMaxBackups(testutils.Int(5)))
multusConfig, err := newMultusConfigWithDelegates(
primaryCNIName,
cniVersion,
primaryCNIFile,
WithLogOptions(logOption))
Expect(err).NotTo(HaveOccurred())
expectedResult := fmt.Sprintf(`
{
"cniVersion":"0.4.0",
"clusterNetwork":"%s",
"name":"multus-cni-network",
"logOptions": {
"maxBackups": 5
},
"type":"myCNI"
}`, primaryCNIFile)
Expect(multusConfig.Generate()).Should(MatchJSON(expectedResult))
})
It("multus config with logging options with log compress", func() {
logOption := &LogOptions{}
MutateLogOptions(logOption, WithLogCompress(testutils.Bool(true)))
multusConfig, err := newMultusConfigWithDelegates(
primaryCNIName,
cniVersion,
primaryCNIFile,
WithLogOptions(logOption))
Expect(err).NotTo(HaveOccurred())
expectedResult := fmt.Sprintf(`
{
"cniVersion":"0.4.0",
"clusterNetwork":"%s",
"name":"multus-cni-network",
"logOptions": {
"compress": true
},
"type":"myCNI"
}`, primaryCNIFile)
Expect(multusConfig.Generate()).Should(MatchJSON(expectedResult))
})
It("multus config with global namespace", func() {
const globalNamespace = "come-along-ns"
multusConfig, err := newMultusConfigWithDelegates(

View File

@@ -161,3 +161,13 @@ func (r *Result) String() string {
}
return fmt.Sprintf("%sDNS:%+v", str, r.DNS)
}
// Int returns a pointer to an int
func Int(i int) *int {
return &i
}
// Bool returns a pointer to a bool.
func Bool(b bool) *bool {
return &b
}

View File

@@ -329,6 +329,7 @@ func LoadNetConf(bytes []byte) (*NetConf, error) {
// Logging
logging.SetLogStderr(netconf.LogToStderr)
logging.SetLogOptions(netconf.LogOptions)
if netconf.LogFile != "" {
logging.SetLogFile(netconf.LogFile)
}

View File

@@ -112,27 +112,54 @@ var _ = Describe("config operations", func() {
It("checks if logFile and logLevel are set correctly", func() {
conf := `{
"name": "node-cni-network",
"type": "multus",
"logLevel": "debug",
"logFile": "/var/log/multus.log",
"kubeconfig": "/etc/kubernetes/node-kubeconfig.yaml",
"delegates": [{
"type": "weave-net"
}],
"runtimeConfig": {
"portMappings": [
{"hostPort": 8080, "containerPort": 80, "protocol": "tcp"}
]
}
}`
"name": "node-cni-network",
"type": "multus",
"logLevel": "debug",
"logFile": "/var/log/multus.log",
"kubeconfig": "/etc/kubernetes/node-kubeconfig.yaml",
"delegates": [{
"type": "weave-net"
}],
"runtimeConfig": {
"portMappings": [
{"hostPort": 8080, "containerPort": 80, "protocol": "tcp"}
]
}
}`
netConf, err := LoadNetConf([]byte(conf))
Expect(err).NotTo(HaveOccurred())
Expect(netConf.LogLevel).To(Equal("debug"))
Expect(netConf.LogFile).To(Equal("/var/log/multus.log"))
})
It("checks if logOptions are set correctly", func() {
conf := `{
"name": "node-cni-network",
"type": "multus",
"logOptions": {
"maxAge": 5,
"maxSize": 100,
"maxBackups": 5,
"compress": true
},
"kubeconfig": "/etc/kubernetes/node-kubeconfig.yaml",
"delegates": [{
"type": "weave-net"
}],
"runtimeConfig": {
"portMappings": [
{"hostPort": 8080, "containerPort": 80, "protocol": "tcp"}
]
}
}`
netConf, err := LoadNetConf([]byte(conf))
Expect(err).NotTo(HaveOccurred())
Expect(*netConf.LogOptions.MaxAge).To(Equal(5))
Expect(*netConf.LogOptions.MaxBackups).To(Equal(5))
Expect(*netConf.LogOptions.MaxSize).To(Equal(100))
Expect(*netConf.LogOptions.Compress).To(Equal(true))
})
It("properly sets namespace isolation using the default namespace", func() {
conf := `{
"name": "node-cni-network",

View File

@@ -16,6 +16,7 @@
package types
import (
"gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/logging"
"net"
"github.com/containernetworking/cni/pkg/types"
@@ -40,14 +41,15 @@ type NetConf struct {
// These parameters are exclusive in one config file:
// - Delegates (directly add delegate CNI config into multus CNI config)
// - ClusterNetwork+DefaultNetworks (add CNI config through CRD, directory or file)
Delegates []*DelegateNetConf `json:"-"`
ClusterNetwork string `json:"clusterNetwork"`
DefaultNetworks []string `json:"defaultNetworks"`
Kubeconfig string `json:"kubeconfig"`
LogFile string `json:"logFile"`
LogLevel string `json:"logLevel"`
LogToStderr bool `json:"logToStderr,omitempty"`
RuntimeConfig *RuntimeConfig `json:"runtimeConfig,omitempty"`
Delegates []*DelegateNetConf `json:"-"`
ClusterNetwork string `json:"clusterNetwork"`
DefaultNetworks []string `json:"defaultNetworks"`
Kubeconfig string `json:"kubeconfig"`
LogFile string `json:"logFile"`
LogLevel string `json:"logLevel"`
LogToStderr bool `json:"logToStderr,omitempty"`
LogOptions *logging.LogOptions `json:"logOptions,omitempty"`
RuntimeConfig *RuntimeConfig `json:"runtimeConfig,omitempty"`
// Default network readiness options
ReadinessIndicatorFile string `json:"readinessindicatorfile"`
// Option to isolate the usage of CR's to the namespace in which a pod resides.