mirror of
https://github.com/siderolabs/sidero.git
synced 2025-08-06 22:57:08 +02:00
Rename to siderolabs, bump dependencies, controller-runtime, get rid of netaddr, new SideroLink API, etc. Use bootstrap cluster with a control plane + worker to avoid nasty restarts when host-mode SideroLink IP pops up. Signed-off-by: Andrey Smirnov <andrey.smirnov@talos-systems.com>
142 lines
3.1 KiB
Go
142 lines
3.1 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 api provides metal machine management via API.
|
|
package api
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"time"
|
|
|
|
metalv1 "github.com/siderolabs/sidero/app/sidero-controller-manager/api/v1alpha2"
|
|
"github.com/siderolabs/sidero/app/sidero-controller-manager/pkg/types"
|
|
)
|
|
|
|
// Client provides management over simple API.
|
|
type Client struct {
|
|
endpoint string
|
|
}
|
|
|
|
// NewClient returns new API client to manage metal machine.
|
|
func NewClient(spec metalv1.ManagementAPI) (*Client, error) {
|
|
return &Client{
|
|
endpoint: spec.Endpoint,
|
|
}, nil
|
|
}
|
|
|
|
// Close the client.
|
|
func (c *Client) Close() error {
|
|
return nil
|
|
}
|
|
|
|
func (c *Client) postRequest(path string) error {
|
|
failureMode := DefaultDice.Roll()
|
|
|
|
switch failureMode { //nolint:exhaustive
|
|
case ExplicitFailure:
|
|
return fmt.Errorf("simulated failure from the power management")
|
|
case SilentFailure:
|
|
// don't do anything
|
|
return nil
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, fmt.Sprintf("http://%s%s", c.endpoint, path), nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if resp.Body != nil {
|
|
defer func() {
|
|
_, _ = io.Copy(io.Discard, resp.Body)
|
|
resp.Body.Close()
|
|
}()
|
|
}
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
return fmt.Errorf("API error: %s", resp.Status)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// PowerOn will power on a given machine.
|
|
func (c *Client) PowerOn() error {
|
|
return c.postRequest("/poweron")
|
|
}
|
|
|
|
// PowerOff will power off a given machine.
|
|
func (c *Client) PowerOff() error {
|
|
return c.postRequest("/poweroff")
|
|
}
|
|
|
|
// PowerCycle will power cycle a given machine.
|
|
func (c *Client) PowerCycle() error {
|
|
return c.postRequest("/reboot")
|
|
}
|
|
|
|
// SetPXE makes sure the node will pxe boot next time.
|
|
func (c *Client) SetPXE(mode types.PXEMode) error {
|
|
// no way to enforce mode via QEMU API
|
|
return c.postRequest("/pxeboot")
|
|
}
|
|
|
|
// IsPoweredOn checks current power state.
|
|
func (c *Client) IsPoweredOn() (bool, error) {
|
|
failureMode := DefaultDice.Roll()
|
|
|
|
switch failureMode { //nolint:exhaustive
|
|
case ExplicitFailure:
|
|
return false, fmt.Errorf("simulated failure from the power management")
|
|
case SilentFailure:
|
|
return time.Now().Second()%2 == 0, nil
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("http://%s/status", c.endpoint), nil)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
if resp.Body != nil {
|
|
defer func() {
|
|
_, _ = io.Copy(io.Discard, resp.Body)
|
|
resp.Body.Close()
|
|
}()
|
|
}
|
|
|
|
var status struct {
|
|
PoweredOn bool
|
|
}
|
|
|
|
if err = json.NewDecoder(resp.Body).Decode(&status); err != nil {
|
|
return false, err
|
|
}
|
|
|
|
return status.PoweredOn, nil
|
|
}
|
|
|
|
// IsFake returns false.
|
|
func (c *Client) IsFake() bool {
|
|
return false
|
|
}
|