2023-02-28 04:44:46 -06:00
// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
2022-10-01 23:33:17 -05:00
package config
import (
2023-04-02 09:41:48 -05:00
"fmt"
2022-10-01 23:33:17 -05:00
"os"
2023-04-02 09:41:48 -05:00
"path/filepath"
"time"
2022-11-23 21:55:52 -06:00
2022-10-01 23:33:17 -05:00
"github.com/joho/godotenv"
Add configuration item of `container.network` (#184)
Close https://gitea.com/gitea/act_runner/issues/177
Related https://gitea.com/gitea/act/pulls/56
### ⚠️ Breaking
The `container.network_mode` is a deprecated configuration item. It may be removed after Gitea 1.20 released.
Previously, if the value of `container.network_mode` is `bridge`, it means that `act_runner` will create a new network for job.But `bridge` is easily confused with the bridge network created by Docker by default.
We recommand that using `container.network` to specify the network to which containers created by `act_runner` connect.
### 🆕 container.network
The configuration file of `act_runner` add a new item of `contianer.network`.
In `config.example.yaml`:
```yaml
container:
# Specifies the network to which the container will connect.
# Could be host, bridge or the name of a custom network.
# If it's empty, act_runner will create a network automatically.
network: ""
```
As the comment in the example above says, the purpose of the `container.network` is specifying the network to which containers created by `act_runner` will connect.
`container.network` accepts the following valid values:
- `host`: All of containers (including job containers and service contianers) created by `act_runner` will be connected to the network named `host` which is created automatically by Docker. Containers will share the host’s network stack and all interfaces from the host will be available to these containers.
- `bridge`: It is similar to `host`. All of containers created by `act_runner` will be connected to the network named `bridge` which is created automatically by Docker. All containers connected to the `bridge` (Perhaps there are containers that are not created by `act_runner`) are allowed to communicate with each other, while providing isolation from containers which are not connected to that `bridge` network.
- `<custom_network>`: Please make sure that the `<custom_network>` network already exists firstly (`act_runner` does not detect whether the specified network exists currently. If not exists yet, will return error in the stage of `docker create`). All of containers created by `act_runner` will be connected to `<custom_network>`. After the job is executed, containers are removed and automatically disconnected from the `<custom_network>`.
- empty: `act_runner` will create a new network for each job container and their service containers (if defined in workflow). So each job container and their service containers share a network environment, but are isolated from others container and the Docker host. Of course, these networks created by `act_runner` will be removed at last.
### Others
- If you do not have special needs, we highly recommend that setting `container.network` to empty string (and do not use `container.network_mode` any more). Because the containers created by `act_runner` will connect to the networks that are created by itself. This point will provide better isolation.
- If you set `contianer.network` to empty string or `<custom_network>`, we can be access to service containers by `<service-id>:<port>` in the steps of job. Because we added an alias to the service container when connecting to the network.
Co-authored-by: Jason Song <i@wolfogre.com>
Reviewed-on: https://gitea.com/gitea/act_runner/pulls/184
Reviewed-by: Jason Song <i@wolfogre.com>
Co-authored-by: sillyguodong <gedong_1994@163.com>
Co-committed-by: sillyguodong <gedong_1994@163.com>
2023-05-16 01:46:59 -05:00
log "github.com/sirupsen/logrus"
2023-04-02 09:41:48 -05:00
"gopkg.in/yaml.v3"
2022-10-01 23:33:17 -05:00
)
2023-06-05 08:11:23 -05:00
// Log represents the configuration for logging.
type Log struct {
Level string ` yaml:"level" ` // Level indicates the logging level.
}
// Runner represents the configuration for the runner.
type Runner struct {
2024-06-06 04:40:31 -05:00
File string ` yaml:"file" ` // File specifies the file path for the runner.
Capacity int ` yaml:"capacity" ` // Capacity specifies the capacity of the runner.
Envs map [ string ] string ` yaml:"envs" ` // Envs stores environment variables for the runner.
EnvFile string ` yaml:"env_file" ` // EnvFile specifies the path to the file containing environment variables for the runner.
Timeout time . Duration ` yaml:"timeout" ` // Timeout specifies the duration for runner timeout.
ShutdownTimeout time . Duration ` yaml:"shutdown_timeout" ` // ShutdownTimeout specifies the duration to wait for running jobs to complete during a shutdown of the runner.
Insecure bool ` yaml:"insecure" ` // Insecure indicates whether the runner operates in an insecure mode.
FetchTimeout time . Duration ` yaml:"fetch_timeout" ` // FetchTimeout specifies the timeout duration for fetching resources.
FetchInterval time . Duration ` yaml:"fetch_interval" ` // FetchInterval specifies the interval duration for fetching resources.
Labels [ ] string ` yaml:"labels" ` // Labels specify the labels of the runner. Labels are declared on each startup
2023-06-05 08:11:23 -05:00
}
// Cache represents the configuration for caching.
type Cache struct {
2023-07-07 03:28:54 -05:00
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.
Dir string ` yaml:"dir" ` // Dir specifies the directory path for caching.
Host string ` yaml:"host" ` // Host specifies the caching host.
Port uint16 ` yaml:"port" ` // Port specifies the caching port.
ExternalServer string ` yaml:"external_server" ` // ExternalServer specifies the URL of external cache server
2023-06-05 08:11:23 -05:00
}
// Container represents the configuration for the container.
type Container struct {
2023-06-16 01:07:48 -05:00
Network string ` yaml:"network" ` // Network specifies the network for the container.
NetworkMode string ` yaml:"network_mode" ` // Deprecated: use Network instead. Could be removed after Gitea 1.20
2023-11-14 12:16:09 -06:00
EnableIPv6 bool ` yaml:"enable_ipv6" ` // EnableIPv6 indicates whether the network is created with IPv6 enabled.
2023-06-16 01:07:48 -05:00
Privileged bool ` yaml:"privileged" ` // Privileged indicates whether the container runs in privileged mode.
Options string ` yaml:"options" ` // Options specifies additional options for the container.
WorkdirParent string ` yaml:"workdir_parent" ` // WorkdirParent specifies the parent directory for the container's working directory.
ValidVolumes [ ] string ` yaml:"valid_volumes" ` // ValidVolumes specifies the volumes (including bind mounts) can be mounted to containers.
2023-06-19 04:01:16 -05:00
DockerHost string ` yaml:"docker_host" ` // DockerHost specifies the Docker host. It overrides the value specified in environment variable DOCKER_HOST.
2023-08-17 01:51:57 -05:00
ForcePull bool ` yaml:"force_pull" ` // Pull docker image(s) even if already present
2023-06-18 00:38:38 -05:00
}
2023-06-20 03:29:05 -05:00
// Host represents the configuration for the host.
type Host struct {
WorkdirParent string ` yaml:"workdir_parent" ` // WorkdirParent specifies the parent directory for the host's working directory.
}
2023-06-05 08:11:23 -05:00
// Config represents the overall configuration.
2023-04-02 09:41:48 -05:00
type Config struct {
2023-06-05 08:11:23 -05:00
Log Log ` yaml:"log" ` // Log represents the configuration for logging.
Runner Runner ` yaml:"runner" ` // Runner represents the configuration for the runner.
Cache Cache ` yaml:"cache" ` // Cache represents the configuration for caching.
Container Container ` yaml:"container" ` // Container represents the configuration for the container.
2023-06-20 03:29:05 -05:00
Host Host ` yaml:"host" ` // Host represents the configuration for the host.
2023-04-02 09:41:48 -05:00
}
2022-10-01 23:33:17 -05:00
2024-01-05 09:07:15 -06:00
// Tune the config settings accordingly to the Forgejo instance that will be used.
func ( c * Config ) Tune ( instanceURL string ) {
if instanceURL == "https://codeberg.org" {
if c . Runner . FetchInterval < 30 * time . Second {
log . Info ( "The runner is configured to be used by a public instance, fetch interval is set to 30 seconds." )
c . Runner . FetchInterval = 30 * time . Second
}
}
}
2023-04-02 09:41:48 -05:00
// LoadDefault returns the default configuration.
// If file is not empty, it will be used to load the configuration.
func LoadDefault ( file string ) ( * Config , error ) {
cfg := & Config { }
if file != "" {
2023-06-15 00:40:37 -05:00
content , err := os . ReadFile ( file )
2023-04-02 09:41:48 -05:00
if err != nil {
2023-06-15 00:40:37 -05:00
return nil , fmt . Errorf ( "open config file %q: %w" , file , err )
2022-11-15 08:42:41 -06:00
}
2023-06-15 00:40:37 -05:00
if err := yaml . Unmarshal ( content , cfg ) ; err != nil {
return nil , fmt . Errorf ( "parse config file %q: %w" , file , err )
2023-02-15 02:51:14 -06:00
}
2022-10-15 03:40:35 -05:00
}
2023-04-02 09:41:48 -05:00
compatibleWithOldEnvs ( file != "" , cfg )
2022-10-01 23:33:17 -05:00
2023-04-02 09:41:48 -05:00
if cfg . Runner . EnvFile != "" {
if stat , err := os . Stat ( cfg . Runner . EnvFile ) ; err == nil && ! stat . IsDir ( ) {
envs , err := godotenv . Read ( cfg . Runner . EnvFile )
if err != nil {
return nil , fmt . Errorf ( "read env file %q: %w" , cfg . Runner . EnvFile , err )
}
2023-11-23 19:56:27 -06:00
if cfg . Runner . Envs == nil {
cfg . Runner . Envs = map [ string ] string { }
}
2023-04-02 09:41:48 -05:00
for k , v := range envs {
cfg . Runner . Envs [ k ] = v
}
2022-11-04 04:23:59 -05:00
}
2022-10-01 23:33:17 -05:00
}
2023-04-02 09:41:48 -05:00
if cfg . Log . Level == "" {
cfg . Log . Level = "info"
2022-10-01 23:33:17 -05:00
}
2023-04-02 09:41:48 -05:00
if cfg . Runner . File == "" {
cfg . Runner . File = ".runner"
2022-10-01 23:33:17 -05:00
}
2023-04-02 09:41:48 -05:00
if cfg . Runner . Capacity <= 0 {
cfg . Runner . Capacity = 1
}
if cfg . Runner . Timeout <= 0 {
cfg . Runner . Timeout = 3 * time . Hour
}
if cfg . Cache . Enabled == nil {
b := true
cfg . Cache . Enabled = & b
}
if * cfg . Cache . Enabled {
if cfg . Cache . Dir == "" {
home , _ := os . UserHomeDir ( )
cfg . Cache . Dir = filepath . Join ( home , ".cache" , "actcache" )
2022-10-01 23:33:17 -05:00
}
}
2023-04-28 09:03:52 -05:00
if cfg . Container . WorkdirParent == "" {
cfg . Container . WorkdirParent = "workspace"
}
2023-06-20 03:29:05 -05:00
if cfg . Host . WorkdirParent == "" {
home , _ := os . UserHomeDir ( )
2023-07-10 03:57:55 -05:00
cfg . Host . WorkdirParent = filepath . Join ( home , ".cache" , "act" )
2023-06-20 03:29:05 -05:00
}
2023-04-05 21:57:36 -05:00
if cfg . Runner . FetchTimeout <= 0 {
cfg . Runner . FetchTimeout = 5 * time . Second
}
if cfg . Runner . FetchInterval <= 0 {
cfg . Runner . FetchInterval = 2 * time . Second
}
2022-10-01 23:33:17 -05:00
Add configuration item of `container.network` (#184)
Close https://gitea.com/gitea/act_runner/issues/177
Related https://gitea.com/gitea/act/pulls/56
### ⚠️ Breaking
The `container.network_mode` is a deprecated configuration item. It may be removed after Gitea 1.20 released.
Previously, if the value of `container.network_mode` is `bridge`, it means that `act_runner` will create a new network for job.But `bridge` is easily confused with the bridge network created by Docker by default.
We recommand that using `container.network` to specify the network to which containers created by `act_runner` connect.
### 🆕 container.network
The configuration file of `act_runner` add a new item of `contianer.network`.
In `config.example.yaml`:
```yaml
container:
# Specifies the network to which the container will connect.
# Could be host, bridge or the name of a custom network.
# If it's empty, act_runner will create a network automatically.
network: ""
```
As the comment in the example above says, the purpose of the `container.network` is specifying the network to which containers created by `act_runner` will connect.
`container.network` accepts the following valid values:
- `host`: All of containers (including job containers and service contianers) created by `act_runner` will be connected to the network named `host` which is created automatically by Docker. Containers will share the host’s network stack and all interfaces from the host will be available to these containers.
- `bridge`: It is similar to `host`. All of containers created by `act_runner` will be connected to the network named `bridge` which is created automatically by Docker. All containers connected to the `bridge` (Perhaps there are containers that are not created by `act_runner`) are allowed to communicate with each other, while providing isolation from containers which are not connected to that `bridge` network.
- `<custom_network>`: Please make sure that the `<custom_network>` network already exists firstly (`act_runner` does not detect whether the specified network exists currently. If not exists yet, will return error in the stage of `docker create`). All of containers created by `act_runner` will be connected to `<custom_network>`. After the job is executed, containers are removed and automatically disconnected from the `<custom_network>`.
- empty: `act_runner` will create a new network for each job container and their service containers (if defined in workflow). So each job container and their service containers share a network environment, but are isolated from others container and the Docker host. Of course, these networks created by `act_runner` will be removed at last.
### Others
- If you do not have special needs, we highly recommend that setting `container.network` to empty string (and do not use `container.network_mode` any more). Because the containers created by `act_runner` will connect to the networks that are created by itself. This point will provide better isolation.
- If you set `contianer.network` to empty string or `<custom_network>`, we can be access to service containers by `<service-id>:<port>` in the steps of job. Because we added an alias to the service container when connecting to the network.
Co-authored-by: Jason Song <i@wolfogre.com>
Reviewed-on: https://gitea.com/gitea/act_runner/pulls/184
Reviewed-by: Jason Song <i@wolfogre.com>
Co-authored-by: sillyguodong <gedong_1994@163.com>
Co-committed-by: sillyguodong <gedong_1994@163.com>
2023-05-16 01:46:59 -05:00
// although `container.network_mode` will be deprecated, but we have to be compatible with it for now.
if cfg . Container . NetworkMode != "" && cfg . Container . Network == "" {
log . Warn ( "You are trying to use deprecated configuration item of `container.network_mode`, please use `container.network` instead." )
if cfg . Container . NetworkMode == "bridge" {
// Previously, if the value of `container.network_mode` is `bridge`, we will create a new network for job.
// But “bridge” is easily confused with the bridge network created by Docker by default.
// So we set the value of `container.network` to empty string to make `act_runner` automatically create a new network for job.
cfg . Container . Network = ""
} else {
cfg . Container . Network = cfg . Container . NetworkMode
}
}
2022-10-15 03:12:32 -05:00
return cfg , nil
2022-10-01 23:33:17 -05:00
}