Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENG-6658 user defined metadata #16

Merged
merged 4 commits into from
Jul 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ module github.com/packethost/hegel
go 1.13

require (
github.com/docker/go-metrics v0.0.1 // indirect
github.com/golang/protobuf v1.4.2
github.com/grpc-ecosystem/go-grpc-middleware v1.2.0
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
github.com/packethost/cacher v0.0.0-20200319200613-5dc1cac4fd33
github.com/packethost/pkg v0.0.0-20190715213007-7c3a64b4b5e3
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.5.1
github.com/tinkerbell/tink v0.0.0-20200708073808-997394055483
github.com/tinkerbell/tink v0.0.0-20200724140154-850584d46c8d
google.golang.org/grpc v1.29.1
)

replace github.com/tinkerbell/tink v0.0.0-20200710050004-a68bec0e8c1b => github.com/kdeng3849/tink v0.0.0-20200713034415-dd6d5ea8d040
66 changes: 66 additions & 0 deletions go.sum

Large diffs are not rendered by default.

40 changes: 27 additions & 13 deletions grpc_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"math"
"net"
Expand Down Expand Up @@ -46,17 +47,8 @@ type exportedHardwareCacher struct {
// exportedHardwareTinkerbell is the structure in which hegel returns to clients using the new tinkerbell data model
// exposes only certain fields of the hardware data returned by tinkerbell
type exportedHardwareTinkerbell struct {
ID string `json:"id"`
Metadata metadata `json:"metadata"`
}

type metadata struct {
State string `json:"state"`
BondingMode int `json:"bonding_mode"`
Manufacturer interface{} `json:"manufacturer"`
Instance instance `json:"instance"`
Custom interface{} `json:"custom"`
Facility interface{} `json:"facility"`
ID string `json:"id"`
Metadata interface{} `json:"metadata"`
}

type instance struct {
Expand Down Expand Up @@ -218,6 +210,29 @@ func (eh *exportedHardwareCacher) UnmarshalJSON(b []byte) error {
return nil
}

// UnmarshalJSON implements the json.Unmarshaler interface for custom unmarshalling of exportedHardwareTinkerbell
// transforms the metadata from a string (as defined in the hardware returned by tink) into a map for cleaner printing
func (eh *exportedHardwareTinkerbell) UnmarshalJSON(b []byte) error {
type ehj exportedHardwareTinkerbell
var tmp ehj
err := json.Unmarshal(b, &tmp)
if err != nil {
return err
}

if md, ok := tmp.Metadata.(string); ok { // won't run block if unable to cast into string (including if nil)
metadata := make(map[string]interface{})
err = json.Unmarshal([]byte(md), &metadata) // metadata is now a map

if err != nil {
fmt.Println(err)
}
tmp.Metadata = metadata
}
*eh = exportedHardwareTinkerbell(tmp)
return nil
}

func (s *server) Get(ctx context.Context, in *hegel.GetRequest) (*hegel.GetResponse, error) {
p, ok := peer.FromContext(ctx)
if !ok {
Expand Down Expand Up @@ -264,7 +279,6 @@ func (s *server) Subscribe(in *hegel.SubscribeRequest, stream hegel.Hegel_Subscr
dataModelVersion := os.Getenv("DATA_MODEL_VERSION")
switch dataModelVersion {
case "1":
//tc := s.hardwareClient.(tink.HardwareServiceClient)
hw, err := s.hardwareClient.ByIP(stream.Context(), &tink.GetRequest{
Ip: ip,
})
Expand Down Expand Up @@ -403,7 +417,7 @@ func getByIP(ctx context.Context, s *server, userIP string) ([]byte, error) {
req := &tink.GetRequest{
Ip: userIP,
}
resp, err := s.hardwareClient.ByIP(ctx, req)
resp, err := s.hardwareClient.ByIP(ctx, req) // use wrapper?

if err != nil {
return nil, err
Expand Down
76 changes: 53 additions & 23 deletions grpc_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"encoding/json"
"os"
"testing"

"github.com/tinkerbell/tink/protos/packet"
)

func TestGetByIPCacher(t *testing.T) {
Expand Down Expand Up @@ -89,43 +91,64 @@ func TestGetByIPTinkerbell(t *testing.T) {
hw := exportedHardwareTinkerbell{}
err = json.Unmarshal(ehw, &hw)
if err != nil {
t.Fatal("Error in unmarshalling hardware", err)
t.Error("Error in unmarshalling hardware:", err)
}

if hw.ID != test.id {
t.Errorf("handler returned unexpected id: got %v want %v",
hw.ID, test.id)
}

if hw.Metadata == nil {
return
}

var metadata packet.Metadata
md, err := json.Marshal(hw.Metadata)
if err != nil {
t.Error("Error in unmarshalling hardware", err)
}
if hw.Metadata.State != test.state {
t.Fatalf("unexpected state, want: %v, got: %v\n", test.state, hw.Metadata.State)
err = json.Unmarshal(md, &metadata)
if err != nil {
t.Error("Error in unmarshalling hardware metadata", err)
}
if hw.Metadata.BondingMode != test.bondingMode {
t.Fatalf("unexpected bonding mode, want: %v, got: %v\n", test.bondingMode, hw.Metadata.BondingMode)

if metadata.State != test.state {
t.Fatalf("unexpected state, want: %v, got: %v\n", test.state, metadata.State)
}
if len(hw.Metadata.Instance.Storage.Disks) > 0 {
if hw.Metadata.Instance.Storage.Disks[0].Device != test.diskDevice {
t.Fatalf("unexpected disk device, want: %v, got: %v\n", test.diskDevice, hw.Metadata.Instance.Storage.Disks[0].Device)
if metadata.BondingMode != test.bondingMode {
t.Fatalf("unexpected bonding mode, want: %v, got: %v\n", test.bondingMode, metadata.BondingMode)
}
if len(metadata.Instance.Storage.Disks) > 0 {
if metadata.Instance.Storage.Disks[0].Device != test.diskDevice {
t.Fatalf("unexpected disk device, want: %v, got: %v\n", test.diskDevice, metadata.Instance.Storage.Disks[0].Device)
}
if hw.Metadata.Instance.Storage.Disks[0].WipeTable != test.wipeTable {
t.Fatalf("unexpected wipe table, want: %v, got: %v\n", test.wipeTable, hw.Metadata.Instance.Storage.Disks[0].WipeTable)
if metadata.Instance.Storage.Disks[0].WipeTable != test.wipeTable {
t.Fatalf("unexpected wipe table, want: %v, got: %v\n", test.wipeTable, metadata.Instance.Storage.Disks[0].WipeTable)
}
if int(hw.Metadata.Instance.Storage.Disks[0].Paritions[0].Size) != test.partitionSize {
t.Fatalf("unexpected partition size, want: %v, got: %v\n", test.partitionSize, hw.Metadata.Instance.Storage.Disks[0].Paritions[0].Size)
if metadata.Instance.Storage.Disks[0].Partitions[0].Size != test.partitionSize {
t.Fatalf("unexpected partition size, want: %v, got: %v\n", test.partitionSize, metadata.Instance.Storage.Disks[0].Partitions[0].Size)
}
}
if len(hw.Metadata.Instance.Storage.Filesystems) > 0 {
if hw.Metadata.Instance.Storage.Filesystems[0].Mount.Device != test.filesystemDevice {
t.Fatalf("unexpected filesystem mount device, want: %v, got: %v\n", test.filesystemDevice, hw.Metadata.Instance.Storage.Filesystems[0].Mount.Device)
if len(metadata.Instance.Storage.Filesystems) > 0 {
if metadata.Instance.Storage.Filesystems[0].Mount.Device != test.filesystemDevice {
t.Fatalf("unexpected filesystem mount device, want: %v, got: %v\n", test.filesystemDevice, metadata.Instance.Storage.Filesystems[0].Mount.Device)
}
if hw.Metadata.Instance.Storage.Filesystems[0].Mount.Format != test.filesystemFormat {
t.Fatalf("unexpected filesystem mount format, want: %v, got: %v\n", test.filesystemFormat, hw.Metadata.Instance.Storage.Filesystems[0].Mount.Format)
if metadata.Instance.Storage.Filesystems[0].Mount.Format != test.filesystemFormat {
t.Fatalf("unexpected filesystem mount format, want: %v, got: %v\n", test.filesystemFormat, metadata.Instance.Storage.Filesystems[0].Mount.Format)
}
}
if hw.Metadata.Instance.OS.OsSlug != test.osSlug {
t.Fatalf("unexpected os slug, want: %v, got: %v\n", test.osSlug, hw.Metadata.Instance.OS.OsSlug)
if metadata.Instance.OperatingSystemVersion.OsSlug != test.osSlug {
t.Fatalf("unexpected os slug, want: %v, got: %v\n", test.osSlug, metadata.Instance.OperatingSystemVersion.OsSlug)
}
if hw.Metadata.Facility.(map[string]interface{})["plan_slug"] != test.planSlug {
t.Fatalf("unexpected os slug, want: %v, got: %v\n", test.planSlug, hw.Metadata.Facility.(map[string]interface{})["plan_slug"])
if metadata.Facility.PlanSlug != test.planSlug {
t.Fatalf("unexpected os slug, want: %v, got: %v\n", test.planSlug, metadata.Facility.PlanSlug)
}
}
}

var cacherGrpcTests = map[string]struct {
id string
remote string
state string
facility string
Expand Down Expand Up @@ -232,12 +255,13 @@ var cacherGrpcTests = map[string]struct {
}

var tinkerbellGrpcTests = map[string]struct {
id string
remote string
state string
bondingMode int
bondingMode int64
diskDevice string
wipeTable bool
partitionSize int
partitionSize int64
filesystemDevice string
filesystemFormat string
osSlug string
Expand All @@ -246,6 +270,7 @@ var tinkerbellGrpcTests = map[string]struct {
error string
}{
"tinkerbell": {
id: "fde7c87c-d154-447e-9fce-7eb7bdec90c0",
remote: "192.168.1.5",
bondingMode: 5,
diskDevice: "/dev/sda",
Expand All @@ -257,4 +282,9 @@ var tinkerbellGrpcTests = map[string]struct {
planSlug: "c2.medium.x86",
json: tinkerbellDataModel,
},
"tinkerbell no metadata": {
id: "363115b0-f03d-4ce5-9a15-5514193d131a",
remote: "192.168.1.5",
json: tinkerbellNoMetadata,
},
}
2 changes: 1 addition & 1 deletion http_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func getMetadata(w http.ResponseWriter, r *http.Request) {
ehw, err := getByIP(context.Background(), hegelServer, userIP)
if err != nil {
metrics.Errors.WithLabelValues("metadata", "lookup").Inc()
logger.Info("Error in finding or exporting hardware ", err)
logger.Info("Error in finding or exporting hardware: ", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
Expand Down
28 changes: 25 additions & 3 deletions http_handlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"net/http/httptest"
"os"
"testing"

"github.com/tinkerbell/tink/protos/packet"
)

func TestGetMetadataCacher(t *testing.T) {
Expand Down Expand Up @@ -79,9 +81,24 @@ func TestGetMetadataTinkerbell(t *testing.T) {
t.Errorf("handler returned unexpected id: got %v want %v",
hw.ID, test.id)
}
if hw.Metadata.BondingMode != test.bondingMode {

if hw.Metadata == nil {
return
}

var metadata packet.Metadata
md, err := json.Marshal(hw.Metadata)
if err != nil {
t.Error("Error in marshalling hardware metadata", err)
}
err = json.Unmarshal(md, &metadata)
if err != nil {
t.Error("Error in unmarshalling hardware metadata", err)
}

if metadata.BondingMode != test.bondingMode {
t.Errorf("handler returned unexpected bonding mode: got %v want %v",
hw.Metadata.BondingMode, test.bondingMode)
metadata.BondingMode, test.bondingMode)
}
}
}
Expand All @@ -103,7 +120,7 @@ var cacherTests = map[string]struct {
var tinkerbellTests = map[string]struct {
id string
remote string
bondingMode int
bondingMode int64
json string
}{
"tinkerbell": {
Expand All @@ -112,4 +129,9 @@ var tinkerbellTests = map[string]struct {
bondingMode: 5,
json: tinkerbellDataModel,
},
"tinkerbell no metadata": {
id: "363115b0-f03d-4ce5-9a15-5514193d131a",
remote: "192.168.1.5",
json: tinkerbellNoMetadata,
},
}
Loading