introduce basic fact collection

This commit is contained in:
2025-07-20 23:14:21 -04:00
parent 62336753c6
commit 3a47fa6706
58 changed files with 2801 additions and 107 deletions

38
client/facts/facts.go Normal file
View File

@@ -0,0 +1,38 @@
package facts
import (
"net/http"
"git.dubyatp.xyz/orphanage/client/httputil"
"github.com/zcalusic/sysinfo"
)
type FactsResponse struct {
APIVersion string `json:"apiVersion"`
CPUInfo sysinfo.CPU `json:"cpu"`
BoardInfo sysinfo.Board `json:"motherboard"`
DeviceInfo sysinfo.Product `json:"device"`
ChassisInfo sysinfo.Chassis `json:"chassis"`
MemoryInfo sysinfo.Memory `json:"memory"`
NetworkInfo []sysinfo.NetworkDevice `json:"network"`
StorageInfo []sysinfo.StorageDevice `json:"storage"`
}
func GetFacts(next http.Handler) http.Handler {
var si sysinfo.SysInfo
si.GetSysInfo()
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
resp := FactsResponse{
APIVersion: "v1",
CPUInfo: si.CPU,
BoardInfo: si.Board,
DeviceInfo: si.Product,
ChassisInfo: si.Chassis,
MemoryInfo: si.Memory,
NetworkInfo: si.Network,
StorageInfo: si.Storage,
}
httputil.WriteJSON(w, http.StatusOK, resp)
})
}

View File

@@ -1,3 +1,7 @@
module git.dubyatp.xyz/orphanage/client
go 1.24.4
require github.com/zcalusic/sysinfo v1.1.3
require github.com/google/uuid v1.6.0 // indirect

4
client/go.sum Normal file
View File

@@ -0,0 +1,4 @@
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/zcalusic/sysinfo v1.1.3 h1:u/AVENkuoikKuIZ4sUEJ6iibpmQP6YpGD8SSMCrqAF0=
github.com/zcalusic/sysinfo v1.1.3/go.mod h1:NX+qYnWGtJVPV0yWldff9uppNKU4h40hJIRPf/pGLv4=

View File

@@ -4,13 +4,31 @@ import (
"context"
"fmt"
"io"
"log"
"os"
"os/signal"
"os/user"
"git.dubyatp.xyz/orphanage/client/server"
)
func check_superuser() bool {
current, err := user.Current()
if err != nil {
log.Fatal(err)
}
if current.Uid != "0" {
return false
} else {
return true
}
}
func run(ctx context.Context, w io.Writer, args []string) error {
if !check_superuser() {
log.Fatal("orphan must run as superuser")
}
ctx, cancel := signal.NotifyContext(ctx, os.Interrupt)
defer cancel()

View File

@@ -3,6 +3,7 @@ package routes
import (
"net/http"
"git.dubyatp.xyz/orphanage/client/facts"
"git.dubyatp.xyz/orphanage/client/httputil"
"git.dubyatp.xyz/orphanage/client/testfunc"
)
@@ -13,4 +14,5 @@ func AddRoutes(
mux.Handle("/", http.NotFoundHandler())
mux.Handle("/helloworld", httputil.HelloWorld(nil))
mux.Handle("/testjson", testfunc.HelloWorldJSON(nil))
mux.Handle("/facts", facts.GetFacts(nil))
}

41
client/vendor/github.com/google/uuid/CHANGELOG.md generated vendored Normal file
View File

@@ -0,0 +1,41 @@
# Changelog
## [1.6.0](https://github.com/google/uuid/compare/v1.5.0...v1.6.0) (2024-01-16)
### Features
* add Max UUID constant ([#149](https://github.com/google/uuid/issues/149)) ([c58770e](https://github.com/google/uuid/commit/c58770eb495f55fe2ced6284f93c5158a62e53e3))
### Bug Fixes
* fix typo in version 7 uuid documentation ([#153](https://github.com/google/uuid/issues/153)) ([016b199](https://github.com/google/uuid/commit/016b199544692f745ffc8867b914129ecb47ef06))
* Monotonicity in UUIDv7 ([#150](https://github.com/google/uuid/issues/150)) ([a2b2b32](https://github.com/google/uuid/commit/a2b2b32373ff0b1a312b7fdf6d38a977099698a6))
## [1.5.0](https://github.com/google/uuid/compare/v1.4.0...v1.5.0) (2023-12-12)
### Features
* Validate UUID without creating new UUID ([#141](https://github.com/google/uuid/issues/141)) ([9ee7366](https://github.com/google/uuid/commit/9ee7366e66c9ad96bab89139418a713dc584ae29))
## [1.4.0](https://github.com/google/uuid/compare/v1.3.1...v1.4.0) (2023-10-26)
### Features
* UUIDs slice type with Strings() convenience method ([#133](https://github.com/google/uuid/issues/133)) ([cd5fbbd](https://github.com/google/uuid/commit/cd5fbbdd02f3e3467ac18940e07e062be1f864b4))
### Fixes
* Clarify that Parse's job is to parse but not necessarily validate strings. (Documents current behavior)
## [1.3.1](https://github.com/google/uuid/compare/v1.3.0...v1.3.1) (2023-08-18)
### Bug Fixes
* Use .EqualFold() to parse urn prefixed UUIDs ([#118](https://github.com/google/uuid/issues/118)) ([574e687](https://github.com/google/uuid/commit/574e6874943741fb99d41764c705173ada5293f0))
## Changelog

26
client/vendor/github.com/google/uuid/CONTRIBUTING.md generated vendored Normal file
View File

@@ -0,0 +1,26 @@
# How to contribute
We definitely welcome patches and contribution to this project!
### Tips
Commits must be formatted according to the [Conventional Commits Specification](https://www.conventionalcommits.org).
Always try to include a test case! If it is not possible or not necessary,
please explain why in the pull request description.
### Releasing
Commits that would precipitate a SemVer change, as described in the Conventional
Commits Specification, will trigger [`release-please`](https://github.com/google-github-actions/release-please-action)
to create a release candidate pull request. Once submitted, `release-please`
will create a release.
For tips on how to work with `release-please`, see its documentation.
### Legal requirements
In order to protect both you and ourselves, you will need to sign the
[Contributor License Agreement](https://cla.developers.google.com/clas).
You may have already signed it for other Google projects.

9
client/vendor/github.com/google/uuid/CONTRIBUTORS generated vendored Normal file
View File

@@ -0,0 +1,9 @@
Paul Borman <borman@google.com>
bmatsuo
shawnps
theory
jboverfelt
dsymonds
cd1
wallclockbuilder
dansouza

27
client/vendor/github.com/google/uuid/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,27 @@
Copyright (c) 2009,2014 Google Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

21
client/vendor/github.com/google/uuid/README.md generated vendored Normal file
View File

@@ -0,0 +1,21 @@
# uuid
The uuid package generates and inspects UUIDs based on
[RFC 4122](https://datatracker.ietf.org/doc/html/rfc4122)
and DCE 1.1: Authentication and Security Services.
This package is based on the github.com/pborman/uuid package (previously named
code.google.com/p/go-uuid). It differs from these earlier packages in that
a UUID is a 16 byte array rather than a byte slice. One loss due to this
change is the ability to represent an invalid UUID (vs a NIL UUID).
###### Install
```sh
go get github.com/google/uuid
```
###### Documentation
[![Go Reference](https://pkg.go.dev/badge/github.com/google/uuid.svg)](https://pkg.go.dev/github.com/google/uuid)
Full `go doc` style documentation for the package can be viewed online without
installing this package by using the GoDoc site here:
http://pkg.go.dev/github.com/google/uuid

80
client/vendor/github.com/google/uuid/dce.go generated vendored Normal file
View File

@@ -0,0 +1,80 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"encoding/binary"
"fmt"
"os"
)
// A Domain represents a Version 2 domain
type Domain byte
// Domain constants for DCE Security (Version 2) UUIDs.
const (
Person = Domain(0)
Group = Domain(1)
Org = Domain(2)
)
// NewDCESecurity returns a DCE Security (Version 2) UUID.
//
// The domain should be one of Person, Group or Org.
// On a POSIX system the id should be the users UID for the Person
// domain and the users GID for the Group. The meaning of id for
// the domain Org or on non-POSIX systems is site defined.
//
// For a given domain/id pair the same token may be returned for up to
// 7 minutes and 10 seconds.
func NewDCESecurity(domain Domain, id uint32) (UUID, error) {
uuid, err := NewUUID()
if err == nil {
uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2
uuid[9] = byte(domain)
binary.BigEndian.PutUint32(uuid[0:], id)
}
return uuid, err
}
// NewDCEPerson returns a DCE Security (Version 2) UUID in the person
// domain with the id returned by os.Getuid.
//
// NewDCESecurity(Person, uint32(os.Getuid()))
func NewDCEPerson() (UUID, error) {
return NewDCESecurity(Person, uint32(os.Getuid()))
}
// NewDCEGroup returns a DCE Security (Version 2) UUID in the group
// domain with the id returned by os.Getgid.
//
// NewDCESecurity(Group, uint32(os.Getgid()))
func NewDCEGroup() (UUID, error) {
return NewDCESecurity(Group, uint32(os.Getgid()))
}
// Domain returns the domain for a Version 2 UUID. Domains are only defined
// for Version 2 UUIDs.
func (uuid UUID) Domain() Domain {
return Domain(uuid[9])
}
// ID returns the id for a Version 2 UUID. IDs are only defined for Version 2
// UUIDs.
func (uuid UUID) ID() uint32 {
return binary.BigEndian.Uint32(uuid[0:4])
}
func (d Domain) String() string {
switch d {
case Person:
return "Person"
case Group:
return "Group"
case Org:
return "Org"
}
return fmt.Sprintf("Domain%d", int(d))
}

12
client/vendor/github.com/google/uuid/doc.go generated vendored Normal file
View File

@@ -0,0 +1,12 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package uuid generates and inspects UUIDs.
//
// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security
// Services.
//
// A UUID is a 16 byte (128 bit) array. UUIDs may be used as keys to
// maps or compared directly.
package uuid

59
client/vendor/github.com/google/uuid/hash.go generated vendored Normal file
View File

@@ -0,0 +1,59 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"crypto/md5"
"crypto/sha1"
"hash"
)
// Well known namespace IDs and UUIDs
var (
NameSpaceDNS = Must(Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8"))
NameSpaceURL = Must(Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8"))
NameSpaceOID = Must(Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8"))
NameSpaceX500 = Must(Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8"))
Nil UUID // empty UUID, all zeros
// The Max UUID is special form of UUID that is specified to have all 128 bits set to 1.
Max = UUID{
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
}
)
// NewHash returns a new UUID derived from the hash of space concatenated with
// data generated by h. The hash should be at least 16 byte in length. The
// first 16 bytes of the hash are used to form the UUID. The version of the
// UUID will be the lower 4 bits of version. NewHash is used to implement
// NewMD5 and NewSHA1.
func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID {
h.Reset()
h.Write(space[:]) //nolint:errcheck
h.Write(data) //nolint:errcheck
s := h.Sum(nil)
var uuid UUID
copy(uuid[:], s)
uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4)
uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant
return uuid
}
// NewMD5 returns a new MD5 (Version 3) UUID based on the
// supplied name space and data. It is the same as calling:
//
// NewHash(md5.New(), space, data, 3)
func NewMD5(space UUID, data []byte) UUID {
return NewHash(md5.New(), space, data, 3)
}
// NewSHA1 returns a new SHA1 (Version 5) UUID based on the
// supplied name space and data. It is the same as calling:
//
// NewHash(sha1.New(), space, data, 5)
func NewSHA1(space UUID, data []byte) UUID {
return NewHash(sha1.New(), space, data, 5)
}

38
client/vendor/github.com/google/uuid/marshal.go generated vendored Normal file
View File

@@ -0,0 +1,38 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import "fmt"
// MarshalText implements encoding.TextMarshaler.
func (uuid UUID) MarshalText() ([]byte, error) {
var js [36]byte
encodeHex(js[:], uuid)
return js[:], nil
}
// UnmarshalText implements encoding.TextUnmarshaler.
func (uuid *UUID) UnmarshalText(data []byte) error {
id, err := ParseBytes(data)
if err != nil {
return err
}
*uuid = id
return nil
}
// MarshalBinary implements encoding.BinaryMarshaler.
func (uuid UUID) MarshalBinary() ([]byte, error) {
return uuid[:], nil
}
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
func (uuid *UUID) UnmarshalBinary(data []byte) error {
if len(data) != 16 {
return fmt.Errorf("invalid UUID (got %d bytes)", len(data))
}
copy(uuid[:], data)
return nil
}

90
client/vendor/github.com/google/uuid/node.go generated vendored Normal file
View File

@@ -0,0 +1,90 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"sync"
)
var (
nodeMu sync.Mutex
ifname string // name of interface being used
nodeID [6]byte // hardware for version 1 UUIDs
zeroID [6]byte // nodeID with only 0's
)
// NodeInterface returns the name of the interface from which the NodeID was
// derived. The interface "user" is returned if the NodeID was set by
// SetNodeID.
func NodeInterface() string {
defer nodeMu.Unlock()
nodeMu.Lock()
return ifname
}
// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs.
// If name is "" then the first usable interface found will be used or a random
// Node ID will be generated. If a named interface cannot be found then false
// is returned.
//
// SetNodeInterface never fails when name is "".
func SetNodeInterface(name string) bool {
defer nodeMu.Unlock()
nodeMu.Lock()
return setNodeInterface(name)
}
func setNodeInterface(name string) bool {
iname, addr := getHardwareInterface(name) // null implementation for js
if iname != "" && addr != nil {
ifname = iname
copy(nodeID[:], addr)
return true
}
// We found no interfaces with a valid hardware address. If name
// does not specify a specific interface generate a random Node ID
// (section 4.1.6)
if name == "" {
ifname = "random"
randomBits(nodeID[:])
return true
}
return false
}
// NodeID returns a slice of a copy of the current Node ID, setting the Node ID
// if not already set.
func NodeID() []byte {
defer nodeMu.Unlock()
nodeMu.Lock()
if nodeID == zeroID {
setNodeInterface("")
}
nid := nodeID
return nid[:]
}
// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes
// of id are used. If id is less than 6 bytes then false is returned and the
// Node ID is not set.
func SetNodeID(id []byte) bool {
if len(id) < 6 {
return false
}
defer nodeMu.Unlock()
nodeMu.Lock()
copy(nodeID[:], id)
ifname = "user"
return true
}
// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is
// not valid. The NodeID is only well defined for version 1 and 2 UUIDs.
func (uuid UUID) NodeID() []byte {
var node [6]byte
copy(node[:], uuid[10:])
return node[:]
}

12
client/vendor/github.com/google/uuid/node_js.go generated vendored Normal file
View File

@@ -0,0 +1,12 @@
// Copyright 2017 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build js
package uuid
// getHardwareInterface returns nil values for the JS version of the code.
// This removes the "net" dependency, because it is not used in the browser.
// Using the "net" library inflates the size of the transpiled JS code by 673k bytes.
func getHardwareInterface(name string) (string, []byte) { return "", nil }

33
client/vendor/github.com/google/uuid/node_net.go generated vendored Normal file
View File

@@ -0,0 +1,33 @@
// Copyright 2017 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !js
package uuid
import "net"
var interfaces []net.Interface // cached list of interfaces
// getHardwareInterface returns the name and hardware address of interface name.
// If name is "" then the name and hardware address of one of the system's
// interfaces is returned. If no interfaces are found (name does not exist or
// there are no interfaces) then "", nil is returned.
//
// Only addresses of at least 6 bytes are returned.
func getHardwareInterface(name string) (string, []byte) {
if interfaces == nil {
var err error
interfaces, err = net.Interfaces()
if err != nil {
return "", nil
}
}
for _, ifs := range interfaces {
if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) {
return ifs.Name, ifs.HardwareAddr
}
}
return "", nil
}

118
client/vendor/github.com/google/uuid/null.go generated vendored Normal file
View File

@@ -0,0 +1,118 @@
// Copyright 2021 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"bytes"
"database/sql/driver"
"encoding/json"
"fmt"
)
var jsonNull = []byte("null")
// NullUUID represents a UUID that may be null.
// NullUUID implements the SQL driver.Scanner interface so
// it can be used as a scan destination:
//
// var u uuid.NullUUID
// err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&u)
// ...
// if u.Valid {
// // use u.UUID
// } else {
// // NULL value
// }
//
type NullUUID struct {
UUID UUID
Valid bool // Valid is true if UUID is not NULL
}
// Scan implements the SQL driver.Scanner interface.
func (nu *NullUUID) Scan(value interface{}) error {
if value == nil {
nu.UUID, nu.Valid = Nil, false
return nil
}
err := nu.UUID.Scan(value)
if err != nil {
nu.Valid = false
return err
}
nu.Valid = true
return nil
}
// Value implements the driver Valuer interface.
func (nu NullUUID) Value() (driver.Value, error) {
if !nu.Valid {
return nil, nil
}
// Delegate to UUID Value function
return nu.UUID.Value()
}
// MarshalBinary implements encoding.BinaryMarshaler.
func (nu NullUUID) MarshalBinary() ([]byte, error) {
if nu.Valid {
return nu.UUID[:], nil
}
return []byte(nil), nil
}
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
func (nu *NullUUID) UnmarshalBinary(data []byte) error {
if len(data) != 16 {
return fmt.Errorf("invalid UUID (got %d bytes)", len(data))
}
copy(nu.UUID[:], data)
nu.Valid = true
return nil
}
// MarshalText implements encoding.TextMarshaler.
func (nu NullUUID) MarshalText() ([]byte, error) {
if nu.Valid {
return nu.UUID.MarshalText()
}
return jsonNull, nil
}
// UnmarshalText implements encoding.TextUnmarshaler.
func (nu *NullUUID) UnmarshalText(data []byte) error {
id, err := ParseBytes(data)
if err != nil {
nu.Valid = false
return err
}
nu.UUID = id
nu.Valid = true
return nil
}
// MarshalJSON implements json.Marshaler.
func (nu NullUUID) MarshalJSON() ([]byte, error) {
if nu.Valid {
return json.Marshal(nu.UUID)
}
return jsonNull, nil
}
// UnmarshalJSON implements json.Unmarshaler.
func (nu *NullUUID) UnmarshalJSON(data []byte) error {
if bytes.Equal(data, jsonNull) {
*nu = NullUUID{}
return nil // valid null UUID
}
err := json.Unmarshal(data, &nu.UUID)
nu.Valid = err == nil
return err
}

59
client/vendor/github.com/google/uuid/sql.go generated vendored Normal file
View File

@@ -0,0 +1,59 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"database/sql/driver"
"fmt"
)
// Scan implements sql.Scanner so UUIDs can be read from databases transparently.
// Currently, database types that map to string and []byte are supported. Please
// consult database-specific driver documentation for matching types.
func (uuid *UUID) Scan(src interface{}) error {
switch src := src.(type) {
case nil:
return nil
case string:
// if an empty UUID comes from a table, we return a null UUID
if src == "" {
return nil
}
// see Parse for required string format
u, err := Parse(src)
if err != nil {
return fmt.Errorf("Scan: %v", err)
}
*uuid = u
case []byte:
// if an empty UUID comes from a table, we return a null UUID
if len(src) == 0 {
return nil
}
// assumes a simple slice of bytes if 16 bytes
// otherwise attempts to parse
if len(src) != 16 {
return uuid.Scan(string(src))
}
copy((*uuid)[:], src)
default:
return fmt.Errorf("Scan: unable to scan type %T into UUID", src)
}
return nil
}
// Value implements sql.Valuer so that UUIDs can be written to databases
// transparently. Currently, UUIDs map to strings. Please consult
// database-specific driver documentation for matching types.
func (uuid UUID) Value() (driver.Value, error) {
return uuid.String(), nil
}

134
client/vendor/github.com/google/uuid/time.go generated vendored Normal file
View File

@@ -0,0 +1,134 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"encoding/binary"
"sync"
"time"
)
// A Time represents a time as the number of 100's of nanoseconds since 15 Oct
// 1582.
type Time int64
const (
lillian = 2299160 // Julian day of 15 Oct 1582
unix = 2440587 // Julian day of 1 Jan 1970
epoch = unix - lillian // Days between epochs
g1582 = epoch * 86400 // seconds between epochs
g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs
)
var (
timeMu sync.Mutex
lasttime uint64 // last time we returned
clockSeq uint16 // clock sequence for this run
timeNow = time.Now // for testing
)
// UnixTime converts t the number of seconds and nanoseconds using the Unix
// epoch of 1 Jan 1970.
func (t Time) UnixTime() (sec, nsec int64) {
sec = int64(t - g1582ns100)
nsec = (sec % 10000000) * 100
sec /= 10000000
return sec, nsec
}
// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and
// clock sequence as well as adjusting the clock sequence as needed. An error
// is returned if the current time cannot be determined.
func GetTime() (Time, uint16, error) {
defer timeMu.Unlock()
timeMu.Lock()
return getTime()
}
func getTime() (Time, uint16, error) {
t := timeNow()
// If we don't have a clock sequence already, set one.
if clockSeq == 0 {
setClockSequence(-1)
}
now := uint64(t.UnixNano()/100) + g1582ns100
// If time has gone backwards with this clock sequence then we
// increment the clock sequence
if now <= lasttime {
clockSeq = ((clockSeq + 1) & 0x3fff) | 0x8000
}
lasttime = now
return Time(now), clockSeq, nil
}
// ClockSequence returns the current clock sequence, generating one if not
// already set. The clock sequence is only used for Version 1 UUIDs.
//
// The uuid package does not use global static storage for the clock sequence or
// the last time a UUID was generated. Unless SetClockSequence is used, a new
// random clock sequence is generated the first time a clock sequence is
// requested by ClockSequence, GetTime, or NewUUID. (section 4.2.1.1)
func ClockSequence() int {
defer timeMu.Unlock()
timeMu.Lock()
return clockSequence()
}
func clockSequence() int {
if clockSeq == 0 {
setClockSequence(-1)
}
return int(clockSeq & 0x3fff)
}
// SetClockSequence sets the clock sequence to the lower 14 bits of seq. Setting to
// -1 causes a new sequence to be generated.
func SetClockSequence(seq int) {
defer timeMu.Unlock()
timeMu.Lock()
setClockSequence(seq)
}
func setClockSequence(seq int) {
if seq == -1 {
var b [2]byte
randomBits(b[:]) // clock sequence
seq = int(b[0])<<8 | int(b[1])
}
oldSeq := clockSeq
clockSeq = uint16(seq&0x3fff) | 0x8000 // Set our variant
if oldSeq != clockSeq {
lasttime = 0
}
}
// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in
// uuid. The time is only defined for version 1, 2, 6 and 7 UUIDs.
func (uuid UUID) Time() Time {
var t Time
switch uuid.Version() {
case 6:
time := binary.BigEndian.Uint64(uuid[:8]) // Ignore uuid[6] version b0110
t = Time(time)
case 7:
time := binary.BigEndian.Uint64(uuid[:8])
t = Time((time>>16)*10000 + g1582ns100)
default: // forward compatible
time := int64(binary.BigEndian.Uint32(uuid[0:4]))
time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32
time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48
t = Time(time)
}
return t
}
// ClockSequence returns the clock sequence encoded in uuid.
// The clock sequence is only well defined for version 1 and 2 UUIDs.
func (uuid UUID) ClockSequence() int {
return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff
}

43
client/vendor/github.com/google/uuid/util.go generated vendored Normal file
View File

@@ -0,0 +1,43 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"io"
)
// randomBits completely fills slice b with random data.
func randomBits(b []byte) {
if _, err := io.ReadFull(rander, b); err != nil {
panic(err.Error()) // rand should never fail
}
}
// xvalues returns the value of a byte as a hexadecimal digit or 255.
var xvalues = [256]byte{
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255,
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
}
// xtob converts hex characters x1 and x2 into a byte.
func xtob(x1, x2 byte) (byte, bool) {
b1 := xvalues[x1]
b2 := xvalues[x2]
return (b1 << 4) | b2, b1 != 255 && b2 != 255
}

365
client/vendor/github.com/google/uuid/uuid.go generated vendored Normal file
View File

@@ -0,0 +1,365 @@
// Copyright 2018 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"bytes"
"crypto/rand"
"encoding/hex"
"errors"
"fmt"
"io"
"strings"
"sync"
)
// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
// 4122.
type UUID [16]byte
// A Version represents a UUID's version.
type Version byte
// A Variant represents a UUID's variant.
type Variant byte
// Constants returned by Variant.
const (
Invalid = Variant(iota) // Invalid UUID
RFC4122 // The variant specified in RFC4122
Reserved // Reserved, NCS backward compatibility.
Microsoft // Reserved, Microsoft Corporation backward compatibility.
Future // Reserved for future definition.
)
const randPoolSize = 16 * 16
var (
rander = rand.Reader // random function
poolEnabled = false
poolMu sync.Mutex
poolPos = randPoolSize // protected with poolMu
pool [randPoolSize]byte // protected with poolMu
)
type invalidLengthError struct{ len int }
func (err invalidLengthError) Error() string {
return fmt.Sprintf("invalid UUID length: %d", err.len)
}
// IsInvalidLengthError is matcher function for custom error invalidLengthError
func IsInvalidLengthError(err error) bool {
_, ok := err.(invalidLengthError)
return ok
}
// Parse decodes s into a UUID or returns an error if it cannot be parsed. Both
// the standard UUID forms defined in RFC 4122
// (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) are decoded. In addition,
// Parse accepts non-standard strings such as the raw hex encoding
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx and 38 byte "Microsoft style" encodings,
// e.g. {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}. Only the middle 36 bytes are
// examined in the latter case. Parse should not be used to validate strings as
// it parses non-standard encodings as indicated above.
func Parse(s string) (UUID, error) {
var uuid UUID
switch len(s) {
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
case 36:
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
case 36 + 9:
if !strings.EqualFold(s[:9], "urn:uuid:") {
return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9])
}
s = s[9:]
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
case 36 + 2:
s = s[1:]
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
case 32:
var ok bool
for i := range uuid {
uuid[i], ok = xtob(s[i*2], s[i*2+1])
if !ok {
return uuid, errors.New("invalid UUID format")
}
}
return uuid, nil
default:
return uuid, invalidLengthError{len(s)}
}
// s is now at least 36 bytes long
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
return uuid, errors.New("invalid UUID format")
}
for i, x := range [16]int{
0, 2, 4, 6,
9, 11,
14, 16,
19, 21,
24, 26, 28, 30, 32, 34,
} {
v, ok := xtob(s[x], s[x+1])
if !ok {
return uuid, errors.New("invalid UUID format")
}
uuid[i] = v
}
return uuid, nil
}
// ParseBytes is like Parse, except it parses a byte slice instead of a string.
func ParseBytes(b []byte) (UUID, error) {
var uuid UUID
switch len(b) {
case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
if !bytes.EqualFold(b[:9], []byte("urn:uuid:")) {
return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9])
}
b = b[9:]
case 36 + 2: // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
b = b[1:]
case 32: // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
var ok bool
for i := 0; i < 32; i += 2 {
uuid[i/2], ok = xtob(b[i], b[i+1])
if !ok {
return uuid, errors.New("invalid UUID format")
}
}
return uuid, nil
default:
return uuid, invalidLengthError{len(b)}
}
// s is now at least 36 bytes long
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' {
return uuid, errors.New("invalid UUID format")
}
for i, x := range [16]int{
0, 2, 4, 6,
9, 11,
14, 16,
19, 21,
24, 26, 28, 30, 32, 34,
} {
v, ok := xtob(b[x], b[x+1])
if !ok {
return uuid, errors.New("invalid UUID format")
}
uuid[i] = v
}
return uuid, nil
}
// MustParse is like Parse but panics if the string cannot be parsed.
// It simplifies safe initialization of global variables holding compiled UUIDs.
func MustParse(s string) UUID {
uuid, err := Parse(s)
if err != nil {
panic(`uuid: Parse(` + s + `): ` + err.Error())
}
return uuid
}
// FromBytes creates a new UUID from a byte slice. Returns an error if the slice
// does not have a length of 16. The bytes are copied from the slice.
func FromBytes(b []byte) (uuid UUID, err error) {
err = uuid.UnmarshalBinary(b)
return uuid, err
}
// Must returns uuid if err is nil and panics otherwise.
func Must(uuid UUID, err error) UUID {
if err != nil {
panic(err)
}
return uuid
}
// Validate returns an error if s is not a properly formatted UUID in one of the following formats:
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
// It returns an error if the format is invalid, otherwise nil.
func Validate(s string) error {
switch len(s) {
// Standard UUID format
case 36:
// UUID with "urn:uuid:" prefix
case 36 + 9:
if !strings.EqualFold(s[:9], "urn:uuid:") {
return fmt.Errorf("invalid urn prefix: %q", s[:9])
}
s = s[9:]
// UUID enclosed in braces
case 36 + 2:
if s[0] != '{' || s[len(s)-1] != '}' {
return fmt.Errorf("invalid bracketed UUID format")
}
s = s[1 : len(s)-1]
// UUID without hyphens
case 32:
for i := 0; i < len(s); i += 2 {
_, ok := xtob(s[i], s[i+1])
if !ok {
return errors.New("invalid UUID format")
}
}
default:
return invalidLengthError{len(s)}
}
// Check for standard UUID format
if len(s) == 36 {
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
return errors.New("invalid UUID format")
}
for _, x := range []int{0, 2, 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 28, 30, 32, 34} {
if _, ok := xtob(s[x], s[x+1]); !ok {
return errors.New("invalid UUID format")
}
}
}
return nil
}
// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
// , or "" if uuid is invalid.
func (uuid UUID) String() string {
var buf [36]byte
encodeHex(buf[:], uuid)
return string(buf[:])
}
// URN returns the RFC 2141 URN form of uuid,
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid.
func (uuid UUID) URN() string {
var buf [36 + 9]byte
copy(buf[:], "urn:uuid:")
encodeHex(buf[9:], uuid)
return string(buf[:])
}
func encodeHex(dst []byte, uuid UUID) {
hex.Encode(dst, uuid[:4])
dst[8] = '-'
hex.Encode(dst[9:13], uuid[4:6])
dst[13] = '-'
hex.Encode(dst[14:18], uuid[6:8])
dst[18] = '-'
hex.Encode(dst[19:23], uuid[8:10])
dst[23] = '-'
hex.Encode(dst[24:], uuid[10:])
}
// Variant returns the variant encoded in uuid.
func (uuid UUID) Variant() Variant {
switch {
case (uuid[8] & 0xc0) == 0x80:
return RFC4122
case (uuid[8] & 0xe0) == 0xc0:
return Microsoft
case (uuid[8] & 0xe0) == 0xe0:
return Future
default:
return Reserved
}
}
// Version returns the version of uuid.
func (uuid UUID) Version() Version {
return Version(uuid[6] >> 4)
}
func (v Version) String() string {
if v > 15 {
return fmt.Sprintf("BAD_VERSION_%d", v)
}
return fmt.Sprintf("VERSION_%d", v)
}
func (v Variant) String() string {
switch v {
case RFC4122:
return "RFC4122"
case Reserved:
return "Reserved"
case Microsoft:
return "Microsoft"
case Future:
return "Future"
case Invalid:
return "Invalid"
}
return fmt.Sprintf("BadVariant%d", int(v))
}
// SetRand sets the random number generator to r, which implements io.Reader.
// If r.Read returns an error when the package requests random data then
// a panic will be issued.
//
// Calling SetRand with nil sets the random number generator to the default
// generator.
func SetRand(r io.Reader) {
if r == nil {
rander = rand.Reader
return
}
rander = r
}
// EnableRandPool enables internal randomness pool used for Random
// (Version 4) UUID generation. The pool contains random bytes read from
// the random number generator on demand in batches. Enabling the pool
// may improve the UUID generation throughput significantly.
//
// Since the pool is stored on the Go heap, this feature may be a bad fit
// for security sensitive applications.
//
// Both EnableRandPool and DisableRandPool are not thread-safe and should
// only be called when there is no possibility that New or any other
// UUID Version 4 generation function will be called concurrently.
func EnableRandPool() {
poolEnabled = true
}
// DisableRandPool disables the randomness pool if it was previously
// enabled with EnableRandPool.
//
// Both EnableRandPool and DisableRandPool are not thread-safe and should
// only be called when there is no possibility that New or any other
// UUID Version 4 generation function will be called concurrently.
func DisableRandPool() {
poolEnabled = false
defer poolMu.Unlock()
poolMu.Lock()
poolPos = randPoolSize
}
// UUIDs is a slice of UUID types.
type UUIDs []UUID
// Strings returns a string slice containing the string form of each UUID in uuids.
func (uuids UUIDs) Strings() []string {
var uuidStrs = make([]string, len(uuids))
for i, uuid := range uuids {
uuidStrs[i] = uuid.String()
}
return uuidStrs
}

44
client/vendor/github.com/google/uuid/version1.go generated vendored Normal file
View File

@@ -0,0 +1,44 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"encoding/binary"
)
// NewUUID returns a Version 1 UUID based on the current NodeID and clock
// sequence, and the current time. If the NodeID has not been set by SetNodeID
// or SetNodeInterface then it will be set automatically. If the NodeID cannot
// be set NewUUID returns nil. If clock sequence has not been set by
// SetClockSequence then it will be set automatically. If GetTime fails to
// return the current NewUUID returns nil and an error.
//
// In most cases, New should be used.
func NewUUID() (UUID, error) {
var uuid UUID
now, seq, err := GetTime()
if err != nil {
return uuid, err
}
timeLow := uint32(now & 0xffffffff)
timeMid := uint16((now >> 32) & 0xffff)
timeHi := uint16((now >> 48) & 0x0fff)
timeHi |= 0x1000 // Version 1
binary.BigEndian.PutUint32(uuid[0:], timeLow)
binary.BigEndian.PutUint16(uuid[4:], timeMid)
binary.BigEndian.PutUint16(uuid[6:], timeHi)
binary.BigEndian.PutUint16(uuid[8:], seq)
nodeMu.Lock()
if nodeID == zeroID {
setNodeInterface("")
}
copy(uuid[10:], nodeID[:])
nodeMu.Unlock()
return uuid, nil
}

76
client/vendor/github.com/google/uuid/version4.go generated vendored Normal file
View File

@@ -0,0 +1,76 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import "io"
// New creates a new random UUID or panics. New is equivalent to
// the expression
//
// uuid.Must(uuid.NewRandom())
func New() UUID {
return Must(NewRandom())
}
// NewString creates a new random UUID and returns it as a string or panics.
// NewString is equivalent to the expression
//
// uuid.New().String()
func NewString() string {
return Must(NewRandom()).String()
}
// NewRandom returns a Random (Version 4) UUID.
//
// The strength of the UUIDs is based on the strength of the crypto/rand
// package.
//
// Uses the randomness pool if it was enabled with EnableRandPool.
//
// A note about uniqueness derived from the UUID Wikipedia entry:
//
// Randomly generated UUIDs have 122 random bits. One's annual risk of being
// hit by a meteorite is estimated to be one chance in 17 billion, that
// means the probability is about 0.00000000006 (6 × 1011),
// equivalent to the odds of creating a few tens of trillions of UUIDs in a
// year and having one duplicate.
func NewRandom() (UUID, error) {
if !poolEnabled {
return NewRandomFromReader(rander)
}
return newRandomFromPool()
}
// NewRandomFromReader returns a UUID based on bytes read from a given io.Reader.
func NewRandomFromReader(r io.Reader) (UUID, error) {
var uuid UUID
_, err := io.ReadFull(r, uuid[:])
if err != nil {
return Nil, err
}
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
return uuid, nil
}
func newRandomFromPool() (UUID, error) {
var uuid UUID
poolMu.Lock()
if poolPos == randPoolSize {
_, err := io.ReadFull(rander, pool[:])
if err != nil {
poolMu.Unlock()
return Nil, err
}
poolPos = 0
}
copy(uuid[:], pool[poolPos:(poolPos+16)])
poolPos += 16
poolMu.Unlock()
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
return uuid, nil
}

56
client/vendor/github.com/google/uuid/version6.go generated vendored Normal file
View File

@@ -0,0 +1,56 @@
// Copyright 2023 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import "encoding/binary"
// UUID version 6 is a field-compatible version of UUIDv1, reordered for improved DB locality.
// It is expected that UUIDv6 will primarily be used in contexts where there are existing v1 UUIDs.
// Systems that do not involve legacy UUIDv1 SHOULD consider using UUIDv7 instead.
//
// see https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03#uuidv6
//
// NewV6 returns a Version 6 UUID based on the current NodeID and clock
// sequence, and the current time. If the NodeID has not been set by SetNodeID
// or SetNodeInterface then it will be set automatically. If the NodeID cannot
// be set NewV6 set NodeID is random bits automatically . If clock sequence has not been set by
// SetClockSequence then it will be set automatically. If GetTime fails to
// return the current NewV6 returns Nil and an error.
func NewV6() (UUID, error) {
var uuid UUID
now, seq, err := GetTime()
if err != nil {
return uuid, err
}
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time_high |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time_mid | time_low_and_version |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|clk_seq_hi_res | clk_seq_low | node (0-1) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| node (2-5) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
binary.BigEndian.PutUint64(uuid[0:], uint64(now))
binary.BigEndian.PutUint16(uuid[8:], seq)
uuid[6] = 0x60 | (uuid[6] & 0x0F)
uuid[8] = 0x80 | (uuid[8] & 0x3F)
nodeMu.Lock()
if nodeID == zeroID {
setNodeInterface("")
}
copy(uuid[10:], nodeID[:])
nodeMu.Unlock()
return uuid, nil
}

104
client/vendor/github.com/google/uuid/version7.go generated vendored Normal file
View File

@@ -0,0 +1,104 @@
// Copyright 2023 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"io"
)
// UUID version 7 features a time-ordered value field derived from the widely
// implemented and well known Unix Epoch timestamp source,
// the number of milliseconds seconds since midnight 1 Jan 1970 UTC, leap seconds excluded.
// As well as improved entropy characteristics over versions 1 or 6.
//
// see https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03#name-uuid-version-7
//
// Implementations SHOULD utilize UUID version 7 over UUID version 1 and 6 if possible.
//
// NewV7 returns a Version 7 UUID based on the current time(Unix Epoch).
// Uses the randomness pool if it was enabled with EnableRandPool.
// On error, NewV7 returns Nil and an error
func NewV7() (UUID, error) {
uuid, err := NewRandom()
if err != nil {
return uuid, err
}
makeV7(uuid[:])
return uuid, nil
}
// NewV7FromReader returns a Version 7 UUID based on the current time(Unix Epoch).
// it use NewRandomFromReader fill random bits.
// On error, NewV7FromReader returns Nil and an error.
func NewV7FromReader(r io.Reader) (UUID, error) {
uuid, err := NewRandomFromReader(r)
if err != nil {
return uuid, err
}
makeV7(uuid[:])
return uuid, nil
}
// makeV7 fill 48 bits time (uuid[0] - uuid[5]), set version b0111 (uuid[6])
// uuid[8] already has the right version number (Variant is 10)
// see function NewV7 and NewV7FromReader
func makeV7(uuid []byte) {
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms | ver | rand_a (12 bit seq) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| rand_b |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| rand_b |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
_ = uuid[15] // bounds check
t, s := getV7Time()
uuid[0] = byte(t >> 40)
uuid[1] = byte(t >> 32)
uuid[2] = byte(t >> 24)
uuid[3] = byte(t >> 16)
uuid[4] = byte(t >> 8)
uuid[5] = byte(t)
uuid[6] = 0x70 | (0x0F & byte(s>>8))
uuid[7] = byte(s)
}
// lastV7time is the last time we returned stored as:
//
// 52 bits of time in milliseconds since epoch
// 12 bits of (fractional nanoseconds) >> 8
var lastV7time int64
const nanoPerMilli = 1000000
// getV7Time returns the time in milliseconds and nanoseconds / 256.
// The returned (milli << 12 + seq) is guarenteed to be greater than
// (milli << 12 + seq) returned by any previous call to getV7Time.
func getV7Time() (milli, seq int64) {
timeMu.Lock()
defer timeMu.Unlock()
nano := timeNow().UnixNano()
milli = nano / nanoPerMilli
// Sequence number is between 0 and 3906 (nanoPerMilli>>8)
seq = (nano - milli*nanoPerMilli) >> 8
now := milli<<12 + seq
if now <= lastV7time {
now = lastV7time + 1
milli = now >> 12
seq = now & 0xfff
}
lastV7time = now
return milli, seq
}

21
client/vendor/github.com/zcalusic/sysinfo/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright © 2016 Zlatko Čalušić
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

204
client/vendor/github.com/zcalusic/sysinfo/README.md generated vendored Normal file
View File

@@ -0,0 +1,204 @@
# Sysinfo
[![Go Report Card](https://goreportcard.com/badge/github.com/zcalusic/sysinfo)](https://goreportcard.com/report/github.com/zcalusic/sysinfo)
[![GoDoc](https://godoc.org/github.com/zcalusic/sysinfo?status.svg)](https://godoc.org/github.com/zcalusic/sysinfo)
[![License](https://img.shields.io/badge/license-MIT-a31f34.svg?maxAge=2592000)](https://github.com/zcalusic/sysinfo/blob/master/LICENSE)
[![Powered by](https://img.shields.io/badge/powered_by-Go-5272b4.svg?maxAge=2592000)](https://go.dev/)
[![Platform](https://img.shields.io/badge/platform-Linux-009bde.svg?maxAge=2592000)](https://www.linuxfoundation.org/)
Package sysinfo is a Go library providing Linux OS / kernel / hardware system information. It's completely standalone,
has no dependencies on the host system and doesn't execute external programs. It collects only "inventory type"
information, things that don't change often.
## Code Example
```go
package main
import (
"encoding/json"
"fmt"
"log"
"os/user"
"github.com/zcalusic/sysinfo"
)
func main() {
current, err := user.Current()
if err != nil {
log.Fatal(err)
}
if current.Uid != "0" {
log.Fatal("requires superuser privilege")
}
var si sysinfo.SysInfo
si.GetSysInfo()
data, err := json.MarshalIndent(&si, "", " ")
if err != nil {
log.Fatal(err)
}
fmt.Println(string(data))
}
```
## Motivation
I couldn't find any self-contained library that would provide set of data/features I needed. So another sysinfo was
born.
The purpose of the library is to collect only inventory info. No metrics like CPU usage or load average will be added.
The rule of thumb is, if it's changing during the day, every day, it doesn't belong in the library.
The library should work well on any modern/supported Linux distribution. There are no plans to add support for older
unsupported Linux distributions/kernels, to keep the code clean and robust and reduce the maintenance burden.
## Requirements
Sysinfo requires:
- Linux kernel 4.2 or later
- access to /sys & /proc Linux virtual file systems
- access to various files in /etc, /var, /run FS hierarchy
- superuser privileges (to access SMBIOS/DMI table and detect RAM size and properties)
Sysinfo doesn't require ANY other external utility on the target system, which is its primary strength, IMHO.
It depends on Linux internals heavily, so there are no plans to support other operating systems.
## Installation
Just use go get.
```
go get github.com/zcalusic/sysinfo
```
There's also a very simple utility demonstrating sysinfo library capabilities. Start it (as superuser) to get pretty
formatted JSON output of all the info that sysinfo library provides. Due to its simplicity, the source code of the
utility also doubles down as an example of how to use the library.
```
go get github.com/zcalusic/sysinfo/cmd/sysinfo
```
--
Build demo utility in Docker container: https://github.com/mattscilipoti/compile_sysinfo
## Sample output
```json
{
"sysinfo": {
"version": "0.9.1",
"timestamp": "2016-09-24T13:30:28.369498856+02:00"
},
"node": {
"hostname": "web12",
"machineid": "04aa55927ebd390829367c1757b98cac",
"timezone": "Europe/Zagreb"
},
"os": {
"name": "CentOS Linux 7 (Core)",
"vendor": "centos",
"version": "7",
"release": "7.2.1511",
"architecture": "amd64"
},
"kernel": {
"release": "3.10.0-327.13.1.el7.x86_64",
"version": "#1 SMP Thu Mar 31 16:04:38 UTC 2016",
"architecture": "x86_64"
},
"product": {
"name": "RH2288H V3",
"vendor": "Huawei",
"version": "V100R003",
"serial": "2103711GEL10F3430658"
},
"board": {
"name": "BC11HGSA0",
"vendor": "Huawei",
"version": "V100R003",
"serial": "033HXVCNG3107624"
},
"chassis": {
"type": 17,
"vendor": "Huawei"
},
"bios": {
"vendor": "Insyde Corp.",
"version": "3.16",
"date": "03/16/2016"
},
"cpu": {
"vendor": "GenuineIntel",
"model": "Intel(R) Xeon(R) CPU E5-2630 v3 @ 2.40GHz",
"speed": 2400,
"cache": 20480,
"cpus": 1,
"cores": 8,
"threads": 16
},
"memory": {
"type": "DRAM",
"speed": 2133,
"size": 65536
},
"storage": [
{
"name": "sda",
"driver": "sd",
"vendor": "ATA",
"model": "ST9500620NS",
"serial": "9XF2HZ9K",
"size": 500
}
],
"network": [
{
"name": "enp3s0f1",
"driver": "ixgbe",
"macaddress": "84:ad:5a:e3:79:71",
"port": "fibre",
"speed": 10000
}
]
}
```
## Contributors
Contributors are welcome, just open a new issue / pull request.
## License
```
The MIT License (MIT)
Copyright © 2016 Zlatko Čalušić
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```

18
client/vendor/github.com/zcalusic/sysinfo/bios.go generated vendored Normal file
View File

@@ -0,0 +1,18 @@
// Copyright © 2016 Zlatko Čalušić
//
// Use of this source code is governed by an MIT-style license that can be found in the LICENSE file.
package sysinfo
// BIOS information.
type BIOS struct {
Vendor string `json:"vendor,omitempty"`
Version string `json:"version,omitempty"`
Date string `json:"date,omitempty"`
}
func (si *SysInfo) getBIOSInfo() {
si.BIOS.Vendor = slurpFile("/sys/class/dmi/id/bios_vendor")
si.BIOS.Version = slurpFile("/sys/class/dmi/id/bios_version")
si.BIOS.Date = slurpFile("/sys/class/dmi/id/bios_date")
}

22
client/vendor/github.com/zcalusic/sysinfo/board.go generated vendored Normal file
View File

@@ -0,0 +1,22 @@
// Copyright © 2016 Zlatko Čalušić
//
// Use of this source code is governed by an MIT-style license that can be found in the LICENSE file.
package sysinfo
// Board information.
type Board struct {
Name string `json:"name,omitempty"`
Vendor string `json:"vendor,omitempty"`
Version string `json:"version,omitempty"`
Serial string `json:"serial,omitempty"`
AssetTag string `json:"assettag,omitempty"`
}
func (si *SysInfo) getBoardInfo() {
si.Board.Name = slurpFile("/sys/class/dmi/id/board_name")
si.Board.Vendor = slurpFile("/sys/class/dmi/id/board_vendor")
si.Board.Version = slurpFile("/sys/class/dmi/id/board_version")
si.Board.Serial = slurpFile("/sys/class/dmi/id/board_serial")
si.Board.AssetTag = slurpFile("/sys/class/dmi/id/board_asset_tag")
}

26
client/vendor/github.com/zcalusic/sysinfo/chassis.go generated vendored Normal file
View File

@@ -0,0 +1,26 @@
// Copyright © 2016 Zlatko Čalušić
//
// Use of this source code is governed by an MIT-style license that can be found in the LICENSE file.
package sysinfo
import "strconv"
// Chassis information.
type Chassis struct {
Type uint `json:"type,omitempty"`
Vendor string `json:"vendor,omitempty"`
Version string `json:"version,omitempty"`
Serial string `json:"serial,omitempty"`
AssetTag string `json:"assettag,omitempty"`
}
func (si *SysInfo) getChassisInfo() {
if chtype, err := strconv.ParseUint(slurpFile("/sys/class/dmi/id/chassis_type"), 10, 64); err == nil {
si.Chassis.Type = uint(chtype)
}
si.Chassis.Vendor = slurpFile("/sys/class/dmi/id/chassis_vendor")
si.Chassis.Version = slurpFile("/sys/class/dmi/id/chassis_version")
si.Chassis.Serial = slurpFile("/sys/class/dmi/id/chassis_serial")
si.Chassis.AssetTag = slurpFile("/sys/class/dmi/id/chassis_asset_tag")
}

85
client/vendor/github.com/zcalusic/sysinfo/cpu.go generated vendored Normal file
View File

@@ -0,0 +1,85 @@
// Copyright © 2016 Zlatko Čalušić
//
// Use of this source code is governed by an MIT-style license that can be found in the LICENSE file.
package sysinfo
import (
"bufio"
"fmt"
"os"
"regexp"
"runtime"
"strconv"
"strings"
)
// CPU information.
type CPU struct {
Vendor string `json:"vendor,omitempty"`
Model string `json:"model,omitempty"`
Speed uint `json:"speed,omitempty"` // CPU clock rate in MHz
Cache uint `json:"cache,omitempty"` // CPU cache size in KB
Cpus uint `json:"cpus,omitempty"` // number of physical CPUs
Cores uint `json:"cores,omitempty"` // number of physical CPU cores
Threads uint `json:"threads,omitempty"` // number of logical (HT) CPU cores
}
var (
reTwoColumns = regexp.MustCompile("\t+: ")
reExtraSpace = regexp.MustCompile(" +")
reCacheSize = regexp.MustCompile(`^(\d+) KB$`)
)
func (si *SysInfo) getCPUInfo() {
si.CPU.Threads = uint(runtime.NumCPU())
f, err := os.Open("/proc/cpuinfo")
if err != nil {
return
}
defer f.Close()
cpu := make(map[string]bool)
core := make(map[string]bool)
var cpuID string
s := bufio.NewScanner(f)
for s.Scan() {
if sl := reTwoColumns.Split(s.Text(), 2); sl != nil {
switch sl[0] {
case "physical id":
cpuID = sl[1]
cpu[cpuID] = true
case "core id":
coreID := fmt.Sprintf("%s/%s", cpuID, sl[1])
core[coreID] = true
case "vendor_id":
if si.CPU.Vendor == "" {
si.CPU.Vendor = sl[1]
}
case "model name":
if si.CPU.Model == "" {
// CPU model, as reported by /proc/cpuinfo, can be a bit ugly. Clean up...
model := reExtraSpace.ReplaceAllLiteralString(sl[1], " ")
si.CPU.Model = strings.Replace(model, "- ", "-", 1)
}
case "cache size":
if si.CPU.Cache == 0 {
if m := reCacheSize.FindStringSubmatch(sl[1]); m != nil {
if cache, err := strconv.ParseUint(m[1], 10, 64); err == nil {
si.CPU.Cache = uint(cache)
}
}
}
}
}
}
if s.Err() != nil {
return
}
si.CPU.Cpus = uint(len(cpu))
si.CPU.Cores = uint(len(core))
}

View File

@@ -0,0 +1,27 @@
Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,9 @@
// Copyright © 2018 Zlatko Čalušić
//
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
// Package cpuid gives Go programs access to CPUID opcode.
package cpuid
// CPUID returns processor identification and feature information.
func CPUID(info *[4]uint32, ax uint32)

View File

@@ -0,0 +1,16 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo
TEXT ·CPUID(SB),$0-8
MOVL ax+4(FP), AX
CPUID
MOVL info+0(FP), DI
MOVL AX, 0(DI)
MOVL BX, 4(DI)
MOVL CX, 8(DI)
MOVL DX, 12(DI)
RET

View File

@@ -0,0 +1,16 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo
TEXT ·CPUID(SB),$0-12
MOVL ax+8(FP), AX
CPUID
MOVQ info+0(FP), DI
MOVL AX, 0(DI)
MOVL BX, 4(DI)
MOVL CX, 8(DI)
MOVL DX, 12(DI)
RET

View File

@@ -0,0 +1,10 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !386,!amd64,!gccgo
#include "textflag.h"
TEXT ·CPUID(SB),NOSPLIT,$0-0
RET

View File

@@ -0,0 +1,65 @@
// Copyright © 2016 Zlatko Čalušić
//
// Use of this source code is governed by an MIT-style license that can be found in the LICENSE file.
package sysinfo
import (
"strings"
"unsafe"
"github.com/zcalusic/sysinfo/cpuid"
)
// https://en.wikipedia.org/wiki/CPUID#EAX.3D0:_Get_vendor_ID
var hvmap = map[string]string{
"bhyve bhyve ": "bhyve",
"KVMKVMKVM": "kvm",
"Microsoft Hv": "hyperv",
" lrpepyh vr": "parallels",
"VMwareVMware": "vmware",
"XenVMMXenVMM": "xenhvm",
}
func isHypervisorActive() bool {
var info [4]uint32
cpuid.CPUID(&info, 0x1)
return info[2]&(1<<31) != 0
}
func getHypervisorCpuid(ax uint32) string {
var info [4]uint32
cpuid.CPUID(&info, ax)
return hvmap[strings.TrimRight(string((*[12]byte)(unsafe.Pointer(&info[1]))[:]), "\000")]
}
func (si *SysInfo) getHypervisor() {
if !isHypervisorActive() {
if hypervisorType := slurpFile("/sys/hypervisor/type"); hypervisorType != "" {
if hypervisorType == "xen" {
si.Node.Hypervisor = "xenpv"
}
}
return
}
// KVM has been caught to move its real signature to this leaf, and put something completely different in the
// standard location. So this leaf must be checked first.
if hv := getHypervisorCpuid(0x40000100); hv != "" {
si.Node.Hypervisor = hv
return
}
if hv := getHypervisorCpuid(0x40000000); hv != "" {
si.Node.Hypervisor = hv
return
}
// getBIOSInfo() must have run first, to detect BIOS vendor
if si.BIOS.Vendor == "Bochs" {
si.Node.Hypervisor = "bochs"
return
}
si.Node.Hypervisor = "unknown"
}

View File

@@ -0,0 +1,14 @@
//go:build darwin
// +build darwin
package sysinfo
// Kernel information.
type Kernel struct {
Release string `json:"release,omitempty"`
Version string `json:"version,omitempty"`
Architecture string `json:"architecture,omitempty"`
}
func (si *SysInfo) getKernelInfo() {
}

View File

@@ -0,0 +1,33 @@
// Copyright © 2016 Zlatko Čalušić
//
// Use of this source code is governed by an MIT-style license that can be found in the LICENSE file.
//go:build linux
// +build linux
package sysinfo
import (
"strings"
"syscall"
"unsafe"
)
// Kernel information.
type Kernel struct {
Release string `json:"release,omitempty"`
Version string `json:"version,omitempty"`
Architecture string `json:"architecture,omitempty"`
}
func (si *SysInfo) getKernelInfo() {
si.Kernel.Release = slurpFile("/proc/sys/kernel/osrelease")
si.Kernel.Version = slurpFile("/proc/sys/kernel/version")
var uname syscall.Utsname
if err := syscall.Uname(&uname); err != nil {
return
}
si.Kernel.Architecture = strings.TrimRight(string((*[65]byte)(unsafe.Pointer(&uname.Machine))[:]), "\000")
}

121
client/vendor/github.com/zcalusic/sysinfo/memory.go generated vendored Normal file
View File

@@ -0,0 +1,121 @@
// Copyright © 2016 Zlatko Čalušić
//
// Use of this source code is governed by an MIT-style license that can be found in the LICENSE file.
package sysinfo
import (
"bytes"
"encoding/binary"
"os"
"strconv"
)
// Memory information.
type Memory struct {
Type string `json:"type,omitempty"`
Speed uint `json:"speed,omitempty"` // RAM data rate in MT/s
Size uint `json:"size,omitempty"` // RAM size in MB
}
func word(data []byte, index int) uint16 {
return binary.LittleEndian.Uint16(data[index : index+2])
}
func dword(data []byte, index int) uint32 {
return binary.LittleEndian.Uint32(data[index : index+4])
}
func qword(data []byte, index int) uint64 {
return binary.LittleEndian.Uint64(data[index : index+8])
}
func (si *SysInfo) getMemoryInfo() {
dmi, err := os.ReadFile("/sys/firmware/dmi/tables/DMI")
if err != nil {
// Xen hypervisor
if targetKB := slurpFile("/sys/devices/system/xen_memory/xen_memory0/target_kb"); targetKB != "" {
si.Memory.Type = "DRAM"
size, _ := strconv.ParseUint(targetKB, 10, 64)
si.Memory.Size = uint(size) / 1024
}
return
}
si.Memory.Size = 0
var memSizeAlt uint
loop:
for p := 0; p < len(dmi)-1; {
recType := dmi[p]
recLen := dmi[p+1]
switch recType {
case 4:
if si.CPU.Speed == 0 {
si.CPU.Speed = uint(word(dmi, p+0x16))
}
case 17:
size := uint(word(dmi, p+0x0c))
if size == 0 || size == 0xffff || size&0x8000 == 0x8000 {
break
}
if size == 0x7fff {
if recLen >= 0x20 {
size = uint(dword(dmi, p+0x1c))
} else {
break
}
}
si.Memory.Size += size
if si.Memory.Type == "" {
// SMBIOS Reference Specification Version 3.0.0, page 92
memTypes := [...]string{
"Other", "Unknown", "DRAM", "EDRAM", "VRAM", "SRAM", "RAM", "ROM", "FLASH",
"EEPROM", "FEPROM", "EPROM", "CDRAM", "3DRAM", "SDRAM", "SGRAM", "RDRAM",
"DDR", "DDR2", "DDR2 FB-DIMM", "Reserved", "Reserved", "Reserved", "DDR3",
"FBD2", "DDR4", "LPDDR", "LPDDR2", "LPDDR3", "LPDDR4",
}
if index := int(dmi[p+0x12]); index >= 1 && index <= len(memTypes) {
si.Memory.Type = memTypes[index-1]
}
}
if si.Memory.Speed == 0 && recLen >= 0x17 {
if speed := uint(word(dmi, p+0x15)); speed != 0 {
si.Memory.Speed = speed
}
}
case 19:
start := uint(dword(dmi, p+0x04))
end := uint(dword(dmi, p+0x08))
if start == 0xffffffff && end == 0xffffffff {
if recLen >= 0x1f {
start64 := qword(dmi, p+0x0f)
end64 := qword(dmi, p+0x17)
memSizeAlt += uint((end64 - start64 + 1) / 1048576)
}
} else {
memSizeAlt += (end - start + 1) / 1024
}
case 127:
break loop
}
for p += int(recLen); p < len(dmi)-1; {
if bytes.Equal(dmi[p:p+2], []byte{0, 0}) {
p += 2
break
}
p++
}
}
// Sometimes DMI type 17 has no information, so we fall back to DMI type 19, to at least get the RAM size.
if si.Memory.Size == 0 && memSizeAlt > 0 {
si.Memory.Type = "DRAM"
si.Memory.Size = memSizeAlt
}
}

18
client/vendor/github.com/zcalusic/sysinfo/meta.go generated vendored Normal file
View File

@@ -0,0 +1,18 @@
// Copyright © 2016 Zlatko Čalušić
//
// Use of this source code is governed by an MIT-style license that can be found in the LICENSE file.
package sysinfo
import "time"
// Meta information.
type Meta struct {
Version string `json:"version"`
Timestamp time.Time `json:"timestamp"`
}
func (si *SysInfo) getMetaInfo() {
si.Meta.Version = Version
si.Meta.Timestamp = time.Now()
}

146
client/vendor/github.com/zcalusic/sysinfo/network.go generated vendored Normal file
View File

@@ -0,0 +1,146 @@
// Copyright © 2016 Zlatko Čalušić
//
// Use of this source code is governed by an MIT-style license that can be found in the LICENSE file.
package sysinfo
import (
"os"
"path"
"strings"
"syscall"
"unsafe"
)
// NetworkDevice information.
type NetworkDevice struct {
Name string `json:"name,omitempty"`
Driver string `json:"driver,omitempty"`
MACAddress string `json:"macaddress,omitempty"`
Port string `json:"port,omitempty"`
Speed uint `json:"speed,omitempty"` // device max supported speed in Mbps
}
func getPortType(supp uint32) (port string) {
for i, p := range [...]string{"tp", "aui", "mii", "fibre", "bnc"} {
if supp&(1<<uint(i+7)) > 0 {
port += p + "/"
}
}
port = strings.TrimRight(port, "/")
return
}
func getMaxSpeed(supp uint32) (speed uint) {
// Fancy, right?
switch {
case supp&0x78000000 > 0:
speed = 56000
case supp&0x07800000 > 0:
speed = 40000
case supp&0x00600000 > 0:
speed = 20000
case supp&0x001c1000 > 0:
speed = 10000
case supp&0x00008000 > 0:
speed = 2500
case supp&0x00020030 > 0:
speed = 1000
case supp&0x0000000c > 0:
speed = 100
case supp&0x00000003 > 0:
speed = 10
}
return
}
func getSupported(name string) uint32 {
fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_IP)
if err != nil {
return 0
}
defer syscall.Close(fd)
// struct ethtool_cmd from /usr/include/linux/ethtool.h
var ethtool struct {
Cmd uint32
Supported uint32
Advertising uint32
Speed uint16
Duplex uint8
Port uint8
PhyAddress uint8
Transceiver uint8
Autoneg uint8
MdioSupport uint8
Maxtxpkt uint32
Maxrxpkt uint32
SpeedHi uint16
EthTpMdix uint8
Reserved2 uint8
LpAdvertising uint32
Reserved [2]uint32
}
// ETHTOOL_GSET from /usr/include/linux/ethtool.h
const GSET = 0x1
ethtool.Cmd = GSET
// struct ifreq from /usr/include/linux/if.h
var ifr struct {
Name [16]byte
Data uintptr
}
copy(ifr.Name[:], name+"\000")
ifr.Data = uintptr(unsafe.Pointer(&ethtool))
// SIOCETHTOOL from /usr/include/linux/sockios.h
const SIOCETHTOOL = 0x8946
_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(SIOCETHTOOL), uintptr(unsafe.Pointer(&ifr)))
if errno == 0 {
return ethtool.Supported
}
return 0
}
func (si *SysInfo) getNetworkInfo() {
sysClassNet := "/sys/class/net"
devices, err := os.ReadDir(sysClassNet)
if err != nil {
return
}
si.Network = make([]NetworkDevice, 0)
for _, link := range devices {
fullpath := path.Join(sysClassNet, link.Name())
dev, err := os.Readlink(fullpath)
if err != nil {
continue
}
if strings.HasPrefix(dev, "../../devices/virtual/") {
continue
}
supp := getSupported(link.Name())
device := NetworkDevice{
Name: link.Name(),
MACAddress: slurpFile(path.Join(fullpath, "address")),
Port: getPortType(supp),
Speed: getMaxSpeed(supp),
}
if driver, err := os.Readlink(path.Join(fullpath, "device", "driver")); err == nil {
device.Driver = path.Base(driver)
}
si.Network = append(si.Network, device)
}
}

99
client/vendor/github.com/zcalusic/sysinfo/node.go generated vendored Normal file
View File

@@ -0,0 +1,99 @@
// Copyright © 2016 Zlatko Čalušić
//
// Use of this source code is governed by an MIT-style license that can be found in the LICENSE file.
package sysinfo
import (
"bufio"
"os"
"strings"
)
// Node information.
type Node struct {
Hostname string `json:"hostname,omitempty"`
MachineID string `json:"machineid,omitempty"`
Hypervisor string `json:"hypervisor,omitempty"`
Timezone string `json:"timezone,omitempty"`
}
func (si *SysInfo) getHostname() {
si.Node.Hostname = slurpFile("/proc/sys/kernel/hostname")
}
func (si *SysInfo) getSetMachineID() {
const pathSystemdMachineID = "/etc/machine-id"
const pathDbusMachineID = "/var/lib/dbus/machine-id"
systemdMachineID := slurpFile(pathSystemdMachineID)
dbusMachineID := slurpFile(pathDbusMachineID)
if systemdMachineID != "" && dbusMachineID != "" {
// All OK, just return the machine id.
if systemdMachineID == dbusMachineID {
si.Node.MachineID = systemdMachineID
return
}
// They both exist, but they don't match! Copy systemd machine id to DBUS machine id.
spewFile(pathDbusMachineID, systemdMachineID, 0444)
si.Node.MachineID = systemdMachineID
return
}
// Copy DBUS machine id to non-existent systemd machine id.
if systemdMachineID == "" && dbusMachineID != "" {
spewFile(pathSystemdMachineID, dbusMachineID, 0444)
si.Node.MachineID = dbusMachineID
return
}
// Copy systemd machine id to non-existent DBUS machine id.
if systemdMachineID != "" && dbusMachineID == "" {
spewFile(pathDbusMachineID, systemdMachineID, 0444)
si.Node.MachineID = systemdMachineID
return
}
}
func (si *SysInfo) getTimezone() {
const zoneInfoPrefix = "/usr/share/zoneinfo/"
if fi, err := os.Lstat("/etc/localtime"); err == nil {
if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
if tzfile, err := os.Readlink("/etc/localtime"); err == nil {
tzfile = strings.TrimPrefix(tzfile, "..")
if strings.HasPrefix(tzfile, zoneInfoPrefix) {
si.Node.Timezone = strings.TrimPrefix(tzfile, zoneInfoPrefix)
return
}
}
}
}
if timezone := slurpFile("/etc/timezone"); timezone != "" {
si.Node.Timezone = timezone
return
}
if f, err := os.Open("/etc/sysconfig/clock"); err == nil {
defer f.Close()
s := bufio.NewScanner(f)
for s.Scan() {
if sl := strings.Split(s.Text(), "="); len(sl) == 2 {
if sl[0] == "ZONE" {
si.Node.Timezone = strings.Trim(sl[1], `"`)
return
}
}
}
}
}
func (si *SysInfo) getNodeInfo() {
si.getHostname()
si.getSetMachineID()
si.getHypervisor()
si.getTimezone()
}

101
client/vendor/github.com/zcalusic/sysinfo/os.go generated vendored Normal file
View File

@@ -0,0 +1,101 @@
// Copyright © 2016 Zlatko Čalušić
//
// Use of this source code is governed by an MIT-style license that can be found in the LICENSE file.
package sysinfo
import (
"bufio"
"os"
"regexp"
"strings"
)
// OS information.
type OS struct {
Name string `json:"name,omitempty"`
Vendor string `json:"vendor,omitempty"`
Version string `json:"version,omitempty"`
Release string `json:"release,omitempty"`
Architecture string `json:"architecture,omitempty"`
}
var (
rePrettyName = regexp.MustCompile(`^PRETTY_NAME=(.*)$`)
reID = regexp.MustCompile(`^ID=(.*)$`)
reVersionID = regexp.MustCompile(`^VERSION_ID=(.*)$`)
reUbuntu = regexp.MustCompile(`[\( ]([\d\.]+)`)
reAlma = regexp.MustCompile(`^AlmaLinux release ([\d\.]+)`)
reCentOS = regexp.MustCompile(`^CentOS( Linux)? release ([\d\.]+)`)
reRocky = regexp.MustCompile(`^Rocky Linux release ([\d\.]+)`)
reRedHat = regexp.MustCompile(`[\( ]([\d\.]+)`)
)
func (si *SysInfo) getOSInfo() {
// This seems to be the best and most portable way to detect OS architecture (NOT kernel!)
if _, err := os.Stat("/lib64/ld-linux-x86-64.so.2"); err == nil {
si.OS.Architecture = "amd64"
} else if _, err := os.Stat("/lib/ld-linux.so.2"); err == nil {
si.OS.Architecture = "i386"
}
f, err := os.Open("/etc/os-release")
if err != nil {
return
}
defer f.Close()
s := bufio.NewScanner(f)
for s.Scan() {
if m := rePrettyName.FindStringSubmatch(s.Text()); m != nil {
si.OS.Name = strings.Trim(m[1], `"`)
} else if m := reID.FindStringSubmatch(s.Text()); m != nil {
si.OS.Vendor = strings.Trim(m[1], `"`)
} else if m := reVersionID.FindStringSubmatch(s.Text()); m != nil {
si.OS.Version = strings.Trim(m[1], `"`)
}
}
switch si.OS.Vendor {
case "debian":
si.OS.Release = slurpFile("/etc/debian_version")
case "ubuntu":
if m := reUbuntu.FindStringSubmatch(si.OS.Name); m != nil {
si.OS.Release = m[1]
}
case "almalinux":
if release := slurpFile("/etc/almalinux-release"); release != "" {
if m := reAlma.FindStringSubmatch(release); m != nil {
si.OS.Release = m[1]
}
}
si.OS.Version = strings.Split(si.OS.Release, ".")[0]
case "centos":
if release := slurpFile("/etc/centos-release"); release != "" {
if m := reCentOS.FindStringSubmatch(release); m != nil {
si.OS.Release = m[2]
}
}
case "rocky":
if release := slurpFile("/etc/rocky-release"); release != "" {
if m := reRocky.FindStringSubmatch(release); m != nil {
si.OS.Release = m[1]
}
}
si.OS.Version = strings.Split(si.OS.Release, ".")[0]
case "rhel":
if release := slurpFile("/etc/redhat-release"); release != "" {
if m := reRedHat.FindStringSubmatch(release); m != nil {
si.OS.Release = m[1]
}
}
if si.OS.Release == "" {
if m := reRedHat.FindStringSubmatch(si.OS.Name); m != nil {
si.OS.Release = m[1]
}
}
}
}

42
client/vendor/github.com/zcalusic/sysinfo/product.go generated vendored Normal file
View File

@@ -0,0 +1,42 @@
// Copyright © 2016 Zlatko Čalušić
//
// Use of this source code is governed by an MIT-style license that can be found in the LICENSE file.
package sysinfo
import "github.com/google/uuid"
// Product information.
type Product struct {
Name string `json:"name,omitempty"`
Vendor string `json:"vendor,omitempty"`
Version string `json:"version,omitempty"`
Serial string `json:"serial,omitempty"`
UUID uuid.UUID `json:"uuid,omitempty"`
SKU string `json:"sku,omitempty"`
}
func (si *SysInfo) getProductInfo() {
si.Product.Name = slurpFile("/sys/class/dmi/id/product_name")
si.Product.Vendor = slurpFile("/sys/class/dmi/id/sys_vendor")
si.Product.Version = slurpFile("/sys/class/dmi/id/product_version")
si.Product.Serial = slurpFile("/sys/class/dmi/id/product_serial")
si.Product.SKU = slurpFile("/sys/class/dmi/id/product_sku")
uid, err := uuid.Parse(slurpFile("/sys/class/dmi/id/product_uuid"))
if err == nil {
si.Product.UUID = uid
}
// try a fallback to device-tree (ex: dmi is not available on ARM devices)
// full details: https://www.devicetree.org/specifications/
// on linux root path is /proc/device-tree (see: https://github.com/torvalds/linux/blob/v5.9/Documentation/ABI/testing/sysfs-firmware-ofw)
if si.Product.Name == "" {
si.Product.Name = slurpFile("/proc/device-tree/model")
}
if si.Product.Serial == "" {
si.Product.Serial = slurpFile("/proc/device-tree/serial-number")
}
}

104
client/vendor/github.com/zcalusic/sysinfo/storage.go generated vendored Normal file
View File

@@ -0,0 +1,104 @@
// Copyright © 2016 Zlatko Čalušić
//
// Use of this source code is governed by an MIT-style license that can be found in the LICENSE file.
package sysinfo
import (
"bufio"
"os"
"path"
"strconv"
"strings"
)
// StorageDevice information.
type StorageDevice struct {
Name string `json:"name,omitempty"`
Driver string `json:"driver,omitempty"`
Vendor string `json:"vendor,omitempty"`
Model string `json:"model,omitempty"`
Serial string `json:"serial,omitempty"`
Size uint `json:"size,omitempty"` // device size in GB
}
func getSerial(name, fullpath string) (serial string) {
var f *os.File
var err error
// Modern location/format of the udev database.
if dev := slurpFile(path.Join(fullpath, "dev")); dev != "" {
if f, err = os.Open(path.Join("/run/udev/data", "b"+dev)); err == nil {
goto scan
}
}
// Legacy location/format of the udev database.
if f, err = os.Open(path.Join("/dev/.udev/db", "block:"+name)); err == nil {
goto scan
}
// No serial :(
return
scan:
defer f.Close()
s := bufio.NewScanner(f)
for s.Scan() {
if sl := strings.Split(s.Text(), "="); len(sl) == 2 {
if sl[0] == "E:ID_SERIAL_SHORT" {
serial = sl[1]
break
}
}
}
return
}
func (si *SysInfo) getStorageInfo() {
sysBlock := "/sys/block"
devices, err := os.ReadDir(sysBlock)
if err != nil {
return
}
si.Storage = make([]StorageDevice, 0)
for _, link := range devices {
fullpath := path.Join(sysBlock, link.Name())
dev, err := os.Readlink(fullpath)
if err != nil {
continue
}
if strings.HasPrefix(dev, "../devices/virtual/") {
continue
}
// We could filter all removable devices here, but some systems boot from USB flash disks, and then we
// would filter them, too. So, let's filter only floppies and CD/DVD devices, and see how it pans out.
if strings.HasPrefix(dev, "../devices/platform/floppy") || slurpFile(path.Join(fullpath, "device", "type")) == "5" {
continue
}
device := StorageDevice{
Name: link.Name(),
Model: slurpFile(path.Join(fullpath, "device", "model")),
Serial: getSerial(link.Name(), fullpath),
}
if driver, err := os.Readlink(path.Join(fullpath, "device", "driver")); err == nil {
device.Driver = path.Base(driver)
}
if vendor := slurpFile(path.Join(fullpath, "device", "vendor")); !strings.HasPrefix(vendor, "0x") {
device.Vendor = vendor
}
size, _ := strconv.ParseUint(slurpFile(path.Join(fullpath, "size")), 10, 64)
device.Size = uint(size) / 1953125 // GiB
si.Storage = append(si.Storage, device)
}
}

49
client/vendor/github.com/zcalusic/sysinfo/sysinfo.go generated vendored Normal file
View File

@@ -0,0 +1,49 @@
// Copyright © 2016 Zlatko Čalušić
//
// Use of this source code is governed by an MIT-style license that can be found in the LICENSE file.
// Package sysinfo is a Go library providing Linux OS / kernel / hardware system information.
package sysinfo
// SysInfo struct encapsulates all other information structs.
type SysInfo struct {
Meta Meta `json:"sysinfo"`
Node Node `json:"node"`
OS OS `json:"os"`
Kernel Kernel `json:"kernel"`
Product Product `json:"product"`
Board Board `json:"board"`
Chassis Chassis `json:"chassis"`
BIOS BIOS `json:"bios"`
CPU CPU `json:"cpu"`
Memory Memory `json:"memory"`
Storage []StorageDevice `json:"storage,omitempty"`
Network []NetworkDevice `json:"network,omitempty"`
}
// GetSysInfo gathers all available system information.
func (si *SysInfo) GetSysInfo() {
// Meta info
si.getMetaInfo()
// DMI info
si.getProductInfo()
si.getBoardInfo()
si.getChassisInfo()
si.getBIOSInfo()
// SMBIOS info
si.getMemoryInfo()
// Node info
si.getNodeInfo() // depends on BIOS info
// Hardware info
si.getCPUInfo() // depends on Node info
si.getStorageInfo()
si.getNetworkInfo()
// Software info
si.getOSInfo()
si.getKernelInfo()
}

26
client/vendor/github.com/zcalusic/sysinfo/util.go generated vendored Normal file
View File

@@ -0,0 +1,26 @@
// Copyright © 2016 Zlatko Čalušić
//
// Use of this source code is governed by an MIT-style license that can be found in the LICENSE file.
package sysinfo
import (
"os"
"strings"
)
// Read one-liner text files, strip newline.
func slurpFile(path string) string {
data, err := os.ReadFile(path)
if err != nil {
return ""
}
// Trim spaces & \u0000 \uffff
return strings.Trim(string(data), " \r\n\t\u0000\uffff")
}
// Write one-liner text files, add newline, ignore errors (best effort).
func spewFile(path string, data string, perm os.FileMode) {
_ = os.WriteFile(path, []byte(data+"\n"), perm)
}

8
client/vendor/github.com/zcalusic/sysinfo/version.go generated vendored Normal file
View File

@@ -0,0 +1,8 @@
// Copyright © 2016 Zlatko Čalušić
//
// Use of this source code is governed by an MIT-style license that can be found in the LICENSE file.
package sysinfo
// Version of the sysinfo library.
const Version = "1.1.3"

7
client/vendor/modules.txt vendored Normal file
View File

@@ -0,0 +1,7 @@
# github.com/google/uuid v1.6.0
## explicit
github.com/google/uuid
# github.com/zcalusic/sysinfo v1.1.3
## explicit; go 1.22
github.com/zcalusic/sysinfo
github.com/zcalusic/sysinfo/cpuid

View File

@@ -22,7 +22,7 @@
default = pkgs.buildGoModule {
pname = "orphanage-client";
inherit version;
src = ./.;
src = ./client;
vendorHash = null;
};
});

3
go.mod
View File

@@ -1,3 +0,0 @@
module git.dubyatp.xyz/orphanage
go 1.24.4

View File

@@ -1,10 +0,0 @@
package http
import "net/http"
func NewServer() http.Handler {
mux := http.NewServeMux()
addRoutes(mux)
var handler http.Handler = mux
return handler
}

View File

@@ -1,9 +0,0 @@
package http
import "net/http"
func HelloWorld(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello world"))
})
}

View File

@@ -1,10 +0,0 @@
package http
import "net/http"
func addRoutes(
mux *http.ServeMux,
) {
mux.Handle("/", http.NotFoundHandler())
mux.Handle("/helloworld", HelloWorld(nil))
}

View File

@@ -1,40 +0,0 @@
package http
import (
"context"
"fmt"
"log"
"net"
"net/http"
"os"
"sync"
"time"
)
func StartServer(ctx context.Context, config struct{ Host, Port string }) error {
srv := NewServer()
httpServer := &http.Server{
Addr: net.JoinHostPort(config.Host, config.Port),
Handler: srv,
}
go func() {
log.Printf("orphan listening on %s\n", httpServer.Addr)
if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
fmt.Fprintf(os.Stderr, "error listening and serving: %s\n", err)
}
}()
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
<-ctx.Done()
shutdownCtx := context.Background()
shutdownCtx, cancel := context.WithTimeout(shutdownCtx, 10*time.Second)
defer cancel()
if err := httpServer.Shutdown(shutdownCtx); err != nil {
fmt.Fprintf(os.Stderr, "error shutting down http server: %s\n", err)
}
}()
wg.Wait()
return nil
}

34
main.go
View File

@@ -1,34 +0,0 @@
package main
import (
"context"
"fmt"
"io"
"os"
"os/signal"
"git.dubyatp.xyz/orphanage/http"
)
func run(ctx context.Context, w io.Writer, args []string) error {
ctx, cancel := signal.NotifyContext(ctx, os.Interrupt)
defer cancel()
config := struct {
Host string
Port string
}{
Host: "0.0.0.0",
Port: "8080",
}
return http.StartServer(ctx, config)
}
func main() {
ctx := context.Background()
if err := run(ctx, os.Stdout, os.Args); err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err)
os.Exit(1)
}
}