Andrey Smirnov 96aa9638f7
chore: rename talos-systems/talos to siderolabs/talos
There's a cyclic dependency on siderolink library which imports talos
machinery back. We will fix that after we get talos pushed under a new
name.

Signed-off-by: Andrey Smirnov <andrey.smirnov@talos-systems.com>
2022-11-03 16:50:32 +04:00

144 lines
3.2 KiB
Go

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package vm
import (
"encoding/json"
"fmt"
"io"
"net/http"
"net/netip"
"os"
"os/signal"
"syscall"
"github.com/siderolabs/talos/pkg/machinery/nethelpers"
"github.com/siderolabs/talos/pkg/provision/internal/inmemhttp"
)
// ReadConfig loads configuration from stdin.
func ReadConfig(config interface{}) error {
d := json.NewDecoder(os.Stdin)
if err := d.Decode(config); err != nil {
return fmt.Errorf("error decoding config from stdin: %w", err)
}
if d.More() {
return fmt.Errorf("extra unexpected input on stdin")
}
return os.Stdin.Close()
}
// ConfigureSignals configures signal handling for the process.
func ConfigureSignals() chan os.Signal {
signal.Ignore(syscall.SIGHUP)
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGTERM, syscall.SIGINT)
return c
}
func httpPostWrapper(f func() error) http.Handler {
return http.HandlerFunc(
func(w http.ResponseWriter, req *http.Request) {
if req.Body != nil {
_, _ = io.Copy(io.Discard, req.Body) //nolint:errcheck
req.Body.Close() //nolint:errcheck
}
if req.Method != http.MethodPost {
w.WriteHeader(http.StatusNotImplemented)
return
}
err := f()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprint(w, err.Error())
return
}
w.WriteHeader(http.StatusOK)
},
)
}
func httpGetWrapper(f func(w io.Writer)) http.Handler {
return http.HandlerFunc(
func(w http.ResponseWriter, req *http.Request) {
if req.Body != nil {
_, _ = io.Copy(io.Discard, req.Body) //nolint:errcheck
req.Body.Close() //nolint:errcheck
}
switch req.Method {
case http.MethodHead:
w.Header().Add("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
case http.MethodGet:
w.Header().Add("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
f(w)
default:
w.WriteHeader(http.StatusNotImplemented)
}
},
)
}
// NewHTTPServer creates new inmemhttp.Server and mounts config file into it.
func NewHTTPServer(gatewayAddr netip.Addr, port int, config []byte, controller Controller) (inmemhttp.Server, error) {
httpServer, err := inmemhttp.NewServer(nethelpers.JoinHostPort(gatewayAddr.String(), port))
if err != nil {
return nil, fmt.Errorf("error launching in-memory HTTP server: %w", err)
}
if err = httpServer.AddFile("config.yaml", config); err != nil {
return nil, err
}
if controller != nil {
for _, method := range []struct {
pattern string
f func() error
}{
{
pattern: "/poweron",
f: controller.PowerOn,
},
{
pattern: "/poweroff",
f: controller.PowerOff,
},
{
pattern: "/reboot",
f: controller.Reboot,
},
{
pattern: "/pxeboot",
f: controller.PXEBootOnce,
},
} {
httpServer.AddHandler(method.pattern, httpPostWrapper(method.f))
}
httpServer.AddHandler(
"/status", httpGetWrapper(
func(w io.Writer) {
json.NewEncoder(w).Encode(controller.Status()) //nolint:errcheck,errchkjson
},
),
)
}
return httpServer, nil
}