package inventory import ( "context" "encoding/json" "errors" "fmt" "time" "github.com/jackc/pgx/v5" ) // MachineAccount is what a machine said it is made of (novox/hq issue 160), from the profile it last // reported: the architecture and kernel family the profile always carried, and the facts a node-engine that // knows how says beside them. Read by `node`, so what a machine says of itself is visible in one place — // collected and shown in the same breath, not collected and read by nothing (issue 160's pattern). type MachineAccount struct { Architecture string `json:"architecture"` Kernel string `json:"kernel"` // Machine is nil when the node-engine that reported is older than the one that says it. Machine *MadeOf `json:"machine"` } // MadeOf is the node-engine's account of what it is made of, as it put it on the wire. A fact it could // not determine is absent here and named in Unknown with why — never a zero. type MadeOf struct { ObservedAt time.Time `json:"observed_at"` KernelRelease string `json:"kernel_release"` Distribution string `json:"distribution"` Version string `json:"version"` Processor string `json:"processor"` Cores int `json:"cores"` Threads int `json:"threads"` MemoryBytes int64 `json:"memory_bytes"` Virtual string `json:"virtual"` BootedAt *time.Time `json:"booted_at"` Timezone string `json:"timezone"` Filesystems []MountedFilesystem `json:"filesystems"` Unknown map[string]string `json:"unknown"` } // MountedFilesystem is one local filesystem a machine has mounted. type MountedFilesystem struct { Mount string `json:"mount"` Device string `json:"device"` Type string `json:"type"` SizeBytes int64 `json:"size_bytes"` FreeBytes int64 `json:"free_bytes"` } // MachineOf is what a node last said it is made of. had is false for a node that has never reported a // profile at all, which is a different answer from one whose node-engine does not say the facts yet. func (i *Inventory) MachineOf(ctx context.Context, nodeName string) (account MachineAccount, had bool, err error) { var raw []byte err = i.store.Pool().QueryRow(ctx, `select profile from node where name = $1`, nodeName).Scan(&raw) if errors.Is(err, pgx.ErrNoRows) { return MachineAccount{}, false, fmt.Errorf("%w: %s", ErrNoSuchNode, nodeName) } if err != nil { return MachineAccount{}, false, err } return machineFrom(raw) } func machineFrom(raw []byte) (MachineAccount, bool, error) { if len(raw) == 0 { return MachineAccount{}, false, nil } var account MachineAccount if err := json.Unmarshal(raw, &account); err != nil { return MachineAccount{}, false, err } return account, true, nil }