This repository has been archived by the owner on Jun 13, 2021. It is now read-only.
/
dockerdesktop.go
153 lines (138 loc) · 4.21 KB
/
dockerdesktop.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package commands
import (
"fmt"
"net/url"
"runtime"
"github.com/pkg/errors"
"github.com/docker/cli/cli/context/docker"
"github.com/docker/cli/cli/context/kubernetes"
"github.com/docker/cli/cli/context/store"
"github.com/docker/docker/client"
apiv1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1 "k8s.io/client-go/kubernetes/typed/core/v1"
)
type dockerDesktopHostProvider func() (string, bool)
func defaultDockerDesktopHostProvider() (string, bool) {
switch runtime.GOOS {
case "windows", "darwin":
default:
// platforms other than windows or mac can't be Docker Desktop
return "", false
}
return client.DefaultDockerHost, true
}
type dockerDesktopLinuxKitIPProvider func() (string, error)
type dockerDesktopDockerEndpointRewriter struct {
defaultHostProvider dockerDesktopHostProvider
}
func (r *dockerDesktopDockerEndpointRewriter) rewrite(ep *docker.EndpointMeta) {
defaultHost, isDockerDesktop := r.defaultHostProvider()
if !isDockerDesktop {
return
}
// on docker desktop, any context with host="" or host=<default host> should be rewritten as host="unix:///var/run/docker.sock" (docker socket path within the linuxkit VM)
if ep.Host == "" || ep.Host == defaultHost {
ep.Host = "unix:///var/run/docker.sock"
}
}
type dockerDesktopKubernetesEndpointRewriter struct {
defaultHostProvider dockerDesktopHostProvider
linuxKitIPProvider dockerDesktopLinuxKitIPProvider
}
func (r *dockerDesktopKubernetesEndpointRewriter) rewrite(ep *kubernetes.EndpointMeta) {
// any error while rewriting makes as if no rewriting rule applies
if _, isDockerDesktop := r.defaultHostProvider(); !isDockerDesktop {
return
}
// if the kube endpoint host points to localhost or 127.0.0.1, we need to rewrite it to whatever is linuxkit VM IP is (with port 6443)
hostURL, err := url.Parse(ep.Host)
if err != nil {
return
}
hostName := hostURL.Hostname()
switch hostName {
case "localhost", "127.0.0.1":
default:
// we are on a context targeting a remote Kubernetes cluster, nothing to rewrite
return
}
ip, err := r.linuxKitIPProvider()
if err != nil {
return
}
ep.Host = fmt.Sprintf("https://%s:6443", ip)
}
func makeLinuxkitIPProvider(contextName string, s store.Store) dockerDesktopLinuxKitIPProvider {
return func() (string, error) {
clientCfg, err := kubernetes.ConfigFromContext(contextName, s)
if err != nil {
return "", err
}
restCfg, err := clientCfg.ClientConfig()
if err != nil {
return "", err
}
coreClient, err := v1.NewForConfig(restCfg)
if err != nil {
return "", err
}
nodes, err := coreClient.Nodes().List(metav1.ListOptions{})
if err != nil {
return "", err
}
if len(nodes.Items) == 0 {
return "", errors.New("no node found")
}
for _, address := range nodes.Items[0].Status.Addresses {
if address.Type == apiv1.NodeInternalIP {
return address.Address, nil
}
}
return "", errors.New("no ip found")
}
}
func rewriteContextIfDockerDesktop(meta *store.ContextMetadata, s store.Store) {
// errors are treated as "don't rewrite"
rewriter := dockerDesktopDockerEndpointRewriter{
defaultHostProvider: defaultDockerDesktopHostProvider,
}
dockerEp, err := docker.EndpointFromContext(*meta)
if err != nil {
return
}
rewriter.rewrite(&dockerEp)
meta.Endpoints[docker.DockerEndpoint] = dockerEp
kubeEp := kubernetes.EndpointFromContext(*meta)
if kubeEp == nil {
return
}
kubeRewriter := dockerDesktopKubernetesEndpointRewriter{
defaultHostProvider: defaultDockerDesktopHostProvider,
linuxKitIPProvider: makeLinuxkitIPProvider(meta.Name, s),
}
kubeRewriter.rewrite(kubeEp)
meta.Endpoints[kubernetes.KubernetesEndpoint] = *kubeEp
}
type dockerDesktopAwareStore struct {
store.Store
}
func (s dockerDesktopAwareStore) ListContexts() ([]store.ContextMetadata, error) {
contexts, err := s.Store.ListContexts()
if err != nil {
return nil, err
}
for ix, c := range contexts {
rewriteContextIfDockerDesktop(&c, s.Store)
contexts[ix] = c
}
return contexts, nil
}
func (s dockerDesktopAwareStore) GetContextMetadata(name string) (store.ContextMetadata, error) {
context, err := s.Store.GetContextMetadata(name)
if err != nil {
return store.ContextMetadata{}, err
}
rewriteContextIfDockerDesktop(&context, s.Store)
return context, nil
}