/
metadata.go
135 lines (121 loc) · 3.62 KB
/
metadata.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
// Package metadata contains all the meta data used by the agent in registration protocol
package agent
import (
"errors"
"io/ioutil"
"net"
"net/http"
"os"
"runtime"
"strconv"
"time"
"github.com/neptuneio/agent/logging"
)
// Host meta data used by the agent in registration protocol.
type HostMetaData struct {
HostName string
AssignedHostname string
ProviderId string
ProviderType string
Platform string
PrivateIpAddress string
PrivateDnsName string
PublicIpAddress string
PublicDnsName string
Region string
}
// Helper function to query the given URL and give back the response.
func queryData(url string) (string, error) {
timeout := time.Duration(5 * time.Second)
client := http.Client{
Timeout: timeout,
}
logging.Debug("Querying the url for cloud metadata.", logging.Fields{"url": url})
resp, err := client.Get(url)
if err != nil {
logging.Warn("Could not query cloud metadata.", logging.Fields{
"url": url,
"error": err,
"response": resp,
})
return "", err
}
if 200 <= resp.StatusCode && resp.StatusCode <= 299 {
defer resp.Body.Close()
contents, err := ioutil.ReadAll(resp.Body)
if err != nil {
logging.Warn("Could not read response.", logging.Fields{"url": url, "error": err})
return "", errors.New("Could not read response.")
}
return string(contents), nil
} else {
return "", errors.New("Server returned unexpected status: " + strconv.Itoa(resp.StatusCode))
}
}
// Returns the non loopback local IP of the host
func getLocalIP() string {
addrs, err := net.InterfaceAddrs()
if err != nil {
return ""
}
for _, address := range addrs {
// check the address type and if it is not a loopback the display it
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
if ipnet.IP.To4() != nil {
return ipnet.IP.String()
}
}
}
return ""
}
// Function to get the complete meta data for the host on which agent is running.
// This method tries to get cloud specific meta data also, in case the machine is in a cloud.
func GetHostMetaData(agentConfig *AgentConfig) (HostMetaData, error) {
logging.Debug("Getting host metadata.", nil)
hostname, e := os.Hostname()
if e != nil {
logging.Error("Could not get host name.", logging.Fields{"error": e})
os.Exit(1)
}
privateIp := getLocalIP()
publicIp, e := queryData("http://ip.42.pl/raw")
platform := string(runtime.GOOS) + " " + string(runtime.GOARCH)
var privateDns string
if addr, err := net.LookupAddr(privateIp); err == nil && len(addr) > 0 {
privateDns = addr[0]
} else {
logging.Warn("Could not get private DNS name.", logging.Fields{"error": err})
}
var publicDns string
if addr, err := net.LookupAddr(publicIp); err == nil && len(addr) > 0 {
publicDns = addr[0]
} else {
logging.Warn("Could not get public DNS name.", logging.Fields{"error": err})
}
var providerServerId string
var providerType string
var region string
providerServerId, e = queryData("http://169.254.169.254/latest/meta-data/instance-id")
if e == nil && len(providerServerId) > 0 {
providerType = "AWS"
regionValue, e := queryData("http://169.254.169.254/latest/meta-data/placement/availability-zone")
if e != nil && len(regionValue) > 0 {
region = regionValue
}
} else {
providerType = "NON_AWS"
}
data := HostMetaData{
HostName: hostname,
AssignedHostname: agentConfig.AssignedHostname,
PrivateIpAddress: privateIp,
PublicIpAddress: publicIp,
Platform: platform,
PrivateDnsName: privateDns,
PublicDnsName: publicDns,
ProviderId: providerServerId,
ProviderType: providerType,
Region: region,
}
return data, nil
}