forked from inc0/cloud-init-server
-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.go
131 lines (116 loc) · 3.16 KB
/
main.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
package main
import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"net/http"
"os"
"path"
"strings"
yaml "gopkg.in/yaml.v2"
)
var configpath string
// MacNotFoundError error thrown when mac is not found in arp table
type MacNotFoundError struct {
Msg string
}
func (e *MacNotFoundError) Error() string {
return fmt.Sprintf(e.Msg)
}
func fileExists(filename string) bool {
info, err := os.Stat(filename)
if os.IsNotExist(err) {
return false
}
return !info.IsDir()
}
func getConfig(r *http.Request) (map[string]interface{}, error) {
var data []byte
var err error
remoteaddr := r.Header.Get("X-Forwarded-For")
if remoteaddr == "" {
remoteaddr = strings.Split(r.RemoteAddr, ":")[0]
}
addressconfig := path.Join(configpath, remoteaddr)
defaultconfig := path.Join(configpath, "default")
if fileExists(addressconfig) {
data, err = ioutil.ReadFile(addressconfig)
if err != nil {
return nil, err
}
} else { //fallback to default
data, err = ioutil.ReadFile(defaultconfig)
if err != nil {
return nil, err
}
}
var config map[string]interface{}
err = json.Unmarshal(data, &config)
if err != nil {
return nil, err
}
return config, nil
}
func metadata(w http.ResponseWriter, r *http.Request) {
dirname, filename := path.Split(r.URL.Path)
if dirname != "/latest/meta-data/" && dirname != "/2009-04-04/meta-data/" {
w.WriteHeader(http.StatusNotFound)
return
}
if filename == "instance-id" {
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "iid-datasource-cloudstack")
return
}
config, err := getConfig(r)
if err != nil {
fmt.Println("Failed to get metadata", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
metadata := config["meta-data"].(map[string]interface{})
w.WriteHeader(http.StatusOK)
if filename == "" {
fmt.Fprintln(w, "instance-id")
for key := range metadata {
fmt.Fprintln(w, key)
}
} else {
fmt.Fprintf(w, metadata[filename].(string))
}
}
func userData(w http.ResponseWriter, r *http.Request) {
config, err := getConfig(r)
if err != nil {
fmt.Println("Failed to get user-data metadata", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
userdata := config["user-data"].(map[string]interface{})
userdata["datasource"] = map[string]map[string]bool{"Ec2": {"strict_id": false}}
userdatabytes, err := yaml.Marshal(userdata)
if err != nil {
fmt.Println("Failed to get user-data metadata", err)
w.WriteHeader(http.StatusInternalServerError)
}
data := "#cloud-config\n" + string(userdatabytes)
w.Header().Set("Content-Type", "text/yaml")
w.WriteHeader(http.StatusOK)
w.Write([]byte(data))
}
func main() {
var bind string
flag.StringVar(&bind, "bind", ":80", "Address to bind on defaults to :80")
flag.StringVar(&configpath, "config", "/etc/cloud-init", "Path to put cloud-init config files in")
flag.Parse()
if _, err := os.Stat(configpath); os.IsNotExist(err) {
fmt.Printf("Config path %s does not exists\n", configpath)
os.Exit(1)
}
http.HandleFunc("/2009-04-04/meta-data/", metadata)
http.HandleFunc("/latest/meta-data/", metadata)
http.HandleFunc("/2009-04-04/user-data", userData)
http.HandleFunc("/latest/user-data", userData)
http.ListenAndServe(bind, nil)
}