google_guest_agent/cfg/cfg.go (226 lines of code) (raw):
// Copyright 2023 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package cfg is package responsible to loading and accessing the guest environment configuration.
package cfg
import (
"fmt"
"runtime"
"github.com/go-ini/ini"
)
var (
// instance is the single instance of configuration sections, once loaded this package
// should always return it.
instance *Sections
// configFile is a pointer to a function which takes the current OS name and returns
// an appropriate config file name. Replaceable by unit tests.
configFile = defaultConfigFile
// dataSource is a pointer to a data source loading/defining function, unit tests will
// want to change this pointer to whatever makes sense to its implementation.
dataSources = defaultDataSources
)
const (
winConfigPath = `C:\Program Files\Google\Compute Engine\instance_configs.cfg`
unixConfigPath = `/etc/default/instance_configs.cfg`
defaultConfig = `
[Core]
cloud_logging_enabled = true
[Accounts]
deprovision_remove = false
gpasswd_add_cmd = gpasswd -a {user} {group}
gpasswd_remove_cmd = gpasswd -d {user} {group}
groupadd_cmd = groupadd {group}
groups = adm,dip,docker,lxd,plugdev,video
reuse_homedir = false
useradd_cmd = useradd -m -s /bin/bash -p * {user}
userdel_cmd = userdel -r {user}
[Daemons]
accounts_daemon = true
clock_skew_daemon = true
network_daemon = true
[IpForwarding]
ethernet_proto_id = 66
ip_aliases = true
target_instance_ips = true
[Instance]
instance_id =
instance_id_dir = /etc/google_instance_id
[InstanceSetup]
host_key_dir = /etc/ssh
host_key_types = ecdsa,ed25519,rsa
network_enabled = true
optimize_local_ssd = true
set_boto_config = true
set_host_keys = true
set_multiqueue = true
[MetadataScripts]
default_shell = /bin/bash
run_dir =
shutdown = true
shutdown-windows = true
startup = true
startup-windows = true
sysprep-specialize = true
[NetworkInterfaces]
dhcp_command =
ip_forwarding = true
setup = true
manage_primary_nic =
restore_debian12_netplan_config = true
vlan_setup_enabled = false
[OSLogin]
cert_authentication = true
[MDS]
disable-https-mds-setup = true
enable-https-mds-native-cert-store = false
[Snapshots]
enabled = false
snapshot_service_ip = 169.254.169.254
snapshot_service_port = 8081
timeout_in_seconds = 60
[Unstable]
command_monitor_enabled = false
command_pipe_mode = 0770
command_pipe_group =
command_request_timeout = 10s
systemd_config_dir = /usr/lib/systemd/network
`
)
// Core contains the core configuration entries of guest agent, all
// configurations not tied/specific to a subsystem are defined in here.
type Core struct {
// CloudLoggingEnabled config toggle controls Guest Agent cloud logger.
// Disabling it will stop Guest Agent for configuring and logging to Cloud Logging.
CloudLoggingEnabled bool `ini:"cloud_logging_enabled,omitempty"`
}
// Sections encapsulates all the configuration sections.
type Sections struct {
// Core defines the core guest-agent's configuration entries/keys.
Core *Core `ini:"Core,omitempty"`
// AccountManager defines the address management configurations. It takes precedence over instance's
// and project's metadata configuration. The default configuration doesn't define values to it, if the
// user has defined it then we shouldn't even consider metadata values. Users must check if this
// pointer is nil or not.
AccountManager *AccountManager `ini:"accountManager,omitempty"`
// Accounts defines the non windows account management options, behaviors and commands.
Accounts *Accounts `ini:"Accounts,omitempty"`
// AddressManager defines the address management configurations. It takes precedence over instance's
// and project's metadata configuration. The default configuration doesn't define values to it, if the
// user has defined it then we shouldn't even consider metadata values. Users must check if this
// pointer is nil or not.
AddressManager *AddressManager `ini:"addressManager,omitempty"`
// Daemons defines the availability of clock skew, network and account managers.
Daemons *Daemons `ini:"Daemons,omitempty"`
// Diagnostics defines the diagnostics configurations. It takes precedence over instance's
// and project's metadata configuration. The default configuration doesn't define values to it, if the
// user has defined it then we shouldn't even consider metadata values. Users must check if this
// pointer is nil or not.
Diagnostics *Diagnostics `ini:"diagnostics,omitempty"`
// IPForwarding defines the ip forwarding configuration options.
IPForwarding *IPForwarding `ini:"IpForwarding,omitempty"`
// Instance defines the instance ID handling behaviors, i.e. where to read the ID from etc.
Instance *Instance `ini:"Instance,omitempty"`
// InstanceSetup defines options to basic instance setup options i.e. optimize local ssd, network,
// host keys etc.
InstanceSetup *InstanceSetup `ini:"InstanceSetup,omitempty"`
// MetadataScripts contains the configurations of the metadata-scripts service.
MetadataScripts *MetadataScripts `ini:"MetadataScripts,omitempty"`
// NetworkInterfaces defines if the network interfaces should be managed/configured by guest-agent
// as well as the commands definitions for network configuration.
NetworkInterfaces *NetworkInterfaces `ini:"NetworkInterfaces,omitempty"`
// OSLogin defines the OS Login configuration options.
OSLogin *OSLogin `ini:"OSLogin,omitempty"`
// MDS defines the MDS configuration options.
MDS *MDS `ini:"MDS,omitempty"`
// Snpashots defines the snapshot listener configuration and behavior i.e. the server address and port.
Snapshots *Snapshots `ini:"Snapshots,omitempty"`
// Unstable is a "under development feature flags" section. No stability or long term support is
// guaranteed for any keys under this section. No application, script or utility should rely on it.
Unstable *Unstable `ini:"Unstable,omitempty"`
// WSFC defines the wsfc configurations. It takes precedence over instance's and project's
// metadata configuration. The default configuration doesn't define values to it, if the user
// has defined it then we shouldn't even consider metadata values. Users must check if this
// pointer is nil or not.
WSFC *WSFC `ini:"wsfc,omitempty"`
}
// AccountManager contains the configurations of AccountManager section.
type AccountManager struct {
Disable bool `ini:"disable,omitempty"`
}
// Accounts contains the configurations of Accounts section.
type Accounts struct {
DeprovisionRemove bool `ini:"deprovision_remove,omitempty"`
GPasswdAddCmd string `ini:"gpasswd_add_cmd,omitempty"`
GPasswdRemoveCmd string `ini:"gpasswd_remove_cmd,omitempty"`
GroupAddCmd string `ini:"groupadd_cmd,omitempty"`
Groups string `ini:"groups,omitempty"`
ReuseHomedir bool `ini:"reuse_homedir,omitempty"`
UserAddCmd string `ini:"useradd_cmd,omitempty"`
UserDelCmd string `ini:"userdel_cmd,omitempty"`
}
// AddressManager contains the configuration of addressManager section.
type AddressManager struct {
Disable bool `ini:"disable,omitempty"`
}
// Daemons contains the configurations of Daemons section.
type Daemons struct {
AccountsDaemon bool `ini:"accounts_daemon,omitempty"`
ClockSkewDaemon bool `ini:"clock_skew_daemon,omitempty"`
NetworkDaemon bool `ini:"network_daemon,omitempty"`
}
// Diagnostics contains the configurations of Diagnostics section.
type Diagnostics struct {
Enable bool `ini:"enable,omitempty"`
}
// IPForwarding contains the configurations of IPForwarding section.
type IPForwarding struct {
EthernetProtoID string `ini:"ethernet_proto_id,omitempty"`
IPAliases bool `ini:"ip_aliases,omitempty"`
TargetInstanceIPs bool `ini:"target_instance_ips,omitempty"`
}
// Instance contains the configurations of Instance section.
type Instance struct {
// InstanceID is a backward compatible key. In the past the instance id was only
// supported/setup via config file, if we can't read the instance_id file then
// try honoring this configuration key.
InstanceID string `ini:"instance_id,omitempty"`
// InstanceIDDir defines where the instance id file should be read from.
InstanceIDDir string `ini:"instance_id_dir,omitempty"`
}
// InstanceSetup contains the configurations of InstanceSetup section.
type InstanceSetup struct {
HostKeyDir string `ini:"host_key_dir,omitempty"`
HostKeyTypes string `ini:"host_key_types,omitempty"`
NetworkEnabled bool `ini:"network_enabled,omitempty"`
OptimizeLocalSSD bool `ini:"optimize_local_ssd,omitempty"`
SetBotoConfig bool `ini:"set_boto_config,omitempty"`
SetHostKeys bool `ini:"set_host_keys,omitempty"`
SetMultiqueue bool `ini:"set_multiqueue,omitempty"`
}
// MetadataScripts contains the configurations of MetadataScripts section.
type MetadataScripts struct {
DefaultShell string `ini:"default_shell,omitempty"`
RunDir string `ini:"run_dir,omitempty"`
Shutdown bool `ini:"shutdown,omitempty"`
ShutdownWindows bool `ini:"shutdown-windows,omitempty"`
Startup bool `ini:"startup,omitempty"`
StartupWindows bool `ini:"startup-windows,omitempty"`
SysprepSpecialize bool `ini:"sysprep_specialize,omitempty"`
}
// OSLogin contains the configurations of OSLogin section.
type OSLogin struct {
CertAuthentication bool `ini:"cert_authentication,omitempty"`
}
// MDS contains the configurations for MDS section. Currently its opt-in only
// and should not assume any defaults. Setting any [defaultConfig] values will
// override user settings from Metadata.
type MDS struct {
// DisableHTTPSMdsSetup enables/disables the mTLS credential refresher.
DisableHTTPSMdsSetup bool `ini:"disable-https-mds-setup,omitempty"`
// HTTPSMDSEnableNativeStore enables/disables the use of OSs native store. Native
// store is Certificate Store on Windows which hosts both Client Credential and
// Root certificate where as its trust store that hosts root certs like
// `/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem` on Linux.
HTTPSMDSEnableNativeStore bool `ini:"enable-https-mds-native-cert-store,omitempty"`
}
// NetworkInterfaces contains the configurations of NetworkInterfaces section.
type NetworkInterfaces struct {
DHCPCommand string `ini:"dhcp_command,omitempty"`
IPForwarding bool `ini:"ip_forwarding,omitempty"`
Setup bool `ini:"setup,omitempty"`
ManagePrimaryNIC bool `ini:"manage_primary_nic,omitempty"`
RestoreDebian12NetplanConfig bool `ini:"restore_debian12_netplan_config,omitempty"`
VlanSetupEnabled bool `ini:"vlan_setup_enabled,omitempty"`
}
// Snapshots contains the configurations of Snapshots section.
type Snapshots struct {
Enabled bool `ini:"enabled,omitempty"`
SnapshotServiceIP string `ini:"snapshot_service_ip,omitempty"`
SnapshotServicePort int `ini:"snapshot_service_port,omitempty"`
TimeoutInSeconds int `ini:"timeout_in_seconds,omitempty"`
}
// Unstable contains the configurations of Unstable section. No long term stability or support
// is guaranteed for configurations defined in the Unstable section. By default all flags defined
// in this section is disabled and is intended to isolate under development features.
type Unstable struct {
CommandMonitorEnabled bool `ini:"command_monitor_enabled,omitempty"`
CommandPipePath string `ini:"command_pipe_path,omitempty"`
CommandRequestTimeout string `ini:"command_request_timeout,omitempty"`
CommandPipeMode string `ini:"command_pipe_mode,omitempty"`
CommandPipeGroup string `ini:"command_pipe_group,omitempty"`
SystemdConfigDir string `ini:"systemd_config_dir,omitempty"`
}
// WSFC contains the configurations of WSFC section.
type WSFC struct {
Addresses string `ini:"addresses,omitempty"`
Enable bool `ini:"enable,omitempty"`
Port string `ini:"port,omitempty"`
}
func defaultConfigFile(osName string) string {
if osName == "windows" {
return winConfigPath
}
return unixConfigPath
}
func defaultDataSources(extraDefaults []byte) []interface{} {
var res = []interface{}{[]byte(defaultConfig)}
config := configFile(runtime.GOOS)
if len(extraDefaults) > 0 {
res = append(res, extraDefaults)
}
return append(res, []interface{}{
config,
config + ".distro",
config + ".template",
}...)
}
// Load loads default configuration and the configuration from default config files.
func Load(extraDefaults []byte) error {
opts := ini.LoadOptions{
Loose: true,
Insensitive: true,
}
sources := dataSources(extraDefaults)
cfg, err := ini.LoadSources(opts, sources[0], sources[1:]...)
if err != nil {
return fmt.Errorf("failed to load configuration: %+v", err)
}
sections := new(Sections)
if err := cfg.MapTo(sections); err != nil {
return fmt.Errorf("failed to map configuration to object: %+v", err)
}
instance = sections
return nil
}
// Get returns the configuration's instance previously loaded with Load().
func Get() *Sections {
if instance == nil {
panic("cfg package was not initialized, Load() " +
"should be called in the early initialization code path")
}
return instance
}