diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 0186d57f4f3..3c6fae75f2b 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -201,7 +201,6 @@ dports dri DSL Duex -dupl dword eagerzeroedthick eastus @@ -274,8 +273,6 @@ globalrole globalrolebinding Gluster gname -gocritic -gocyclo gofmt goland golangci @@ -731,8 +728,6 @@ storybookjs strem stretchr stringifying -structcheck -stylecheck subshells subvar sumologic diff --git a/.github/workflows/config/.golangci.yaml b/.github/workflows/config/.golangci.yaml index 5d4486acb51..b2fa1959f99 100644 --- a/.github/workflows/config/.golangci.yaml +++ b/.github/workflows/config/.golangci.yaml @@ -1,8 +1,4 @@ linters-settings: - dogsled: - # syscall.Syscall() has three return values, and we often don't care about - # the results, especially on Windows. - max-blank-identifiers: 3 dupl: threshold: 100 funlen: @@ -40,8 +36,6 @@ linters-settings: - '3' ignored-functions: - strings.SplitN - - os.FileMode # file permissions - - os.MkdirAll # file permissions lll: line-length: 140 @@ -57,6 +51,7 @@ linters: disable-all: true enable: - bodyclose + - deadcode - dogsled - dupl - errcheck @@ -111,7 +106,6 @@ issues: exclude-rules: - path: _test\.go linters: - - dupl # Ignore code duplication in tests + - gosec - errcheck - gocritic - - gosec diff --git a/.github/workflows/wsl-helper-build.yaml b/.github/workflows/wsl-helper-build.yaml index 187508a9d72..1d99766ce7e 100644 --- a/.github/workflows/wsl-helper-build.yaml +++ b/.github/workflows/wsl-helper-build.yaml @@ -1,10 +1,11 @@ -name: 'Lint: WSL-Helper' +# This workflow builds the WSL Helper +name: 'GitHub Runner: WSL Helper' on: - push: - paths: [ src/go/wsl-helper/** ] - pull_request: - paths: [ src/go/wsl-helper/** ] + #push: + # paths: [ src/go/wsl-helper/** ] + #pull_request: + # paths: [ src/go/wsl-helper/** ] workflow_dispatch: permissions: @@ -39,6 +40,11 @@ jobs: env: GOOS: linux CGO_ENABLED: '0' + - uses: actions/upload-artifact@v3 + with: + name: wsl-helper-linux + path: src/go/wsl-helper/wsl-helper + if-no-files-found: error - uses: golangci/golangci-lint-action@v3.7.0 # This is only safe because this workflow does not allow writing with: diff --git a/src/go/wsl-helper/cmd/certificates_windows.go b/src/go/wsl-helper/cmd/certificates_windows.go index d65501aaa0a..9aded44513f 100644 --- a/src/go/wsl-helper/cmd/certificates_windows.go +++ b/src/go/wsl-helper/cmd/certificates_windows.go @@ -64,6 +64,6 @@ var certificatesCmd = &cobra.Command{ func init() { certificatesCmd.Flags().StringSlice("stores", []string{"CA", "ROOT"}, "Certificate stores to enumerate") certificatesViper.AutomaticEnv() - _ = certificatesViper.BindPFlags(certificatesCmd.Flags()) + certificatesViper.BindPFlags(certificatesCmd.Flags()) rootCmd.AddCommand(certificatesCmd) } diff --git a/src/go/wsl-helper/cmd/dockerproxy_kill_linux.go b/src/go/wsl-helper/cmd/dockerproxy_kill_linux.go index 6c29f1e515a..219b22a65ab 100644 --- a/src/go/wsl-helper/cmd/dockerproxy_kill_linux.go +++ b/src/go/wsl-helper/cmd/dockerproxy_kill_linux.go @@ -43,6 +43,6 @@ var dockerproxyKillCmd = &cobra.Command{ func init() { dockerproxyKillViper.AutomaticEnv() - _ = dockerproxyKillViper.BindPFlags(dockerproxyKillCmd.Flags()) + dockerproxyKillViper.BindPFlags(dockerproxyKillCmd.Flags()) dockerproxyCmd.AddCommand(dockerproxyKillCmd) } diff --git a/src/go/wsl-helper/cmd/dockerproxy_serve_linux.go b/src/go/wsl-helper/cmd/dockerproxy_serve_linux.go index 0f203417598..455e30db546 100644 --- a/src/go/wsl-helper/cmd/dockerproxy_serve_linux.go +++ b/src/go/wsl-helper/cmd/dockerproxy_serve_linux.go @@ -64,6 +64,6 @@ func init() { dockerproxyServeCmd.Flags().String("endpoint", platform.DefaultEndpoint, "Endpoint to listen on") dockerproxyServeCmd.Flags().String("proxy-endpoint", defaultProxyEndpoint, "Endpoint dockerd is listening on") dockerproxyServeViper.AutomaticEnv() - _ = dockerproxyServeViper.BindPFlags(dockerproxyServeCmd.Flags()) + dockerproxyServeViper.BindPFlags(dockerproxyServeCmd.Flags()) dockerproxyCmd.AddCommand(dockerproxyServeCmd) } diff --git a/src/go/wsl-helper/cmd/dockerproxy_serve_windows.go b/src/go/wsl-helper/cmd/dockerproxy_serve_windows.go index f1e640143c6..75582e77519 100644 --- a/src/go/wsl-helper/cmd/dockerproxy_serve_windows.go +++ b/src/go/wsl-helper/cmd/dockerproxy_serve_windows.go @@ -54,6 +54,6 @@ func init() { dockerproxyServeCmd.Flags().String("endpoint", platform.DefaultEndpoint, "Endpoint to listen on") dockerproxyServeCmd.Flags().Uint32("port", dockerproxy.DefaultPort, "Vsock port docker is listening on") dockerproxyServeViper.AutomaticEnv() - _ = dockerproxyServeViper.BindPFlags(dockerproxyServeCmd.Flags()) + dockerproxyServeViper.BindPFlags(dockerproxyServeCmd.Flags()) dockerproxyCmd.AddCommand(dockerproxyServeCmd) } diff --git a/src/go/wsl-helper/cmd/dockerproxy_start.go b/src/go/wsl-helper/cmd/dockerproxy_start.go index 56bb5230ad3..53bfd643572 100644 --- a/src/go/wsl-helper/cmd/dockerproxy_start.go +++ b/src/go/wsl-helper/cmd/dockerproxy_start.go @@ -49,6 +49,6 @@ func init() { dockerproxyStartCmd.Flags().Uint32("port", dockerproxy.DefaultPort, "Vsock port to listen on") dockerproxyStartCmd.Flags().String("endpoint", defaultProxyEndpoint, "Dockerd socket endpoint") dockerproxyStartViper.AutomaticEnv() - _ = dockerproxyStartViper.BindPFlags(dockerproxyStartCmd.Flags()) + dockerproxyStartViper.BindPFlags(dockerproxyStartCmd.Flags()) dockerproxyCmd.AddCommand(dockerproxyStartCmd) } diff --git a/src/go/wsl-helper/cmd/k3s_kubeconfig.go b/src/go/wsl-helper/cmd/k3s_kubeconfig.go index 0e74fb4e2bb..d21b9762aaf 100644 --- a/src/go/wsl-helper/cmd/k3s_kubeconfig.go +++ b/src/go/wsl-helper/cmd/k3s_kubeconfig.go @@ -32,16 +32,15 @@ import ( "gopkg.in/yaml.v3" ) -type kubeConfigCluster struct { - Cluster struct { - Server string - Extras map[string]interface{} `yaml:",inline"` - } `yaml:"cluster"` - Name string `yaml:"name"` - Extras map[string]interface{} `yaml:",inline"` -} type kubeConfig struct { - Clusters []kubeConfigCluster `yaml:"clusters"` + Clusters []struct { + Cluster struct { + Server string + Extras map[string]interface{} `yaml:",inline"` + } `yaml:"cluster"` + Name string `yaml:"name"` + Extras map[string]interface{} `yaml:",inline"` + } `yaml:"clusters"` Contexts []struct { Name string `yaml:"name"` Extras map[string]interface{} `yaml:",inline"` @@ -54,11 +53,6 @@ type kubeConfig struct { Extras map[string]interface{} `yaml:",inline"` } -const ( - // kubeconfigExistTimeout is the time we wait for kubeconfig to appear. - kubeconfigExistTimeout = 10 * time.Second -) - var ( k3sKubeconfigViper = viper.New() rdNetworking bool @@ -87,11 +81,11 @@ var k3sKubeconfigCmd = &cobra.Command{ } }() var err error - timeout := time.After(kubeconfigExistTimeout) + timeout := time.After(10 * time.Second) var configFile *os.File select { case <-timeout: - return fmt.Errorf("timed out waiting for k3s kubeconfig to exist") + return fmt.Errorf("Timed out waiting for k3s kubeconfig to exist") case configFile = <-ch: break } @@ -178,6 +172,6 @@ func init() { k3sKubeconfigCmd.Flags().String("k3sconfig", "/etc/rancher/k3s/k3s.yaml", "Path to k3s kubeconfig") k3sKubeconfigCmd.Flags().BoolVar(&rdNetworking, "rd-networking", false, "Enable the experimental Rancher Desktop Networking") k3sKubeconfigViper.AutomaticEnv() - _ = k3sKubeconfigViper.BindPFlags(k3sKubeconfigCmd.Flags()) + k3sKubeconfigViper.BindPFlags(k3sKubeconfigCmd.Flags()) k3sCmd.AddCommand(k3sKubeconfigCmd) } diff --git a/src/go/wsl-helper/cmd/kill_process_windows.go b/src/go/wsl-helper/cmd/kill_process_windows.go index 7668e28fabc..294a0a4bd20 100644 --- a/src/go/wsl-helper/cmd/kill_process_windows.go +++ b/src/go/wsl-helper/cmd/kill_process_windows.go @@ -37,6 +37,6 @@ var killProcessCmd = &cobra.Command{ func init() { killProcessCmd.Flags().Int("pid", 0, "PID of process to kill") killProcessViper.AutomaticEnv() - _ = killProcessViper.BindPFlags(killProcessCmd.Flags()) + killProcessViper.BindPFlags(killProcessCmd.Flags()) rootCmd.AddCommand(killProcessCmd) } diff --git a/src/go/wsl-helper/cmd/kubeconfig.go b/src/go/wsl-helper/cmd/kubeconfig.go index aa87bfd1d4f..4b6a63c6f35 100644 --- a/src/go/wsl-helper/cmd/kubeconfig.go +++ b/src/go/wsl-helper/cmd/kubeconfig.go @@ -54,7 +54,6 @@ var kubeconfigCmd = &cobra.Command{ if winConfigPath == "" { //lint:ignore ST1005 The capitalization is for a proper noun. - //nolint:stylecheck // The capitalization is for a proper noun. return errors.New("Windows kubeconfig not supplied") } @@ -87,9 +86,9 @@ var kubeconfigCmd = &cobra.Command{ return err } - cleanConfig := removeExistingRDConfig(rdCluster, linuxConfig) + cleanConfig := removeExistingRDConfig(rdCluster, &linuxConfig) - kubeConfig, err := updateKubeConfig(winConfig, cleanConfig, rdNetworking) + kubeConfig, err := updateKubeConfig(winConfig, *cleanConfig, rdNetworking) if err != nil { return fmt.Errorf("failed to construct kubeconfig: %w", err) } @@ -111,32 +110,29 @@ var kubeconfigCmd = &cobra.Command{ }, } -func readKubeConfig(configPath string) (*kubeConfig, error) { +func readKubeConfig(configPath string) (kubeConfig, error) { var config kubeConfig configFile, err := os.Open(configPath) if err != nil { - return nil, fmt.Errorf("could not open kubeconfig file %s: %w", configPath, err) + return config, fmt.Errorf("could not open kubeconfig file %s: %w", configPath, err) } defer configFile.Close() err = yaml.NewDecoder(configFile).Decode(&config) if err != nil { - return nil, fmt.Errorf("could not read kubeconfig %s: %w", configPath, err) + return config, fmt.Errorf("could not read kubeconfig %s: %w", configPath, err) } - return &config, nil + return config, nil } -// updateKubeConfig updates the Linux-side kubeconfig with the rancher-desktop -// cluster read from Windows (ignoring all other clusters from the Windows side). -// While doing so, it ensures that the server address will be correct. -// It updates the Linux kubeconfig in-place and returns it. -func updateKubeConfig(winConfig, linuxConfig *kubeConfig, rdNetworking bool) (*kubeConfig, error) { - // We act on a copy of the Windows config to avoid mutating it. - winConfigCopy := *winConfig - winConfigCopy.Clusters = append([]kubeConfigCluster{}, winConfig.Clusters...) +// updateKubeConfig reads the kube config from windows side it also +// modifies the cluster's server host to an appropriate address. +// It then merges the config with an existing configuration on +// users distro and returns the merged config. +func updateKubeConfig(winConfig, linuxConfig kubeConfig, rdNetworking bool) (kubeConfig, error) { for clusterIdx, cluster := range winConfig.Clusters { // Ignore any non rancher-desktop clusters - if winConfigCopy.Clusters[clusterIdx].Name != rdCluster { + if winConfig.Clusters[clusterIdx].Name != rdCluster { continue } server, err := url.Parse(cluster.Cluster.Server) @@ -148,7 +144,7 @@ func updateKubeConfig(winConfig, linuxConfig *kubeConfig, rdNetworking bool) (*k if !rdNetworking { ip, err := getClusterIP() if err != nil { - return nil, err + return winConfig, err } host = ip.String() @@ -157,16 +153,21 @@ func updateKubeConfig(winConfig, linuxConfig *kubeConfig, rdNetworking bool) (*k host = net.JoinHostPort(host, server.Port()) } server.Host = host - winConfigCopy.Clusters[clusterIdx].Cluster.Server = server.String() + winConfig.Clusters[clusterIdx].Cluster.Server = server.String() } - return mergeKubeConfigs(&winConfigCopy, linuxConfig), nil + return mergeKubeConfigs(winConfig, linuxConfig), nil } -// removeExistingRDConfig removes the rancher-desktop configuration from the -// passed in kubeconfig in-place, and returns the modified input. func removeExistingRDConfig(name string, config *kubeConfig) *kubeConfig { // Remove clusters with the specified name - var filteredClusters []kubeConfigCluster + var filteredClusters []struct { + Cluster struct { + Server string + Extras map[string]interface{} `yaml:",inline"` + } `yaml:"cluster"` + Name string `yaml:"name"` + Extras map[string]interface{} `yaml:",inline"` + } for _, cluster := range config.Clusters { if cluster.Name != name { filteredClusters = append(filteredClusters, cluster) @@ -201,10 +202,7 @@ func removeExistingRDConfig(name string, config *kubeConfig) *kubeConfig { return config } -// mergeKubeConfig updates the Linux kubeconfig with the Rancher Desktop -// cluster configuration read from the Windows kubeconfig, returning the -// Linux kubeconfig that has been updated in-place. -func mergeKubeConfigs(winConfig, linuxConfig *kubeConfig) *kubeConfig { +func mergeKubeConfigs(winConfig, linuxConfig kubeConfig) kubeConfig { for _, ctx := range winConfig.Clusters { if ctx.Name == rdCluster { linuxConfig.Clusters = append(linuxConfig.Clusters, ctx) @@ -230,6 +228,6 @@ func init() { kubeconfigCmd.PersistentFlags().String("kubeconfig", "", "Path to Windows kubeconfig, in /mnt/... form.") kubeconfigCmd.Flags().BoolVar(&rdNetworking, "rd-networking", false, "Enable the experimental Rancher Desktop Networking") kubeconfigViper.AutomaticEnv() - _ = kubeconfigViper.BindPFlags(kubeconfigCmd.PersistentFlags()) + kubeconfigViper.BindPFlags(kubeconfigCmd.PersistentFlags()) rootCmd.AddCommand(kubeconfigCmd) } diff --git a/src/go/wsl-helper/cmd/wsl_integration_docker_plugin_linux.go b/src/go/wsl-helper/cmd/wsl_integration_docker_plugin_linux.go index 9bc546db69f..e8197ee7746 100644 --- a/src/go/wsl-helper/cmd/wsl_integration_docker_plugin_linux.go +++ b/src/go/wsl-helper/cmd/wsl_integration_docker_plugin_linux.go @@ -45,8 +45,8 @@ var wslIntegrationDockerPluginCmd = &cobra.Command{ func init() { wslIntegrationDockerPluginCmd.Flags().String("plugin", "", "Full path to plugin") wslIntegrationDockerPluginCmd.Flags().Bool("state", false, "Desired state") - _ = wslIntegrationDockerPluginCmd.MarkFlagRequired("plugin") + wslIntegrationDockerPluginCmd.MarkFlagRequired("plugin") wslIntegrationDockerPluginViper.AutomaticEnv() - _ = wslIntegrationDockerPluginViper.BindPFlags(wslIntegrationDockerPluginCmd.Flags()) + wslIntegrationDockerPluginViper.BindPFlags(wslIntegrationDockerPluginCmd.Flags()) wslIntegrationCmd.AddCommand(wslIntegrationDockerPluginCmd) } diff --git a/src/go/wsl-helper/cmd/wsl_integration_state_linux.go b/src/go/wsl-helper/cmd/wsl_integration_state_linux.go index f34d7e19b02..e25f823b268 100644 --- a/src/go/wsl-helper/cmd/wsl_integration_state_linux.go +++ b/src/go/wsl-helper/cmd/wsl_integration_state_linux.go @@ -54,8 +54,8 @@ var wslIntegrationStateCmd = &cobra.Command{ func init() { wslIntegrationStateCmd.Flags().Var(&enumValue{val: "show", allowed: []string{"show", "set", "delete"}}, "mode", "Operation mode") - _ = wslIntegrationStateCmd.MarkFlagRequired("mode") + wslIntegrationStateCmd.MarkFlagRequired("mode") wslIntegrationStateViper.AutomaticEnv() - _ = wslIntegrationStateViper.BindPFlags(wslIntegrationStateCmd.Flags()) + wslIntegrationStateViper.BindPFlags(wslIntegrationStateCmd.Flags()) wslIntegrationCmd.AddCommand(wslIntegrationStateCmd) } diff --git a/src/go/wsl-helper/pkg/certificates/certificates_windows.go b/src/go/wsl-helper/pkg/certificates/certificates_windows.go index afa13aa4688..80c98b7482b 100644 --- a/src/go/wsl-helper/pkg/certificates/certificates_windows.go +++ b/src/go/wsl-helper/pkg/certificates/certificates_windows.go @@ -60,7 +60,7 @@ func GetSystemCertificates(storeName string) (<-chan Entry, error) { ch := make(chan Entry) go func() { defer close(ch) - defer windows.CertCloseStore(store, 0) //nolint:errcheck // We can't do anything about it if this fails + defer windows.CertCloseStore(store, 0) var certCtx *windows.CertContext var err error for { diff --git a/src/go/wsl-helper/pkg/dockerproxy/mungers/containers_create_linux.go b/src/go/wsl-helper/pkg/dockerproxy/mungers/containers_create_linux.go index 48401dd4952..15ce293ed37 100644 --- a/src/go/wsl-helper/pkg/dockerproxy/mungers/containers_create_linux.go +++ b/src/go/wsl-helper/pkg/dockerproxy/mungers/containers_create_linux.go @@ -82,7 +82,7 @@ type bindManager struct { // empty, then the bind is incomplete (the container create failed) and it // should not be used. type bindManagerEntry struct { - ContainerID string `json:"ContainerId"` + ContainerId string HostPath string } @@ -169,7 +169,7 @@ func (b *bindManager) makeMount() string { } // prepareMountPath creates target directory or file, as mount point -func (b *bindManager) prepareMountPath(target, bindKey string) error { +func (b *bindManager) prepareMountPath(target string, bindKey string) error { mountPath := path.Join(b.mountRoot, bindKey) hostPathStat, err := os.Stat(target) if os.IsNotExist(err) { @@ -206,11 +206,7 @@ type containersCreateRequestBody struct { } // munge incoming request for POST /containers/create -func (b *bindManager) mungeContainersCreateRequest( - req *http.Request, - contextValue *dockerproxy.RequestContextValue, - templates map[string]string, -) error { +func (b *bindManager) mungeContainersCreateRequest(req *http.Request, contextValue *dockerproxy.RequestContextValue, templates map[string]string) error { body := containersCreateRequestBody{} err := readRequestBodyJSON(req, &body) if err != nil { @@ -224,19 +220,19 @@ func (b *bindManager) mungeContainersCreateRequest( modified := false for bindIndex, bind := range body.HostConfig.Binds { logrus.WithField(fmt.Sprintf("bind %d", bindIndex), bind).Trace("got bind") - bindConfig := platform.ParseBindString(bind) - if !bindConfig.IsHostPath { + host, container, options, isPath := platform.ParseBindString(bind) + if !isPath { continue } bindKey := b.makeMount() - binds[bindKey] = bindConfig.Src - bindConfig.Src = path.Join(b.mountRoot, bindKey) + binds[bindKey] = host + host = path.Join(b.mountRoot, bindKey) modified = true - if bindConfig.Options == "" { - body.HostConfig.Binds[bindIndex] = fmt.Sprintf("%s:%s", bindConfig.Src, bindConfig.Dest) + if options == "" { + body.HostConfig.Binds[bindIndex] = fmt.Sprintf("%s:%s", host, container) } else { - body.HostConfig.Binds[bindIndex] = fmt.Sprintf("%s:%s:%s", bindConfig.Src, bindConfig.Dest, bindConfig.Options) + body.HostConfig.Binds[bindIndex] = fmt.Sprintf("%s:%s:%s", host, container, options) } } @@ -286,16 +282,12 @@ func (b *bindManager) mungeContainersCreateRequest( // containersCreateResponseBody describes the contents of a /containers/create response. type containersCreateResponseBody struct { - ID string `json:"Id"` + Id string Warnings []string } // munge outgoing response for POST /containers/create -func (b *bindManager) mungeContainersCreateResponse( - resp *http.Response, - contextValue *dockerproxy.RequestContextValue, - templates map[string]string, -) error { +func (b *bindManager) mungeContainersCreateResponse(resp *http.Response, contextValue *dockerproxy.RequestContextValue, templates map[string]string) error { binds, ok := (*contextValue)[contextKey].(*map[string]string) if !ok { // No binds, meaning either the user didn't specify any, or we didn't need to remap. @@ -320,9 +312,9 @@ func (b *bindManager) mungeContainersCreateResponse( } b.Lock() - for mountID, hostPath := range *binds { - b.entries[mountID] = bindManagerEntry{ - ContainerID: body.ID, + for mountId, hostPath := range *binds { + b.entries[mountId] = bindManagerEntry{ + ContainerId: body.Id, HostPath: hostPath, } } @@ -340,16 +332,12 @@ func (b *bindManager) mungeContainersCreateResponse( // munge incoming request to activate the mount, on // POST /containers/{id}/start // POST /containers/{id}/restart -func (b *bindManager) mungeContainersStartRequest( - req *http.Request, - contextValue *dockerproxy.RequestContextValue, - templates map[string]string, -) error { +func (b *bindManager) mungeContainersStartRequest(req *http.Request, contextValue *dockerproxy.RequestContextValue, templates map[string]string) error { // Look up all the mappings this container needs mapping := make(map[string]string) b.RLock() for key, data := range b.entries { - if data.ContainerID == templates["id"] { + if data.ContainerId == templates["id"] { mapping[key] = data.HostPath } } @@ -387,11 +375,7 @@ func (b *bindManager) mungeContainersStartRequest( // munge outgoing response to deactivate the mount, on // POST /containers/{id}/start // POST /containers/{id}/restart -func (b *bindManager) mungeContainersStartResponse( - req *http.Response, - contextValue *dockerproxy.RequestContextValue, - templates map[string]string, -) error { +func (b *bindManager) mungeContainersStartResponse(req *http.Response, contextValue *dockerproxy.RequestContextValue, templates map[string]string) error { binds, ok := (*contextValue)[contextKey].(*map[string]string) if !ok { // No binds, meaning we didn't do any mounting; nothing to undo here. @@ -421,11 +405,7 @@ func (b *bindManager) mungeContainersStartResponse( } // DELETE /containers/{id} -func (b *bindManager) mungeContainersDeleteResponse( - resp *http.Response, - contextValue *dockerproxy.RequestContextValue, - templates map[string]string, -) error { +func (b *bindManager) mungeContainersDeleteResponse(resp *http.Response, contextValue *dockerproxy.RequestContextValue, templates map[string]string) error { logEntry := logrus.WithField("templates", templates) if resp.StatusCode != http.StatusNoContent && resp.StatusCode != http.StatusNotFound { logEntry.WithField("status-code", resp.StatusCode).Debug("unexpected status code") @@ -436,14 +416,14 @@ func (b *bindManager) mungeContainersDeleteResponse( var toDelete []string for key, data := range b.entries { - if data.ContainerID == templates["id"] { + if data.ContainerId == templates["id"] { toDelete = append(toDelete, key) } } for _, key := range toDelete { delete(b.entries, key) } - _ = b.persist() + b.persist() return nil } diff --git a/src/go/wsl-helper/pkg/dockerproxy/mungers/containers_create_linux_test.go b/src/go/wsl-helper/pkg/dockerproxy/mungers/containers_create_linux_test.go index b4d8edafa40..c8285a822b9 100644 --- a/src/go/wsl-helper/pkg/dockerproxy/mungers/containers_create_linux_test.go +++ b/src/go/wsl-helper/pkg/dockerproxy/mungers/containers_create_linux_test.go @@ -22,6 +22,7 @@ import ( "encoding/json" "fmt" "io" + "io/ioutil" "net/http" "os" "path" @@ -41,7 +42,7 @@ func TestNewBindManager(t *testing.T) { // We're not testing loading the state here; if it happens to fail, we'll // just have to skip the test. if err != nil { - t.Skipf("skipping test, got error %s", err) + t.Skip(fmt.Sprintf("skipping test, got error %s", err)) } else { mountPoint, err := platform.GetWSLMountPoint() assert.NoError(t, err) @@ -62,7 +63,7 @@ func TestBindManagerPersist(t *testing.T) { assert.NoFileExists(t, original.statePath) original.entries = map[string]bindManagerEntry{ "foo": { - ContainerID: "hello", + ContainerId: "hello", HostPath: "world", }, } @@ -110,7 +111,7 @@ func TestContainersCreate(t *testing.T) { // Handle the response buf, err = json.Marshal(&containersCreateResponseBody{ - ID: "hello", + Id: "hello", }) require.NoError(t, err) resp := &http.Response{ @@ -135,14 +136,14 @@ func TestContainersCreate(t *testing.T) { // Assert state assert.Len(t, bindManager.entries, 1) - var mountID string + var mountId string var entry bindManagerEntry - for mountID, entry = range bindManager.entries { + for mountId, entry = range bindManager.entries { } - assert.NotEmpty(t, mountID) - assert.Equal(t, "hello", entry.ContainerID) - assert.Equal(t, "hello", responseBody.ID) - expectedMount := path.Join(bindManager.mountRoot, mountID) + assert.NotEmpty(t, mountId) + assert.Equal(t, "hello", entry.ContainerId) + assert.Equal(t, "hello", responseBody.Id) + expectedMount := path.Join(bindManager.mountRoot, mountId) expectedBind := fmt.Sprintf("%s:/foo", expectedMount) assert.Equal(t, expectedBind, requestBody.HostConfig.Binds[0]) }) @@ -183,7 +184,7 @@ func TestContainersCreate(t *testing.T) { // Handle the response buf, err = json.Marshal(&containersCreateResponseBody{ - ID: "hello", + Id: "hello", }) require.NoError(t, err) resp := &http.Response{ @@ -208,21 +209,21 @@ func TestContainersCreate(t *testing.T) { // Assert state assert.Len(t, bindManager.entries, 1) - var mountID string + var mountId string var entry bindManagerEntry - for mountID, entry = range bindManager.entries { + for mountId, entry = range bindManager.entries { } - assert.NotEmpty(t, mountID) - assert.Equal(t, "hello", entry.ContainerID) + assert.NotEmpty(t, mountId) + assert.Equal(t, "hello", entry.ContainerId) assert.ElementsMatch(t, []*models.Mount{ { Consistency: "cached", - Source: path.Join(bindManager.mountRoot, mountID), + Source: path.Join(bindManager.mountRoot, mountId), Target: "/host", Type: "bind", }, }, requestBody.HostConfig.Mounts) - assert.Equal(t, "hello", responseBody.ID) + assert.Equal(t, "hello", responseBody.Id) }) } @@ -236,7 +237,7 @@ func TestContainersStart(t *testing.T) { mountRoot: t.TempDir(), entries: map[string]bindManagerEntry{ "mount-id": { - ContainerID: "container-id", + ContainerId: "container-id", HostPath: hostPath, }, }, @@ -265,7 +266,7 @@ func TestContainersStart(t *testing.T) { // getBindMounts returns a map of bind mount directory -> underlying path // Note that this may also return items that are not bind mounts. getBindMounts := func() (map[string]string, error) { - mountBuf, err := os.ReadFile("/proc/self/mountinfo") + mountBuf, err := ioutil.ReadFile("/proc/self/mountinfo") if err != nil { return nil, fmt.Errorf("could not read /proc/self/mountinfo: %w", err) } @@ -305,7 +306,7 @@ func TestContainerDelete(t *testing.T) { mountRoot: t.TempDir(), entries: map[string]bindManagerEntry{ "mount-id": { - ContainerID: "container-id", + ContainerId: "container-id", HostPath: hostPath, }, }, diff --git a/src/go/wsl-helper/pkg/dockerproxy/mungers/containers_create_windows.go b/src/go/wsl-helper/pkg/dockerproxy/mungers/containers_create_windows.go index 99ced4e140f..4c910f1adb9 100644 --- a/src/go/wsl-helper/pkg/dockerproxy/mungers/containers_create_windows.go +++ b/src/go/wsl-helper/pkg/dockerproxy/mungers/containers_create_windows.go @@ -48,19 +48,19 @@ func mungeContainersCreate(req *http.Request, contextValue *dockerproxy.RequestC modified := false for bindIndex, bind := range body.HostConfig.Binds { logrus.WithField(fmt.Sprintf("bind %d", bindIndex), bind).Debug("got bind") - bindConfig := platform.ParseBindString(bind) - src := bindConfig.Src - if bindConfig.IsHostPath { - src, err = platform.TranslatePathFromClient(bindConfig.Src) + host, container, options, isPath := platform.ParseBindString(bind) + if isPath { + translated, err := platform.TranslatePathFromClient(host) if err != nil { - return fmt.Errorf("could not translate bind path %s: %w", bindConfig.Src, err) + return fmt.Errorf("could not translate bind path %s: %w", host, err) } + host = translated modified = true } - if bindConfig.Options == "" { - body.HostConfig.Binds[bindIndex] = fmt.Sprintf("%s:%s", src, bindConfig.Dest) + if options == "" { + body.HostConfig.Binds[bindIndex] = fmt.Sprintf("%s:%s", host, container) } else { - body.HostConfig.Binds[bindIndex] = fmt.Sprintf("%s:%s:%s", src, bindConfig.Dest, bindConfig.Options) + body.HostConfig.Binds[bindIndex] = fmt.Sprintf("%s:%s:%s", host, container, options) } } diff --git a/src/go/wsl-helper/pkg/dockerproxy/platform/serve_linux.go b/src/go/wsl-helper/pkg/dockerproxy/platform/serve_linux.go index 74fe1b7f209..ae9456d8ad5 100644 --- a/src/go/wsl-helper/pkg/dockerproxy/platform/serve_linux.go +++ b/src/go/wsl-helper/pkg/dockerproxy/platform/serve_linux.go @@ -106,20 +106,10 @@ func Listen(endpoint string) (net.Listener, error) { return listener, nil } -// bindConfig is the result of calling ParseBindString. -type bindConfig struct { - // The source of the bind, either a host path or a volume name. - Src string - // The destination of the bind. - Dest string - // Optional extra Options. - Options string - // Whether the src field is a host path. - IsHostPath bool -} - -// ParseBindString parses a HostConfig.Binds entry. -func ParseBindString(input string) bindConfig { +// ParseBindString parses a HostConfig.Binds entry, returning the ( or +// ), , and (optional) . Additionally, it +// also returns a boolean indicating if the first argument is a host path. +func ParseBindString(input string) (string, string, string, bool) { // The volumes here are [:][:options] // For a first pass, let's just assume there are no colons in any of this... // The API spec says that if the first part is a host path, then it _must_ @@ -129,36 +119,18 @@ func ParseBindString(input string) bindConfig { lastIndex := strings.LastIndex(input, ":") if firstIndex < 0 { // just /foo -- map the same path on the host to the container. - return bindConfig{ - Src: input, - Dest: input, - IsHostPath: hostIsPath, - } + return input, input, "", hostIsPath } start := input[:firstIndex] end := input[lastIndex+1:] if lastIndex > firstIndex { // /foo:/bar:ro middle := input[firstIndex+1 : lastIndex] - return bindConfig{ - Src: start, - Dest: middle, - Options: end, - IsHostPath: hostIsPath, - } + return start, middle, end, hostIsPath } // either /foo:/bar or /foo:ro if strings.HasPrefix(end, "/") { - return bindConfig{ - Src: start, - Dest: end, - IsHostPath: hostIsPath, - } - } - return bindConfig{ - Src: start, - Dest: start, - Options: end, - IsHostPath: hostIsPath, + return start, end, "", hostIsPath } + return start, start, end, hostIsPath } diff --git a/src/go/wsl-helper/pkg/dockerproxy/platform/serve_windows.go b/src/go/wsl-helper/pkg/dockerproxy/platform/serve_windows.go index 69eb614c1e3..1f96aa2ee62 100644 --- a/src/go/wsl-helper/pkg/dockerproxy/platform/serve_windows.go +++ b/src/go/wsl-helper/pkg/dockerproxy/platform/serve_windows.go @@ -37,12 +37,12 @@ var ErrListenerClosed = winio.ErrPipeListenerClosed // MakeDialer computes the dial function. func MakeDialer(port uint32) (func() (net.Conn, error), error) { - vmGUID, err := probeVMGUID(port) + vmGuid, err := probeVMGUID(port) if err != nil { return nil, fmt.Errorf("could not detect WSL2 VM: %w", err) } dial := func() (net.Conn, error) { - conn, err := dialHvsock(vmGUID, port) + conn, err := dialHvsock(vmGuid, port) if err != nil { return nil, err } @@ -53,16 +53,16 @@ func MakeDialer(port uint32) (func() (net.Conn, error), error) { // dialHvsock creates a net.Conn to a Hyper-V VM running Linux with the given // GUID, listening on the given vsock port. -func dialHvsock(vmGUID hvsock.GUID, port uint32) (net.Conn, error) { +func dialHvsock(vmGuid hvsock.GUID, port uint32) (net.Conn, error) { // go-winio doesn't implement DialHvsock(), but luckily LinuxKit has an // implementation. We still need go-winio to convert port to GUID. - svcGUID, err := hvsock.GUIDFromString(winio.VsockServiceID(port).String()) + svcGuid, err := hvsock.GUIDFromString(winio.VsockServiceID(port).String()) if err != nil { return nil, fmt.Errorf("could not parse Hyper-V service GUID: %w", err) } addr := hvsock.Addr{ - VMID: vmGUID, - ServiceID: svcGUID, + VMID: vmGuid, + ServiceID: svcGuid, } conn, err := hvsock.Dial(addr) @@ -89,20 +89,10 @@ func Listen(endpoint string) (net.Listener, error) { return listener, nil } -// bindConfig is the result of calling ParseBindString. -type bindConfig struct { - // The source of the bind, either a host path or a volume name. - Src string - // The destination of the bind. - Dest string - // Optional extra Options. - Options string - // Whether the src field is a host path. - IsHostPath bool -} - -// ParseBindString parses a HostConfig.Binds entry. -func ParseBindString(input string) bindConfig { +// ParseBindString parses a HostConfig.Binds entry, returning the ( or +// ), , and (optional) . Additionally, it +// also returns a boolean indicating if the first argument is a host path. +func ParseBindString(input string) (string, string, string, bool) { // Windows names can be one of a few things: // C:\foo\bar colon is possible after the drive letter // \\?\C:\foo\bar colon is possible after the drive letter @@ -119,35 +109,17 @@ func ParseBindString(input string) bindConfig { firstIndex := strings.Index(input, ":") lastIndex := strings.LastIndex(input, ":") if firstIndex == lastIndex { - return bindConfig{ - Src: input[:firstIndex], - Dest: input[firstIndex+1:], - IsHostPath: false, - } - } - return bindConfig{ - Src: input[:firstIndex], - Dest: input[firstIndex+1 : lastIndex], - Options: input[lastIndex+1:], - IsHostPath: false, + return input[:firstIndex], input[firstIndex+1:], "", false } + return input[:firstIndex], input[firstIndex+1 : lastIndex], input[lastIndex+1:], false } else { // The first part is a path. rest := input[len(match)+1:] index := strings.LastIndex(rest, ":") if index > -1 { - return bindConfig{ - Src: match, - Dest: rest[:index], - Options: rest[index+1:], - IsHostPath: true, - } - } - return bindConfig{ - Src: match, - Dest: rest, - IsHostPath: true, + return match, rest[:index], rest[index+1:], true } + return match, rest, "", true } } diff --git a/src/go/wsl-helper/pkg/dockerproxy/platform/serve_windows_test.go b/src/go/wsl-helper/pkg/dockerproxy/platform/serve_windows_test.go index ce973ba2d75..3ec8586854f 100644 --- a/src/go/wsl-helper/pkg/dockerproxy/platform/serve_windows_test.go +++ b/src/go/wsl-helper/pkg/dockerproxy/platform/serve_windows_test.go @@ -41,11 +41,11 @@ func TestParseBindString(t *testing.T) { for input, expected := range cases { t.Run(input, func(t *testing.T) { - hostConfig := ParseBindString(input) - assert.Equal(t, expected.host, hostConfig.Src) - assert.Equal(t, expected.container, hostConfig.Dest) - assert.Equal(t, expected.options, hostConfig.Options) - assert.Equal(t, expected.isPath, hostConfig.IsHostPath) + host, container, options, isPath := ParseBindString(input) + assert.Equal(t, expected.host, host) + assert.Equal(t, expected.container, container) + assert.Equal(t, expected.options, options) + assert.Equal(t, expected.isPath, isPath) }) } } diff --git a/src/go/wsl-helper/pkg/dockerproxy/platform/vsock_linux.go b/src/go/wsl-helper/pkg/dockerproxy/platform/vsock_linux.go index 6549c698f70..93f2e2c7cff 100644 --- a/src/go/wsl-helper/pkg/dockerproxy/platform/vsock_linux.go +++ b/src/go/wsl-helper/pkg/dockerproxy/platform/vsock_linux.go @@ -33,7 +33,8 @@ import ( // Convert a generic unix.Sockaddr to a Addr func sockaddrToVsock(sa unix.Sockaddr) *vsock.Addr { - if sa, ok := sa.(*unix.SockaddrVM); ok { + switch sa := sa.(type) { + case *unix.SockaddrVM: return &vsock.Addr{CID: sa.CID, Port: sa.Port} } return nil @@ -92,8 +93,8 @@ type vsockConn struct { } func newVsockConn(fd uintptr, local, remote *vsock.Addr) *vsockConn { - vs := os.NewFile(fd, fmt.Sprintf("vsock:%d", fd)) - return &vsockConn{vsock: vs, fd: fd, local: local, remote: remote} + vsock := os.NewFile(fd, fmt.Sprintf("vsock:%d", fd)) + return &vsockConn{vsock: vsock, fd: fd, local: local, remote: remote} } // LocalAddr returns the local address of a connection @@ -133,23 +134,23 @@ func (v *vsockConn) Write(buf []byte) (int, error) { // SetDeadline sets the read and write deadlines associated with the connection func (v *vsockConn) SetDeadline(t time.Time) error { - return nil // FIXME Not implemented, not needed so far. + return nil // FIXME } // SetReadDeadline sets the deadline for future Read calls. func (v *vsockConn) SetReadDeadline(t time.Time) error { - return nil // FIXME Not implemented, not needed so far. + return nil // FIXME } // SetWriteDeadline sets the deadline for future Write calls func (v *vsockConn) SetWriteDeadline(t time.Time) error { - return nil // FIXME Not implemented, not needed so far. + return nil // FIXME } // File duplicates the underlying socket descriptor and returns it. func (v *vsockConn) File() (*os.File, error) { // This is equivalent to dup(2) but creates the new fd with CLOEXEC already set. - r0, _, e1 := syscall.Syscall(syscall.SYS_FCNTL, v.vsock.Fd(), syscall.F_DUPFD_CLOEXEC, 0) + r0, _, e1 := syscall.Syscall(syscall.SYS_FCNTL, uintptr(v.vsock.Fd()), syscall.F_DUPFD_CLOEXEC, 0) if e1 != 0 { return nil, os.NewSyscallError("fcntl", e1) } diff --git a/src/go/wsl-helper/pkg/dockerproxy/platform/wsl_mountpoint_linux.go b/src/go/wsl-helper/pkg/dockerproxy/platform/wsl_mountpoint_linux.go index ca1635b9bae..0af54a12b22 100644 --- a/src/go/wsl-helper/pkg/dockerproxy/platform/wsl_mountpoint_linux.go +++ b/src/go/wsl-helper/pkg/dockerproxy/platform/wsl_mountpoint_linux.go @@ -18,22 +18,16 @@ package platform import ( "fmt" - "os" + "io/ioutil" "strings" "github.com/sirupsen/logrus" ) -const ( - // mountPointField is the zero-indexed field offset in mountinfo - // https://www.kernel.org/doc/html/latest/filesystems/proc.html#proc-pid-mountinfo-information-about-mounts - mountPointField = 4 -) - // Get the WSL mount point; typically, this is /mnt/wsl. // If we fail to find one, we will use /mnt/wsl instead. func GetWSLMountPoint() (string, error) { - buf, err := os.ReadFile("/proc/self/mountinfo") + buf, err := ioutil.ReadFile("/proc/self/mountinfo") if err != nil { return "", fmt.Errorf("error reading mounts: %w", err) } @@ -43,9 +37,9 @@ func GetWSLMountPoint() (string, error) { continue } fields := strings.Split(line, " ") - if len(fields) >= mountPointField+1 { - if strings.HasSuffix(fields[mountPointField], "/wsl") { - return fields[mountPointField], nil + if len(fields) >= 5 { + if strings.HasSuffix(fields[4], "/wsl") { + return fields[4], nil } } } diff --git a/src/go/wsl-helper/pkg/dockerproxy/serve.go b/src/go/wsl-helper/pkg/dockerproxy/serve.go index 1a3019ffb90..4e87325b0be 100644 --- a/src/go/wsl-helper/pkg/dockerproxy/serve.go +++ b/src/go/wsl-helper/pkg/dockerproxy/serve.go @@ -32,7 +32,6 @@ import ( "os/signal" "regexp" "sync" - "time" "github.com/Masterminds/semver" "github.com/sirupsen/logrus" @@ -48,11 +47,9 @@ type RequestContextValue map[interface{}]interface{} var requestContext = struct{}{} type containerInspectResponseBody struct { - ID string `json:"Id"` + Id string } -type dialerFunc func() (net.Conn, error) - const dockerAPIVersion = "v1.41.0" // Serve up the docker proxy at the given endpoint, using the given function to @@ -138,12 +135,7 @@ func Serve(endpoint string, dialer func() (net.Conn, error)) error { logrus.WithField("endpoint", endpoint).Info("Listening") - server := &http.Server{ - ReadTimeout: 30 * time.Second, - WriteTimeout: 30 * time.Second, - Handler: contextAttacher, - } - err = server.Serve(listener) + err = http.Serve(listener, contextAttacher) if err != nil { logrus.WithError(err).Error("serve exited with error") } @@ -209,7 +201,7 @@ func (m *requestMunger) MungeRequest(req *http.Request, dialer func() (net.Conn, if err != nil { logEntry.WithField("id", id).WithError(err).Error("unable to resolve container id") } else { - templates["id"] = inspect.ID + templates["id"] = inspect.Id } } @@ -250,7 +242,7 @@ func (m *requestMunger) MungeResponse(resp *http.Response, dialer func() (net.Co if err != nil { logEntry.WithField("id", id).WithError(err).Error("unable to resolve container id") } else { - templates["id"] = inspect.ID + templates["id"] = inspect.Id } } @@ -270,7 +262,7 @@ we use the provided id path template variable to make an upstream request to the Fortunately it supports both id or name as the container identifier. The Id returned will be the full long container id that is used to lookup in docker-binds.json. */ -func (m *requestMunger) CanonicalizeContainerID(req *http.Request, id string, dialer dialerFunc) (*containerInspectResponseBody, error) { +func (m *requestMunger) CanonicalizeContainerID(req *http.Request, id string, dialer func() (net.Conn, error)) (*containerInspectResponseBody, error) { // url for inspecting container inspectURL, err := req.URL.Parse(fmt.Sprintf("/%s/containers/%s/json", dockerAPIVersion, id)) if err != nil { @@ -286,15 +278,10 @@ func (m *requestMunger) CanonicalizeContainerID(req *http.Request, id string, di } // make the inspect request - innerRequest, err := http.NewRequestWithContext(req.Context(), http.MethodGet, inspectURL.String(), http.NoBody) - if err != nil { - return nil, err - } - inspectResponse, err := client.Do(innerRequest) + inspectResponse, err := client.Get(inspectURL.String()) if err != nil { return nil, err } - defer inspectResponse.Body.Close() // parse response as json body := containerInspectResponseBody{} @@ -346,8 +333,6 @@ type mungerMethodMapping struct { // getRequestMunger gets the munger to use for this request, as well as the // path templating elements (if relevant for the munger). -// -//nolint:gocritic // The returns values are unnamed to avoid accidental assignment. func (m *mungerMethodMapping) getRequestMunger(apiPath string) (requestMungerFunc, map[string]string) { if munger, ok := m.requests[apiPath]; ok { return munger, nil @@ -366,7 +351,6 @@ func (m *mungerMethodMapping) getRequestMunger(apiPath string) (requestMungerFun return nil, nil } -//nolint:gocritic // The returns values are unnamed to avoid accidental assignment. func (m *mungerMethodMapping) getResponseMunger(apiPath string) (responseMungerFunc, map[string]string) { if munger, ok := m.responses[apiPath]; ok { return munger, nil @@ -410,7 +394,6 @@ func convertPattern(apiPath string) *regexp.Regexp { return regexp.MustCompile(pattern) } -//nolint:dupl // This is RegisterResponseMunger but with a different set of mungers. func RegisterRequestMunger(method, apiPath string, munger requestMungerFunc) { mungerMapping.Lock() defer mungerMapping.Unlock() @@ -433,7 +416,6 @@ func RegisterRequestMunger(method, apiPath string, munger requestMungerFunc) { } } -//nolint:dupl // This is RegisterRequestMunger but with a different set of mungers. func RegisterResponseMunger(method, apiPath string, munger responseMungerFunc) { mungerMapping.Lock() defer mungerMapping.Unlock() diff --git a/src/go/wsl-helper/pkg/dockerproxy/start.go b/src/go/wsl-helper/pkg/dockerproxy/start.go index 8267e068613..8188a57682f 100644 --- a/src/go/wsl-helper/pkg/dockerproxy/start.go +++ b/src/go/wsl-helper/pkg/dockerproxy/start.go @@ -35,21 +35,13 @@ import ( "github.com/rancher-sandbox/rancher-desktop/src/go/wsl-helper/pkg/dockerproxy/util" ) -const ( - // defaultProxyEndpoint is the path on which dockerd should listen on, relative - // to the WSL mount point. - defaultProxyEndpoint = "rancher-desktop/run/docker.sock" - - // fileExistPollInterval is the time between polling to see if the file exists. - fileExistPollInterval = 500 * time.Millisecond - - // dockerSocketTimeout is the time to wait for the docker socket to exist. - dockerSocketTimeout = 30 * time.Second -) +// defaultProxyEndpoint is the path on which dockerd should listen on, relative +// to the WSL mount point. +const defaultProxyEndpoint = "rancher-desktop/run/docker.sock" // waitForFileToExist will block until the given path exists. If the given // timeout is reached, an error will be returned. -func waitForFileToExist(filePath string, timeout time.Duration) error { +func waitForFileToExist(path string, timeout time.Duration) error { timer := time.After(timeout) ready := make(chan struct{}) expired := false @@ -59,11 +51,11 @@ func waitForFileToExist(filePath string, timeout time.Duration) error { // We just do polling here, since inotify / fanotify both have fairly // low limits on the concurrent number of watchers. for !expired { - _, err := os.Lstat(filePath) + _, err := os.Lstat(path) if err == nil { return } - time.Sleep(fileExistPollInterval) + time.Sleep(500 * time.Millisecond) } }() @@ -72,7 +64,7 @@ func waitForFileToExist(filePath string, timeout time.Duration) error { return nil case <-timer: expired = true - return fmt.Errorf("timed out waiting for %s to exist", filePath) + return fmt.Errorf("timed out waiting for %s to exist", path) } } @@ -104,11 +96,8 @@ func Start(port uint32, dockerSocket string, args []string) error { return fmt.Errorf("could not set up docker socket: %w", err) } - args = append( - args, - fmt.Sprintf("--host=unix://%s", dockerSocket), - "--host=unix:///var/run/docker.sock", - ) + args = append(args, fmt.Sprintf("--host=unix://%s", dockerSocket)) + args = append(args, "--host=unix:///var/run/docker.sock") cmd := exec.Command(dockerd, args...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr @@ -127,7 +116,7 @@ func Start(port uint32, dockerSocket string, args []string) error { }() // Wait for the docker socket to exist... - err = waitForFileToExist(dockerSocket, dockerSocketTimeout) + err = waitForFileToExist(dockerSocket, 30*time.Second) if err != nil { return err } @@ -138,7 +127,7 @@ func Start(port uint32, dockerSocket string, args []string) error { } defer listener.Close() - sigch := make(chan os.Signal, 1) + sigch := make(chan os.Signal) signal.Notify(sigch, unix.SIGTERM) go func() { <-sigch @@ -153,6 +142,8 @@ func Start(port uint32, dockerSocket string, args []string) error { } go handleConnection(conn, dockerSocket) } + + return nil } // handleConnection handles piping the connection from the client to the docker diff --git a/src/go/wsl-helper/pkg/process/kill_others_linux.go b/src/go/wsl-helper/pkg/process/kill_others_linux.go index b46fcf70d07..3a87c8f53c8 100644 --- a/src/go/wsl-helper/pkg/process/kill_others_linux.go +++ b/src/go/wsl-helper/pkg/process/kill_others_linux.go @@ -13,8 +13,6 @@ import ( ) // KillOthers will kill any other processes with the executable. -// -//nolint:gocyclo // TODO: clean up function func KillOthers(args ...string) error { selfPid := fmt.Sprintf("%d", os.Getpid()) selfFile, err := os.Readlink("/proc/self/exe") diff --git a/src/go/wsl-helper/pkg/process/kill_windows.go b/src/go/wsl-helper/pkg/process/kill_windows.go index e2389542d1f..bc1004de8aa 100644 --- a/src/go/wsl-helper/pkg/process/kill_windows.go +++ b/src/go/wsl-helper/pkg/process/kill_windows.go @@ -25,7 +25,6 @@ import ( ) const ( - //nolint:stylecheck // The constant name matches Win32 API. ATTACH_PARENT_PROCESS = math.MaxUint32 ) @@ -51,7 +50,7 @@ func Kill(pid int) error { } // Prevent _this_ process from being affected by Ctrl+C (so we exit cleanly). // Ignore any errors if this fails. - _, _, _ = setConsoleCtrlHandler.Call(uintptr(unsafe.Pointer(nil)), 1) + setConsoleCtrlHandler.Call(uintptr(unsafe.Pointer(nil)), 1) err = windows.GenerateConsoleCtrlEvent(windows.CTRL_C_EVENT, 0) if err != nil { diff --git a/src/go/wsl-helper/pkg/process/wait_windows.go b/src/go/wsl-helper/pkg/process/wait_windows.go index 7305a1d6e3b..77112907cbf 100644 --- a/src/go/wsl-helper/pkg/process/wait_windows.go +++ b/src/go/wsl-helper/pkg/process/wait_windows.go @@ -36,7 +36,6 @@ func WaitPid(pid uint32) error { return fmt.Errorf("could not get handle to process %d: %w", pid, err) } hProc := windows.Handle(hProcRaw) - //nolint:errcheck // We can't do anything about it if this fails defer windows.CloseHandle(hProc) logEntry.Trace("waiting for process") diff --git a/src/go/wsl-helper/pkg/wsl-utils/dism_windows.go b/src/go/wsl-helper/pkg/wsl-utils/dism_windows.go index 5fdfcb86c87..dab60a40b0f 100644 --- a/src/go/wsl-helper/pkg/wsl-utils/dism_windows.go +++ b/src/go/wsl-helper/pkg/wsl-utils/dism_windows.go @@ -37,20 +37,16 @@ const ( kWindowsFeature = "VirtualMachinePlatform" // DISM_ONLINE_IMAGE is the DISM "image path" that signifies we're trying // to modify the running Windows installation. - //nolint:stylecheck // Constant name follows Win32 API DISM_ONLINE_IMAGE = "DISM_{53BFAE52-B167-4E2F-A258-0A37B57FF845}" DismLogErrorsWarningsInfo = 2 - // win32ErrorMask is used to turn a HRESULT_FROM_WIN32(x) back into a Win32 - // error code. - win32ErrorMask = 0xFFFF ) var ( - dllDismAPI = windows.NewLazySystemDLL("dismapi.dll") - dismInitialize = dllDismAPI.NewProc("DismInitialize") - dismOpenSession = dllDismAPI.NewProc("DismOpenSession") - dismCloseSession = dllDismAPI.NewProc("DismCloseSession") - dismEnableFeature = dllDismAPI.NewProc("DismEnableFeature") + dllDismApi = windows.NewLazySystemDLL("dismapi.dll") + dismInitialize = dllDismApi.NewProc("DismInitialize") + dismOpenSession = dllDismApi.NewProc("DismOpenSession") + dismCloseSession = dllDismApi.NewProc("DismCloseSession") + dismEnableFeature = dllDismApi.NewProc("DismEnableFeature") ) func errorFromHResult(hr int32, err error) error { @@ -91,9 +87,8 @@ func DismDoInstall(ctx context.Context, log *logrus.Entry) error { uintptr(unsafe.Pointer(&session)), ) if hr != uintptr(windows.S_OK) { - return errorFromWin32("failed to open DISM session", hr&win32ErrorMask, err) + return errorFromWin32("failed to open DISM session", hr&0xFFFF, err) } - //nolint:errcheck // We can't do anything about any failures here. defer dismCloseSession.Call(uintptr(session)) if buf, err = windows.UTF16PtrFromString(kWindowsFeature); err != nil { diff --git a/src/go/wsl-helper/pkg/wsl-utils/utf16writer_windows.go b/src/go/wsl-helper/pkg/wsl-utils/utf16writer_windows.go index 1345bea26db..544d3cd3ca8 100644 --- a/src/go/wsl-helper/pkg/wsl-utils/utf16writer_windows.go +++ b/src/go/wsl-helper/pkg/wsl-utils/utf16writer_windows.go @@ -13,10 +13,8 @@ type utf16Writer struct { } func (w *utf16Writer) Write(p []byte) (int, error) { - buf := make([]byte, 0, len(p)+2) - copy(buf, p) output := windows.UTF16PtrToString( - (*uint16)(unsafe.Pointer(unsafe.SliceData(append(buf, 0, 0)))), + (*uint16)(unsafe.Pointer(unsafe.SliceData(append(p, 0, 0)))), ) n, err := w.Writer.Write( unsafe.Slice(unsafe.StringData(output), len(output)), diff --git a/src/go/wsl-helper/pkg/wsl-utils/version_windows.go b/src/go/wsl-helper/pkg/wsl-utils/version_windows.go index 5d84e060f8e..05838f9c431 100644 --- a/src/go/wsl-helper/pkg/wsl-utils/version_windows.go +++ b/src/go/wsl-helper/pkg/wsl-utils/version_windows.go @@ -42,11 +42,9 @@ const ( // kPackageFamily is the package family for the WSL app (MSIX). kPackageFamily = "MicrosoftCorporationII.WindowsSubsystemForLinux_8wekyb3d8bbwe" // spellcheck-ignore-line // kMsiUpgradeCode is the upgrade code for the WSL kernel (for in-box WSL2) - kMsiUpgradeCode = "{1C3DB5B6-65A5-4EBC-A5B9-2F2D6F665F48}" - //nolint:stylecheck // Constant name follows Win32 API. + kMsiUpgradeCode = "{1C3DB5B6-65A5-4EBC-A5B9-2F2D6F665F48}" PACKAGE_INFORMATION_BASIC = 0x00000000 - //nolint:stylecheck // Constant name follows Win32 API. - PACKAGE_INFORMATION_FULL = 0x00000100 + PACKAGE_INFORMATION_FULL = 0x00000100 // wslExitNotInstalled is the exit code from `wsl --status` when WSL is not // installed. wslExitNotInstalled = 50 @@ -138,22 +136,20 @@ func (v PackageVersion) String() string { } // packageInfo corresponds to the PACKAGE_INFO structure. -// -//nolint:structcheck // We need the struct to match the Win32 API, so we can't drop unused fields. type packageInfo struct { reserved uint32 flags uint32 path *uint16 packageFullName *uint16 packageFamilyName *uint16 - packageID struct { + packageId struct { reserved uint32 processorArchitecture uint32 version PackageVersion name *uint16 publisher *uint16 - resourceID *uint16 - publisherID *uint16 + resourceId *uint16 + publisherId *uint16 } } @@ -173,7 +169,6 @@ func getPackageVersion(fullName string) (*PackageVersion, error) { if rv != uintptr(windows.ERROR_SUCCESS) { return nil, errorFromWin32("error opening package info", rv, err) } - //nolint:errcheck // We can't do anything about any failures here. defer closePackageInfo.Call(packageInfoReference) var bufferLength, count uint32 @@ -209,7 +204,7 @@ func getPackageVersion(fullName string) (*PackageVersion, error) { for _, info := range infos { // `info` is a pointer to an unsafe slice; make a copy of the version // on the stack and then return that so the GC knows about it. - versionCopy := info.packageID.version + versionCopy := info.packageId.version return &versionCopy, nil } @@ -218,17 +213,17 @@ func getPackageVersion(fullName string) (*PackageVersion, error) { // isInboxWSLInstalled checks if the "in-box" version of WSL is installed, // returning whether it's installed, and whether the kernel is installed -func isInboxWSLInstalled(ctx context.Context, log *logrus.Entry) (isCoreInstalled, isKernelInstalled bool, err error) { +func isInboxWSLInstalled(ctx context.Context, log *logrus.Entry) (bool, bool, error) { var allErrors []error // Check if the core is installed - isCoreInstalled = false + coreInstalled := false newRunnerFunc := NewWSLRunner if f := ctx.Value(&kWSLExeOverride); f != nil { newRunnerFunc = f.(func() WSLRunner) } output := &bytes.Buffer{} - err = newRunnerFunc().WithStdout(output).WithStderr(os.Stderr).Run(ctx, "--status") + err := newRunnerFunc().WithStdout(output).WithStderr(os.Stderr).Run(ctx, "--status") var exitErr *exec.ExitError if errors.As(err, &exitErr) && exitErr.ExitCode() == wslExitNotInstalled { // When WSL is not installed, we seem to get exit code 50 @@ -238,14 +233,14 @@ func isInboxWSLInstalled(ctx context.Context, log *logrus.Entry) (isCoreInstalle } else { lines := strings.Split(strings.TrimSpace(output.String()), "\n") if len(lines) > 0 { - isCoreInstalled = true + coreInstalled = true } else { allErrors = append(allErrors, fmt.Errorf("no output from wsl --status")) } } // Check if the kernel is installed. - isKernelInstalled = false + kernelInstalled := false upgradeCodeString := kMsiUpgradeCode if v := ctx.Value(&kUpgradeCodeOverride); v != nil { upgradeCodeString = v.(string) @@ -254,7 +249,7 @@ func isInboxWSLInstalled(ctx context.Context, log *logrus.Entry) (isCoreInstalle if err != nil { allErrors = append(allErrors, err) } else { - productCode := make([]uint16, len(kMsiUpgradeCode)+1) + productCode := make([]uint16, 39) rv, _, _ := msiEnumRelatedProducts.Call( uintptr(unsafe.Pointer(upgradeCode)), @@ -264,7 +259,7 @@ func isInboxWSLInstalled(ctx context.Context, log *logrus.Entry) (isCoreInstalle ) switch rv { case uintptr(windows.ERROR_SUCCESS): - isKernelInstalled = true + kernelInstalled = true case uintptr(windows.ERROR_NO_MORE_ITEMS): // kernel is not installed default: @@ -274,7 +269,7 @@ func isInboxWSLInstalled(ctx context.Context, log *logrus.Entry) (isCoreInstalle } err = errors.Join(allErrors...) - return isCoreInstalled, isKernelInstalled, err + return coreInstalled, kernelInstalled, err } func GetWSLInfo(ctx context.Context, log *logrus.Entry) (*WSLInfo, error) { diff --git a/src/go/wsl-helper/wix/check_windows.go b/src/go/wsl-helper/wix/check_windows.go index a3f2be7a93f..01bb6c7e90d 100644 --- a/src/go/wsl-helper/wix/check_windows.go +++ b/src/go/wsl-helper/wix/check_windows.go @@ -24,7 +24,6 @@ import ( ) const ( - //nolint:stylecheck // Windows Installer exposed properties by convention use all caps. PROP_WSL_INSTALLED = "WSLINSTALLED" ) diff --git a/src/go/wsl-helper/wix/helpers_windows.go b/src/go/wsl-helper/wix/helpers_windows.go index 7283400ae61..a3c4ecb8032 100644 --- a/src/go/wsl-helper/wix/helpers_windows.go +++ b/src/go/wsl-helper/wix/helpers_windows.go @@ -26,7 +26,6 @@ import ( type messageType uintptr -//nolint:stylecheck // Constants follow style of Windows API const ( INSTALLMESSAGE_INFO messageType = 0x04000000 INSTALLMESSAGE_ACTIONSTART messageType = 0x08000000 @@ -37,7 +36,7 @@ func submitMessage(hInstall MSIHANDLE, message messageType, data []string) error if record == 0 { return fmt.Errorf("failed to create record") } - defer msiCloseHandle.Call(record) //nolint:errcheck // We can't usefully handle the error. + defer msiCloseHandle.Call(record) for i, item := range data { buf, err := windows.UTF16PtrFromString(item) if err != nil { @@ -76,7 +75,7 @@ func setProperty(hInstall MSIHANDLE, name, value string) error { if err != nil { return fmt.Errorf("failed to encode property value %q: %w", value, err) } - _, _, _ = msiSetPropertyW.Call( + msiSetPropertyW.Call( uintptr(hInstall), uintptr(unsafe.Pointer(nameBuf)), uintptr(unsafe.Pointer(valueBuf)), diff --git a/src/go/wsl-helper/wix/imports_windows.go b/src/go/wsl-helper/wix/imports_windows.go index f3ab1fb778d..727eb46318d 100644 --- a/src/go/wsl-helper/wix/imports_windows.go +++ b/src/go/wsl-helper/wix/imports_windows.go @@ -21,10 +21,12 @@ import "golang.org/x/sys/windows" type MSIHANDLE uint32 var ( + dllKernel32 = windows.NewLazySystemDLL("kernel32.dll") dllMsi = windows.NewLazySystemDLL("msi.dll") msiCloseHandle = dllMsi.NewProc("MsiCloseHandle") msiCreateRecord = dllMsi.NewProc("MsiCreateRecord") msiRecordSetStringW = dllMsi.NewProc("MsiRecordSetStringW") msiProcessMessage = dllMsi.NewProc("MsiProcessMessage") msiSetPropertyW = dllMsi.NewProc("MsiSetPropertyW") + outputDebugStringW = dllKernel32.NewProc("OutputDebugStringW") ) diff --git a/src/go/wsl-helper/wix/install_windows.go b/src/go/wsl-helper/wix/install_windows.go index 60af59165e2..d5b1bf12b76 100644 --- a/src/go/wsl-helper/wix/install_windows.go +++ b/src/go/wsl-helper/wix/install_windows.go @@ -37,7 +37,7 @@ func InstallWindowsFeatureImpl(hInstall MSIHANDLE) uint32 { }) log.Infof("Installing Windows feature...") - _ = submitMessage(hInstall, INSTALLMESSAGE_ACTIONSTART, []string{ + submitMessage(hInstall, INSTALLMESSAGE_ACTIONSTART, []string{ "", "InstalWindowsFeature", "Installing required Windows features...", "", }) if err := wslutils.DismDoInstall(ctx, log); err != nil { @@ -63,7 +63,7 @@ func InstallWSLImpl(hInstall MSIHANDLE) uint32 { }) log.Info("Installing WSL...") - _ = submitMessage(hInstall, INSTALLMESSAGE_ACTIONSTART, []string{ + submitMessage(hInstall, INSTALLMESSAGE_ACTIONSTART, []string{ "", "InstallWSL", "Installing Windows Subsystem for Linux...", "", }) if err := wslutils.InstallWSL(ctx, log); err != nil {