diff --git a/.github/workflows/config/.golangci.yaml b/.github/workflows/config/.golangci.yaml index c4eca6bb08a..4a695cc3353 100644 --- a/.github/workflows/config/.golangci.yaml +++ b/.github/workflows/config/.golangci.yaml @@ -52,7 +52,19 @@ linters-settings: linters: disable-all: true enable: + - bodyclose + - dogsled + - errcheck + - exportloopref + - goconst - gofmt + - goimports + - goprintffuncname + - ineffassign + - typecheck + - unconvert + - unused + - whitespace issues: # Excluding configuration per-path, per-linter, per-text and per-source exclude-rules: @@ -61,6 +73,11 @@ issues: - gosec - errcheck - gocritic + - # Exclude bodyclose when it's passed to client.ProcessRequestForAPI + # or client.ProcessRequestForUtility which internally closes the body. + path: src/go/rdctl/ + linters: [ bodyclose ] + source: "client.ProcessRequestFor(API|Utility)\\(rdClient.DoRequest(WithPayload)?\\(" - # Exclude ST1005 when it encounters errors starting with proper noun linters: [ stylecheck ] text: "ST1005:" @@ -73,6 +90,6 @@ issues: path: src/go/wsl-helper/pkg/dockerproxy/platform/vsock_linux\.go linters: [ gocritic ] text: todoCommentWithoutDetail - - # Exclude ignoring errors from syscall + - # Ignore errors from syscall linters: [ dogsled ] source: ^\s*_, _, _ = .*\.Call\( diff --git a/src/go/guestagent/pkg/kube/servicewatcher.go b/src/go/guestagent/pkg/kube/servicewatcher_linux.go similarity index 100% rename from src/go/guestagent/pkg/kube/servicewatcher.go rename to src/go/guestagent/pkg/kube/servicewatcher_linux.go diff --git a/src/go/guestagent/pkg/kube/watcher.go b/src/go/guestagent/pkg/kube/watcher_linux.go similarity index 100% rename from src/go/guestagent/pkg/kube/watcher.go rename to src/go/guestagent/pkg/kube/watcher_linux.go diff --git a/src/go/guestagent/pkg/kube/watcher_stub.go b/src/go/guestagent/pkg/kube/watcher_stub.go new file mode 100644 index 00000000000..1b68e4fb274 --- /dev/null +++ b/src/go/guestagent/pkg/kube/watcher_stub.go @@ -0,0 +1,34 @@ +//go:build !linux + +/* +Copyright © 2024 SUSE LLC +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 kube + +import ( + "context" + "fmt" + "net" + + "github.com/rancher-sandbox/rancher-desktop/src/go/guestagent/pkg/tracker" +) + +func WatchForServices( + ctx context.Context, + configPath string, + k8sServiceListenerIP net.IP, + enableListeners bool, + portTracker tracker.Tracker, +) error { + return fmt.Errorf("not implemented for non-linux") +} diff --git a/src/go/guestagent/pkg/tracker/listenertracker.go b/src/go/guestagent/pkg/tracker/listenertracker_linux.go similarity index 100% rename from src/go/guestagent/pkg/tracker/listenertracker.go rename to src/go/guestagent/pkg/tracker/listenertracker_linux.go diff --git a/src/go/guestagent/pkg/tracker/listenertracker_test.go b/src/go/guestagent/pkg/tracker/listenertracker_linux_test.go similarity index 100% rename from src/go/guestagent/pkg/tracker/listenertracker_test.go rename to src/go/guestagent/pkg/tracker/listenertracker_linux_test.go diff --git a/src/go/guestagent/pkg/tracker/listenertracker_stub.go b/src/go/guestagent/pkg/tracker/listenertracker_stub.go new file mode 100644 index 00000000000..00d2aaf6ade --- /dev/null +++ b/src/go/guestagent/pkg/tracker/listenertracker_stub.go @@ -0,0 +1,36 @@ +//go:build !linux + +/* +Copyright © 2024 SUSE LLC +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 tracker + +import ( + "context" + "fmt" + "net" +) + +type ListenerTracker struct{} + +func NewListenerTracker() *ListenerTracker { + panic("not implement for non-Linux") +} + +func (l *ListenerTracker) AddListener(ctx context.Context, ip net.IP, port int) error { + return fmt.Errorf("not implemented for non-Linux") +} + +func (l *ListenerTracker) RemoveListener(_ context.Context, ip net.IP, port int) error { + return fmt.Errorf("not implemented for non-Linux") +} diff --git a/src/go/nerdctl-stub/generate/main_linux.go b/src/go/nerdctl-stub/generate/main_linux.go index 27b6b631b0d..9b77c137df8 100644 --- a/src/go/nerdctl-stub/generate/main_linux.go +++ b/src/go/nerdctl-stub/generate/main_linux.go @@ -65,6 +65,8 @@ func main() { logrus.WithError(err).WithField("path", outputPath).Fatal("error creating output") } defer output.Close() + //nolint:dogsled // we only require the file name; we can also ignore `ok`, as + // on failure we just have no useful file name. _, filename, _, _ := runtime.Caller(0) data := map[string]interface{}{ "package": filename, diff --git a/src/go/privileged-service/pkg/manage/install_windows.go b/src/go/privileged-service/pkg/manage/install_windows.go index ddab2875aa6..f7c839704d7 100644 --- a/src/go/privileged-service/pkg/manage/install_windows.go +++ b/src/go/privileged-service/pkg/manage/install_windows.go @@ -44,12 +44,12 @@ func InstallService(name, displayName, desc string) error { if err != nil { return err } - defer m.Disconnect() + defer disconnect(m) // We always need uninstall first to unregister, // the event logger recreation service can yield to a registry key error // e.g RancherDesktopPrivilegedService registry key already exists - UninstallService(name) + _ = UninstallService(name) s, err := m.CreateService(name, instPath, mgr.Config{DisplayName: displayName, Description: desc}) if err != nil { @@ -62,7 +62,7 @@ func InstallService(name, displayName, desc string) error { err = eventlog.InstallAsEventCreate(name, eventlog.Error|eventlog.Warning|eventlog.Info) if err != nil { - s.Delete() + _ = s.Delete() return fmt.Errorf("setup event log for [%s] failed: %w", name, err) } return nil diff --git a/src/go/privileged-service/pkg/manage/manage_windows.go b/src/go/privileged-service/pkg/manage/manage_windows.go index eba7cb7c49b..224f03adbdf 100644 --- a/src/go/privileged-service/pkg/manage/manage_windows.go +++ b/src/go/privileged-service/pkg/manage/manage_windows.go @@ -41,7 +41,7 @@ func StartService(name string) error { if err != nil { return err } - defer m.Disconnect() + defer disconnect(m) s, err := openService(m.Handle, name) if err != nil { return fmt.Errorf("could not access service: %w", err) @@ -61,7 +61,7 @@ func ControlService(name string, control svc.Cmd, desiredState svc.State) error if err != nil { return err } - defer m.Disconnect() + defer disconnect(m) s, err := openService(m.Handle, name) if err != nil { return fmt.Errorf("could not access service: %w", err) @@ -97,10 +97,19 @@ func connect() (*mgr.Mgr, error) { return &mgr.Mgr{Handle: h}, nil } +// disconnect from the manager, swallowing errors. +func disconnect(m *mgr.Mgr) { + _ = m.Disconnect() +} + // connect is same as mgr.OpenService with minimal // access control func openService(svcHandle windows.Handle, name string) (*mgr.Service, error) { - h, err := windows.OpenService(svcHandle, syscall.StringToUTF16Ptr(name), SERVICE_MINIMAL_ACCESS) + ptr, err := syscall.UTF16PtrFromString(name) + if err != nil { + return nil, err + } + h, err := windows.OpenService(svcHandle, ptr, SERVICE_MINIMAL_ACCESS) if err != nil { return nil, err } diff --git a/src/go/privileged-service/pkg/manage/uninstall_windows.go b/src/go/privileged-service/pkg/manage/uninstall_windows.go index 777e6f4e59e..8fec12effca 100644 --- a/src/go/privileged-service/pkg/manage/uninstall_windows.go +++ b/src/go/privileged-service/pkg/manage/uninstall_windows.go @@ -32,7 +32,7 @@ func UninstallService(name string) error { if err != nil { return fmt.Errorf("connect to service [%s] failed: %w", name, err) } - defer m.Disconnect() + defer disconnect(m) s, err := m.OpenService(name) if err != nil { if errors.Is(err, windows.ERROR_SERVICE_DOES_NOT_EXIST) { diff --git a/src/go/privileged-service/pkg/port/server_windows.go b/src/go/privileged-service/pkg/port/server_windows.go index fa474dcee42..3c4ad2e43fb 100644 --- a/src/go/privileged-service/pkg/port/server_windows.go +++ b/src/go/privileged-service/pkg/port/server_windows.go @@ -76,7 +76,7 @@ func (s *Server) Start() error { if err != nil { select { case <-s.quit: - s.eventLogger.Info(uint32(windows.NO_ERROR), "port server received a stop signal") + _ = s.eventLogger.Info(uint32(windows.NO_ERROR), "port server received a stop signal") return nil default: return fmt.Errorf("port server connection accept error: %w", err) @@ -93,12 +93,12 @@ func (s *Server) handleEvent(conn net.Conn) { var pm types.PortMapping err := json.NewDecoder(conn).Decode(&pm) if err != nil { - s.eventLogger.Error(uint32(windows.ERROR_EXCEPTION_IN_SERVICE), fmt.Sprintf("port server decoding received payload error: %v", err)) + _ = s.eventLogger.Error(uint32(windows.ERROR_EXCEPTION_IN_SERVICE), fmt.Sprintf("port server decoding received payload error: %v", err)) return } - s.eventLogger.Info(uint32(windows.NO_ERROR), fmt.Sprintf("handleEvent for %+v", pm)) + _ = s.eventLogger.Info(uint32(windows.NO_ERROR), fmt.Sprintf("handleEvent for %+v", pm)) if err = s.proxy.exec(pm); err != nil { - s.eventLogger.Error(uint32(windows.ERROR_EXCEPTION_IN_SERVICE), fmt.Sprintf("port proxy [%+v] failed: %v", pm, err)) + _ = s.eventLogger.Error(uint32(windows.ERROR_EXCEPTION_IN_SERVICE), fmt.Sprintf("port proxy [%+v] failed: %v", pm, err)) } } @@ -106,9 +106,9 @@ func (s *Server) handleEvent(conn net.Conn) { func (s *Server) Stop() { close(s.quit) s.listener.Close() - s.eventLogger.Info(uint32(windows.NO_ERROR), fmt.Sprintf("remove all %+v", s.proxy.portMappings)) + _ = s.eventLogger.Info(uint32(windows.NO_ERROR), fmt.Sprintf("remove all %+v", s.proxy.portMappings)) if err := s.proxy.removeAll(); err != nil { - s.eventLogger.Warning(uint32(windows.ERROR_EXCEPTION_IN_SERVICE), err.Error()) + _ = s.eventLogger.Warning(uint32(windows.ERROR_EXCEPTION_IN_SERVICE), err.Error()) } s.stopped = true } diff --git a/src/go/privileged-service/pkg/svc/service_windows.go b/src/go/privileged-service/pkg/svc/service_windows.go index b2c41013e8d..941a8d06a85 100644 --- a/src/go/privileged-service/pkg/svc/service_windows.go +++ b/src/go/privileged-service/pkg/svc/service_windows.go @@ -35,7 +35,7 @@ func RunService(name string, isDebug bool) error { return errors.Wrap(err, "RunService could not initialize event logger") } defer elog.Close() - elog.Info(uint32(windows.NO_ERROR), fmt.Sprintf("%s service starting", name)) + _ = elog.Info(uint32(windows.NO_ERROR), fmt.Sprintf("%s service starting", name)) run := svc.Run if isDebug { run = debug.Run @@ -45,10 +45,10 @@ func RunService(name string, isDebug bool) error { supervisor := NewSupervisor(portServer, elog) err = run(name, supervisor) if err != nil { - elog.Error(uint32(windows.ERROR_EXCEPTION_IN_SERVICE), fmt.Sprintf("%s service failed: %v", name, err)) + _ = elog.Error(uint32(windows.ERROR_EXCEPTION_IN_SERVICE), fmt.Sprintf("%s service failed: %v", name, err)) return err } - elog.Info(uint32(windows.NO_ERROR), fmt.Sprintf("%s service stopped", name)) + _ = elog.Info(uint32(windows.NO_ERROR), fmt.Sprintf("%s service stopped", name)) return nil } diff --git a/src/go/privileged-service/pkg/svc/supervisor_windows.go b/src/go/privileged-service/pkg/svc/supervisor_windows.go index bcbc610740e..b2f3e3ed5f4 100644 --- a/src/go/privileged-service/pkg/svc/supervisor_windows.go +++ b/src/go/privileged-service/pkg/svc/supervisor_windows.go @@ -51,7 +51,7 @@ func (s *Supervisor) Execute(args []string, r <-chan svc.ChangeRequest, changes changes <- svc.Status{State: svc.StartPending} startErr := make(chan error) go func() { - s.eventLogger.Info(uint32(windows.NO_ERROR), "port server is starting") + _ = s.eventLogger.Info(uint32(windows.NO_ERROR), "port server is starting") startErr <- s.portServer.Start() }() changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted} @@ -59,7 +59,7 @@ loop: for { select { case e := <-startErr: - s.eventLogger.Error(uint32(windows.ERROR_EXCEPTION_IN_SERVICE), fmt.Sprintf("supervisor failed to start: %v", e)) + _ = s.eventLogger.Error(uint32(windows.ERROR_EXCEPTION_IN_SERVICE), fmt.Sprintf("supervisor failed to start: %v", e)) return false, uint32(windows.ERROR_SERVICE_NEVER_STARTED) case c := <-r: switch c.Cmd { @@ -67,11 +67,11 @@ loop: changes <- c.CurrentStatus case svc.Stop, svc.Shutdown: s.portServer.Stop() - s.eventLogger.Info(uint32(windows.NO_ERROR), "port server is stopping") + _ = s.eventLogger.Info(uint32(windows.NO_ERROR), "port server is stopping") changes <- svc.Status{State: svc.Stopped, Accepts: cmdsAccepted} break loop default: - s.eventLogger.Error(uint32(windows.ERROR_INVALID_SERVICE_CONTROL), fmt.Sprintf("unexpected control request #%d", c)) + _ = s.eventLogger.Error(uint32(windows.ERROR_INVALID_SERVICE_CONTROL), fmt.Sprintf("unexpected control request #%d", c)) } } } diff --git a/src/go/rdctl/cmd/api.go b/src/go/rdctl/cmd/api.go index afa81294e5c..d8bc8373dff 100644 --- a/src/go/rdctl/cmd/api.go +++ b/src/go/rdctl/cmd/api.go @@ -101,14 +101,16 @@ func doAPICommand(cmd *cobra.Command, args []string) error { if err != nil { return err } - response, err := rdClient.DoRequestWithPayload(apiSettings.Method, endpoint, bytes.NewBuffer(contents)) - result, errorPacket, err = client.ProcessRequestForAPI(response, err) + method := apiSettings.Method + payload := bytes.NewBuffer(contents) + result, errorPacket, err = client.ProcessRequestForAPI(rdClient.DoRequestWithPayload(method, endpoint, payload)) } else if apiSettings.Body != "" { if apiSettings.Method == "" { apiSettings.Method = "PUT" } - response, err := rdClient.DoRequestWithPayload(apiSettings.Method, endpoint, bytes.NewBufferString(apiSettings.Body)) - result, errorPacket, err = client.ProcessRequestForAPI(response, err) + method := apiSettings.Method + payload := bytes.NewBufferString(apiSettings.Body) + result, errorPacket, err = client.ProcessRequestForAPI(rdClient.DoRequestWithPayload(method, endpoint, payload)) } else { if apiSettings.Method == "" { apiSettings.Method = "GET" diff --git a/src/go/rdctl/cmd/createProfile.go b/src/go/rdctl/cmd/createProfile.go index ca221eb0c5d..ee1104c6f76 100644 --- a/src/go/rdctl/cmd/createProfile.go +++ b/src/go/rdctl/cmd/createProfile.go @@ -101,13 +101,13 @@ func createProfile() (string, error) { // This should have been caught in validateProfileFormatFlags return "", fmt.Errorf(`no input format specified: must specify exactly one input format of "--input FILE|-", "--body|-b STRING", or "--from-settings"`) } - connectionInfo, err := config.GetConnectionInfo(false) - if err != nil { - return "", fmt.Errorf("failed to get connection info: %w", err) + connectionInfo, err2 := config.GetConnectionInfo(false) + if err2 != nil { + return "", fmt.Errorf("failed to get connection info: %w", err2) } rdClient := client.NewRDClient(connectionInfo) - response, err := rdClient.DoRequest("GET", client.VersionCommand("", "settings")) - output, err = client.ProcessRequestForUtility(response, err) + command := client.VersionCommand("", "settings") + output, err = client.ProcessRequestForUtility(rdClient.DoRequest("GET", command)) } if err != nil { return "", err diff --git a/src/go/rdctl/cmd/extension.go b/src/go/rdctl/cmd/extension.go index 41fe0393845..c27f708430b 100644 --- a/src/go/rdctl/cmd/extension.go +++ b/src/go/rdctl/cmd/extension.go @@ -19,6 +19,7 @@ package cmd import ( "fmt" + "github.com/spf13/cobra" ) diff --git a/src/go/rdctl/cmd/extensionInstall.go b/src/go/rdctl/cmd/extensionInstall.go index a9cf8808aa2..c2d98a21ecd 100644 --- a/src/go/rdctl/cmd/extensionInstall.go +++ b/src/go/rdctl/cmd/extensionInstall.go @@ -19,6 +19,7 @@ package cmd import ( "fmt" + "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/client" "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/config" "github.com/spf13/cobra" diff --git a/src/go/rdctl/cmd/listSettings.go b/src/go/rdctl/cmd/listSettings.go index ac6faac688d..165e9c77f2b 100644 --- a/src/go/rdctl/cmd/listSettings.go +++ b/src/go/rdctl/cmd/listSettings.go @@ -18,6 +18,7 @@ package cmd import ( "fmt" + "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/client" "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/config" "github.com/spf13/cobra" @@ -52,6 +53,6 @@ func getListSettings() ([]byte, error) { return []byte{}, fmt.Errorf("failed to get connection info: %w", err) } rdClient := client.NewRDClient(connectionInfo) - response, err := rdClient.DoRequest("GET", client.VersionCommand("", "settings")) - return client.ProcessRequestForUtility(response, err) + command := client.VersionCommand("", "settings") + return client.ProcessRequestForUtility(rdClient.DoRequest("GET", command)) } diff --git a/src/go/rdctl/cmd/paths.go b/src/go/rdctl/cmd/paths.go index 3c7fe67fa3f..76accd83d96 100644 --- a/src/go/rdctl/cmd/paths.go +++ b/src/go/rdctl/cmd/paths.go @@ -3,9 +3,10 @@ package cmd import ( "encoding/json" "fmt" + "os" + p "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/paths" "github.com/spf13/cobra" - "os" ) var pathsCmd = &cobra.Command{ diff --git a/src/go/rdctl/cmd/set.go b/src/go/rdctl/cmd/set.go index 371a681cdcf..beb8f1452ee 100644 --- a/src/go/rdctl/cmd/set.go +++ b/src/go/rdctl/cmd/set.go @@ -23,7 +23,7 @@ import ( "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/client" "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/config" - "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/options/generated" + options "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/options/generated" "github.com/spf13/cobra" ) @@ -65,8 +65,9 @@ func doSetCommand(cmd *cobra.Command) error { return err } - response, err := rdClient.DoRequestWithPayload("PUT", client.VersionCommand("", "settings"), bytes.NewBuffer(jsonBuffer)) - result, err := client.ProcessRequestForUtility(response, err) + command := client.VersionCommand("", "settings") + buf := bytes.NewBuffer(jsonBuffer) + result, err := client.ProcessRequestForUtility(rdClient.DoRequestWithPayload("PUT", command, buf)) if err != nil { return err } diff --git a/src/go/rdctl/cmd/shutdown.go b/src/go/rdctl/cmd/shutdown.go index 359e5f4131f..a5e8436eeda 100644 --- a/src/go/rdctl/cmd/shutdown.go +++ b/src/go/rdctl/cmd/shutdown.go @@ -63,8 +63,8 @@ func doShutdown(shutdownSettings *shutdownSettingsStruct, initiatingCommand shut connectionInfo, err := config.GetConnectionInfo(true) if err == nil && connectionInfo != nil { rdClient := client.NewRDClient(connectionInfo) - request, err := rdClient.DoRequest("PUT", client.VersionCommand("", "shutdown")) - output, _ = client.ProcessRequestForUtility(request, err) + command := client.VersionCommand("", "shutdown") + output, _ = client.ProcessRequestForUtility(rdClient.DoRequest("PUT", command)) logrus.WithError(err).Trace("Shut down requested") } err = shutdown.FinishShutdown(shutdownSettings.WaitForShutdown, initiatingCommand) diff --git a/src/go/rdctl/cmd/snapshotList_test.go b/src/go/rdctl/cmd/snapshotList_test.go index 1094cf1ed71..b4a098e1953 100644 --- a/src/go/rdctl/cmd/snapshotList_test.go +++ b/src/go/rdctl/cmd/snapshotList_test.go @@ -2,8 +2,9 @@ package cmd import ( "fmt" - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func TestTruncateToNewlineOrMaxRunes(t *testing.T) { diff --git a/src/go/rdctl/cmd/snapshotUnlock.go b/src/go/rdctl/cmd/snapshotUnlock.go index a88239442fd..1a2dbacf8e3 100644 --- a/src/go/rdctl/cmd/snapshotUnlock.go +++ b/src/go/rdctl/cmd/snapshotUnlock.go @@ -2,6 +2,7 @@ package cmd import ( "fmt" + "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/snapshot" "github.com/spf13/cobra" ) diff --git a/src/go/rdctl/cmd/start.go b/src/go/rdctl/cmd/start.go index 7a09ffb2fe5..799828c60c3 100644 --- a/src/go/rdctl/cmd/start.go +++ b/src/go/rdctl/cmd/start.go @@ -23,7 +23,7 @@ import ( "runtime" "strings" - "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/options/generated" + options "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/options/generated" "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/utils" "github.com/sirupsen/logrus" "github.com/spf13/cobra" diff --git a/src/go/rdctl/cmd/version.go b/src/go/rdctl/cmd/version.go index 4872c8377dd..e050be988fe 100644 --- a/src/go/rdctl/cmd/version.go +++ b/src/go/rdctl/cmd/version.go @@ -18,6 +18,7 @@ package cmd import ( "fmt" + "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/client" "github.com/spf13/cobra" ) diff --git a/src/go/rdctl/pkg/autostart/autostart_darwin.go b/src/go/rdctl/pkg/autostart/autostart_darwin.go index e686382a5f8..fd53182f43f 100644 --- a/src/go/rdctl/pkg/autostart/autostart_darwin.go +++ b/src/go/rdctl/pkg/autostart/autostart_darwin.go @@ -73,7 +73,6 @@ func EnsureAutostart(autostartDesired bool) error { return fmt.Errorf("failed to write LaunchAgent file: %w", err) } } - } else { err := os.RemoveAll(launchAgentFilePath) if err != nil { diff --git a/src/go/rdctl/pkg/autostart/autostart_linux.go b/src/go/rdctl/pkg/autostart/autostart_linux.go index a44fb8f0de0..73f09e3a0a1 100644 --- a/src/go/rdctl/pkg/autostart/autostart_linux.go +++ b/src/go/rdctl/pkg/autostart/autostart_linux.go @@ -51,7 +51,10 @@ func init() { } func EnsureAutostart(autostartDesired bool) error { - os.MkdirAll(autostartDirPath, 0755) + err := os.MkdirAll(autostartDirPath, 0755) + if err != nil { + return err + } if autostartDesired { currentContents, err := os.ReadFile(autostartFilePath) diff --git a/src/go/rdctl/pkg/client/client.go b/src/go/rdctl/pkg/client/client.go index f2bbaddfcf7..d2774c38c75 100644 --- a/src/go/rdctl/pkg/client/client.go +++ b/src/go/rdctl/pkg/client/client.go @@ -5,10 +5,11 @@ import ( "encoding/json" "errors" "fmt" - "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/config" "io" "net/http" "strings" + + "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/config" ) const ( diff --git a/src/go/rdctl/pkg/client/handle_unix.go b/src/go/rdctl/pkg/client/handle_unix.go index 3f6a6cc6af4..36ae30857bc 100644 --- a/src/go/rdctl/pkg/client/handle_unix.go +++ b/src/go/rdctl/pkg/client/handle_unix.go @@ -4,6 +4,7 @@ package client import ( "errors" + "golang.org/x/sys/unix" ) diff --git a/src/go/rdctl/pkg/client/handle_windows.go b/src/go/rdctl/pkg/client/handle_windows.go index bbe9ab21f98..b438ff960a4 100644 --- a/src/go/rdctl/pkg/client/handle_windows.go +++ b/src/go/rdctl/pkg/client/handle_windows.go @@ -2,6 +2,7 @@ package client import ( "errors" + "golang.org/x/sys/windows" ) diff --git a/src/go/rdctl/pkg/client/utils.go b/src/go/rdctl/pkg/client/utils.go index 3035b7412ab..09abf05ec14 100644 --- a/src/go/rdctl/pkg/client/utils.go +++ b/src/go/rdctl/pkg/client/utils.go @@ -48,6 +48,10 @@ func ProcessRequestForUtility(response *http.Response, err error) ([]byte, error if err := handleConnectionRefused(err); err != nil { return nil, err } + if response != nil && response.Body != nil { + defer response.Body.Close() + } + statusMessage := "" if response.StatusCode < 200 || response.StatusCode >= 300 { // Note that response.Status includes response.StatusCode @@ -55,7 +59,6 @@ func ProcessRequestForUtility(response *http.Response, err error) ([]byte, error case 400: statusMessage = response.Status // Prefer the error message in the body written by the command-server, not the one from the http server. - break case 401: return nil, fmt.Errorf("%s: user/password not accepted", response.Status) case 413: @@ -67,8 +70,6 @@ func ProcessRequestForUtility(response *http.Response, err error) ([]byte, error } } - defer response.Body.Close() - body, err := io.ReadAll(response.Body) if err != nil { if statusMessage != "" { diff --git a/src/go/rdctl/pkg/directories/directories_windows.go b/src/go/rdctl/pkg/directories/directories_windows.go index ba9fd79713e..ae4811c73b2 100644 --- a/src/go/rdctl/pkg/directories/directories_windows.go +++ b/src/go/rdctl/pkg/directories/directories_windows.go @@ -121,7 +121,7 @@ func getKnownFolder(folder *windows.KNOWNFOLDERID) (string, error) { ) // SHGetKnownFolderPath documentation says we _must_ free the result with // CoTaskMemFree, even if the call failed. - defer CoTaskMemFree.Call(result) + defer func() { _, _, _ = CoTaskMemFree.Call(result) }() if hr != 0 { return "", windows.Errno(hr) } diff --git a/src/go/rdctl/pkg/factoryreset/delete_data.go b/src/go/rdctl/pkg/factoryreset/delete_data.go index ba4429134e3..5a6f718f71f 100644 --- a/src/go/rdctl/pkg/factoryreset/delete_data.go +++ b/src/go/rdctl/pkg/factoryreset/delete_data.go @@ -22,213 +22,11 @@ import ( "fmt" "io/fs" "os" - "os/exec" "path" - "path/filepath" - "regexp" - "strings" dockerconfig "github.com/docker/cli/cli/config" - "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/directories" - "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/paths" - "github.com/sirupsen/logrus" ) -// appHomeDirectories() returns the path to the AppHome directory, -// if it can be deleted. There may be some subdirectories inside it -// that need to be preserved across a factory reset, so if any of -// those exist and are non-empty, then a list of all files/directories -// that don't match the exclusion list will be returned instead. -func appHomeDirectories(appPaths paths.Paths) []string { - // Use lowercase names for comparison in case the user created the subdirectory manually - // with the wrong case on a case-preserving filesystem (default on macOS). - excludeDir := map[string]string{ - strings.ToLower(appPaths.Snapshots): appPaths.Snapshots, - strings.ToLower(appPaths.ContainerdShims): appPaths.ContainerdShims, - } - haveExclusions := false - for _, dirname := range excludeDir { - files, err := os.ReadDir(dirname) - if err == nil && len(files) > 0 { - haveExclusions = true - break - } - } - if !haveExclusions { - return []string{appPaths.AppHome} - } - appHomeFiles, err := os.ReadDir(appPaths.AppHome) - if err != nil { - logrus.Errorf("failed to read contents of dir %s: %s", appPaths.AppHome, err) - return []string{} - } - pathList := make([]string, 0, len(appHomeFiles)) - for _, file := range appHomeFiles { - fullname := strings.ToLower(filepath.Join(appPaths.AppHome, file.Name())) - if _, ok := excludeDir[fullname]; !ok { - pathList = append(pathList, fullname) - } - } - return pathList -} - -// Most of the errors in this function are reported, but we continue to try to delete things, -// because there isn't really a dependency graph here. -// For example, if we can't delete the Lima VM, that doesn't mean we can't remove docker files -// or pull the path settings out of the shell profile files. -func deleteUnixLikeData(appPaths paths.Paths, pathList []string) error { - if err := deleteLimaVM(); err != nil { - logrus.Errorf("Error trying to delete the Lima VM: %s\n", err) - } - for _, currentPath := range pathList { - if err := os.RemoveAll(currentPath); err != nil { - logrus.Errorf("Error trying to remove %s: %s", currentPath, err) - } - } - if err := clearDockerContext(); err != nil { - logrus.Errorf("Error trying to clear the docker context %s", err) - } - if err := removeDockerCliPlugins(appPaths.AltAppHome); err != nil { - logrus.Errorf("Error trying to remove docker plugins %s", err) - } - - homeDir, err := os.UserHomeDir() - if err != nil { - // If we can't get home directory, none of the below code is valid - logrus.Errorf("Error trying to get home dir: %s", err) - return nil - } - rawPaths := []string{ - ".bashrc", - ".bash_profile", - ".bash_login", - ".profile", - ".zshrc", - ".cshrc", - ".tcshrc", - } - for i, s := range rawPaths { - rawPaths[i] = path.Join(homeDir, s) - } - rawPaths = append(rawPaths, path.Join(homeDir, ".config", "fish", "config.fish")) - - return removePathManagement(rawPaths) -} - -func deleteLimaVM() error { - appPaths, err := paths.GetPaths() - if err != nil { - return err - } - if err := directories.SetupLimaHome(appPaths.AppHome); err != nil { - return err - } - execPath, err := os.Executable() - if err != nil { - return err - } - execPath, err = filepath.EvalSymlinks(execPath) - if err != nil { - return err - } - limactl := path.Join(path.Dir(path.Dir(execPath)), "lima", "bin", "limactl") - return exec.Command(limactl, "delete", "-f", "0").Run() -} - -func removeDockerCliPlugins(altAppHomePath string) error { - cliPluginsDir := path.Join(dockerconfig.Dir(), "cli-plugins") - entries, err := os.ReadDir(cliPluginsDir) - if err != nil { - if errors.Is(err, fs.ErrNotExist) { - // Nothing left to do here, since there is no cli-plugins dir - return nil - } - return err - } - for _, entry := range entries { - if entry.Type()&os.ModeSymlink != os.ModeSymlink { - continue - } - fullPathName := path.Join(cliPluginsDir, entry.Name()) - target, err := os.Readlink(fullPathName) - if err != nil { - logrus.Errorf("Failed to follow the symbolic link for file %s: error: %s\n", fullPathName, err) - continue - } - if strings.HasPrefix(target, path.Join(altAppHomePath, "bin")+"/") { - os.Remove(fullPathName) - } - } - return nil -} - -func removePathManagement(dotFiles []string) error { - const startTarget = `### MANAGED BY RANCHER DESKTOP START \(DO NOT EDIT\)` - const endTarget = `### MANAGED BY RANCHER DESKTOP END \(DO NOT EDIT\)` - - // bash files etc. break if they contain \r's, so don't worry about them - ptn := regexp.MustCompile(fmt.Sprintf(`(?ms)^(?P.*?)(?P\n*)^%s.*?^%s\s*?$(?P\n*)(?P.*)$`, startTarget, endTarget)) - - for _, dotFile := range dotFiles { - byteContents, err := os.ReadFile(dotFile) - if err != nil { - if !errors.Is(err, fs.ErrNotExist) { - logrus.Errorf("Error trying to read %s: %s\n", dotFile, err) - } - continue - } - contents := string(byteContents) - parts := ptn.FindStringSubmatch(contents) - if len(parts) == 0 { - continue - } - - preMarkerTextIndex := ptn.SubexpIndex("preMarkerText") - preMarkerNewlineIndex := ptn.SubexpIndex("preMarkerNewlines") - postMarkerNewlineIndex := ptn.SubexpIndex("postMarkerNewlines") - postMarkerTextIndex := ptn.SubexpIndex("postMarkerText") - if len(parts[preMarkerTextIndex]) == 0 && len(parts[postMarkerTextIndex]) == 0 { - // Nothing of interest left in this file, so delete it - err = os.RemoveAll(dotFile) - if err != nil { - // but continue processing the other files - logrus.Errorf("Failed to delete file %s (error %s)\n", dotFile, err) - } - continue - } - - newParts := []string{parts[preMarkerTextIndex]} - - preMarkerNewlines := parts[preMarkerNewlineIndex] - postMarkerNewlines := parts[postMarkerNewlineIndex] - if len(preMarkerNewlines) == 1 { - newParts = append(newParts, preMarkerNewlines) - } else if len(preMarkerNewlines) > 1 { - // One of the newlines was inserted by the dotfile manager, but keep the others - newParts = append(newParts, preMarkerNewlines[1:]) - } - if len(parts[postMarkerTextIndex]) > 0 { - if len(postMarkerNewlines) > 1 { - // Either there was a newline before the marker block, and we have copied - // it into the new file, - // or the marker block was at the start of the file, in which case we can - // drop one of the post-marker block newlines - newParts = append(newParts, postMarkerNewlines[1:]) - } - newParts = append(newParts, parts[postMarkerTextIndex]) - } - newContents := strings.Join(newParts, "") - filestat, err := os.Stat(dotFile) - if err != nil { - return fmt.Errorf("error trying to stat %q: %w", dotFile, err) - } - if err = os.WriteFile(dotFile, []byte(newContents), filestat.Mode()); err != nil { - logrus.Errorf("error trying to update %s: %s\n", dotFile, err) - } - } - return nil -} - type dockerConfigType map[string]interface{} type PartialMeta struct { diff --git a/src/go/rdctl/pkg/factoryreset/delete_data_unix.go b/src/go/rdctl/pkg/factoryreset/delete_data_unix.go new file mode 100644 index 00000000000..fe82d7b8474 --- /dev/null +++ b/src/go/rdctl/pkg/factoryreset/delete_data_unix.go @@ -0,0 +1,231 @@ +//go:build unix + +/* +Copyright © 2022 SUSE LLC + +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 factoryreset + +import ( + "errors" + "fmt" + "io/fs" + "os" + "os/exec" + "path" + "path/filepath" + "regexp" + "strings" + + dockerconfig "github.com/docker/cli/cli/config" + "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/directories" + "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/paths" + "github.com/sirupsen/logrus" +) + +// appHomeDirectories() returns the path to the AppHome directory, +// if it can be deleted. There may be some subdirectories inside it +// that need to be preserved across a factory reset, so if any of +// those exist and are non-empty, then a list of all files/directories +// that don't match the exclusion list will be returned instead. +func appHomeDirectories(appPaths paths.Paths) []string { + // Use lowercase names for comparison in case the user created the subdirectory manually + // with the wrong case on a case-preserving filesystem (default on macOS). + excludeDir := map[string]string{ + strings.ToLower(appPaths.Snapshots): appPaths.Snapshots, + strings.ToLower(appPaths.ContainerdShims): appPaths.ContainerdShims, + } + haveExclusions := false + for _, dirname := range excludeDir { + files, err := os.ReadDir(dirname) + if err == nil && len(files) > 0 { + haveExclusions = true + break + } + } + if !haveExclusions { + return []string{appPaths.AppHome} + } + appHomeFiles, err := os.ReadDir(appPaths.AppHome) + if err != nil { + logrus.Errorf("failed to read contents of dir %s: %s", appPaths.AppHome, err) + return []string{} + } + pathList := make([]string, 0, len(appHomeFiles)) + for _, file := range appHomeFiles { + fullname := strings.ToLower(filepath.Join(appPaths.AppHome, file.Name())) + if _, ok := excludeDir[fullname]; !ok { + pathList = append(pathList, fullname) + } + } + return pathList +} + +// Most of the errors in this function are reported, but we continue to try to delete things, +// because there isn't really a dependency graph here. +// For example, if we can't delete the Lima VM, that doesn't mean we can't remove docker files +// or pull the path settings out of the shell profile files. +func deleteUnixLikeData(appPaths paths.Paths, pathList []string) error { + if err := deleteLimaVM(); err != nil { + logrus.Errorf("Error trying to delete the Lima VM: %s\n", err) + } + for _, currentPath := range pathList { + if err := os.RemoveAll(currentPath); err != nil { + logrus.Errorf("Error trying to remove %s: %s", currentPath, err) + } + } + if err := clearDockerContext(); err != nil { + logrus.Errorf("Error trying to clear the docker context %s", err) + } + if err := removeDockerCliPlugins(appPaths.AltAppHome); err != nil { + logrus.Errorf("Error trying to remove docker plugins %s", err) + } + + homeDir, err := os.UserHomeDir() + if err != nil { + // If we can't get home directory, none of the below code is valid + logrus.Errorf("Error trying to get home dir: %s", err) + return nil + } + rawPaths := []string{ + ".bashrc", + ".bash_profile", + ".bash_login", + ".profile", + ".zshrc", + ".cshrc", + ".tcshrc", + } + for i, s := range rawPaths { + rawPaths[i] = path.Join(homeDir, s) + } + rawPaths = append(rawPaths, path.Join(homeDir, ".config", "fish", "config.fish")) + + return removePathManagement(rawPaths) +} + +func deleteLimaVM() error { + appPaths, err := paths.GetPaths() + if err != nil { + return err + } + if err := directories.SetupLimaHome(appPaths.AppHome); err != nil { + return err + } + execPath, err := os.Executable() + if err != nil { + return err + } + execPath, err = filepath.EvalSymlinks(execPath) + if err != nil { + return err + } + limactl := path.Join(path.Dir(path.Dir(execPath)), "lima", "bin", "limactl") + return exec.Command(limactl, "delete", "-f", "0").Run() +} + +func removeDockerCliPlugins(altAppHomePath string) error { + cliPluginsDir := path.Join(dockerconfig.Dir(), "cli-plugins") + entries, err := os.ReadDir(cliPluginsDir) + if err != nil { + if errors.Is(err, fs.ErrNotExist) { + // Nothing left to do here, since there is no cli-plugins dir + return nil + } + return err + } + for _, entry := range entries { + if entry.Type()&os.ModeSymlink != os.ModeSymlink { + continue + } + fullPathName := path.Join(cliPluginsDir, entry.Name()) + target, err := os.Readlink(fullPathName) + if err != nil { + logrus.Errorf("Failed to follow the symbolic link for file %s: error: %s\n", fullPathName, err) + continue + } + if strings.HasPrefix(target, path.Join(altAppHomePath, "bin")+"/") { + os.Remove(fullPathName) + } + } + return nil +} + +func removePathManagement(dotFiles []string) error { + const startTarget = `### MANAGED BY RANCHER DESKTOP START \(DO NOT EDIT\)` + const endTarget = `### MANAGED BY RANCHER DESKTOP END \(DO NOT EDIT\)` + + // bash files etc. break if they contain \r's, so don't worry about them + ptn := regexp.MustCompile(fmt.Sprintf(`(?ms)^(?P.*?)(?P\n*)^%s.*?^%s\s*?$(?P\n*)(?P.*)$`, startTarget, endTarget)) + + for _, dotFile := range dotFiles { + byteContents, err := os.ReadFile(dotFile) + if err != nil { + if !errors.Is(err, fs.ErrNotExist) { + logrus.Errorf("Error trying to read %s: %s\n", dotFile, err) + } + continue + } + contents := string(byteContents) + parts := ptn.FindStringSubmatch(contents) + if len(parts) == 0 { + continue + } + + preMarkerTextIndex := ptn.SubexpIndex("preMarkerText") + preMarkerNewlineIndex := ptn.SubexpIndex("preMarkerNewlines") + postMarkerNewlineIndex := ptn.SubexpIndex("postMarkerNewlines") + postMarkerTextIndex := ptn.SubexpIndex("postMarkerText") + if len(parts[preMarkerTextIndex]) == 0 && len(parts[postMarkerTextIndex]) == 0 { + // Nothing of interest left in this file, so delete it + err = os.RemoveAll(dotFile) + if err != nil { + // but continue processing the other files + logrus.Errorf("Failed to delete file %s (error %s)\n", dotFile, err) + } + continue + } + + newParts := []string{parts[preMarkerTextIndex]} + + preMarkerNewlines := parts[preMarkerNewlineIndex] + postMarkerNewlines := parts[postMarkerNewlineIndex] + if len(preMarkerNewlines) == 1 { + newParts = append(newParts, preMarkerNewlines) + } else if len(preMarkerNewlines) > 1 { + // One of the newlines was inserted by the dotfile manager, but keep the others + newParts = append(newParts, preMarkerNewlines[1:]) + } + if len(parts[postMarkerTextIndex]) > 0 { + if len(postMarkerNewlines) > 1 { + // Either there was a newline before the marker block, and we have copied + // it into the new file, + // or the marker block was at the start of the file, in which case we can + // drop one of the post-marker block newlines + newParts = append(newParts, postMarkerNewlines[1:]) + } + newParts = append(newParts, parts[postMarkerTextIndex]) + } + newContents := strings.Join(newParts, "") + filestat, err := os.Stat(dotFile) + if err != nil { + return fmt.Errorf("error trying to stat %q: %w", dotFile, err) + } + if err = os.WriteFile(dotFile, []byte(newContents), filestat.Mode()); err != nil { + logrus.Errorf("error trying to update %s: %s\n", dotFile, err) + } + } + return nil +} diff --git a/src/go/rdctl/pkg/factoryreset/delete_data_test.go b/src/go/rdctl/pkg/factoryreset/delete_data_unix_test.go similarity index 99% rename from src/go/rdctl/pkg/factoryreset/delete_data_test.go rename to src/go/rdctl/pkg/factoryreset/delete_data_unix_test.go index b2574aaae61..d07c2b251b2 100644 --- a/src/go/rdctl/pkg/factoryreset/delete_data_test.go +++ b/src/go/rdctl/pkg/factoryreset/delete_data_unix_test.go @@ -1,5 +1,5 @@ //go:test !windows -// +test !windows +//go:build !windows /* Copyright © 2022 SUSE LLC diff --git a/src/go/rdctl/pkg/factoryreset/empty.go b/src/go/rdctl/pkg/factoryreset/factory_reset_unix.go similarity index 76% rename from src/go/rdctl/pkg/factoryreset/empty.go rename to src/go/rdctl/pkg/factoryreset/factory_reset_unix.go index 8a6e15cae31..f381c22cf34 100644 --- a/src/go/rdctl/pkg/factoryreset/empty.go +++ b/src/go/rdctl/pkg/factoryreset/factory_reset_unix.go @@ -1,4 +1,4 @@ -//go:build !windows +//go:build unix /* Copyright © 2022 SUSE LLC @@ -27,11 +27,3 @@ func CheckProcessWindows() (bool, error) { func KillRancherDesktop() error { return fmt.Errorf("internal error: KillRancherDesktop shouldn't be called") } - -func deleteWindowsData(_ bool, _ string) error { - return fmt.Errorf("internal error: deleteWindowsData shouldn't be called") -} - -func unregisterWSL() error { - return fmt.Errorf("internal error: unregisterWSL shouldn't be called") -} diff --git a/src/go/rdctl/pkg/factoryreset/factory_reset_windows.go b/src/go/rdctl/pkg/factoryreset/factory_reset_windows.go index 1ed59c78a27..37a8ea55214 100644 --- a/src/go/rdctl/pkg/factoryreset/factory_reset_windows.go +++ b/src/go/rdctl/pkg/factoryreset/factory_reset_windows.go @@ -70,7 +70,6 @@ func CheckProcessWindows() (bool, error) { // KillRancherDesktop terminates all processes where the executable is from the // Rancher Desktop application, excluding the current process. func KillRancherDesktop() error { - err := stopPrivilegedService() if err != nil { return fmt.Errorf("failed to stop privileged service: %w", err) @@ -128,7 +127,7 @@ func KillRancherDesktop() error { logrus.Tracef("failed to open pid %d: %s (skipping)", pid, err) return } - defer windows.CloseHandle(hProc) + defer func() { _ = windows.CloseHandle(hProc) }() var imageName string err = directories.InvokeWin32WithBuffer(func(size int) error { @@ -175,7 +174,7 @@ func KillRancherDesktop() error { logrus.Infof("failed to open process %d for termination, skipping", pid) return } - defer windows.CloseHandle(hProc) + defer func() { _ = windows.CloseHandle(hProc) }() if err = windows.TerminateProcess(hProc, 0); err != nil { logrus.Infof("failed to terminate process %d: %s", pid, err) diff --git a/src/go/rdctl/pkg/lock/lock.go b/src/go/rdctl/pkg/lock/lock.go index 8ed23733afb..b554b98fdf6 100644 --- a/src/go/rdctl/pkg/lock/lock.go +++ b/src/go/rdctl/pkg/lock/lock.go @@ -4,12 +4,13 @@ import ( "encoding/json" "errors" "fmt" - "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/client" - "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/config" - "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/paths" "os" "path/filepath" "time" + + "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/client" + "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/config" + "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/paths" ) const backendLockName = "backend.lock" diff --git a/src/go/rdctl/pkg/paths/paths.go b/src/go/rdctl/pkg/paths/paths.go index 6b0d8c7012a..4fd7389cba9 100644 --- a/src/go/rdctl/pkg/paths/paths.go +++ b/src/go/rdctl/pkg/paths/paths.go @@ -2,9 +2,10 @@ package paths import ( "fmt" - "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/utils" "os" "path/filepath" + + "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/utils" ) const appName = "rancher-desktop" diff --git a/src/go/rdctl/pkg/plist/plist_test.go b/src/go/rdctl/pkg/plist/plist_test.go index e80eff89627..a8630732f98 100644 --- a/src/go/rdctl/pkg/plist/plist_test.go +++ b/src/go/rdctl/pkg/plist/plist_test.go @@ -1,8 +1,9 @@ package plist import ( - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func TestJsonToPlistFormat(t *testing.T) { @@ -408,5 +409,4 @@ func TestJsonToPlistFormat(t *testing.T) { `, s) }) - } diff --git a/src/go/rdctl/pkg/reg/reg.go b/src/go/rdctl/pkg/reg/reg.go index 26d7353e2a5..fb595f19bf7 100644 --- a/src/go/rdctl/pkg/reg/reg.go +++ b/src/go/rdctl/pkg/reg/reg.go @@ -10,11 +10,12 @@ package reg import ( "encoding/json" "fmt" - options "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/options/generated" - "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/utils" "reflect" "strings" "unicode/utf16" + + options "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/options/generated" + "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/utils" ) const HkcuRegistryHive = "hkcu" diff --git a/src/go/rdctl/pkg/reg/reg_test.go b/src/go/rdctl/pkg/reg/reg_test.go index 552650263cd..012c53b53f1 100644 --- a/src/go/rdctl/pkg/reg/reg_test.go +++ b/src/go/rdctl/pkg/reg/reg_test.go @@ -2,13 +2,17 @@ package reg import ( "fmt" - "github.com/stretchr/testify/assert" "sort" "testing" + + "github.com/stretchr/testify/assert" ) -func TestJsonToRegFormat(t *testing.T) { +const ( + DefaultsHeader = "HKEY_CURRENT_USER\\SOFTWARE\\Policies\\Rancher Desktop\\defaults" +) +func TestJsonToRegFormat(t *testing.T) { t.Run("complains about bad arguments", func(t *testing.T) { type errorTestCases struct { hiveType string @@ -47,9 +51,8 @@ func TestJsonToRegFormat(t *testing.T) { t.Run("handles empty bodies", func(t *testing.T) { lines, err := JsonToReg("hkcu", "defaults", "{}") assert.NoError(t, err) - header := "HKEY_CURRENT_USER\\SOFTWARE\\Policies\\Rancher Desktop\\defaults" assert.NoError(t, err) - assert.Equal(t, fmt.Sprintf("[%s]", header), lines[3]) + assert.Equal(t, fmt.Sprintf("[%s]", DefaultsHeader), lines[3]) assert.Equal(t, 5, len(lines)) assert.Equal(t, "Windows Registry Editor Version 5.00", lines[0]) assert.Equal(t, "[HKEY_CURRENT_USER\\SOFTWARE\\Policies]", lines[1]) @@ -67,7 +70,7 @@ func TestJsonToRegFormat(t *testing.T) { { hiveType: "hkcu", profileType: "defaults", - expectedHeader: "HKEY_CURRENT_USER\\SOFTWARE\\Policies\\Rancher Desktop\\defaults", + expectedHeader: DefaultsHeader, }, { hiveType: "hklm", diff --git a/src/go/rdctl/pkg/snapshot/manager_test.go b/src/go/rdctl/pkg/snapshot/manager_test.go index 7d21a208456..5fd236669f4 100644 --- a/src/go/rdctl/pkg/snapshot/manager_test.go +++ b/src/go/rdctl/pkg/snapshot/manager_test.go @@ -19,7 +19,6 @@ type TestFile struct { } func TestManager(t *testing.T) { - t.Run("ValidateName should disallow two snapshots with the same name, but only when the first is complete", func(t *testing.T) { paths, _ := populateFiles(t, true) manager := newTestManager(paths) @@ -187,7 +186,7 @@ func TestManager(t *testing.T) { t.Run("Delete", func(t *testing.T) { paths, _ := populateFiles(t, true) manager := newTestManager(paths) - snapshot, err := manager.Create(context.Background(), "test-snapshot", "") + snapshot, err := manager.Create(context.Background(), "test-snapshot-delete", "") if err != nil { t.Fatalf("failed to create snapshot: %s", err) } @@ -221,7 +220,7 @@ func TestManager(t *testing.T) { t.Run("Restore should return the proper error if asked to restore from an incomplete snapshot", func(t *testing.T) { paths, _ := populateFiles(t, true) manager := newTestManager(paths) - snapshot, err := manager.Create(context.Background(), "test-snapshot", "") + snapshot, err := manager.Create(context.Background(), "test-snapshot-restore-incomplete", "") if err != nil { t.Fatalf("failed to create snapshot: %s", err) } @@ -237,7 +236,7 @@ func TestManager(t *testing.T) { t.Run("Restore should return proper error and not run RestoreFiles when context is already cancelled", func(t *testing.T) { paths, _ := populateFiles(t, true) manager := newTestManager(paths) - snapshotName := "test-snapshot" + snapshotName := "test-snapshot-restore-cancelled" _, err := manager.Create(context.Background(), snapshotName, "") if err != nil { t.Fatalf("failed to create snapshot: %s", err) @@ -252,7 +251,7 @@ func TestManager(t *testing.T) { t.Run("Restore should return data reset error when RestoreFiles encounters an error and resets data", func(t *testing.T) { paths, _ := populateFiles(t, true) manager := newTestManager(paths) - snapshotName := "test-snapshot" + snapshotName := "test-snapshot-error" snapshot, err := manager.Create(context.Background(), snapshotName, "") if err != nil { t.Fatalf("failed to create snapshot: %s", err) diff --git a/src/go/rdctl/pkg/snapshot/manager_unix_test.go b/src/go/rdctl/pkg/snapshot/manager_unix_test.go index c53e5815963..fc74eea5c15 100644 --- a/src/go/rdctl/pkg/snapshot/manager_unix_test.go +++ b/src/go/rdctl/pkg/snapshot/manager_unix_test.go @@ -6,11 +6,12 @@ import ( "context" "errors" "fmt" - "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/lock" - "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/paths" "os" "path/filepath" "testing" + + "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/lock" + "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/paths" ) func populateFiles(t *testing.T, includeOverrideYaml bool) (paths.Paths, map[string]TestFile) { diff --git a/src/go/rdctl/pkg/snapshot/snapshotter.go b/src/go/rdctl/pkg/snapshot/snapshotter.go index f86c47309cc..e0a22f18849 100644 --- a/src/go/rdctl/pkg/snapshot/snapshotter.go +++ b/src/go/rdctl/pkg/snapshot/snapshotter.go @@ -3,6 +3,7 @@ package snapshot import ( "context" "errors" + "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/paths" ) diff --git a/src/go/rdctl/pkg/utils/utils_unix.go b/src/go/rdctl/pkg/utils/utils_unix.go index 47627d83eea..bde5713f2d6 100644 --- a/src/go/rdctl/pkg/utils/utils_unix.go +++ b/src/go/rdctl/pkg/utils/utils_unix.go @@ -5,9 +5,10 @@ package utils import ( "errors" "fmt" - "golang.org/x/sys/unix" "io/fs" "os" + + "golang.org/x/sys/unix" ) // Verify that the candidatePath is usable as a Rancher Desktop "executable". This means: