This repository has been archived by the owner on Jul 11, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 277
/
util.go
179 lines (149 loc) · 5.67 KB
/
util.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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
package k8s
import (
"fmt"
"strings"
goversion "github.com/hashicorp/go-version"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes"
"github.com/openservicemesh/osm/pkg/service"
)
// GetHostnamesForService returns the hostnames over which the service is accessible
func GetHostnamesForService(svc service.MeshService, localNamespace bool) []string {
var hostnames []string
if localNamespace {
hostnames = append(hostnames, []string{
svc.Name, // service
fmt.Sprintf("%s:%d", svc.Name, svc.Port), // service:port
}...)
}
hostnames = append(hostnames, []string{
fmt.Sprintf("%s.%s", svc.Name, svc.Namespace), // service.namespace
fmt.Sprintf("%s.%s:%d", svc.Name, svc.Namespace, svc.Port), // service.namespace:port
fmt.Sprintf("%s.%s.svc", svc.Name, svc.Namespace), // service.namespace.svc
fmt.Sprintf("%s.%s.svc:%d", svc.Name, svc.Namespace, svc.Port), // service.namespace.svc:port
fmt.Sprintf("%s.%s.svc.cluster", svc.Name, svc.Namespace), // service.namespace.svc.cluster
fmt.Sprintf("%s.%s.svc.cluster:%d", svc.Name, svc.Namespace, svc.Port), // service.namespace.svc.cluster:port
fmt.Sprintf("%s.%s.svc.cluster.local", svc.Name, svc.Namespace), // service.namespace.svc.cluster.local
fmt.Sprintf("%s.%s.svc.cluster.local:%d", svc.Name, svc.Namespace, svc.Port), // service.namespace.svc.cluster.local:port
}...)
return hostnames
}
// splitHostName takes a k8s FQDN (i.e. host) and retrieves the service name
// as well as the subdomain (may be empty)
func splitHostName(c Controller, host string) (svc string, subdomain string) {
host = strings.Split(host, ":")[0] // chop port off the end
serviceComponents := strings.Split(host, ".")
// The service name is usually the first string in the host name for a service.
// Ex. service.namespace, service.namespace.svc.cluster.local
// However, if there's a subdomain, we the service name is the second string.
// Ex. mysql-0.service.namespace, mysql-0.service.namespace.svc.cluster.local, mysql-0.service.namespace.svc.cluster.local
switch l := len(serviceComponents); {
case l == 1:
// e.g. service
svc = serviceComponents[0]
subdomain = ""
case l == 2:
// e.g. service.namespace, mysql-0.service
p1 := serviceComponents[0] // service name or pod name
p2 := serviceComponents[1] // namespace name or service name
// by default, assume service.namespace
svc = p1
subdomain = ""
if c == nil {
// no controller was passed in; default to non-heuristic behavior
return
}
ns := c.GetNamespace(p2)
if ns == nil {
// namespace not present in cache/doesn't exist; this is probably subdomain.service
subdomain = p1
svc = p2
return
}
// namespace does exist in the cache, so this is service.namespace
case l == 3:
tld := serviceComponents[2]
if c == nil {
// use a more basic heuristic since we don't have a kubecontroller
if tld == "svc" {
// e.g. service.namespace.svc
svc = serviceComponents[0]
subdomain = ""
return
}
// e.g. mysql-0.service.namespace
svc = serviceComponents[1]
subdomain = serviceComponents[0]
return
}
ns := c.GetNamespace(tld)
if ns == nil {
// tld isn't a namespace; so this is service.namespace.svc
svc = serviceComponents[0]
subdomain = ""
return
}
// tld is a namespace, so this is mysql-0.service.namespace
svc = serviceComponents[1]
subdomain = serviceComponents[0]
case l == 4:
// e.g mysql-0.service.namespace.svc
svc = serviceComponents[1]
subdomain = serviceComponents[0]
case l == 5:
// e.g. service.namespace.svc.cluster.local
svc = serviceComponents[0]
subdomain = ""
case l == 6:
// e.g. mysql-0.service.namespace.svc.cluster.local
svc = serviceComponents[1]
subdomain = serviceComponents[0]
default:
svc = serviceComponents[0]
subdomain = ""
}
return
}
// GetServiceFromHostname returns the service name from its hostname
// This assumes the default k8s trustDomain: cluster.local
func GetServiceFromHostname(c Controller, host string) string {
svc, _ := splitHostName(c, host)
return svc
}
// GetSubdomainFromHostname returns the service subdomain from its hostname
// This assumes the default k8s trustDomain: cluster.local
func GetSubdomainFromHostname(c Controller, host string) string {
_, subdomain := splitHostName(c, host)
return subdomain
}
// GetKubernetesServerVersionNumber returns the Kubernetes server version number in chunks, ex. v1.19.3 => [1, 19, 3]
func GetKubernetesServerVersionNumber(kubeClient kubernetes.Interface) ([]int, error) {
if kubeClient == nil {
return nil, fmt.Errorf("Kubernetes client is not initialized")
}
version, err := kubeClient.Discovery().ServerVersion()
if err != nil {
return nil, fmt.Errorf("Error getting K8s server version: %w", err)
}
ver, err := goversion.NewVersion(version.String())
if err != nil {
return nil, fmt.Errorf("Error parsing k8s server version %s: %w", version, err)
}
return ver.Segments(), nil
}
// NamespacedNameFrom returns the namespaced name for the given name if possible, otherwise an error
func NamespacedNameFrom(name string) (types.NamespacedName, error) {
var nsName types.NamespacedName
chunks := strings.Split(name, "/")
if len(chunks) != 2 {
return nsName, fmt.Errorf("%s is not a namespaced name", name)
}
nsName.Namespace = chunks[0]
nsName.Name = chunks[1]
return nsName, nil
}
// IsHeadlessService determines whether or not a corev1.Service is a headless service
func IsHeadlessService(svc corev1.Service) bool {
return len(svc.Spec.ClusterIP) == 0 || svc.Spec.ClusterIP == corev1.ClusterIPNone
}