vendor c/{buildah,common}: appendable containers.conf strings, Part 1

This change is the first step of integrating appendable string arrays
into containers.conf and starts with enabling the `Env`, `Mounts`, and
`Volumes` fields in the `[Containers]` table.

Both, Buildah and Podman, read (and sometimes write) the fields of the
`Config` struct at various places, so I decided to migrate the fields
step-by-step.  The ones in this change are most critical ones for
customers.  Once all string slices/arrays are migrated, the docs of
containers.conf will be updated.  The current changes are entirely
transparent to users.

Signed-off-by: Valentin Rothberg <vrothberg@redhat.com>
This commit is contained in:
Valentin Rothberg
2023-10-24 09:05:41 +02:00
parent 35121f67bf
commit 989afd910e
15 changed files with 251 additions and 78 deletions

View File

@ -0,0 +1,92 @@
package attributedstring
import (
"bytes"
"fmt"
"github.com/BurntSushi/toml"
)
// Slice allows for extending a TOML string array with custom
// attributes that control how the array is marshaled into a Go string.
//
// Specifically, an Slice can be configured to avoid it being
// overridden by a subsequent unmarshal sequence. When the `append` attribute
// is specified, the array will be appended instead (e.g., `array=["9",
// {append=true}]`).
type Slice struct { // A "mixed-type array" in TOML.
// Note that the fields below _must_ be exported. Otherwise the TOML
// encoder would fail during type reflection.
Values []string
Attributes struct { // Using a struct allows for adding more attributes in the future.
Append *bool // Nil if not set by the user
}
}
// Get returns the Slice values or an empty string slice.
func (a *Slice) Get() []string {
if a.Values == nil {
return []string{}
}
return a.Values
}
// UnmarshalTOML is the custom unmarshal method for Slice.
func (a *Slice) UnmarshalTOML(data interface{}) error {
iFaceSlice, ok := data.([]interface{})
if !ok {
return fmt.Errorf("unable to cast to interface array: %v", data)
}
var loadedStrings []string
for _, x := range iFaceSlice { // Iterate over each item in the slice.
switch val := x.(type) {
case string: // Strings are directly appended to the slice.
loadedStrings = append(loadedStrings, val)
case map[string]interface{}: // The attribute struct is represented as a map.
for k, v := range val { // Iterate over all _supported_ keys.
switch k {
case "append":
boolVal, ok := v.(bool)
if !ok {
return fmt.Errorf("unable to cast append to bool: %v", k)
}
a.Attributes.Append = &boolVal
default: // Unsupported map key.
return fmt.Errorf("unsupported key %q in map: %v", k, val)
}
}
default: // Unsupported item.
return fmt.Errorf("unsupported item in attributed string slice: %v", x)
}
}
if a.Attributes.Append != nil && *a.Attributes.Append { // If _explicitly_ configured, append the loaded slice.
a.Values = append(a.Values, loadedStrings...)
} else { // Default: override the existing Slice.
a.Values = loadedStrings
}
return nil
}
// MarshalTOML is the custom marshal method for Slice.
func (a *Slice) MarshalTOML() ([]byte, error) {
iFaceSlice := make([]interface{}, 0, len(a.Values))
for _, x := range a.Values {
iFaceSlice = append(iFaceSlice, x)
}
if a.Attributes.Append != nil {
Attributes := make(map[string]any)
Attributes["append"] = *a.Attributes.Append
iFaceSlice = append(iFaceSlice, Attributes)
}
buf := new(bytes.Buffer)
enc := toml.NewEncoder(buf)
if err := enc.Encode(iFaceSlice); err != nil {
return nil, err
}
return buf.Bytes(), nil
}

View File

@ -10,6 +10,7 @@ import (
"strings"
"github.com/BurntSushi/toml"
"github.com/containers/common/internal/attributedstring"
"github.com/containers/common/libnetwork/types"
"github.com/containers/common/pkg/capabilities"
"github.com/containers/common/pkg/util"
@ -71,7 +72,7 @@ type ContainersConfig struct {
Devices []string `toml:"devices,omitempty"`
// Volumes to add to all containers
Volumes []string `toml:"volumes,omitempty"`
Volumes attributedstring.Slice `toml:"volumes,omitempty"`
// ApparmorProfile is the apparmor profile name which is used as the
// default for the runtime.
@ -133,7 +134,7 @@ type ContainersConfig struct {
EnableLabeledUsers bool `toml:"label_users,omitempty"`
// Env is the environment variable list for container process.
Env []string `toml:"env,omitempty"`
Env attributedstring.Slice `toml:"env,omitempty"`
// EnvHost Pass all host environment variables into the container.
EnvHost bool `toml:"env_host,omitempty"`
@ -171,7 +172,7 @@ type ContainersConfig struct {
LogTag string `toml:"log_tag,omitempty"`
// Mount to add to all containers
Mounts []string `toml:"mounts,omitempty"`
Mounts attributedstring.Slice `toml:"mounts,omitempty"`
// NetNS indicates how to create a network namespace for the container
NetNS string `toml:"netns,omitempty"`
@ -907,7 +908,7 @@ func (c *Config) GetDefaultEnvEx(envHost, httpProxy bool) []string {
}
}
}
return append(env, c.Containers.Env...)
return append(env, c.Containers.Env.Get()...)
}
// Capabilities returns the capabilities parses the Add and Drop capability

View File

@ -9,6 +9,7 @@ import (
"runtime"
"strings"
"github.com/containers/common/internal/attributedstring"
nettypes "github.com/containers/common/libnetwork/types"
"github.com/containers/common/pkg/apparmor"
"github.com/containers/common/pkg/cgroupv2"
@ -204,8 +205,8 @@ func defaultConfig() (*Config, error) {
Devices: []string{},
EnableKeyring: true,
EnableLabeling: selinuxEnabled(),
Env: []string{
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
Env: attributedstring.Slice{
Values: []string{"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"},
},
EnvHost: false,
HTTPProxy: true,
@ -214,7 +215,7 @@ func defaultConfig() (*Config, error) {
InitPath: "",
LogDriver: defaultLogDriver(),
LogSizeMax: DefaultLogSizeMax,
Mounts: []string{},
Mounts: attributedstring.Slice{},
NetNS: "private",
NoHosts: false,
PidNS: "private",
@ -224,7 +225,7 @@ func defaultConfig() (*Config, error) {
UTSNS: "private",
Umask: "0022",
UserNSSize: DefaultUserNSSize, // Deprecated
Volumes: []string{},
Volumes: attributedstring.Slice{},
},
Network: NetworkConfig{
DefaultNetwork: "podman",
@ -509,12 +510,12 @@ func (c *Config) Sysctls() []string {
// Volumes returns the default set of volumes that should be mounted in containers.
func (c *Config) Volumes() []string {
return c.Containers.Volumes
return c.Containers.Volumes.Get()
}
// Mounts returns the default set of mounts that should be mounted in containers.
func (c *Config) Mounts() []string {
return c.Containers.Mounts
return c.Containers.Mounts.Get()
}
// Devices returns the default additional devices for containers.
@ -539,7 +540,7 @@ func (c *Config) DNSOptions() []string {
// Env returns the default additional environment variables to add to containers.
func (c *Config) Env() []string {
return c.Containers.Env
return c.Containers.Env.Values
}
// IPCNS returns the default IPC Namespace configuration to run containers with.