Skip to content

Commit

Permalink
Load machine-name directly, instead of generating it from a serial nu…
Browse files Browse the repository at this point in the history
…mber (#124)
  • Loading branch information
ethanjli authored Apr 22, 2024
1 parent 5648a78 commit a1f1f7c
Show file tree
Hide file tree
Showing 7 changed files with 33 additions and 78 deletions.
2 changes: 1 addition & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ linters-settings:
gocyclo:
min-complexity: 15
govet:
check-shadowing: true
shadow: true
misspell:
locale: US
nolintlint:
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ All dates in this file are given in the [UTC time zone](https://en.wikipedia.org

## Unreleased

## 0.2.0 - 2024-04-22

### Changed

- (Breaking change) Instead of generating a machine name from a serial number which is either specified as the `MACHINENAME_SN` environment variable or loaded from a file specified by the `MACHINENAME_SNFILE` environment variable, now the device portal just tries to load the machine name from the `MACHINENAME_NAME` environment variable or else from a file specified by the `MACHINENAME_NAMEFILE` environment variable (which defaults to `/run/machine-name`), and it falls back to a name of "unknown" if no machine name is found.

## 0.1.15 - 2024-01-11

### Fixed
Expand Down
18 changes: 10 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ tar -xzf device-portal_{version number}_{os}_{cpu architecture}.tar.gz device-po

Then you may need to move the device-portal binary into a directory in your system path, or you can just run the device-portal binary in your current directory (in which case you should replace `device-portal` with `./device-portal` in the commands listed below).

Once you have device-portal, you should run it as follows on a Raspberry Pi:
Once you have device-portal, you can run it as follows on a Raspberry Pi:
```
device-portal
./device-portal
```

Then you can view the landing page at http://localhost:3000 . Note that if you are running it on a computer other than the Raspberry Pi with the standard PlanktoScope software distribution, then you will need to set some environment variables (see below) to non-default values.
Then you can view the landing page at http://localhost:3000 . Note that if you are running it on a computer other than the Raspberry Pi with the standard PlanktoScope OS, then you will need to set some environment variables (see below) to non-default values.

### Development

Expand All @@ -39,14 +39,16 @@ To execute the full build pipeline, run `make`; to build the docker images, run

### Environment Variables

If you are running device-portal on a computer which is not a Raspberry Pi with the standard PlanktoScope software distribution, then you'll need to set some environment variables. Specifically, you'll need to set:
If you are running device-portal on a computer which is not a Raspberry Pi with the standard PlanktoScope OS, then you'll need to set some environment variables. Specifically, you'll need to set:

- Either `MACHINENAME_SN`, which should be a 32-bit hex number representing the computer's serial number (which is used for determining the computer's machine name to be displayed on the landing page), or `MACHINENAME_SNFILE`, which should be the path to a file containing a hex number, the least-significant 32 bits of which will be interpreted as a 32-bit serial number.
- Either `MACHINENAME_NAME`, which should be a string representing the name of the machine to be displayed on the landing page, or `MACHINENAME_NAMEFILE`, which should be the path to a file containing the name of the machine to be displayed on the landing page.

For example, you could run device-portal with the fake serial number `0xdeadc0de` using any of the following commands:
For example, you could run device-portal with the machine name `metal-slope-23501` with one of the following commands:
```
MACHINENAME_SN=deadc0de make run
MACHINENAME_SN=0xdeadc0de make run
# If you downloaded a device-portal binary:
MACHINENAME_NAME=metal-slope-23501 ./device-portal
# If you are developing the project:
MACHINENAME_NAME=metal-slope-23501 make run
```

## Licensing
Expand Down
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ go 1.22

require (
github.com/Masterminds/sprig/v3 v3.2.3
github.com/PlanktoScope/machine-name v0.1.3
github.com/benbjohnson/hashfs v0.2.2
github.com/dgraph-io/ristretto v0.1.1
github.com/labstack/echo/v4 v4.11.4
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7Y
github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
github.com/PlanktoScope/machine-name v0.1.3 h1:vOorbZm5QcEJTrmruYpxX81eyWXJPQDNf2ZdydZdyy0=
github.com/PlanktoScope/machine-name v0.1.3/go.mod h1:38x/CvfkMFPAr5xnnDyi0pfln7jo8e/oSVMQR4g+yoU=
github.com/benbjohnson/hashfs v0.2.2 h1:vFZtksphM5LcnMRFctj49jCUkCc7wp3NP6INyfjkse4=
github.com/benbjohnson/hashfs v0.2.2/go.mod h1:7OMXaMVo1YkfiIPxKrl7OXkUTUgWjmsAKyR+E6xDIRM=
github.com/bmatcuk/doublestar/v4 v4.6.0 h1:HTuxyug8GyFbRkrffIpzNCSK4luc0TY3wzXvzIZhEXc=
Expand Down
49 changes: 12 additions & 37 deletions internal/clients/machinename/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,8 @@ package machinename
import (
"os"
"path/filepath"
"strconv"
"strings"

"github.com/PlanktoScope/machine-name/pkg/haikunator"
"github.com/PlanktoScope/machine-name/pkg/wordlists"
"github.com/pkg/errors"
"github.com/sargassum-world/godest"
"github.com/sargassum-world/godest/clientcache"
Expand Down Expand Up @@ -52,16 +49,13 @@ func (c *Client) getNameFromCache() (string, bool) {
}

func (c *Client) getNameFromSystem() (string, error) {
sn, err := c.getSerialNumber()
name, err := c.getMachineName()
if err != nil {
return "", errors.Wrap(err, "couldn't determine serial number")
}
name, err := generateMachineName(c.Config.Lang, sn)
if err != nil {
return "", errors.Wrapf(
err, "couldn't generate machine name from serial number %d in language %s",
sn, c.Config.Lang,
c.Logger.Warnf(
"falling back to 'unknown' as the machine name, which couldn't be determined: %s",
err.Error(),
)
return "unknown", nil
}
if err := c.Cache.SetName(name, c.Config.CacheCost); err != nil {
return "", errors.Wrapf(err, "couldn't cache machine name %s", name)
Expand All @@ -72,34 +66,15 @@ func (c *Client) getNameFromSystem() (string, error) {
return name, nil
}

func (c *Client) getSerialNumber() (sn uint32, err error) {
rawSN := env.GetString(envPrefix+"SN", "")
if rawSN == "" {
rawFile, err := os.ReadFile(filepath.Clean(c.Config.SNFile))
func (c *Client) getMachineName() (string, error) {
name := env.GetString(envPrefix+"NAME", "")
if name == "" {
rawFile, err := os.ReadFile(filepath.Clean(c.Config.NameFile))
if err != nil {
return 0, errors.Wrapf(err, "couldn't read serial number from file '%s'", c.Config.SNFile)
}
rawSN = strings.TrimSpace(strings.TrimRight(string(rawFile), "\x00"))
const length = 8 // 8 hex chars = 32 bits
if len(rawSN) > length {
rawSN = rawSN[len(rawSN)-length:]
return "", errors.Wrapf(err, "couldn't read machine name from file %s", c.Config.NameFile)
}
name = strings.TrimSpace(string(rawFile))
}

return parseSerialNumber(rawSN)
}

func parseSerialNumber(raw string) (uint32, error) {
const base = 16
const parsedWidth = 32
parsed64, err := strconv.ParseUint(strings.TrimPrefix(raw, "0x"), base, parsedWidth)
return uint32(parsed64), errors.Wrapf(err, "couldn't parse serial number '%s'", raw)
}

func generateMachineName(lang string, sn uint32) (name string, err error) {
first, second, err := wordlists.Load(wordlists.FS, lang)
if err != nil {
return "", errors.Wrapf(err, "couldn't load naming wordlists for language '%s", lang)
}
return haikunator.SelectName(sn, first, second), nil
return name, nil
}
33 changes: 4 additions & 29 deletions internal/clients/machinename/conf.go
Original file line number Diff line number Diff line change
@@ -1,31 +1,22 @@
package machinename

import (
"fmt"

"github.com/PlanktoScope/machine-name/pkg/wordlists"
"github.com/pkg/errors"
"github.com/sargassum-world/godest/env"
)

const envPrefix = "MACHINENAME_"

type Config struct {
Lang string
SNFile string
NameFile string

CacheCost float32
}

func GetConfig() (c Config, err error) {
c.Lang, err = getLangConfig()
if err != nil {
return Config{}, errors.Wrap(err, "couldn't make lang config")
}

// This is a file path specific to the Raspberry Pi
const defaultSNFilePath = "/sys/firmware/devicetree/base/serial-number"
c.SNFile = env.GetString(envPrefix+"SNFILE", defaultSNFilePath)
// This is a file path specific to the PlanktoScope OS
const defaultNameFilePath = "/run/machine-name"
c.NameFile = env.GetString(envPrefix+"NAMEFILE", defaultNameFilePath)

const defaultCacheCost = 1.0
c.CacheCost, err = env.GetFloat32(envPrefix+"CACHE_COST", defaultCacheCost)
Expand All @@ -34,19 +25,3 @@ func GetConfig() (c Config, err error) {
}
return c, nil
}

func getLangConfig() (lang string, err error) {
const defaultLang = "en_US.UTF-8"
lang = env.GetString("LANG", defaultLang)

allowed, err := wordlists.ListLanguages(wordlists.FS)
if err != nil {
return "", errors.Wrap(err, "couldn't determine the list of supported languages")
}
if _, ok := allowed[lang]; !ok {
// FIXME: log this warning properly
fmt.Printf("Warning: language '%s' is not supported, reverting to '%s'\n", lang, defaultLang)
lang = defaultLang
}
return lang, nil
}

0 comments on commit a1f1f7c

Please sign in to comment.