Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions cmd/daemon/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package main

import (
"flag"
"fmt"
"os"
"time"

Expand All @@ -38,9 +39,10 @@ var (
"present within the cluster",
Run: runControllerCmd,
}
windowsService bool
logDir string
caBundle string
windowsService bool
logDir string
logFileMaxSizeMb uint64
caBundle string
// Certificate-based authentication options
certDir string
certDuration string
Expand All @@ -50,6 +52,9 @@ func init() {
rootCmd.AddCommand(controllerCmd)
controllerCmd.PersistentFlags().StringVar(&logDir, "log-dir", "", "Directory to write logs to, "+
"if not provided, the command will log to stdout/stderr")
controllerCmd.PersistentFlags().Uint64Var(&logFileMaxSizeMb, "log-file-max-size", 0,
"Maximum size in megabytes log file can grow to before being rotated. "+
"Only effective when --log-dir is set. Set 0 for unlimited.")
controllerCmd.PersistentFlags().BoolVar(&windowsService, "windows-service", false,
"Enables running as a Windows service")
controllerCmd.PersistentFlags().StringVar(&caBundle, "ca-bundle", "",
Expand All @@ -67,6 +72,14 @@ func runControllerCmd(cmd *cobra.Command, args []string) {
// When the logtostderr flag is set to true, which is the default, the log_dir arg is ignored
fs.Set("logtostderr", "false")
fs.Set("log_dir", logDir)

logFileMaxSizeString := fmt.Sprintf("%d", logFileMaxSizeMb)
fs.Set("log_file_max_size", logFileMaxSizeString)

if logFileMaxSizeString == "0" {
logFileMaxSizeString = "unlimited"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this be default unlimited and then if set to a value other than 0, then set to that value?

}
klog.Infof("service controller max log file size set to %s megabytes for log dir %s", logFileMaxSizeString, logDir)
Comment thread
jrvaldes marked this conversation as resolved.
}
duration, err := time.ParseDuration(certDuration)
if err != nil {
Expand Down
25 changes: 25 additions & 0 deletions pkg/logconfig/init.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package logconfig

import (
ctrl "sigs.k8s.io/controller-runtime"
)

func init() {
log := ctrl.Log.WithName("logconfig").WithName("init")

var err error
logFileSize, err = getEnvQuantityString(LogFileSizeEnvVar)
if err != nil {
log.Error(err, "cannot load environment variable", "name", LogFileSizeEnvVar)
}

logFileAge, err = getEnvDurationString(LogFileAgeEnvVar)
if err != nil {
log.Error(err, "cannot load environment variable", "name", LogFileAgeEnvVar)
}

flushInterval, err = getEnvDurationString(LogFlushIntervalEnvVar)
if err != nil {
log.Error(err, "cannot load environment variable", "name", LogFlushIntervalEnvVar)
}
}
Comment thread
jrvaldes marked this conversation as resolved.
109 changes: 109 additions & 0 deletions pkg/logconfig/logconfig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package logconfig

import (
"fmt"
"os"
"strings"
"time"

"k8s.io/apimachinery/pkg/api/resource"
)

const (
// LogFileSizeEnvVar is the environment variable name for log file size limit
LogFileSizeEnvVar = "SERVICES_LOG_FILE_SIZE"
// LogFileAgeEnvVar is the environment variable name for log file age retention
LogFileAgeEnvVar = "SERVICES_LOG_FILE_AGE"
// LogFlushIntervalEnvVar is the environment variable name for log flush interval
LogFlushIntervalEnvVar = "SERVICES_LOG_FLUSH_INTERVAL"
)

// logFileSize, logFileAge, and flushInterval hold the configuration values
// for log file size, log file age, and flush interval respectively.
var logFileSize, logFileAge, flushInterval string

// GetLogFileSizeMegabytes returns the configured log file size resource value in megabytes
func GetLogFileSizeMegabytes() uint64 {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can still keep this as GetLogFileSize if there isn't going to be another function that will need to return size not in megabytes. Function doc can state that the value will be in megabytes.

if logFileSize == "" {
return 0
}
q, err := resource.ParseQuantity(logFileSize)
if err != nil {
return 0
}
mb := q.ScaledValue(resource.Mega)
// check overflow
if mb < 0 {
return 0
}
return uint64(mb)
}

// GenerateKubeLogRunnerCmd returns the command string to run the given commandPath with kube-log-runner
// logging to the given logfilePath. Log rotation parameters logFileSize, logFileAge, and flushInterval
// are read via environment variables.
func GenerateKubeLogRunnerCmd(kubeLogRunnerPath, commandPath, logfilePath string) string {
cmdBuilder := strings.Builder{}
cmdBuilder.WriteString(kubeLogRunnerPath)

cmdBuilder.WriteString(" -log-file=")
cmdBuilder.WriteString(logfilePath)

if logFileSize != "" {
cmdBuilder.WriteString(" -log-file-size=")
cmdBuilder.WriteString(logFileSize)
}

if logFileAge != "" {
cmdBuilder.WriteString(" -log-file-age=")
cmdBuilder.WriteString(logFileAge)
}

if flushInterval != "" {
cmdBuilder.WriteString(" -flush-interval=")
cmdBuilder.WriteString(flushInterval)
}

cmdBuilder.WriteString(" " + commandPath)

return cmdBuilder.String()
}

// getEnvQuantityString returns the string value of the environment variable for the given key
// if it represents a valid and non-negative quantity, otherwise returns error
func getEnvQuantityString(key string) (string, error) {
value := os.Getenv(key)
value = strings.TrimSpace(value)
if value == "" {
// not present
return "", nil
}
// validate value as quantity
q, err := resource.ParseQuantity(value)
if err != nil {
return "", fmt.Errorf("invalid quantity value for %s: %w", key, err)
}
if q.Sign() < 0 {
return "", fmt.Errorf("quantity cannot be negative for %s", key)
}
return value, nil
}

// getEnvDurationString returns the string value of the environment variable for the given key
// if it represents a valid and non-negative duration, otherwise returns error
func getEnvDurationString(key string) (string, error) {
value := os.Getenv(key)
value = strings.TrimSpace(value)
if value == "" {
return "", nil
}
if strings.HasPrefix(value, "-") {
return "", fmt.Errorf("duration cannot be negative for %s", key)
}

// validate value as duration
if _, err := time.ParseDuration(value); err != nil {
return "", fmt.Errorf("invalid duration value for %s: %w", key, err)
}
return value, nil
}
Loading