commit google-guest-agent for openSUSE:Factory
Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package google-guest-agent for openSUSE:Factory checked in at 2024-08-05 17:22:22 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/google-guest-agent (Old) and /work/SRC/openSUSE:Factory/.google-guest-agent.new.7232 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "google-guest-agent" Mon Aug 5 17:22:22 2024 rev:37 rq:1191634 version:20240802.00 Changes: -------- --- /work/SRC/openSUSE:Factory/google-guest-agent/google-guest-agent.changes 2024-07-08 19:09:33.061572432 +0200 +++ /work/SRC/openSUSE:Factory/.google-guest-agent.new.7232/google-guest-agent.changes 2024-08-05 17:23:24.156355551 +0200 @@ -1,0 +2,63 @@ +Mon Aug 5 07:26:29 UTC 2024 - John Paul Adrian Glaubitz <adrian.glaubitz@suse.com> + +- Update to version 20240802.00 + * Fix where agent panics on nil event (#409) +- from version 20240801.00 + * Configure primary nic if only set in cfg file (#408) + * Update NIC management strategy (#402) + * Only release dhclient leases for an interface if the respective dhclient is still running (#407) + * Disable OS Login without pruning off any extra suffix. (#400) + * Skip root cert rotation if installed once (#405) + * Add ipv6 support to guest agent (#404) + * Update Accounts documentation (#403) + * Update google-startup-scripts.service to enable logging (#399) + * Network subsystem remove os rules (#396) + * oslogin: don't remove sshca watcher when oslogin is disabled (#398) + * Update dependencies to catch up on CVE fixes (#397) + * Network manager netplan implementation (#386) + * Update dependencies to catch up on CVE fixes (#391) + * Log current available routes on error (#388) + * Fix command monitor bugs (#389) + * Windows account: ignore "user already belogs to group" error (#387) + * Add more error logging in snapshot handling requests, use common retry util (#384) + * All non-200 status code from MDS should raise error (#383) + * Change metadata key to enable-oslogin-certificates (#382) + * Update dhclient pid/lease file directory to abide apparmor rules (#381) + * Add COS homedir-gid patch to upstream. (#365) + * Add require-oslogin-certificates logic to disable keys (#368) + * systemd-networkd: support debian 12's version (#372) + * Minor update typo in comment (#380) + * NetworkManager: only set secondary interfaces as up (#378) + * address manager: make sure we check for oldMetadata (#375) + * network: early setup network (#374) + * NetworkManager: fix ipv6 and ipv4 mode attribute (#373) + * Network Manager: make sure we clean up ifcfg files (#371) + * metadata script runner: fix script download (#370) + * oslogin: avoid adding extra empty line at the end of /etc/security/group.conf (#369) + * Dynamic vlan (#361) + * Check for nil response (#366) + * Create NetworkManager implementation (#362) + * Skip interface manager on Windows (#363) + * network: remove ignore setup (#360) + * Create wicked network service implementation and its respective unit (#356) + * Update metadata script runner, add tests (#357) + * Refactor guest-agent to use common retry util (#355) + * Flush logs before exiting #358 (#359) + * Create systemd-networkd unit tests. (#354) + * Update network manager unit tests (#351) + * Implement retry util (#350) + * Refactor utils package to not dump everything unrelated into one file (#352) + * Set version on metadata script runner (#353) + * Implement cleanup of deprecated configuration directives (#348) + * Ignore DHCP offered routes only for secondary nics (#347) + * Deprecate DHClient in favor of systemd-networkd (#342) + * Generate windows and linux licenses (#346) + * Remove quintonamore from OWNERS (#345) + * Delete integration tests (#343) +- from version 20240716.00 + * Update dep: golang.org/x/crypto to v0.17.0 + * Update dep: google.golang.org/protobuf to 1.33.0 + * Update dep: golang.org/x/net to 0.17.0 + * Update dep: google.golang.org/grpc to v1.57.1 + +------------------------------------------------------------------- Old: ---- guest-agent-20240701.00.tar.gz New: ---- guest-agent-20240802.00.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ google-guest-agent.spec ++++++ --- /var/tmp/diff_new_pack.QcUaNl/_old 2024-08-05 17:23:25.368405254 +0200 +++ /var/tmp/diff_new_pack.QcUaNl/_new 2024-08-05 17:23:25.368405254 +0200 @@ -24,7 +24,7 @@ %global import_path %{provider_prefix} Name: google-guest-agent -Version: 20240701.00 +Version: 20240802.00 Release: 0 Summary: Google Cloud Guest Agent License: Apache-2.0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.QcUaNl/_old 2024-08-05 17:23:25.408406894 +0200 +++ /var/tmp/diff_new_pack.QcUaNl/_new 2024-08-05 17:23:25.412407058 +0200 @@ -3,8 +3,8 @@ <param name="url">https://github.com/GoogleCloudPlatform/guest-agent/</param> <param name="scm">git</param> <param name="exclude">.git</param> - <param name="versionformat">20240701.00</param> - <param name="revision">20240701.00</param> + <param name="versionformat">20240802.00</param> + <param name="revision">20240802.00</param> <param name="changesgenerate">enable</param> </service> <service name="recompress" mode="disabled"> @@ -15,7 +15,7 @@ <param name="basename">guest-agent</param> </service> <service name="go_modules" mode="disabled"> - <param name="archive">guest-agent-20240701.00.tar.gz</param> + <param name="archive">guest-agent-20240802.00.tar.gz</param> </service> </services> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.QcUaNl/_old 2024-08-05 17:23:25.432407879 +0200 +++ /var/tmp/diff_new_pack.QcUaNl/_new 2024-08-05 17:23:25.436408043 +0200 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/GoogleCloudPlatform/guest-agent/</param> - <param name="changesrevision">79a1124a2cfb01675889e9a8a9ace93ae42475e4</param></service></servicedata> + <param name="changesrevision">d592f5648412dfefbfa12c3602d5cfd1892b054f</param></service></servicedata> (No newline at EOF) ++++++ guest-agent-20240701.00.tar.gz -> guest-agent-20240802.00.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/guest-agent-20240701.00/README.md new/guest-agent-20240802.00/README.md --- old/guest-agent-20240701.00/README.md 2024-06-25 00:57:12.000000000 +0200 +++ new/guest-agent-20240802.00/README.md 2024-08-02 21:57:07.000000000 +0200 @@ -58,9 +58,12 @@ `google-sudoers` group. * The daemon stores a file in the guest to record which user accounts are managed by Google. -* User accounts not managed by Google are not touched by the accounts daemon. +* User accounts not managed by the agent are not touched by the accounts daemon. * The authorized keys file for a Google managed user is deleted when all SSH keys for the user are removed from metadata. +* Users accounts managed by the agent will be added to the `groups` config + line in the `Accounts` section. If these groups do not exist, the agent + will not create them. #### OS Login @@ -79,6 +82,9 @@ If the user disables OS login via metadata, the configuration changes will be removed. +Note that options under the `Accounts` section of the configuration do not apply +to oslogin users. + #### Clock Skew (Linux only) @@ -183,7 +189,7 @@ Section | Option | Value ----------------- | ---------------------- | ----- Accounts | deprovision\_remove | `true` makes deprovisioning a user destructive. -Accounts | groups | Comma separated list of groups for newly provisioned users. +Accounts | groups | Comma separated list of groups for newly provisioned users created from metadata ssh keys. Accounts | useradd\_cmd | Command string to create a new user. Accounts | userdel\_cmd | Command string to delete a user. Accounts | usermod\_cmd | Command string to modify a user's groups. @@ -208,6 +214,7 @@ MetadataScripts | shutdown | `false` disables shutdown script execution. NetworkInterfaces | setup | `false` skips network interface setup. NetworkInterfaces | ip\_forwarding | `false` skips IP forwarding. +NetworkInterfaces | manage\_primary\_nic | `true` will start managing the primary NIC in addition to the secondary NICs. NetworkInterfaces | dhcp\_command | String path for alternate dhcp executable used to enable network interfaces. OSLogin | cert_authentication | `false` prevents guest-agent from setting up sshd's `TrustedUserCAKeys`, `AuthorizedPrincipalsCommand` and `AuthorizedPrincipalsCommandUser` configuration keys. Default value: `true`. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/guest-agent-20240701.00/google_guest_agent/addresses.go new/guest-agent-20240802.00/google_guest_agent/addresses.go --- old/guest-agent-20240701.00/google_guest_agent/addresses.go 2024-06-25 00:57:12.000000000 +0200 +++ new/guest-agent-20240802.00/google_guest_agent/addresses.go 2024-08-02 21:57:07.000000000 +0200 @@ -382,7 +382,14 @@ if runtime.GOOS == "windows" { // Don't addAddress if this is already configured. if !slices.Contains(configuredIPs, ip) { - err = addAddress(net.ParseIP(ip), net.IPv4Mask(255, 255, 255, 255), uint32(iface.Index)) + // In case of forwardedIpv6 we get IPV6 CIDR and Parse IP will return nil. + netip := net.ParseIP(ip) + if netip != nil && !isIPv6(netip) { + // Retains existing behavior for ipv4 addresses. + err = addAddress(netip, net.IPv4Mask(255, 255, 255, 255), uint32(iface.Index)) + } else { + err = addIpv6Address(ip, uint32(iface.Index)) + } } } else { err = addLocalRoute(ctx, config, ip, iface.Name) @@ -400,7 +407,14 @@ if !slices.Contains(configuredIPs, ip) { continue } - err = removeAddress(net.ParseIP(ip), uint32(iface.Index)) + netip := net.ParseIP(ip) + // In case of forwardedIpv6 we get IPV6 CIDR and Parse IP will return nil. + if netip != nil && !isIPv6(netip) { + // Retains existing behavior for ipv4 addresses. + err = removeAddress(netip, net.IPv4Mask(255, 255, 255, 255), uint32(iface.Index)) + } else { + err = removeIpv6Address(ip, uint32(iface.Index)) + } } else { err = removeLocalRoute(ctx, config, ip, iface.Name) } @@ -417,6 +431,30 @@ } } } + logger.Infof("Completed adding/removing routes for aliases, forwarded IP and target-instance IPs") return nil } + +// isIPv6 returns true if the IP address is an IPv6 address. +func isIPv6(ip net.IP) bool { + return ip.To4() == nil +} + +// addIpv6Address adds given IP on the provided network interface. +func addIpv6Address(s string, idx uint32) error { + ip, n, err := net.ParseCIDR(s) + if err != nil { + return err + } + return addAddress(ip, n.Mask, idx) +} + +// removeIpv6Address removes the given IP on the network interface. +func removeIpv6Address(s string, idx uint32) error { + ip, n, err := net.ParseCIDR(s) + if err != nil { + return err + } + return removeAddress(ip, n.Mask, idx) +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/guest-agent-20240701.00/google_guest_agent/addresses_test.go new/guest-agent-20240802.00/google_guest_agent/addresses_test.go --- old/guest-agent-20240701.00/google_guest_agent/addresses_test.go 2024-06-25 00:57:12.000000000 +0200 +++ new/guest-agent-20240802.00/google_guest_agent/addresses_test.go 2024-08-02 21:57:07.000000000 +0200 @@ -18,6 +18,7 @@ "context" "encoding/json" "fmt" + "net" "reflect" "testing" @@ -214,4 +215,31 @@ } }) } +} + +func TestIsIPv6(t *testing.T) { + tests := []struct { + ip net.IP + want bool + name string + }{ + { + name: "valid_ipv4", + ip: net.ParseIP("1.2.3.4"), + want: false, + }, + { + name: "valid_ipv6", + ip: net.ParseIP("fd20:b8f:5d95:2000:0:2::"), + want: true, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if got := isIPv6(test.ip); got != test.want { + t.Errorf("isIPv6(%s) = %t, want %t", test.ip.String(), got, test.want) + } + }) + } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/guest-agent-20240701.00/google_guest_agent/addresses_unix.go new/guest-agent-20240802.00/google_guest_agent/addresses_unix.go --- old/guest-agent-20240701.00/google_guest_agent/addresses_unix.go 2024-06-25 00:57:12.000000000 +0200 +++ new/guest-agent-20240802.00/google_guest_agent/addresses_unix.go 2024-08-02 21:57:07.000000000 +0200 @@ -23,7 +23,7 @@ ) // TODO: addLocalRoute and addRoute should be merged with the addition of ipForwardType to ipForwardEntry. -func addIPForwardEntry(route ipForwardEntry) error { +func addIPForwardEntry(ipForwardEntry) error { return errors.New("addIPForwardEntry unimplemented on non Windows systems") } @@ -32,10 +32,10 @@ return nil, errors.New("getIPForwardEntries unimplemented on non Windows systems") } -func addAddress(ip net.IP, mask net.IPMask, index uint32) error { +func addAddress(net.IP, net.IPMask, uint32) error { return errors.New("addAddress unimplemented on non Windows systems") } -func removeAddress(ip net.IP, index uint32) error { +func removeAddress(net.IP, net.IPMask, uint32) error { return errors.New("removeAddress unimplemented on non Windows systems") } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/guest-agent-20240701.00/google_guest_agent/addresses_windows.go new/guest-agent-20240802.00/google_guest_agent/addresses_windows.go --- old/guest-agent-20240701.00/google_guest_agent/addresses_windows.go 2024-06-25 00:57:12.000000000 +0200 +++ new/guest-agent-20240802.00/google_guest_agent/addresses_windows.go 2024-08-02 21:57:07.000000000 +0200 @@ -25,6 +25,7 @@ "syscall" "unsafe" + "github.com/GoogleCloudPlatform/guest-logging-go/logger" "golang.org/x/sys/windows" ) @@ -120,15 +121,32 @@ ) func addAddress(ip net.IP, mask net.IPMask, index uint32) error { + logger.Infof("Adding %q ip address", ip.String()) + subnet, _ := mask.Size() // CreateUnicastIpAddressEntry only available Vista onwards. - if err := procCreateUnicastIpAddressEntry.Find(); err != nil { + // AddIPAddress api supports only ipv4 address. + if isIPv6(ip) { + return createUnicastIpAddressEntry6(ip, uint8(subnet), index) + } + + // https://learn.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-add... + if err := procCreateUnicastIpAddressEntry.Find(); err != nil && !isIPv6(ip) { return addIPAddress(ip, mask, index) } - subnet, _ := mask.Size() return createUnicastIpAddressEntry(ip, uint8(subnet), index) } -func removeAddress(ip net.IP, index uint32) error { +func removeAddress(ip net.IP, mask net.IPMask, index uint32) error { + logger.Infof("Removing %q ip address", ip.String()) + subnet, _ := mask.Size() + if isIPv6(ip) { + // Unlike ipv4 that can be added either by addIPAddress or createUnicastIpAddressEntry + // ipv6 addresses can only be added by createUnicastIpAddressEntry6. + // Try removing them by deleteUnicastIpAddressEntry6 only as deleteIPAddress deletes + // IP address previously added using AddIPAddress only. + return deleteUnicastIpAddressEntry6(ip, uint8(subnet), index) + } + // DeleteUnicastIpAddressEntry only available Vista onwards. if err := procDeleteUnicastIpAddressEntry.Find(); err != nil { return deleteIPAddress(ip) @@ -136,6 +154,87 @@ return deleteUnicastIpAddressEntry(ip, index) } +// LUID represents the locally unique identifier (LUID) for a network interface. +// https://learn.microsoft.com/en-us/windows/win32/api/ifdef/ns-ifdef-net_luid_... +type LUID uint64 + +// RawSockaddrInet represents an IPv4/IPv6 address and family. +// https://learn.microsoft.com/en-us/windows/win32/api/ws2ipdef/ns-ws2ipdef-soc... +type RawSockaddrInet struct { + Family uint16 + data [26]byte +} + +// MIBUnicastIPAddressRow6 stores unicast IP address information used with for +// ipforwarding addresses. +// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-mib... +type MIBUnicastIPAddressRow6 struct { + Address RawSockaddrInet + InterfaceLuid LUID + InterfaceIndex uint32 + PrefixOrigin uint32 + SuffixOrigin uint32 + ValidLifetime uint32 + PreferredLifetime uint32 + OnLinkPrefixLength uint8 + SkipAsSource bool +} + +// setAddr is helper function to set net.IP in a structure windows syscalls understand. +func (addr *RawSockaddrInet) setAddr(ip net.IP) { + addr6 := (*windows.RawSockaddrInet6)(unsafe.Pointer(addr)) + addr6.Family = windows.AF_INET6 + copy(addr6.Addr[:], ip) +} + +// initIpRow6 initializes the MIB_UNICASTIPADDRESS_ROW6 struct based on Ip, prefix length +// and the index. +func initIpRow6(ip net.IP, prefix uint8, index uint32) (*MIBUnicastIPAddressRow6, error) { + ipRow := new(MIBUnicastIPAddressRow6) + // No return value. + procInitializeUnicastIpAddressEntry.Call(uintptr(unsafe.Pointer(ipRow))) + + ipRow.InterfaceIndex = index + ipRow.OnLinkPrefixLength = prefix + // https://blogs.technet.microsoft.com/rmilne/2012/02/08/fine-grained-control-w... + ipRow.SkipAsSource = true + + addr := RawSockaddrInet{} + addr.setAddr(ip) + ipRow.Address = addr + return ipRow, nil +} + +// createUnicastIpAddressEntry6 adds a new unicast IPv6 address entry on local machine. +func createUnicastIpAddressEntry6(ip net.IP, prefix uint8, index uint32) error { + logger.Infof("CreateUnicastIpAddressEntry6 %v, with prefix %d on interface %d", ip, prefix, index) + + ipRow, err := initIpRow6(ip, prefix, index) + if err != nil { + return fmt.Errorf("initialize MIB_UNICASTIPADDRESS_ROW failed: %w", err) + } + + if ret, _, err := procCreateUnicastIpAddressEntry.Call(uintptr(unsafe.Pointer(ipRow))); ret != 0 { + return fmt.Errorf("nonzero return code from CreateUnicastIpAddressEntry: %s, last err: %w", syscall.Errno(ret), err) + } + return nil +} + +// deleteUnicastIpAddressEntry6 removes a unicast IPv6 address entry from local machine. +func deleteUnicastIpAddressEntry6(ip net.IP, prefix uint8, index uint32) error { + logger.Infof("DeleteUnicastIpAddressEntry6 %v, with prefix %d on interface %d", ip, prefix, index) + + ipRow, err := initIpRow6(ip, prefix, index) + if err != nil { + return fmt.Errorf("initialize MIB_UNICASTIPADDRESS_ROW failed: %w", err) + } + + if ret, _, err := procDeleteUnicastIpAddressEntry.Call(uintptr(unsafe.Pointer(ipRow))); ret != 0 { + return fmt.Errorf("nonzero return code from DeleteUnicastIpAddressEntry: %s, last err: %w", syscall.Errno(ret), err) + } + return nil +} + func createUnicastIpAddressEntry(ip net.IP, prefix uint8, index uint32) error { ipRow := new(MIB_UNICASTIPADDRESS_ROW) // No return value. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/guest-agent-20240701.00/google_guest_agent/agentcrypto/mtls_mds.go new/guest-agent-20240802.00/google_guest_agent/agentcrypto/mtls_mds.go --- old/guest-agent-20240701.00/google_guest_agent/agentcrypto/mtls_mds.go 2024-06-25 00:57:12.000000000 +0200 +++ new/guest-agent-20240802.00/google_guest_agent/agentcrypto/mtls_mds.go 2024-08-02 21:57:07.000000000 +0200 @@ -19,6 +19,7 @@ "context" "fmt" "path/filepath" + "sync/atomic" "time" "github.com/GoogleCloudPlatform/guest-agent/google_guest_agent/uefi" @@ -52,7 +53,15 @@ // CredsJob implements job scheduler interface for generating/rotating credentials. type CredsJob struct { + // client is the client used for communicating with MDS. client metadata.MDSClientInterface + // rootCertsInstalled tracks if MDS root certificates were installed successfully + // atleast once. This allows to skip unnecessary work of refreshing root certs + // which are updated only when instance stops/starts which will restart agent + // as well. Allowing refresh on agent restarts regardless of instance reboots allows + // to fix any issues encountered with root certificate without having to restart + // compute instance. + rootCertsInstalled atomic.Bool } // New initializer new job. @@ -160,16 +169,19 @@ // $cert = Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.Issuer -like "*google.internal*" } // Invoke-RestMethod -Uri https://169.254.169.254 -Method Get -Headers @{"Metadata-Flavor"="Google"} -Certificate $cert func (j *CredsJob) Run(ctx context.Context) (bool, error) { - logger.Infof("Fetching Root CA cert...") - - v, err := j.readRootCACert(googleRootCACertUEFIVar) - if err != nil { - return true, fmt.Errorf("failed to read Root CA cert with an error: %w", err) - } - - if err := j.writeRootCACert(ctx, v.Content, filepath.Join(defaultCredsDir, rootCACertFileName)); err != nil { - return true, fmt.Errorf("failed to store Root CA cert with an error: %w", err) + if !j.rootCertsInstalled.Load() { + logger.Infof("Fetching Root CA cert...") + v, err := j.readRootCACert(googleRootCACertUEFIVar) + if err != nil { + return true, fmt.Errorf("failed to read Root CA cert with an error: %w", err) + } + + if err := j.writeRootCACert(ctx, v.Content, filepath.Join(defaultCredsDir, rootCACertFileName)); err != nil { + return true, fmt.Errorf("failed to store Root CA cert with an error: %w", err) + } } + // Set only when agent has atleast one successful run for installing root certs. + j.rootCertsInstalled.Store(true) logger.Infof("Fetching client credentials...") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/guest-agent-20240701.00/google_guest_agent/cfg/cfg.go new/guest-agent-20240802.00/google_guest_agent/cfg/cfg.go --- old/guest-agent-20240701.00/google_guest_agent/cfg/cfg.go 2024-06-25 00:57:12.000000000 +0200 +++ new/guest-agent-20240802.00/google_guest_agent/cfg/cfg.go 2024-08-02 21:57:07.000000000 +0200 @@ -87,6 +87,7 @@ dhcp_command = ip_forwarding = true setup = true +manage_primary_nic = [OSLogin] cert_authentication = true @@ -260,9 +261,10 @@ // 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"` + DHCPCommand string `ini:"dhcp_command,omitempty"` + IPForwarding bool `ini:"ip_forwarding,omitempty"` + Setup bool `ini:"setup,omitempty"` + ManagePrimaryNIC bool `ini:"manage_primary_nic,omitempty"` } // Snapshots contains the configurations of Snapshots section. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/guest-agent-20240701.00/google_guest_agent/events/sshtrustedca/sshtrustedca_linux.go new/guest-agent-20240802.00/google_guest_agent/events/sshtrustedca/sshtrustedca_linux.go --- old/guest-agent-20240701.00/google_guest_agent/events/sshtrustedca/sshtrustedca_linux.go 2024-06-25 00:57:12.000000000 +0200 +++ new/guest-agent-20240802.00/google_guest_agent/events/sshtrustedca/sshtrustedca_linux.go 2024-08-02 21:57:07.000000000 +0200 @@ -20,6 +20,7 @@ "os" "os/exec" "path/filepath" + "sync/atomic" "syscall" "time" @@ -78,7 +79,7 @@ // Run listens to ssh_trusted_ca's pipe open calls and report back the event. func (mp *Watcher) Run(ctx context.Context, evType string) (bool, interface{}, error) { - var canceled bool + var canceled atomic.Bool for mp.isWaitingWrite() { time.Sleep(10 * time.Millisecond) @@ -95,7 +96,7 @@ case <-cancelContext: break case <-ctx.Done(): - canceled = true + canceled.Store(true) // Open the pipe as O_RDONLY to release the blocking open O_WRONLY. pipeFile, err := os.OpenFile(mp.pipePath, os.O_RDONLY, 0644) @@ -127,7 +128,7 @@ // Have we got a ctx.Done()? if so lets just return from here and unregister // the watcher. - if canceled { + if canceled.Load() { if err := pipeFile.Close(); err != nil { logger.Errorf("Failed to close readonly pipe: %+v", err) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/guest-agent-20240701.00/google_guest_agent/instance_setup.go new/guest-agent-20240802.00/google_guest_agent/instance_setup.go --- old/guest-agent-20240701.00/google_guest_agent/instance_setup.go 2024-06-25 00:57:12.000000000 +0200 +++ new/guest-agent-20240802.00/google_guest_agent/instance_setup.go 2024-08-02 21:57:07.000000000 +0200 @@ -27,6 +27,7 @@ "github.com/GoogleCloudPlatform/guest-agent/google_guest_agent/agentcrypto" "github.com/GoogleCloudPlatform/guest-agent/google_guest_agent/cfg" + network "github.com/GoogleCloudPlatform/guest-agent/google_guest_agent/network/manager" "github.com/GoogleCloudPlatform/guest-agent/google_guest_agent/run" "github.com/GoogleCloudPlatform/guest-agent/google_guest_agent/scheduler" "github.com/GoogleCloudPlatform/guest-agent/retry" @@ -157,7 +158,17 @@ newMetadata, err = mdsClient.Get(ctx) if err != nil { logger.Errorf("Failed to reach MDS(all retries exhausted): %+v", err) - os.Exit(1) + logger.Infof("Falling to OS default network configuration to attempt to recover.") + if err := network.FallbackToDefault(ctx); err != nil { + // Just log error and attempt to continue anyway, if we can't reach MDS + // we can't do anything. + logger.Errorf("Failed to rollback guest-agent network configuration: %v", err) + } + newMetadata, err = mdsClient.Get(ctx) + if err != nil { + logger.Errorf("Failed to reach MDS after attempt to recover network configuration(all retries exhausted): %+v", err) + os.Exit(1) + } } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/guest-agent-20240701.00/google_guest_agent/network/manager/dhclient_linux.go new/guest-agent-20240802.00/google_guest_agent/network/manager/dhclient_linux.go --- old/guest-agent-20240701.00/google_guest_agent/network/manager/dhclient_linux.go 2024-06-25 00:57:12.000000000 +0200 +++ new/guest-agent-20240802.00/google_guest_agent/network/manager/dhclient_linux.go 2024-08-02 21:57:07.000000000 +0200 @@ -425,7 +425,12 @@ var obtainIpv6Interfaces []string var releaseIpv6Interfaces []string - for _, iface := range interfaces { + for i, iface := range interfaces { + if !shouldManageInterface(i == 0) { + // Do not setup anything for this interface to avoid duplicate processes. + continue + } + // Check for IPv4 interfaces for which to obtain a lease. processExists, err := dhclientProcessExists(ctx, iface, ipv4) if err != nil { @@ -494,13 +499,25 @@ // Release all the interface leases from dhclient. for _, iface := range googleInterfaces { - if err := runDhclient(ctx, ipv4, iface, true); err != nil { - return err + ipv4Exists, err := dhclientProcessExists(ctx, iface, ipv4) + if err != nil { + return fmt.Errorf("error checking if ipv4 dhclient process for %s exists: %v", iface, err) + } + if ipv4Exists { + if err = runDhclient(ctx, ipv4, iface, true); err != nil { + return err + } } } for _, iface := range googleIpv6Interfaces { - if err := runDhclient(ctx, ipv6, iface, true); err != nil { - return err + ipv6Exists, err := dhclientProcessExists(ctx, iface, ipv6) + if err != nil { + return fmt.Errorf("error checking if ipv6 dhclient process for %s exists: %v", iface, err) + } + if ipv6Exists { + if err = runDhclient(ctx, ipv6, iface, true); err != nil { + return err + } } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/guest-agent-20240701.00/google_guest_agent/network/manager/dhclient_linux_test.go new/guest-agent-20240802.00/google_guest_agent/network/manager/dhclient_linux_test.go --- old/guest-agent-20240701.00/google_guest_agent/network/manager/dhclient_linux_test.go 2024-06-25 00:57:12.000000000 +0200 +++ new/guest-agent-20240802.00/google_guest_agent/network/manager/dhclient_linux_test.go 2024-08-02 21:57:07.000000000 +0200 @@ -25,6 +25,7 @@ "testing" "time" + "github.com/GoogleCloudPlatform/guest-agent/google_guest_agent/cfg" "github.com/GoogleCloudPlatform/guest-agent/google_guest_agent/osinfo" "github.com/GoogleCloudPlatform/guest-agent/google_guest_agent/ps" "github.com/GoogleCloudPlatform/guest-agent/google_guest_agent/run" @@ -135,6 +136,9 @@ // dhclientTestSetup sets up the test. func dhclientTestSetup(t *testing.T, opts dhclientTestOpts) { t.Helper() + if err := cfg.Load(nil); err != nil { + t.Fatalf("cfg.Load(nil) = %v, nil", err) + } // We have to mock dhclientProcessExists as we cannot mock where the ps // package checks for processes here. @@ -276,42 +280,42 @@ }{ { name: "all-ipv4", - testInterfaces: []string{"obtain1", "obtain2"}, + testInterfaces: []string{"primary1", "obtain2"}, testIpv6Interfaces: []string{}, existFlags: []bool{false, false}, ipVersions: []ipVersion{ipv4, ipv4}, - expectedObtainIpv4: []string{"obtain1", "obtain2"}, + expectedObtainIpv4: []string{"obtain2"}, expectedObtainIpv6: []string{}, expectedReleaseIpv6: []string{}, }, { name: "all-ipv6", - testInterfaces: []string{"obtain1", "obtain2"}, - testIpv6Interfaces: []string{"obtain1", "obtain2"}, + testInterfaces: []string{"primary1", "obtain2"}, + testIpv6Interfaces: []string{"primary1", "obtain2"}, existFlags: []bool{false, false}, ipVersions: []ipVersion{ipv6, ipv6}, - expectedObtainIpv4: []string{"obtain1", "obtain2"}, - expectedObtainIpv6: []string{"obtain1", "obtain2"}, + expectedObtainIpv4: []string{"obtain2"}, + expectedObtainIpv6: []string{"obtain2"}, expectedReleaseIpv6: []string{}, }, { name: "ipv4-ipv6", - testInterfaces: []string{"obtain1", "obtain2"}, + testInterfaces: []string{"primary1", "obtain2"}, testIpv6Interfaces: []string{"obtain2"}, existFlags: []bool{false, false}, ipVersions: []ipVersion{ipv4, ipv6}, - expectedObtainIpv4: []string{"obtain1", "obtain2"}, + expectedObtainIpv4: []string{"obtain2"}, expectedObtainIpv6: []string{"obtain2"}, expectedReleaseIpv6: []string{}, }, { name: "release-ipv6", - testInterfaces: []string{"obtain1", "release1"}, - testIpv6Interfaces: []string{"obtain1"}, + testInterfaces: []string{"primary1", "release1"}, + testIpv6Interfaces: []string{"primary1"}, existFlags: []bool{false, true}, ipVersions: []ipVersion{ipv4, ipv6}, - expectedObtainIpv4: []string{"obtain1", "release1"}, - expectedObtainIpv6: []string{"obtain1"}, + expectedObtainIpv4: []string{"release1"}, + expectedObtainIpv6: []string{}, expectedReleaseIpv6: []string{"release1"}, }, } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/guest-agent-20240701.00/google_guest_agent/network/manager/manager.go new/guest-agent-20240802.00/google_guest_agent/network/manager/manager.go --- old/guest-agent-20240701.00/google_guest_agent/network/manager/manager.go 2024-06-25 00:57:12.000000000 +0200 +++ new/guest-agent-20240802.00/google_guest_agent/network/manager/manager.go 2024-08-02 21:57:07.000000000 +0200 @@ -19,6 +19,7 @@ import ( "context" "fmt" + "net" "github.com/GoogleCloudPlatform/guest-agent/google_guest_agent/cfg" "github.com/GoogleCloudPlatform/guest-agent/google_guest_agent/osinfo" @@ -68,28 +69,6 @@ VlanInterfaces map[int]metadata.VlanInterface } -// osConfigRule describes matching rules for OS's, used for specifying either -// network interfaces to ignore during setup or native config hookups. -type osConfigRule struct { - // osNames is a list of OS's names matching the rule (as described by osInfo) - osNames []string - - // majorVersions is a map of this OS's versions to ignore. - majorVersions map[int]bool - - // action defines what action or exception to perform for this rule. - action osConfigAction -} - -// osConfigAction defines the action to be taken in an osConfigRule. -type osConfigAction struct { - // ignorePrimary determines whether to ignore the primary network interface. - ignorePrimary bool - - // ignoreSecondary determines whether to ignore all non-primary network interfaces. - ignoreSecondary bool -} - // guestAgentSection is the section added to guest-agent-written ini files to indicate // that the ini file is managed by the agent. type guestAgentSection struct { @@ -131,9 +110,9 @@ return nil, fmt.Errorf("no network manager impl found for %s", iface) } -// SetupInterfaces sets up all the network interfaces on the system, applying rules described -// by osRules and using the native network manager service detected to be managing the primary -// network interface. +// SetupInterfaces sets up all secondary network interfaces on the system, and primary network +// interface if enabled in the configuration using the native network manager service detected +// to be managing the primary network interface. func SetupInterfaces(ctx context.Context, config *cfg.Sections, mds *metadata.Descriptor) error { // User may have disabled network interface setup entirely. if !config.NetworkInterfaces.Setup { @@ -195,3 +174,56 @@ return nil } + +// FallbackToDefault will attempt to rescue broken networking by rolling back +// all guest-agent modifications to the network configuration. +func FallbackToDefault(ctx context.Context) error { + nics, err := buildInterfacesFromAllPhysicalNICs() + if err != nil { + return fmt.Errorf("could not build list of NICs for fallback: %v", err) + } + + // Rollback every NIC with every known network manager. + for _, svc := range knownNetworkManagers { + logger.Infof("Rolling back %s", svc.Name()) + if err := svc.Rollback(ctx, nics); err != nil { + logger.Errorf("Failed to roll back config for %s: %v", svc.Name(), err) + } + } + + return nil +} + +// Build a *Interfaces from all physical interfaces rather than the MDS. +func buildInterfacesFromAllPhysicalNICs() (*Interfaces, error) { + nics := &Interfaces{ + EthernetInterfaces: nil, + VlanInterfaces: map[int]metadata.VlanInterface{}, + } + + interfaces, err := net.Interfaces() + if err != nil { + return nil, fmt.Errorf("failed to get interfaces: %v", err) + } + + for _, iface := range interfaces { + mac := iface.HardwareAddr.String() + if mac == "" { + continue + } + nics.EthernetInterfaces = append(nics.EthernetInterfaces, metadata.NetworkInterfaces{ + Mac: mac, + }) + } + + return nics, nil +} + +// shouldManageInterface returns whether the guest agent should manage an interface +// provided whether the interface of interest is the primary interface or not. +func shouldManageInterface(isPrimary bool) bool { + if isPrimary { + return cfg.Get().NetworkInterfaces.ManagePrimaryNIC + } + return true +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/guest-agent-20240701.00/google_guest_agent/network/manager/manager_linux.go new/guest-agent-20240802.00/google_guest_agent/network/manager/manager_linux.go --- old/guest-agent-20240701.00/google_guest_agent/network/manager/manager_linux.go 2024-06-25 00:57:12.000000000 +0200 +++ new/guest-agent-20240802.00/google_guest_agent/network/manager/manager_linux.go 2024-08-02 21:57:07.000000000 +0200 @@ -18,7 +18,7 @@ // knownNetworkManagers is a list of supported/available network managers. knownNetworkManagers = []Service{ &netplan{ - netplanConfigDir: "/etc/netplan/", + netplanConfigDir: "/run/netplan/", networkdDropinDir: "/etc/systemd/network/", priority: 20, }, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/guest-agent-20240701.00/google_guest_agent/network/manager/manager_test.go new/guest-agent-20240802.00/google_guest_agent/network/manager/manager_test.go --- old/guest-agent-20240701.00/google_guest_agent/network/manager/manager_test.go 2024-06-25 00:57:12.000000000 +0200 +++ new/guest-agent-20240802.00/google_guest_agent/network/manager/manager_test.go 2024-08-02 21:57:07.000000000 +0200 @@ -40,10 +40,16 @@ // managingError indicates whether isManaging() should return an error. managingError bool + + // rollbackError indicates whether Rollback() should return an error. + rollbackError bool + + // rolledBack indicates whether the network config was rolled back + rolledBack bool } // Name implements the Service interface. -func (n mockService) Name() string { +func (n *mockService) Name() string { if n.isFallback { return "fallback" } @@ -52,11 +58,11 @@ // Configure gives the opportunity for the Service implementation to adjust its configuration // based on the Guest Agent configuration. -func (n mockService) Configure(ctx context.Context, config *cfg.Sections) { +func (n *mockService) Configure(context.Context, *cfg.Sections) { } // IsManaging implements the Service interface. -func (n mockService) IsManaging(ctx context.Context, iface string) (bool, error) { +func (n *mockService) IsManaging(context.Context, string) (bool, error) { if n.managingError { return false, fmt.Errorf("mock error") } @@ -64,17 +70,21 @@ } // SetupEthernetInterface implements the Service interface. -func (n mockService) SetupEthernetInterface(ctx context.Context, config *cfg.Sections, nics *Interfaces) error { +func (n *mockService) SetupEthernetInterface(context.Context, *cfg.Sections, *Interfaces) error { return nil } // SetupVlanInterface implements the Service interface. -func (n mockService) SetupVlanInterface(ctx context.Context, config *cfg.Sections, nics *Interfaces) error { +func (n *mockService) SetupVlanInterface(context.Context, *cfg.Sections, *Interfaces) error { return nil } // Rollback implements the Service interface. -func (n mockService) Rollback(ctx context.Context, nics *Interfaces) error { +func (n *mockService) Rollback(context.Context, *Interfaces) error { + n.rolledBack = true + if n.rollbackError { + return fmt.Errorf("mock error") + } return nil } @@ -109,7 +119,7 @@ name string // managers are the list of mock services to register. - services []mockService + services []*mockService // expectedManager is the manager expected to be returned. expectedManager mockService @@ -123,7 +133,7 @@ // Base test case testing if it works. { name: "no-error", - services: []mockService{ + services: []*mockService{ { isFallback: false, isManaging: true, @@ -142,7 +152,7 @@ // Test if an error is returned if no network manager is found. { name: "no-manager-found", - services: []mockService{ + services: []*mockService{ { isFallback: false, isManaging: false, @@ -158,7 +168,7 @@ // Test if an error is returned if IsManaging() fails. { name: "is-managing-fail", - services: []mockService{ + services: []*mockService{ { isFallback: false, managingError: true, @@ -174,7 +184,7 @@ // Test if the fallback service is returned if all other services are not detected. { name: "fallback", - services: []mockService{ + services: []*mockService{ { isFallback: false, isManaging: false, @@ -231,62 +241,77 @@ t.Fatalf("no error returned when error expected, expected error: %s", test.expectedErrorMessage) } - if activeService.manager != test.expectedManager { + if *activeService.manager.(*mockService) != test.expectedManager { t.Fatalf("did not get expected network manager. Expected: %v, Actual: %v", test.expectedManager, activeService) } }) } } -// TestFindOSRule tests whether findOSRule() correctly returns the expected values -// depending on whether a matching rule exists or not. -func TestFindOSRule(t *testing.T) { +// TestRollbackToDefault ensures that all network managers are rolled back, +// including the active manager. +func TestFallbackToDefault(t *testing.T) { managerTestSetup() + ctx := context.Background() - tests := []struct { - // name is the name of the test. - name string - - // rules are mock OSConfig rules. - rules []osConfigRule - - // expectedNil indicates to expect a nil return when set to true. - expectedNil bool - }{ - // ignoreRule exists. - { - name: "ignore-exist", - rules: []osConfigRule{ - { - osNames: []string{"test"}, - majorVersions: map[int]bool{ - testOSVersion: true, - }, - action: osConfigAction{}, - }, - }, - expectedNil: false, + prevKnownNetworkManager := knownNetworkManagers + t.Cleanup(func() { + knownNetworkManagers = prevKnownNetworkManager + }) + knownNetworkManagers = []Service{ + &mockService{ + isManaging: true, }, - // ignoreRule does not exist. - { - name: "ignore-no-exist", - rules: []osConfigRule{ - { - osNames: []string{"non-test"}, - majorVersions: map[int]bool{ - 0: true, - }, - action: osConfigAction{}, - }, - }, - expectedNil: true, + &mockService{ + isManaging: true, + rollbackError: true, + }, + &mockService{ + isManaging: false, }, } - // Run the tests. - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - managerTestSetup() - }) + if err := FallbackToDefault(ctx); err != nil { + t.Fatalf("FallbackToDefault(ctx) = %v, want nil", err) + } + + for i, svc := range knownNetworkManagers { + if !svc.(*mockService).rolledBack { + t.Errorf("knownNetworkManagers[%d].rolledBack = %t, want true", i, svc.(*mockService).rolledBack) + } + } +} + +func TestBuildInterfacesFromAllPhysicalNICs(t *testing.T) { + nics, err := buildInterfacesFromAllPhysicalNICs() + if err != nil { + t.Fatalf("buildInterfacesFromAllPhysicalNICs() = %v, want nil", err) + } + + for _, nic := range nics.EthernetInterfaces { + if _, err := GetInterfaceByMAC(nic.Mac); err != nil { + t.Errorf("GetInterfaceByMAC(%q) = %v, want nil)", nic.Mac, err) + } + } +} + +func TestShouldManageInterface(t *testing.T) { + if err := cfg.Load(nil); err != nil { + t.Fatalf("cfg.Load(nil) = %v, want nil", err) + } + if shouldManageInterface(true) { + t.Error("with default config, shouldManageInterface(isPrimary = true) = true, want false") + } + if !shouldManageInterface(false) { + t.Error("with default config, shouldManageInterface(isPrimary = false) = false, want true") + } + if err := cfg.Load([]byte("[NetworkInterfaces]\nmanage_primary_nic=true")); err != nil { + t.Fatalf("cfg.Load(%q) = %v, want nil", "[NetworkInterfaces]\nmanage_primary_nic=true", err) + } + if !shouldManageInterface(true) { + t.Error("with manage_primary_nic=false, shouldManageInterface(isPrimary = true) = false, want true") + } + if !shouldManageInterface(false) { + t.Error("with manage_primary_nic=false, shouldManageInterface(isPrimary = false) = false, want true") } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/guest-agent-20240701.00/google_guest_agent/network/manager/netplan_linux.go new/guest-agent-20240802.00/google_guest_agent/network/manager/netplan_linux.go --- old/guest-agent-20240701.00/google_guest_agent/network/manager/netplan_linux.go 2024-06-25 00:57:12.000000000 +0200 +++ new/guest-agent-20240802.00/google_guest_agent/network/manager/netplan_linux.go 2024-08-02 21:57:07.000000000 +0200 @@ -97,7 +97,7 @@ type netplanDHCPOverrides struct { // When true, the domain name received from the DHCP server will be used as DNS // search domain over this link. - UseDomains bool `yaml:"use-domains,omitempty"` + UseDomains *bool `yaml:"use-domains,omitempty"` } // netplanMatch contains the keys uses to match an interface. @@ -181,15 +181,6 @@ return fmt.Errorf("error writing systemd-networkd's drop-in: %v", err) } - osInfo := osinfoGet() - // Debian 12 has a pretty generic matching netplan configuration for gce, until we have that - // changed we are only removing. - if osInfo.OS == "debian" && osInfo.Version.Major == 12 { - if err := os.Remove("/etc/netplan/90-default.yaml"); err != nil { - logger.Debugf("Failed to remove default netplan config: %s", err) - } - } - // Avoid restarting systemd-networkd. if err := run.Quiet(ctx, "networkctl", "reload"); err != nil { return fmt.Errorf("error reloading systemd-networkd network configs: %v", err) @@ -216,6 +207,9 @@ } for i, iface := range interfaces { + if !shouldManageInterface(i == 0) { + continue + } logger.Debugf("writing systemd-networkd drop-in config for %s", iface) var dhcp = "ipv4" @@ -283,6 +277,12 @@ return nil } +// shouldUseDomains returns true if interface index is 0. +func shouldUseDomains(idx int) *bool { + res := idx == 0 + return &res +} + // writeNetplanEthernetDropin selects the ethernet configuration, transforms it // into a netplan dropin format and writes it down to the netplan's drop-in directory. func (n netplan) writeNetplanEthernetDropin(mtuMap map[string]int, interfaces, ipv6Interfaces []string) error { @@ -294,6 +294,9 @@ } for i, iface := range interfaces { + if !shouldManageInterface(i == 0) { + continue + } logger.Debugf("Adding %s(%d) to drop-in configuration.", iface, i) trueVal := true @@ -301,7 +304,7 @@ Match: netplanMatch{Name: iface}, DHCPv4: &trueVal, DHCP4Overrides: &netplanDHCPOverrides{ - UseDomains: true, + UseDomains: shouldUseDomains(i), }, } @@ -312,7 +315,7 @@ if slices.Contains(ipv6Interfaces, iface) { ne.DHCPv6 = &trueVal ne.DHCP6Overrides = &netplanDHCPOverrides{ - UseDomains: true, + UseDomains: shouldUseDomains(i), } } @@ -329,6 +332,12 @@ // write writes the netplan dropin file. func (n netplan) write(nd netplanDropin, suffix string) error { dropinFile := n.dropinFile(suffix) + dropinDir := filepath.Dir(dropinFile) + err := os.MkdirAll(dropinDir, 0755) + if err != nil { + return fmt.Errorf("failed to create networkd dropin dir: %w", err) + } + if err := writeYamlFile(dropinFile, &nd); err != nil { return fmt.Errorf("error saving netplan drop-in file %s: %w", dropinFile, err) } @@ -423,5 +432,12 @@ } } + if err := run.Quiet(ctx, "networkctl", "reload"); err != nil { + return fmt.Errorf("error reloading systemd-networkd network configs: %v", err) + } + if err := run.Quiet(ctx, "netplan", "apply"); err != nil { + return fmt.Errorf("error applying netplan changes: %w", err) + } + return nil } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/guest-agent-20240701.00/google_guest_agent/network/manager/network_manager_linux.go new/guest-agent-20240802.00/google_guest_agent/network/manager/network_manager_linux.go --- old/guest-agent-20240701.00/google_guest_agent/network/manager/network_manager_linux.go 2024-06-25 00:57:12.000000000 +0200 +++ new/guest-agent-20240802.00/google_guest_agent/network/manager/network_manager_linux.go 2024-08-02 21:57:07.000000000 +0200 @@ -256,5 +256,8 @@ } } + if err := run.Quiet(ctx, "nmcli", "conn", "reload"); err != nil { + return fmt.Errorf("error reloading NetworkManager config cache: %v", err) + } return nil } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/guest-agent-20240701.00/google_guest_agent/network/manager/wicked_linux.go new/guest-agent-20240802.00/google_guest_agent/network/manager/wicked_linux.go --- old/guest-agent-20240701.00/google_guest_agent/network/manager/wicked_linux.go 2024-06-25 00:57:12.000000000 +0200 +++ new/guest-agent-20240802.00/google_guest_agent/network/manager/wicked_linux.go 2024-08-02 21:57:07.000000000 +0200 @@ -55,7 +55,7 @@ // Configure gives the opportunity for the Service implementation to adjust its configuration // based on the Guest Agent configuration. -func (n wicked) Configure(ctx context.Context, config *cfg.Sections) { +func (n *wicked) Configure(ctx context.Context, config *cfg.Sections) { wickedCommand, err := exec.LookPath("wicked") if err != nil { logger.Infof("failed to find wicked path, falling back to default: %+v", err) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/guest-agent-20240701.00/google_guest_agent/oslogin.go new/guest-agent-20240802.00/google_guest_agent/oslogin.go --- old/guest-agent-20240701.00/google_guest_agent/oslogin.go 2024-06-25 00:57:12.000000000 +0200 +++ new/guest-agent-20240802.00/google_guest_agent/oslogin.go 2024-08-02 21:57:07.000000000 +0200 @@ -356,7 +356,7 @@ if enable && !present { line += oslogin } else if !enable && present { - line = strings.TrimSuffix(line, oslogin) + line = strings.Replace(line, oslogin, "", 1) } if runtime.GOOS == "freebsd" { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/guest-agent-20240701.00/google_guest_agent/oslogin_test.go new/guest-agent-20240802.00/google_guest_agent/oslogin_test.go --- old/guest-agent-20240701.00/google_guest_agent/oslogin_test.go 2024-06-25 00:57:12.000000000 +0200 +++ new/guest-agent-20240802.00/google_guest_agent/oslogin_test.go 2024-08-02 21:57:07.000000000 +0200 @@ -173,6 +173,19 @@ }, enable: true, }, + { + contents: []string{ + "line1", + "passwd: line2" + oslogin + " some_other_service", + "group: line3" + oslogin + " another_service", + }, + want: []string{ + "line1", + "passwd: line2 some_other_service", + "group: line3 another_service", + }, + enable: false, + }, } for idx, tt := range tests { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/guest-agent-20240701.00/google_guest_agent/sshca/sshca.go new/guest-agent-20240802.00/google_guest_agent/sshca/sshca.go --- old/guest-agent-20240701.00/google_guest_agent/sshca/sshca.go 2024-06-25 00:57:12.000000000 +0200 +++ new/guest-agent-20240802.00/google_guest_agent/sshca/sshca.go 2024-08-02 21:57:07.000000000 +0200 @@ -63,7 +63,12 @@ } // Make sure we close the pipe after we've done writing to it. - pipeData := evData.Data.(*sshtrustedca.PipeData) + pipeData, ok := evData.Data.(*sshtrustedca.PipeData) + if !ok { + logger.Errorf("Received invalid event data (%+v), ignoring this event and un-subscribing %s", evData.Data, evType) + return false + } + defer func() { if err := pipeData.File.Close(); err != nil { logger.Errorf("Failed to close pipe: %+v", err) ++++++ vendor.tar.gz ++++++
participants (1)
-
Source-Sync