Skip to content

Commit

Permalink
update node extra info (#1590)
Browse files Browse the repository at this point in the history
  • Loading branch information
muhamadazmy authored Feb 16, 2022
1 parent d53ad04 commit c3e183c
Show file tree
Hide file tree
Showing 6 changed files with 189 additions and 58 deletions.
13 changes: 12 additions & 1 deletion cmds/modules/noded/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,18 @@ func action(cli *cli.Context) error {
}
}()

node, twin, err := registration(ctx, redis, env, cap)
secureBoot, err := capacity.IsSecureBoot()
if err != nil {
log.Error().Err(err).Msg("failed to detect secure boot flags")
}

var info RegistrationInfo
info = info.WithCapacity(cap).
WithSerialNumber(dmi.BoardVersion()).
WithSecureBoot(secureBoot).
WithVirtualized(len(hypervisor) != 0)

node, twin, err := registration(ctx, redis, env, info)
if err != nil {
return errors.Wrap(err, "failed during node registration")
}
Expand Down
173 changes: 117 additions & 56 deletions cmds/modules/noded/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,46 @@ const (
tcHash = ""
)

func registration(ctx context.Context, cl zbus.Client, env environment.Environment, cap gridtypes.Capacity) (nodeID, twinID uint32, err error) {
type RegistrationInfo struct {
Capacity gridtypes.Capacity
Location geoip.Location
Ygg net.IP
SecureBoot bool
Virtualized bool
SerialNumber string
}

func (r RegistrationInfo) WithCapacity(v gridtypes.Capacity) RegistrationInfo {
r.Capacity = v
return r
}

func (r RegistrationInfo) WithLocation(v geoip.Location) RegistrationInfo {
r.Location = v
return r
}

func (r RegistrationInfo) WithYggdrail(v net.IP) RegistrationInfo {
r.Ygg = v
return r
}

func (r RegistrationInfo) WithSecureBoot(v bool) RegistrationInfo {
r.SecureBoot = v
return r
}

func (r RegistrationInfo) WithVirtualized(v bool) RegistrationInfo {
r.Virtualized = v
return r
}

func (r RegistrationInfo) WithSerialNumber(v string) RegistrationInfo {
r.SerialNumber = v
return r
}

func registration(ctx context.Context, cl zbus.Client, env environment.Environment, info RegistrationInfo) (nodeID, twinID uint32, err error) {
var (
netMgr = stubs.NewNetworkerStub(cl)
)
Expand All @@ -55,22 +94,24 @@ func registration(ctx context.Context, cl zbus.Client, env environment.Environme
}

log.Debug().
Uint64("cru", cap.CRU).
Uint64("mru", uint64(cap.MRU)).
Uint64("sru", uint64(cap.SRU)).
Uint64("hru", uint64(cap.HRU)).
Uint64("cru", info.Capacity.CRU).
Uint64("mru", uint64(info.Capacity.MRU)).
Uint64("sru", uint64(info.Capacity.SRU)).
Uint64("hru", uint64(info.Capacity.HRU)).
Msg("node capacity")

sub, err := env.GetSubstrate()
if err != nil {
return 0, 0, errors.Wrap(err, "failed to create substrate client")
}

info = info.WithLocation(loc).WithYggdrail(ygg)

exp := backoff.NewExponentialBackOff()
exp.MaxInterval = 2 * time.Minute
bo := backoff.WithContext(exp, ctx)
err = backoff.RetryNotify(func() error {
nodeID, twinID, err = registerNode(ctx, env, cl, sub, cap, loc, ygg)
nodeID, twinID, err = registerNode(ctx, env, cl, sub, info)
return err
}, bo, retryNotify)

Expand All @@ -83,7 +124,7 @@ func registration(ctx context.Context, cl zbus.Client, env environment.Environme
// to twin ip.
go func() {
for {
err := watch(ctx, env, cl, sub, cap, loc, ygg)
err := watch(ctx, env, cl, sub, info)
if errors.Is(err, context.Canceled) {
return
} else if err != nil {
Expand All @@ -101,9 +142,7 @@ func watch(
env environment.Environment,
cl zbus.Client,
sub *substrate.Substrate,
cap gridtypes.Capacity,
loc geoip.Location,
ygg net.IP,
info RegistrationInfo,
) error {
var (
netMgr = stubs.NewNetworkerStub(cl)
Expand All @@ -125,8 +164,8 @@ func watch(
if len(yggInput) > 0 {
yggNew = yggInput[0].IP
}
if !yggNew.Equal(ygg) {
ygg = yggNew
if !yggNew.Equal(info.Ygg) {
info = info.WithYggdrail(yggNew)
update = true
}
}
Expand All @@ -140,7 +179,7 @@ func watch(
exp.MaxInterval = 2 * time.Minute
bo := backoff.WithContext(exp, ctx)
err = backoff.RetryNotify(func() error {
_, _, err := registerNode(ctx, env, cl, sub, cap, loc, ygg)
_, _, err := registerNode(ctx, env, cl, sub, info)
return err
}, bo, retryNotify)

Expand All @@ -159,9 +198,7 @@ func registerNode(
env environment.Environment,
cl zbus.Client,
sub *substrate.Substrate,
cap gridtypes.Capacity,
loc geoip.Location,
ygg net.IP,
info RegistrationInfo,
) (nodeID, twinID uint32, err error) {
var (
mgr = stubs.NewIdentityManagerStub(cl)
Expand Down Expand Up @@ -189,15 +226,15 @@ func registerNode(
}

resources := substrate.Resources{
HRU: types.U64(cap.HRU),
SRU: types.U64(cap.SRU),
CRU: types.U64(cap.CRU),
MRU: types.U64(cap.MRU),
HRU: types.U64(info.Capacity.HRU),
SRU: types.U64(info.Capacity.SRU),
CRU: types.U64(info.Capacity.CRU),
MRU: types.U64(info.Capacity.MRU),
}

location := substrate.Location{
Longitude: fmt.Sprint(loc.Longitute),
Latitude: fmt.Sprint(loc.Latitude),
Longitude: fmt.Sprint(info.Location.Longitute),
Latitude: fmt.Sprint(info.Location.Latitude),
}

log.Info().Str("id", mgr.NodeID(ctx).Identity()).Msg("start registration of the node")
Expand All @@ -212,63 +249,87 @@ func registerNode(
return 0, 0, errors.Wrap(err, "failed to ensure account")
}

twinID, err = ensureTwin(sub, sk, ygg)
twinID, err = ensureTwin(sub, sk, info.Ygg)
if err != nil {
return 0, 0, errors.Wrap(err, "failed to ensure twin")
}

nodeID, err = sub.GetNodeByTwinID(twinID)
if err != nil && !errors.Is(err, substrate.ErrNotFound) {
return 0, 0, err
} else if err == nil {
// node exists. we validate everything is good
// otherwise we update the node
log.Debug().Uint32("node", nodeID).Msg("node already found on blockchain")
node, err := sub.GetNode(nodeID)

if errors.Is(err, substrate.ErrNotFound) {
// create node here

// create node
nodeID, err = sub.CreateNode(id, substrate.Node{
FarmID: types.U32(env.FarmerID),
TwinID: types.U32(twinID),
Resources: resources,
Location: location,
Country: info.Location.Country,
City: info.Location.City,
Interfaces: interfaces,
})

if err != nil {
return 0, 0, errors.Wrapf(err, "failed to get node with id: %d", nodeID)
return nodeID, 0, err
}
} else if err != nil {
return 0, 0, errors.Wrapf(err, "failed to get node information for twin id: %d", twinID)
}

if reflect.DeepEqual(node.Resources, resources) &&
reflect.DeepEqual(node.Location, location) &&
reflect.DeepEqual(node.Interfaces, interfaces) &&
node.Country == loc.Country {
// so node exists AND pub config, nor resources hasn't changed
log.Debug().Msg("node information has not changed")
return uint32(node.ID), uint32(node.TwinID), nil
}
// node exists. we validate everything is good
// otherwise we update the node
log.Debug().Uint32("node", nodeID).Msg("node already found on blockchain")
node, err := sub.GetNode(nodeID)
if err != nil {
return 0, 0, errors.Wrapf(err, "failed to get node with id: %d", nodeID)
}

if !reflect.DeepEqual(node.Resources, resources) ||
!reflect.DeepEqual(node.Location, location) ||
!reflect.DeepEqual(node.Interfaces, interfaces) ||
node.Country != info.Location.Country {
// node information has changed. we need to update the node object
// we need to update the node
node.ID = types.U32(nodeID)
node.FarmID = types.U32(env.FarmerID)
node.TwinID = types.U32(twinID)
node.Resources = resources
node.Location = location
node.Country = loc.Country
node.City = loc.City
node.Country = info.Location.Country
node.City = info.Location.City
node.Interfaces = interfaces

log.Debug().Msgf("node data have changing, issuing an update node: %+v", node)
_, err = sub.UpdateNode(id, *node)
return uint32(node.ID), uint32(node.TwinID), err
_, err := sub.UpdateNode(id, *node)
if err != nil {
return 0, 0, errors.Wrapf(err, "failed to update node data with id: %d", nodeID)
}
}

// create node
nodeID, err = sub.CreateNode(id, substrate.Node{
FarmID: types.U32(env.FarmerID),
TwinID: types.U32(twinID),
Resources: resources,
Location: location,
Country: loc.Country,
City: loc.City,
Interfaces: interfaces,
})
current := substrate.NodeExtra{
Secure: info.SecureBoot,
Virtualized: info.Virtualized,
SerialNumber: info.SerialNumber,
}

if err != nil {
return nodeID, 0, err
// last thing we need to do to validate the node extra information.
extra, err := sub.GetNodeExtra(nodeID)
force := false
if errors.Is(err, substrate.ErrNotFound) {
force = true
} else if err != nil {
return 0, 0, errors.Wrap(err, "failed to get node extra information")
}

return nodeID, twinID, nil
if !reflect.DeepEqual(current, extra) || force {
// set node extra information
if err := sub.SetNodeExtra(id, current); err != nil {
return 0, 0, errors.Wrap(err, "failed to set set node extra information")
}
}
return uint32(node.ID), uint32(node.TwinID), err

}

func ensureTwin(sub *substrate.Substrate, sk ed25519.PrivateKey, ip net.IP) (uint32, error) {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ require (
github.com/stretchr/testify v1.7.0
github.com/threefoldtech/0-fs v1.3.1-0.20201203163303-d963de9adea7
github.com/threefoldtech/go-rmb v0.1.10-0.20220127085422-3c3667e4fc58
github.com/threefoldtech/substrate-client v0.0.0-20220118133601-4e68945dc064
github.com/threefoldtech/substrate-client v0.0.0-20220216120005-9fdd675d81f8
github.com/threefoldtech/zbus v0.1.5
github.com/tinylib/msgp v1.1.5 // indirect
github.com/tyler-smith/go-bip39 v1.1.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1025,6 +1025,8 @@ github.com/threefoldtech/go-rmb v0.1.10-0.20220127085422-3c3667e4fc58 h1:oefoA0K
github.com/threefoldtech/go-rmb v0.1.10-0.20220127085422-3c3667e4fc58/go.mod h1:kWpSCWxgc7OUGVYmDqioSUkV99xLoZVlBZNbxleex8o=
github.com/threefoldtech/substrate-client v0.0.0-20220118133601-4e68945dc064 h1:JgJ2X7EnJuZ311wDF/3zLBttU/so4maOoKQDQQ3U6ZY=
github.com/threefoldtech/substrate-client v0.0.0-20220118133601-4e68945dc064/go.mod h1:kI84UXFN+t0v7I3Qtj+otQwIaGel+AT86L5B0t/zQpI=
github.com/threefoldtech/substrate-client v0.0.0-20220216120005-9fdd675d81f8 h1:XkmDdLLt3xnrmYID6Y1Q2bnqxtkYK7n4s0KeV9yO8BI=
github.com/threefoldtech/substrate-client v0.0.0-20220216120005-9fdd675d81f8/go.mod h1:kI84UXFN+t0v7I3Qtj+otQwIaGel+AT86L5B0t/zQpI=
github.com/threefoldtech/zbus v0.1.5 h1:S9kXbjejoRRnJw1yKHEXFGF2vqL+Drae2n4vpj0pGHo=
github.com/threefoldtech/zbus v0.1.5/go.mod h1:ZtiRpcqzEBJetVQDsEbw0p48h/AF3O1kf0tvd30I0BU=
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
Expand Down
44 changes: 44 additions & 0 deletions pkg/capacity/capacity.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
package capacity

import (
"io/ioutil"
"os"
"os/exec"
"strings"
"syscall"

"github.com/pkg/errors"
"github.com/rs/zerolog/log"
"github.com/shirou/gopsutil/host"
"github.com/threefoldtech/zos/pkg/capacity/dmi"
"github.com/threefoldtech/zos/pkg/capacity/smartctl"
"github.com/threefoldtech/zos/pkg/gridtypes"
"github.com/threefoldtech/zos/pkg/storage/filesystem"
"github.com/threefoldtech/zos/pkg/stubs"
)

Expand Down Expand Up @@ -54,6 +58,46 @@ func (r *ResourceOracle) Total() (c gridtypes.Capacity, err error) {
return c, nil
}

func IsSecureBoot() (bool, error) {
// check if node is booted via efi
const (
efi = "/sys/firmware/efi"
efivars = "/sys/firmware/efi/efivars"
secureBoot = "/sys/firmware/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c"
)

_, err := os.Stat(efi)
if os.IsNotExist(err) {
// not even booted with uefi
return false, nil
}

if !filesystem.IsMountPoint(efivars) {
if err := syscall.Mount("none", efivars, "efivarfs", 0, ""); err != nil {
return false, errors.Wrap(err, "failed to mount efivars")
}

defer func() {
if err := syscall.Unmount(efivars, 0); err != nil {
log.Error().Err(err).Msg("failed to unmount efivars")
}
}()
}

bytes, err := ioutil.ReadFile(secureBoot)
if os.IsNotExist(err) {
return false, nil
} else if err != nil {
return false, errors.Wrap(err, "failed to read secure boot status")
}

if len(bytes) != 5 {
return false, errors.Wrap(err, "invalid efivar data for secure boot flag")
}

return bytes[4] == 1, nil
}

// DMI run and parse dmidecode commands
func (r *ResourceOracle) DMI() (*dmi.DMI, error) {
return dmi.Decode()
Expand Down
13 changes: 13 additions & 0 deletions pkg/capacity/dmi/dmi.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,19 @@ func Decode() (*DMI, error) {

}

func (d *DMI) BoardVersion() string {
if len(d.Sections) < int(TypeBaseboard) {
return ""
}

board := d.Sections[TypeBaseboard]
if len(board.SubSections) < 1 {
return ""
}

return board.SubSections[0].Properties["Serial Number"].Val
}

// dmiTypeToString returns string representation of Type t
func dmiTypeToString(t Type) string {
str := dmitypeToString[t]
Expand Down

0 comments on commit c3e183c

Please sign in to comment.