-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update machine controller to implement provider opts:
This makes the provider opts in the CRD operational via the bmclib client. Rename pkg; controllers -> controller: this is the preferred practive in Go. Added a requeue interval. Signed-off-by: Jacob Weinstock <jakobweinstock@gmail.com>
- Loading branch information
1 parent
1656c1c
commit 70c2f54
Showing
18 changed files
with
403 additions
and
218 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
apiVersion: v1 | ||
kind: Secret | ||
metadata: | ||
name: secret1 | ||
type: Opaque | ||
data: # echo -n 'superSecret1' | base64; | ||
secret: c3VwZXJTZWNyZXQx |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
apiVersion: v1 | ||
kind: Secret | ||
metadata: | ||
name: secret2 | ||
type: Opaque | ||
data: # echo -n 'superSecret2' | base64; | ||
secret: c3VwZXJTZWNyZXQy |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
apiVersion: bmc.tinkerbell.org/v1alpha1 | ||
kind: Machine | ||
metadata: | ||
name: machine-sample-with-opts | ||
spec: | ||
connection: | ||
host: 127.0.0.1 | ||
insecureTLS: true | ||
providerOptions: | ||
rpc: | ||
consumerURL: "https://example.com/rpc" | ||
hmac: | ||
secrets: | ||
sha256: | ||
- name: secret1 | ||
namespace: default | ||
- name: secret2 | ||
namespace: default | ||
sha512: | ||
- name: secret1 | ||
namespace: default | ||
- name: secret2 | ||
namespace: default | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
package controller | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"strconv" | ||
"time" | ||
|
||
"dario.cat/mergo" | ||
bmclib "github.com/bmc-toolbox/bmclib/v2" | ||
"github.com/bmc-toolbox/bmclib/v2/providers/rpc" | ||
"github.com/go-logr/logr" | ||
"github.com/tinkerbell/rufio/api/v1alpha1" | ||
) | ||
|
||
// ClientFunc defines a func that returns a bmclib.Client. | ||
type ClientFunc func(ctx context.Context, log logr.Logger, hostIP, username, password string, opts *BMCOptions) (*bmclib.Client, error) | ||
|
||
// NewClientFunc returns a new BMCClientFactoryFunc. The timeout parameter determines the | ||
// maximum time to probe for compatible interfaces. | ||
func NewClientFunc(timeout time.Duration) ClientFunc { | ||
// Initializes a bmclib client based on input host and credentials | ||
// Establishes a connection with the bmc with client.Open | ||
// Returns a bmclib.Client. | ||
return func(ctx context.Context, log logr.Logger, hostIP, username, password string, opts *BMCOptions) (*bmclib.Client, error) { | ||
o := opts.translate(hostIP) | ||
log = log.WithValues("host", hostIP, "username", username) | ||
o = append(o, bmclib.WithLogger(log)) | ||
client := bmclib.NewClient(hostIP, username, password, o...) | ||
|
||
ctx, cancel := context.WithTimeout(ctx, timeout) | ||
defer cancel() | ||
|
||
// TODO (pokearu): Make an option | ||
client.Registry.Drivers = client.Registry.PreferProtocol("redfish") | ||
if err := client.Open(ctx); err != nil { | ||
md := client.GetMetadata() | ||
log.Info("Failed to open connection to BMC", "error", err, "providersAttempted", md.ProvidersAttempted, "successfulProvider", md.SuccessfulOpenConns) | ||
|
||
return nil, fmt.Errorf("failed to open connection to BMC: %w", err) | ||
} | ||
md := client.GetMetadata() | ||
log.Info("Connected to BMC", "providersAttempted", md.ProvidersAttempted, "successfulProvider", md.SuccessfulOpenConns) | ||
|
||
return client, nil | ||
} | ||
} | ||
|
||
type BMCOptions struct { | ||
*v1alpha1.ProviderOptions | ||
rpcSecrets map[rpc.Algorithm][]string | ||
} | ||
|
||
func (b BMCOptions) translate(host string) []bmclib.Option { | ||
o := []bmclib.Option{} | ||
|
||
if b.ProviderOptions == nil { | ||
return o | ||
} | ||
|
||
// redfish options | ||
if b.Redfish != nil { | ||
if b.Redfish.Port != 0 { | ||
o = append(o, bmclib.WithRedfishPort(strconv.Itoa(b.Redfish.Port))) | ||
} | ||
} | ||
|
||
// ipmitool options | ||
if b.IPMITOOL != nil { | ||
if b.IPMITOOL.Port != 0 { | ||
o = append(o, bmclib.WithIpmitoolPort(strconv.Itoa(b.IPMITOOL.Port))) | ||
} | ||
if b.IPMITOOL.CipherSuite != "" { | ||
o = append(o, bmclib.WithIpmitoolCipherSuite(b.IPMITOOL.CipherSuite)) | ||
} | ||
} | ||
|
||
// intelAmt options | ||
if b.IntelAMT != nil { | ||
amt := bmclib.WithIntelAMTPort(uint32(b.IntelAMT.Port)) | ||
o = append(o, amt) | ||
} | ||
|
||
// rpc options | ||
if b.RPC != nil { | ||
op := b.translateRPC(host) | ||
o = append(o, bmclib.WithRPCOpt(op)) | ||
} | ||
|
||
return o | ||
} | ||
|
||
func (b BMCOptions) translateRPC(host string) rpc.Provider { | ||
s := map[rpc.Algorithm][]string{} | ||
if b.rpcSecrets != nil { | ||
s = b.rpcSecrets | ||
} | ||
|
||
defaults := rpc.Provider{ | ||
Opts: rpc.Opts{ | ||
Request: rpc.RequestOpts{ | ||
TimestampHeader: "X-Rufio-Timestamp", | ||
}, | ||
Signature: rpc.SignatureOpts{ | ||
HeaderName: "X-Rufio-Signature", | ||
IncludedPayloadHeaders: []string{"X-Rufio-Timestamp"}, | ||
}, | ||
}, | ||
} | ||
o := rpc.Provider{ | ||
ConsumerURL: b.RPC.ConsumerURL, | ||
Host: host, | ||
Opts: rpc.Opts{ | ||
Request: rpc.RequestOpts{ | ||
HTTPContentType: b.RPC.Request.HTTPContentType, | ||
HTTPMethod: b.RPC.Request.HTTPMethod, | ||
StaticHeaders: b.RPC.Request.StaticHeaders, | ||
TimestampFormat: b.RPC.Request.TimestampFormat, | ||
TimestampHeader: b.RPC.Request.TimestampHeader, | ||
}, | ||
Signature: rpc.SignatureOpts{ | ||
HeaderName: b.RPC.Signature.HeaderName, | ||
AppendAlgoToHeaderDisabled: b.RPC.Signature.AppendAlgoToHeaderDisabled, | ||
IncludedPayloadHeaders: b.RPC.Signature.IncludedPayloadHeaders, | ||
}, | ||
HMAC: rpc.HMACOpts{ | ||
PrefixSigDisabled: b.RPC.HMAC.PrefixSigDisabled, | ||
Secrets: s, | ||
}, | ||
Experimental: rpc.Experimental{ | ||
CustomRequestPayload: []byte(b.RPC.Experimental.CustomRequestPayload), | ||
DotPath: b.RPC.Experimental.DotPath, | ||
}, | ||
}, | ||
} | ||
|
||
_ = mergo.Merge(&o, &defaults, mergo.WithOverride, mergo.WithTransformers(&rpc.Provider{})) | ||
|
||
return o | ||
} | ||
|
||
// func (r BMCOptions) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package controller | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/tinkerbell/rufio/api/v1alpha1" | ||
v1 "k8s.io/api/core/v1" | ||
apierrors "k8s.io/apimachinery/pkg/api/errors" | ||
"k8s.io/apimachinery/pkg/types" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
) | ||
|
||
// resolveAuthSecretRef Gets the Secret from the SecretReference. | ||
// Returns the username and password encoded in the Secret. | ||
func resolveAuthSecretRef(ctx context.Context, c client.Client, secretRef v1.SecretReference) (string, string, error) { | ||
secret := &v1.Secret{} | ||
key := types.NamespacedName{Namespace: secretRef.Namespace, Name: secretRef.Name} | ||
|
||
if err := c.Get(ctx, key, secret); err != nil { | ||
if apierrors.IsNotFound(err) { | ||
return "", "", fmt.Errorf("secret %s not found: %w", key, err) | ||
} | ||
|
||
return "", "", fmt.Errorf("failed to retrieve secret %s : %w", secretRef, err) | ||
} | ||
|
||
username, ok := secret.Data["username"] | ||
if !ok { | ||
return "", "", fmt.Errorf("'username' required in Machine secret") | ||
} | ||
|
||
password, ok := secret.Data["password"] | ||
if !ok { | ||
return "", "", fmt.Errorf("'password' required in Machine secret") | ||
} | ||
|
||
return string(username), string(password), nil | ||
} | ||
|
||
// toPowerState takes a raw BMC power state response and converts it to a v1alpha1.PowerState. | ||
func toPowerState(state string) v1alpha1.PowerState { | ||
// Normalize the response string for comparison. | ||
state = strings.ToLower(state) | ||
|
||
switch { | ||
case strings.Contains(state, "on"): | ||
return v1alpha1.On | ||
case strings.Contains(state, "off"): | ||
return v1alpha1.Off | ||
default: | ||
return v1alpha1.Unknown | ||
} | ||
} |
Oops, something went wrong.