mkvm/http.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))
}
}