1// Copyright 2022 The Gitea Authors. All rights reserved.2// SPDX-License-Identifier: MIT34package config56import (7 "fmt"8 "os"9 "path/filepath"10 "time"1112 "github.com/joho/godotenv"13 log "github.com/sirupsen/logrus"14 "gopkg.in/yaml.v3"15)1617// Log represents the configuration for logging.18type Log struct {19 Level string `yaml:"level"` // Level indicates the logging level.20}2122// Runner represents the configuration for the runner.23type Runner struct {24 File string `yaml:"file"` // File specifies the file path for the runner.25 Capacity int `yaml:"capacity"` // Capacity specifies the capacity of the runner.26 Envs map[string]string `yaml:"envs"` // Envs stores environment variables for the runner.27 EnvFile string `yaml:"env_file"` // EnvFile specifies the path to the file containing environment variables for the runner.28 Timeout time.Duration `yaml:"timeout"` // Timeout specifies the duration for runner timeout.29 ShutdownTimeout time.Duration `yaml:"shutdown_timeout"` // ShutdownTimeout specifies the duration to wait for running jobs to complete during a shutdown of the runner.30 Insecure bool `yaml:"insecure"` // Insecure indicates whether the runner operates in an insecure mode.31 FetchTimeout time.Duration `yaml:"fetch_timeout"` // FetchTimeout specifies the timeout duration for fetching resources.32 FetchInterval time.Duration `yaml:"fetch_interval"` // FetchInterval specifies the interval duration for fetching resources.33 ReportInterval time.Duration `yaml:"report_interval"` // ReportInterval specifies the interval duration for reporting status and logs of a running job.34 Labels []string `yaml:"labels"` // Labels specify the labels of the runner. Labels are declared on each startup35}3637// Cache represents the configuration for caching.38type Cache struct {39 Enabled *bool `yaml:"enabled"` // Enabled indicates whether caching is enabled. It is a pointer to distinguish between false and not set. If not set, it will be true.40 Dir string `yaml:"dir"` // Dir specifies the directory path for caching.41 Host string `yaml:"host"` // Host specifies the caching host.42 Port uint16 `yaml:"port"` // Port specifies the caching port.43 ExternalServer string `yaml:"external_server"` // ExternalServer specifies the URL of external cache server44}4546// Container represents the configuration for the container.47type Container struct {48 Network string `yaml:"network"` // Network specifies the network for the container.49 NetworkMode string `yaml:"network_mode"` // Deprecated: use Network instead. Could be removed after Gitea 1.2050 EnableIPv6 bool `yaml:"enable_ipv6"` // EnableIPv6 indicates whether the network is created with IPv6 enabled.51 Privileged bool `yaml:"privileged"` // Privileged indicates whether the container runs in privileged mode.52 Options string `yaml:"options"` // Options specifies additional options for the container.53 WorkdirParent string `yaml:"workdir_parent"` // WorkdirParent specifies the parent directory for the container's working directory.54 ValidVolumes []string `yaml:"valid_volumes"` // ValidVolumes specifies the volumes (including bind mounts) can be mounted to containers.55 DockerHost string `yaml:"docker_host"` // DockerHost specifies the Docker host. It overrides the value specified in environment variable DOCKER_HOST.56 ForcePull bool `yaml:"force_pull"` // Pull docker image(s) even if already present57}5859// Host represents the configuration for the host.60type Host struct {61 WorkdirParent string `yaml:"workdir_parent"` // WorkdirParent specifies the parent directory for the host's working directory.62}6364// Config represents the overall configuration.65type Config struct {66 Log Log `yaml:"log"` // Log represents the configuration for logging.67 Runner Runner `yaml:"runner"` // Runner represents the configuration for the runner.68 Cache Cache `yaml:"cache"` // Cache represents the configuration for caching.69 Container Container `yaml:"container"` // Container represents the configuration for the container.70 Host Host `yaml:"host"` // Host represents the configuration for the host.71}7273// Tune the config settings accordingly to the Forgejo instance that will be used.74func (c *Config) Tune(instanceURL string) {75 if instanceURL == "https://codeberg.org" {76 if c.Runner.FetchInterval < 30*time.Second {77 log.Info("The runner is configured to be used by a public instance, fetch interval is set to 30 seconds.")78 c.Runner.FetchInterval = 30 * time.Second79 }80 }81}8283// LoadDefault returns the default configuration.84// If file is not empty, it will be used to load the configuration.85func LoadDefault(file string) (*Config, error) {86 cfg := &Config{}87 if file != "" {88 content, err := os.ReadFile(file)89 if err != nil {90 return nil, fmt.Errorf("open config file %q: %w", file, err)91 }92 if err := yaml.Unmarshal(content, cfg); err != nil {93 return nil, fmt.Errorf("parse config file %q: %w", file, err)94 }95 }96 compatibleWithOldEnvs(file != "", cfg)9798 if cfg.Runner.EnvFile != "" {99 if stat, err := os.Stat(cfg.Runner.EnvFile); err == nil && !stat.IsDir() {100 envs, err := godotenv.Read(cfg.Runner.EnvFile)101 if err != nil {102 return nil, fmt.Errorf("read env file %q: %w", cfg.Runner.EnvFile, err)103 }104 if cfg.Runner.Envs == nil {105 cfg.Runner.Envs = map[string]string{}106 }107 for k, v := range envs {108 cfg.Runner.Envs[k] = v109 }110 }111 }112113 if cfg.Log.Level == "" {114 cfg.Log.Level = "info"115 }116 if cfg.Runner.File == "" {117 cfg.Runner.File = ".runner"118 }119 if cfg.Runner.Capacity <= 0 {120 cfg.Runner.Capacity = 1121 }122 if cfg.Runner.Timeout <= 0 {123 cfg.Runner.Timeout = 3 * time.Hour124 }125 if cfg.Cache.Enabled == nil {126 b := true127 cfg.Cache.Enabled = &b128 }129 if *cfg.Cache.Enabled {130 if cfg.Cache.Dir == "" {131 home, _ := os.UserHomeDir()132 cfg.Cache.Dir = filepath.Join(home, ".cache", "actcache")133 }134 }135 if cfg.Container.WorkdirParent == "" {136 cfg.Container.WorkdirParent = "workspace"137 }138 if cfg.Host.WorkdirParent == "" {139 home, _ := os.UserHomeDir()140 cfg.Host.WorkdirParent = filepath.Join(home, ".cache", "act")141 }142 if cfg.Runner.FetchTimeout <= 0 {143 cfg.Runner.FetchTimeout = 5 * time.Second144 }145 if cfg.Runner.FetchInterval <= 0 {146 cfg.Runner.FetchInterval = 2 * time.Second147 }148 if cfg.Runner.ReportInterval <= 0 {149 cfg.Runner.ReportInterval = time.Second150 }151152 // although `container.network_mode` will be deprecated, but we have to be compatible with it for now.153 if cfg.Container.NetworkMode != "" && cfg.Container.Network == "" {154 log.Warn("You are trying to use deprecated configuration item of `container.network_mode`, please use `container.network` instead.")155 if cfg.Container.NetworkMode == "bridge" {156 // Previously, if the value of `container.network_mode` is `bridge`, we will create a new network for job.157 // But “bridge” is easily confused with the bridge network created by Docker by default.158 // So we set the value of `container.network` to empty string to make `act_runner` automatically create a new network for job.159 cfg.Container.Network = ""160 } else {161 cfg.Container.Network = cfg.Container.NetworkMode162 }163 }164165 return cfg, nil166}