125 lines
2.5 KiB
Go
125 lines
2.5 KiB
Go
package main
|
|
|
|
import (
|
|
"io"
|
|
"net/http"
|
|
|
|
"entanglement.garden/common/cloudinit"
|
|
"github.com/sirupsen/logrus"
|
|
"gopkg.in/yaml.v2"
|
|
)
|
|
|
|
var (
|
|
httpStaticContent = map[string][]byte{}
|
|
)
|
|
|
|
func runHTTPServer(bind string) {
|
|
logrus.WithField("bind", bind).Debug("starting temporary HTTP server")
|
|
http.ListenAndServe(bind, httphandler{})
|
|
}
|
|
|
|
type httphandler struct{}
|
|
|
|
func (httphandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
log := logrus.WithFields(logrus.Fields{
|
|
"method": r.Method,
|
|
"path": r.URL,
|
|
"remote_addr": r.RemoteAddr,
|
|
})
|
|
|
|
log.Debug("handling HTTP request")
|
|
|
|
switch r.Method {
|
|
case http.MethodGet:
|
|
resp, ok := httpStaticContent[r.URL.Path]
|
|
if !ok {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
if resp == nil {
|
|
w.WriteHeader(http.StatusNoContent)
|
|
return
|
|
}
|
|
|
|
_, err := w.Write(resp)
|
|
if err != nil {
|
|
log.WithError(err).Error("error serving HTTP response")
|
|
}
|
|
|
|
case http.MethodPost:
|
|
printRequestBody(r)
|
|
log.Info("VM booted")
|
|
w.WriteHeader(http.StatusNoContent)
|
|
wg.Done()
|
|
|
|
default:
|
|
w.WriteHeader(http.StatusNotFound)
|
|
w.Write([]byte("not found"))
|
|
}
|
|
|
|
}
|
|
|
|
func buildCloudConfig(base cloudinit.UserData, name string, phoneHomeURL string) error {
|
|
userdata, err := yaml.Marshal(base)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
httpStaticContent["/user-data"] = append([]byte("#cloud-config\n"), userdata...)
|
|
|
|
metadata, err := yaml.Marshal(cloudinit.MetaData{
|
|
InstanceID: name,
|
|
LocalHostname: name,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
httpStaticContent["/meta-data"] = metadata
|
|
|
|
vendorData, err := yaml.Marshal(cloudinit.UserData{
|
|
PhoneHome: cloudinit.PhoneHome{
|
|
URL: phoneHomeURL,
|
|
Post: []string{"pub_key_dsa", "pub_key_rsa", "pub_key_ed25519", "fqdn"},
|
|
},
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
httpStaticContent["/vendor-data"] = vendorData
|
|
|
|
return nil
|
|
}
|
|
|
|
func printRequestBody(r *http.Request) {
|
|
log := logrus.WithFields(logrus.Fields{
|
|
"method": r.Method,
|
|
"path": r.URL,
|
|
"remote_addr": r.RemoteAddr,
|
|
})
|
|
|
|
switch r.Header.Get("Content-Type") {
|
|
case "application/x-www-form-urlencoded":
|
|
if err := r.ParseForm(); err != nil {
|
|
logrus.WithError(err).Error("error parsing request body")
|
|
return
|
|
}
|
|
fields := logrus.Fields{}
|
|
for k, v := range r.Form {
|
|
if len(v) == 1 {
|
|
fields[k] = v[0]
|
|
} else {
|
|
fields[k] = v
|
|
}
|
|
}
|
|
log.WithFields(fields).Debug("form request body")
|
|
default:
|
|
body, err := io.ReadAll(r.Body)
|
|
if err != nil {
|
|
log.WithError(err).Error("error reading body")
|
|
}
|
|
r.Body.Close()
|
|
|
|
log.Debug(string(body))
|
|
}
|
|
|
|
}
|