Skip to content

Commit

Permalink
feat: add support for Intel AMT power control [wip]
Browse files Browse the repository at this point in the history
  • Loading branch information
ammmze committed Dec 21, 2021
1 parent d5f8f4e commit cba3b96
Show file tree
Hide file tree
Showing 10 changed files with 253 additions and 7 deletions.
22 changes: 22 additions & 0 deletions app/sidero-controller-manager/api/v1alpha1/server_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,27 @@ type BMC struct {
Interface string `json:"interface,omitempty"`
}

// AMT defines data about how to talk to the node via the AMT api.
type AMT struct {
// AMT endpoint.
Endpoint string `json:"endpoint"`
// AMT port. Defaults to 16992.
// +optional
Port uint32 `json:"port,omitempty"`
// AMT user value.
// +optional
User string `json:"user,omitempty"`
// Source for the user value. Cannot be used if User is not empty.
// +optional
UserFrom *CredentialSource `json:"userFrom,omitempty"`
// AMT password value.
// +optional
Pass string `json:"pass,omitempty"`
// Source for the password value. Cannot be used if Pass is not empty.
// +optional
PassFrom *CredentialSource `json:"passFrom,omitempty"`
}

// CredentialSource defines a reference to the credential value.
type CredentialSource struct {
SecretKeyRef *SecretKeyRef `json:"secretKeyRef,omitempty"`
Expand Down Expand Up @@ -150,6 +171,7 @@ type ServerSpec struct {
SystemInformation *SystemInformation `json:"system,omitempty"`
CPU *CPUInformation `json:"cpu,omitempty"`
BMC *BMC `json:"bmc,omitempty"`
AMT *AMT `json:"amt,omitempty"`
ManagementAPI *ManagementAPI `json:"managementApi,omitempty"`
ConfigPatches []ConfigPatches `json:"configPatches,omitempty"`
Accepted bool `json:"accepted"`
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,74 @@ spec:
properties:
accepted:
type: boolean
amt:
description: AMT defines data about how to talk to the node via the
AMT api.
properties:
endpoint:
description: AMT endpoint.
type: string
pass:
description: AMT password value.
type: string
passFrom:
description: Source for the password value. Cannot be used if
Pass is not empty.
properties:
secretKeyRef:
description: SecretKeyRef defines a ref to a given key within
a secret.
properties:
key:
description: Key to select
type: string
name:
type: string
namespace:
description: 'Namespace and name of credential secret
nb: can''t use namespacedname here b/c it doesn''t have
json tags in the struct :('
type: string
required:
- key
- name
- namespace
type: object
type: object
port:
description: AMT port. Defaults to 16992.
format: int32
type: integer
user:
description: AMT user value.
type: string
userFrom:
description: Source for the user value. Cannot be used if User
is not empty.
properties:
secretKeyRef:
description: SecretKeyRef defines a ref to a given key within
a secret.
properties:
key:
description: Key to select
type: string
name:
type: string
namespace:
description: 'Namespace and name of credential secret
nb: can''t use namespacedname here b/c it doesn''t have
json tags in the struct :('
type: string
required:
- key
- name
- namespace
type: object
type: object
required:
- endpoint
type: object
bmc:
description: BMC defines data about how to talk to the node via ipmitool.
properties:
Expand Down
64 changes: 64 additions & 0 deletions app/sidero-controller-manager/internal/power/amt/amt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package amt

import (
amt "github.com/ammmze/go-amt"
metalv1alpha1 "github.com/talos-systems/sidero/app/sidero-controller-manager/api/v1alpha1"
"github.com/talos-systems/sidero/app/sidero-controller-manager/internal/power/metal"
)

type Client struct {
AMTClient *amt.Client
}

// NewClient creates an amt client to use.
func NewClient(amtInfo metalv1alpha1.AMT) (*Client, error) {
connection := &amt.Connection{
Host: amtInfo.Endpoint,
Port: amtInfo.Port,
User: amtInfo.User,
Pass: amtInfo.Pass,
}
amtClient, err := amt.NewClient(*connection)
if err != nil {
return nil, err
}
return &Client{
AMTClient: amtClient,
}, nil
}

// Close the client.
func (c *Client) Close() error {
return nil
}

// PowerOn will power on a given machine.
func (c *Client) PowerOn() error {
return c.AMTClient.PowerOn()
}

// PowerOff will power off a given machine.
func (c *Client) PowerOff() error {
return c.AMTClient.PowerOff()
}

// PowerCycle will power cycle a given machine.
func (c *Client) PowerCycle() error {
return c.AMTClient.PowerCycle()
}

// SetPXE makes sure the node will pxe boot next time.
func (c *Client) SetPXE(mode metal.PXEMode) error {
// TODO: not sure how/if we can use the pxe mode
return c.AMTClient.SetPXE()
}

// IsPoweredOn checks current power state.
func (c *Client) IsPoweredOn() (bool, error) {
return c.AMTClient.isPoweredOn()
}

// IsFake returns false.
func (c *Client) IsFake() bool {
return false
}
30 changes: 30 additions & 0 deletions app/sidero-controller-manager/internal/power/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/talos-systems/sidero/app/sidero-controller-manager/api/v1alpha1"
"github.com/talos-systems/sidero/app/sidero-controller-manager/internal/power/amt"
"github.com/talos-systems/sidero/app/sidero-controller-manager/internal/power/api"
"github.com/talos-systems/sidero/app/sidero-controller-manager/internal/power/ipmi"
"github.com/talos-systems/sidero/app/sidero-controller-manager/internal/power/metal"
Expand Down Expand Up @@ -53,6 +54,35 @@ func NewManagementClient(ctx context.Context, client client.Client, spec *v1alph
}

return ipmi.NewClient(bmcSpec)
case spec.AMT != nil:
var err error

amtSpec := *spec.AMT

if amtSpec.User == "" {
amtSpec.User, err = amtSpec.UserFrom.Resolve(ctx, client)
if err != nil {
return nil, err
}
}

if amtSpec.Pass == "" {
amtSpec.Pass, err = amtSpec.PassFrom.Resolve(ctx, client)
if err != nil {
return nil, err
}
}

if amtSpec.User == "" || amtSpec.Pass == "" {
// no username and password, BMC information is not fully populated yet
return fakeClient{}, nil
}

if amtSpec.Port == 0 {
amtSpec.Port = constants.DefaultAMTPort
}

return amt.NewClient(amtSpec)
case spec.ManagementAPI != nil:
return api.NewClient(*spec.ManagementAPI)
default:
Expand Down
1 change: 1 addition & 0 deletions app/sidero-controller-manager/pkg/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const (
DefaultServerRebootTimeout = time.Minute * 20

DefaultBMCPort = uint32(623)
DefaultAMTPort = uint32(16992)

SideroLinkInternalAPIEndpoint = "localhost:4000"
)
12 changes: 9 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ go 1.17
replace github.com/pensando/goipmi v0.0.0-20200303170213-e858ec1cf0b5 => github.com/talos-systems/goipmi v0.0.0-20211214143420-35f956689e67

require (
github.com/VictorLowther/simplexml v0.0.0-20180716164440-0bff93621230
github.com/ammmze/wsman v0.0.2
github.com/evanphx/json-patch v5.6.0+incompatible
github.com/ghodss/yaml v1.0.0
github.com/go-logr/logr v0.4.0
Expand All @@ -31,7 +33,7 @@ require (
go.uber.org/zap v1.19.0
golang.org/x/net v0.0.0-20211108170745-6635138e15ea
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20211109184856-51b60fd695b3
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20211109202428-0073765f69ba
google.golang.org/grpc v1.42.0
google.golang.org/protobuf v1.27.1
Expand All @@ -49,6 +51,8 @@ require (
cloud.google.com/go v0.93.3 // indirect
github.com/AlekSi/pointer v1.2.0 // indirect
github.com/BurntSushi/toml v0.4.1 // indirect
github.com/VictorLowther/soap v0.0.0-20150314151524-8e36fca84b22 // indirect
github.com/ammmze/go-amt v0.0.4 // indirect
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver v3.5.1+incompatible // indirect
Expand Down Expand Up @@ -90,6 +94,7 @@ require (
github.com/prometheus/common v0.26.0 // indirect
github.com/prometheus/procfs v0.7.2 // indirect
github.com/ryanuber/go-glob v1.0.0 // indirect
github.com/satori/go.uuid v1.2.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.3.0 // indirect
github.com/talos-systems/crypto v0.3.4 // indirect
Expand All @@ -98,12 +103,13 @@ require (
go4.org/intern v0.0.0-20211027215823-ae77deb06f29 // indirect
go4.org/unsafe/assume-no-moving-gc v0.0.0-20211027215541-db492cf91b37 // indirect
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa // indirect
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect
golang.org/x/mod v0.5.1 // indirect
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f // indirect
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
golang.org/x/text v0.3.6 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
golang.org/x/tools v0.1.7 // indirect
golang.org/x/tools v0.1.8 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
golang.zx2c4.com/go118/netip v0.0.0-20211106132939-9d41d90554dd // indirect
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect
Expand Down
Loading

0 comments on commit cba3b96

Please sign in to comment.