forked from openshift/origin
-
Notifications
You must be signed in to change notification settings - Fork 1
/
helpers.go
151 lines (129 loc) · 4.95 KB
/
helpers.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
package login
import (
"bytes"
"crypto/x509"
"fmt"
"io"
"net"
"net/http"
"net/url"
"os"
"github.com/openshift/origin/pkg/client"
userapi "github.com/openshift/origin/pkg/user/apis/user"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"github.com/openshift/origin/pkg/cmd/util/term"
kerrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/sets"
restclient "k8s.io/client-go/rest"
kclientcmdapi "k8s.io/client-go/tools/clientcmd/api"
kterm "k8s.io/kubernetes/pkg/util/term"
)
// getMatchingClusters examines the kubeconfig for all clusters that point to the same server
func getMatchingClusters(clientConfig restclient.Config, kubeconfig clientcmdapi.Config) sets.String {
ret := sets.String{}
for key, cluster := range kubeconfig.Clusters {
if (cluster.Server == clientConfig.Host) && (cluster.InsecureSkipTLSVerify == clientConfig.Insecure) && (cluster.CertificateAuthority == clientConfig.CAFile) && (bytes.Compare(cluster.CertificateAuthorityData, clientConfig.CAData) == 0) {
ret.Insert(key)
}
}
return ret
}
// findExistingClientCA returns *either* the existing client CA file name as a string,
// *or* data in a []byte for a given host, and true if it exists in the given config
func findExistingClientCA(host string, kubeconfig clientcmdapi.Config) (string, []byte, bool) {
for _, cluster := range kubeconfig.Clusters {
if cluster.Server == host {
if len(cluster.CertificateAuthority) > 0 {
return cluster.CertificateAuthority, nil, true
}
if len(cluster.CertificateAuthorityData) > 0 {
return "", cluster.CertificateAuthorityData, true
}
}
}
return "", nil, false
}
// dialToServer takes the Server URL from the given clientConfig and dials to
// make sure the server is reachable. Note the config received is not mutated.
func dialToServer(clientConfig restclient.Config) error {
// take a RoundTripper based on the config we already have (TLS, proxies, etc)
rt, err := restclient.TransportFor(&clientConfig)
if err != nil {
return err
}
parsedURL, err := url.Parse(clientConfig.Host)
if err != nil {
return err
}
// Do a HEAD request to serverPathToDial to make sure the server is alive.
// We don't care about the response, any err != nil is valid for the sake of reachability.
serverURLToDial := (&url.URL{Scheme: parsedURL.Scheme, Host: parsedURL.Host, Path: "/"}).String()
req, err := http.NewRequest("HEAD", serverURLToDial, nil)
if err != nil {
return err
}
res, err := rt.RoundTrip(req)
if err != nil {
return err
}
defer res.Body.Close()
return nil
}
func promptForInsecureTLS(reader io.Reader, out io.Writer, reason error) bool {
var insecureTLSRequestReason string
if reason != nil {
switch reason.(type) {
case x509.UnknownAuthorityError:
insecureTLSRequestReason = "The server uses a certificate signed by an unknown authority."
case x509.HostnameError:
insecureTLSRequestReason = fmt.Sprintf("The server is using a certificate that does not match its hostname: %s", reason.Error())
case x509.CertificateInvalidError:
insecureTLSRequestReason = fmt.Sprintf("The server is using an invalid certificate: %s", reason.Error())
}
}
var input bool
if kterm.IsTerminal(reader) {
if len(insecureTLSRequestReason) > 0 {
fmt.Fprintln(out, insecureTLSRequestReason)
}
fmt.Fprintln(out, "You can bypass the certificate check, but any data you send to the server could be intercepted by others.")
input = term.PromptForBool(os.Stdin, out, "Use insecure connections? (y/n): ")
fmt.Fprintln(out)
}
return input
}
func hasExistingInsecureCluster(clientConfigToTest restclient.Config, kubeconfig kclientcmdapi.Config) bool {
clientConfigToTest.Insecure = true
matchingClusters := getMatchingClusters(clientConfigToTest, kubeconfig)
return len(matchingClusters) > 0
}
// getHostPort returns the host and port parts of the given URL string. It's
// expected that the provided URL is already normalized (always has host and port).
func getHostPort(hostURL string) (string, string, *url.URL, error) {
parsedURL, err := url.Parse(hostURL)
if err != nil {
return "", "", nil, err
}
host, port, err := net.SplitHostPort(parsedURL.Host)
return host, port, parsedURL, err
}
func whoAmI(clientConfig *restclient.Config) (*userapi.User, error) {
client, err := client.New(clientConfig)
me, err := client.Users().Get("~", metav1.GetOptions{})
// if we're talking to kube (or likely talking to kube),
if kerrors.IsNotFound(err) || kerrors.IsForbidden(err) {
switch {
case len(clientConfig.BearerToken) > 0:
// the user has already been willing to provide the token on the CLI, so they probably
// don't mind using it again if they switch to and from this user
return &userapi.User{ObjectMeta: metav1.ObjectMeta{Name: clientConfig.BearerToken}}, nil
case len(clientConfig.Username) > 0:
return &userapi.User{ObjectMeta: metav1.ObjectMeta{Name: clientConfig.Username}}, nil
}
}
if err != nil {
return nil, err
}
return me, nil
}