mirror of
https://github.com/siderolabs/talos.git
synced 2025-09-04 05:21:12 +02:00
As this implements Go client for Talos API, it makes sense to publish it one the top level. Signed-off-by: Andrey Smirnov <smirnov.andrey@gmail.com>
132 lines
3.0 KiB
Go
132 lines
3.0 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 client
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
|
|
"github.com/hashicorp/go-multierror"
|
|
)
|
|
|
|
// NodeError is RPC error from some node
|
|
type NodeError struct {
|
|
Node string
|
|
Err string
|
|
}
|
|
|
|
func (ne *NodeError) Error() string {
|
|
return fmt.Sprintf("%s: %s", ne.Node, ne.Err)
|
|
}
|
|
|
|
// FilterMessages removes error Messagess from resp and builds multierror.
|
|
//
|
|
//nolint: gocyclo
|
|
func FilterMessages(resp interface{}, err error) (interface{}, error) {
|
|
if resp == nil {
|
|
return nil, err
|
|
}
|
|
|
|
respStructPtr := reflect.ValueOf(resp)
|
|
if respStructPtr.Kind() != reflect.Ptr {
|
|
panic("response should be pointer to struct")
|
|
}
|
|
|
|
if respStructPtr.IsNil() {
|
|
return nil, err
|
|
}
|
|
|
|
respStruct := respStructPtr.Elem()
|
|
if respStruct.Kind() != reflect.Struct {
|
|
panic("response should be struct")
|
|
}
|
|
|
|
messagesField := respStruct.FieldByName("Messages")
|
|
if !messagesField.IsValid() {
|
|
panic("Messages field missing")
|
|
}
|
|
|
|
if messagesField.Kind() != reflect.Slice {
|
|
panic("Messages field should be a slice")
|
|
}
|
|
|
|
var multiErr *multierror.Error
|
|
|
|
for i := 0; i < messagesField.Len(); {
|
|
MessagesPtr := messagesField.Index(i)
|
|
if MessagesPtr.Kind() != reflect.Ptr {
|
|
panic("Messages slice should container pointers")
|
|
}
|
|
|
|
Messages := MessagesPtr.Elem()
|
|
if Messages.Kind() != reflect.Struct {
|
|
panic("Messages slice should container pointers to structs")
|
|
}
|
|
|
|
metadataField := Messages.FieldByName("Metadata")
|
|
if !metadataField.IsValid() {
|
|
panic("Messages metadata field missing")
|
|
}
|
|
|
|
if metadataField.Kind() != reflect.Ptr {
|
|
panic("Messages metadata field should be a pointer")
|
|
}
|
|
|
|
if metadataField.IsNil() {
|
|
// missing metadata, skip the field
|
|
i++
|
|
continue
|
|
}
|
|
|
|
metadata := metadataField.Elem()
|
|
if metadata.Kind() != reflect.Struct {
|
|
panic("Messages metadata should be struct")
|
|
}
|
|
|
|
errorField := metadata.FieldByName("Error")
|
|
if !errorField.IsValid() {
|
|
panic("metadata.Error field missing")
|
|
}
|
|
|
|
if errorField.Kind() != reflect.String {
|
|
panic("metadata.Error should be string")
|
|
}
|
|
|
|
if errorField.IsZero() {
|
|
// no error, leave it as is
|
|
i++
|
|
continue
|
|
}
|
|
|
|
hostnameField := metadata.FieldByName("Hostname")
|
|
if !hostnameField.IsValid() {
|
|
panic("metadata.Hostname field missing")
|
|
}
|
|
|
|
if hostnameField.Kind() != reflect.String {
|
|
panic("metadata.Hostname should be string")
|
|
}
|
|
|
|
// extract error
|
|
nodeError := &NodeError{
|
|
Node: hostnameField.String(),
|
|
Err: errorField.String(),
|
|
}
|
|
|
|
multiErr = multierror.Append(multiErr, nodeError)
|
|
|
|
// remove ith Messages
|
|
reflect.Copy(messagesField.Slice(i, messagesField.Len()), messagesField.Slice(i+1, messagesField.Len()))
|
|
messagesField.SetLen(messagesField.Len() - 1)
|
|
}
|
|
|
|
// if all the Messagess were error Messagess...
|
|
if multiErr != nil && messagesField.Len() == 0 {
|
|
resp = nil
|
|
}
|
|
|
|
return resp, multiErr.ErrorOrNil()
|
|
}
|