Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cluster: fix settings write payload #268

Merged
merged 1 commit into from
Dec 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 46 additions & 19 deletions pkg/cluster/docker_desktop.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ import (
klog "k8s.io/klog/v2"
)

type ddProtocol int

const (
// Pre DD 4.12
ddProtocolV1 ddProtocol = iota

// Post DD 4.12
ddProtocolV2 = 1
)

type HTTPClient interface {
Do(req *http.Request) (*http.Response, error)
}
Expand All @@ -26,25 +36,25 @@ type HTTPClient interface {
// There isn't an off-the-shelf library or documented protocol we can use
// for this, so we do the best we can.
type DockerDesktopClient struct {
guiClient HTTPClient
backendClient HTTPClient
backendNativeClient HTTPClient
backendClient HTTPClient
}

func NewDockerDesktopClient() (DockerDesktopClient, error) {
socketPaths, err := dockerDesktopSocketPaths()
backendNativeSocketPaths, err := dockerDesktopBackendNativeSocketPaths()
if err != nil {
return DockerDesktopClient{}, err
}

guiClient := &http.Client{
backendNativeClient := &http.Client{
Transport: &http.Transport{
DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
var lastErr error

// Different versions of docker use different socket paths,
// so return all of them and connect to the first one that
// accepts a TCP dial.
for _, socketPath := range socketPaths {
for _, socketPath := range backendNativeSocketPaths {
conn, err := dialDockerDesktop(socketPath)
if err == nil {
return conn, nil
Expand All @@ -63,8 +73,8 @@ func NewDockerDesktopClient() (DockerDesktopClient, error) {
},
}
return DockerDesktopClient{
guiClient: guiClient,
backendClient: backendClient,
backendNativeClient: backendNativeClient,
backendClient: backendClient,
}, nil
}

Expand Down Expand Up @@ -127,7 +137,7 @@ func (c DockerDesktopClient) ResetCluster(ctx context.Context) error {
headers: map[string]string{"Content-Type": "application/json"},
},
{
client: c.guiClient,
client: c.backendNativeClient,
method: "POST",
url: "http://localhost/kubernetes/reset",
headers: map[string]string{"Content-Type": "application/json"},
Expand All @@ -145,7 +155,7 @@ func (c DockerDesktopClient) SettingsValues(ctx context.Context) (interface{}, e
if err != nil {
return nil, err
}
return c.settingsForWrite(s), nil
return c.settingsForWrite(s, ddProtocolV1), nil
}

func (c DockerDesktopClient) SetSettingValue(ctx context.Context, key, newValue string) error {
Expand Down Expand Up @@ -258,27 +268,38 @@ func (c DockerDesktopClient) applySet(settings map[string]interface{}, key, newV
return false, fmt.Errorf("Cannot set key: %q", key)
}

func (c DockerDesktopClient) writeSettings(ctx context.Context, settings map[string]interface{}) error {
func (c DockerDesktopClient) settingsForWriteJSON(settings map[string]interface{}, v ddProtocol) ([]byte, error) {
buf := bytes.NewBuffer(nil)
err := json.NewEncoder(buf).Encode(c.settingsForWrite(settings))
err := json.NewEncoder(buf).Encode(c.settingsForWrite(settings, v))
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}

func (c DockerDesktopClient) writeSettings(ctx context.Context, settings map[string]interface{}) error {
v2Body, err := c.settingsForWriteJSON(settings, ddProtocolV2)
if err != nil {
return errors.Wrap(err, "writing docker-desktop settings")
}
v1Body, err := c.settingsForWriteJSON(settings, ddProtocolV1)
if err != nil {
return errors.Wrap(err, "writing docker-desktop settings")
}
body := buf.Bytes()
resp, err := c.tryRequests("writing docker-desktop settings", []clientRequest{
{
client: c.backendClient,
method: "POST",
url: "http://localhost/app/settings",
headers: map[string]string{"Content-Type": "application/json"},
body: body,
body: v2Body,
},
{
client: c.guiClient,
client: c.backendNativeClient,
method: "POST",
url: "http://localhost/settings",
headers: map[string]string{"Content-Type": "application/json"},
body: body,
body: v1Body,
},
})
if err != nil {
Expand All @@ -296,7 +317,7 @@ func (c DockerDesktopClient) settings(ctx context.Context) (map[string]interface
url: "http://localhost/app/settings",
},
{
client: c.guiClient,
client: c.backendNativeClient,
method: "GET",
url: "http://localhost/settings",
},
Expand Down Expand Up @@ -367,7 +388,7 @@ func (c DockerDesktopClient) ensureMinCPU(settings map[string]interface{}, desir
return true, nil
}

func (c DockerDesktopClient) settingsForWrite(settings interface{}) interface{} {
func (c DockerDesktopClient) settingsForWrite(settings interface{}, v ddProtocol) interface{} {
settingsMap, ok := settings.(map[string]interface{})
if !ok {
return settings
Expand All @@ -376,7 +397,13 @@ func (c DockerDesktopClient) settingsForWrite(settings interface{}) interface{}
_, hasLocked := settingsMap["locked"]
value, hasValue := settingsMap["value"]
if hasLocked && hasValue {
return value
// In the old protocol, we only sent the value back. In the new protocol,
// we send the whole struct.
if v == ddProtocolV1 {
return value
} else {
return settingsMap
}
}

if hasLocked && len(settingsMap) == 1 {
Expand All @@ -390,7 +417,7 @@ func (c DockerDesktopClient) settingsForWrite(settings interface{}) interface{}
}

for key, value := range settingsMap {
newVal := c.settingsForWrite(value)
newVal := c.settingsForWrite(value, v)
if newVal != nil {
settingsMap[key] = newVal
} else {
Expand Down
2 changes: 1 addition & 1 deletion pkg/cluster/docker_desktop_dial.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"github.com/mitchellh/go-homedir"
)

func dockerDesktopSocketPaths() ([]string, error) {
func dockerDesktopBackendNativeSocketPaths() ([]string, error) {
socketDir, err := dockerDesktopSocketDir()
if err != nil {
return nil, err
Expand Down
2 changes: 1 addition & 1 deletion pkg/cluster/docker_desktop_dial_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"gopkg.in/natefinch/npipe.v2"
)

func dockerDesktopSocketPaths() ([]string, error) {
func dockerDesktopBackendNativeSocketPaths() ([]string, error) {
return []string{
`\\.\pipe\dockerBackendNativeApiServer`,
`\\.\pipe\dockerWebApiServer`,
Expand Down
Loading