mirror of
https://github.com/siderolabs/talos.git
synced 2025-10-08 14:11:13 +02:00
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>
144 lines
3.2 KiB
Go
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
|
|
}
|