Giter Club home page Giter Club logo

nerves_hub_web's Introduction

NervesHub

GitHub Actions

This is the source code for the NervesHub firmware update and device management server.

Important

This is the 2.0 development branch of NervesHub. If you have been using NervesHub prior to around April, 2023 and are not following 2.0 development, see the maint-v1.0 branch. The maint-v1.0 branch is being used in production. 2.0 development is in progress, and we don't have guides or good documentation yet. If you use the 2.0 development branch, we don't expect breaking changes, but please bear with us as we complete the 2.0 release.

Project overview and setup

Development environment setup

For best compatibility with Erlang SSL versions, we use Erlang/OTP 23.0.4. If you're coming to NervesHub without OTP 23 or earlier devices, don't worry about this. OTP 23.0.4 is difficult to install on Apple M1/M2 hardware so developing on Linux is highly recommended if you're keeping to the OTP 23.0.4 requirement.

The .tool-versions files contains the Erlang, Elixir and NodeJS versions. Install asdf-vm and run the following for quick setup:

cd nerves_hub_web

asdf plugin-add nodejs
bash ~/.asdf/plugins/nodejs/bin/import-release-team-keyring # this requires gpg to be installed
asdf install

Modify the .tool-versions if you want to use a later version of Erlang.

You'll also need to install fwup and xdelta3. See the fwup installation instructions and the xdelta3 instructions.

On Debian/Ubuntu, you will also need to install the following packages:

sudo apt install inotify-tools

Local development uses the host nerves-hub.org for connections and cert validation. To properly map to your local running server, you'll need to add a host record for it:

echo "127.0.0.1 nerves-hub.org" | sudo tee -a /etc/hosts

First time application setup

  1. Setup database connection

    NervesHub currently runs with Postgres 10.7. For development, you can use a local postgres or use the configured docker image:

    Using local postgres

    • Make sure your postgres is running
    • If you need to edit the DATABASE_URL, create a .env.dev.local and .env.test.local to adjust to your local postgres connection
  2. Fetch dependencies: mix do deps.get, compile

  3. Initialize the database: mix ecto.reset

  4. Compile web assets (this only needs to be done once and requires python2 or a symlink for python3): mix assets.install

Starting the application

  • mix phx.server - start the server process
  • iex -S mix phx.server - start the server with the interactive shell

Note: The whole app may need to be compiled the first time you run this, so please be patient

Once the server is running, by default in development you can access it at http://localhost:4000

In development you can login into a pre-generated account with the username nerveshub and password nerveshub.

Running Tests

  1. Make sure you've completed your database connection setup
  2. Fetch and compile test dependencies: MIX_ENV=test mix do deps.get, compile
  3. Initialize the test databases: MIX_ENV=test mix ecto.migrate.reset
  4. Run tests: make test

nerves_hub_web's People

Contributors

acrogenesis avatar axelson avatar brianberlin avatar chazwatkins avatar chrisdambrosio avatar connorrigby avatar coryjewell avatar danielspofford avatar dependabot[bot] avatar esvinson avatar fhunleth avatar grace-in-wonderland avatar hassanshaikley avatar jjcarstens avatar jlmcgehee21 avatar joshk avatar lawik avatar lostkobrakai avatar magreenbaum avatar mattlorey avatar mattludwigs avatar mobileoverlord avatar mrjaco12 avatar oestrich avatar paulstatezny avatar pcmarks avatar pojiro avatar squaresurf avatar supersimple avatar tonnenpinguin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nerves_hub_web's Issues

Initial Database Schema

Setup initial schema:

tenants

id
name
jwt/auth key? - or user specific?
public key(s)

users

id
tenant_id
name
email
password

devices

id
tenant_id
identifier (name?) text, unique
current_version
target_version
last_comm
last_update?
channel
architecture/platform?
tags array<string>
metadata - from [nerves](https://github.com/nerves-project/nerves_runtime#nerves-system-and-firmware-metadata)

firmwares

id
tenant_id
signed?
in_use?
s3/gcs/identifier (start with s3, can be adapted)
(can extract metadata)
channel
architecture/platform

deployments

id
tenant_id
conditions/query
firmware_id
status
started_at
finished_at

Deployment View

Detail view of a deployment

Acceptance Criteria

  • Logged in user should only be able to see deployments for their own tenant
  • Show name, criteria and status of deployment
  • Ability to toggle the status of a deployment between inactive and active

Technical Acceptance Criteria

  • Change status to a boolean is_active field

Password Strength Requirements

Acceptance Criteria:

  • Any time a password is created/updated, there is a sane password strength check in place to ensure terrible/short passwords aren't used.
  • There's no upper limit on password length or complexity, and no characters are disallowed.

Create Device Page

Acceptance Criteria:

  • On the "Manage Devices" page there's an "Add" button that takes the user to a page where they can create a device.
  • The user provides a device ID, Description, and Tags. (Text fields; Tags are interpreted as a comma separated list.)
  • Device ID and Description are required (validation errors are shown and the device isn't created, if either are missing)
  • Device ID is unique per tenant.

Update Device

Acceptance Criteria

  • On the device view, the user should be able to edit the tags list
  • On save/update, the tag input should be split on commas and trimmed and then stored
  • Tags is the only field that is editable

Tenant Settings

Acceptance Criteria:

  • A logged in user can view the settings for the tenant they belong to
    • Not sure what those settings are yet

Progress bar for uploading .fw files

Current behavior:
When you upload a .fw file, the browser acts like it is working, but it's hard to tell how far it's gotten.

Expected behavior:
There's a progress bar or some feedback that lets you know that things are happening.

Steps to reproduce:
Go to the firmware tab, browse and then upload a .fw file.

Tenant Dashboard/Home Page

Acceptance Criteria:

  • When a user logs in, they're taken to the "logged in home page" (at / -- but it detects they're logged in so it doesn't show the login page).
  • The page displays links:
    • Manage Devices
    • Manage Firmware
    • Manage Updates
    • Settings
  • There's a logout link (for all logged in pages; do this via a Phoenix layout) and the user's name / email address is displayed in the same toolbar/area as the logout link.

Device List

Acceptance Criteria:

  • When the user clicks on the Manage Devices link from #13, they're taken to a page that lists all of their devices in a table.
  • The table has the following columns:
    • Device (shows device name/id)
    • Version
    • Update Pending (has a disabled checkbox)
    • Last Connect
    • Operations (shows Delete and Disable links)

Document device->nerves_hub channel API

Minimum requirements for the device to report to Nerves Hub:

  • Firmware version - so that the server knows if new firmware needs to be sent down and can record that an upgrade completed.

Minimum needed to send back down to the device:

  • Whether the device should update its firmware
  • A URL to the new firmware

Nice to have notifications from the device:

  • An error message if the firmware failed to download or apply - useful for debug

Other items to consider:

  • If devices report more of their metadata (see https://github.com/nerves-project/nerves_runtime#nerves-system-and-firmware-metadata), the server can detect misconfigurations
  • We've had requests for lightweight device management features like remote reboot, retrieving recent logs (like the most recent 16KB or so of log messages from RingLogger), and setting key/value pairs to modify the device configuration.
  • Would be good to know when devices have not connected for some amount of time - this may not require anything from the protocol - just that the system tracks when a device is connected.

User Invitation System

Acceptance Criteria:

  • Any user can invite others to create an account with access to the given tenant.
  • There is a page where users send these invitations, by simply providing an email address.
  • When the form is submitted, an email is sent to the given email address, and an "invitation" record is created, associating the invitation to the tenant of the inviter.
  • The invitation email includes a link to create an account. When the user clicks the link, the page shows a form with their email address (read only), optional name field, and a field to create a password (required).
  • When the user submits the form, the new user is created. (If a blank password is supplied, a validation error is shown and the form is re-displayed.)

10K' View of deployment UX

Hi.
So without any concern of how things get done, or what anyone else needs, I've looked the deployments from a birds eye view of how I'd like things to work. I figured I'd jot it down here. Feel free to ignore or dismiss as unworkable lol. It could be a good starting point or at least we can define our use cases by analyzing what this misses.

To me it seems like we are missing something in our current schemas. I'd add a Product and a DeviceGroup (names tbd).

So, a Tenant has multiple Products.

A Product has one or more DeviceGroups.

A DeviceGroup would hold the set of conditions that defined its membership (processor, memory, etc) and have one or more deployments, some active, some inactive, one Deployment which is "current".

A Deployment should have one firmware, possibly some conditions and zero or more devices that have reported running that firmware. I would like to keep this info static, so it could provide a history of what device got what firmware when.

So the paths a product would go on...

Case 1:
Identity DeviceGroup, its criteria is '*' and it has one active and current deployment. Whenever you release a new firwmare you would upload it to the DeviceGroup and mark it as current and active. It would create a new deployment with with that firmware and start notifying whatever Devices are logged in, adding them to the deployment once they have updated. The former current deployment would be marked as inactive and hidden but would still be there. So you'd have a history of what devices got what firmware when, which could be useful.

Case 2:
Still the identity DeviceGroup, but theres now just a happy path, ie all devices get version 1.2.0 except v0.9.0 which needs v1.0.1 first, etc. So theres an still a current deployment with firmware v1.2 but an extra active deployment exists that differentiates by v0.9.0. But you could differentiate on other things too. We could set it up where the order does matter for the non current and active deployments and if they all fail, apply the current one.

Case 3:
For a split in the Product firmware builds we would need to create a second DeviceGroup for the product. To indicate a hardware change most likely, but it could be anything, even a firmware version that could not be upgraded, anything that required a different build of the firmware. Devices logging in would be queried and placed in the current DeviceGroup by any number of criteria and receive the correct deployment. Each DeviceGroup would be on its own as far as receiving new deployments and persisting the devices that have upgraded.

Alpha, Beta, BleedingEdge etc.
It seems like all of the non production kind of labels would really want to be applied at the DeviceGroup level. If you were shipping one beta firmware for DeviceGroup RPI0 and one for DeviceGroup RPI0W you would want to be testing devices for each firmware. So there would be one beta tag, but which firmwware each device gets depends on what DeviceGroup its in. That would be adding an extra active deployment to each DeviceGroup using tags instead of firmware version as the qualifier. These you would want to make sure are applied first.

Anyway thanks for taking the time to read this! Its just an idea and I'm sure there are plenty of necessary use cases it doesn't encompass.

Homepage / Authentication

Acceptance Criteria:

  • A home page exists with email/password fields.
  • The user can log in via the homepage login form.

Device status

It's useful to know a high level status of the device (like red, yellow, green or failed, warnings, ok). The idea is that once you get enough devices, it's convenient to be able to see at a glance what's happening rather than clicking through to a device detail view.

It seems difficult to combine all interesting device status into one field, so here's a high level idea that has two columns:

  • Overall status

    • Red/failed -> offline for > 1 day
    • Yellow/warning -> connected in the past day; an error has been submitted
    • Green/ok -> connected in the past day; no error logs
  • Firmware update status

    • Red/failed -> firmware update needed, but errors or retries detected
    • Yellow/warning -> firmware out-of-date. An update will be requested on next connect
    • Green/ok - firmware up-to-date

The firmware update status field would replace the "update pending" column

Initial Device HTTP Endpoint Implementation

Acceptance Criteria:

  • There is an API endpoint at GET /firmware-update
  • When any of the following conditions are met, the endpoint returns a 401 error:
    • The X-Client-Dn header is missing.
    • The X-Client-Dn header is not in the format CN=identifier.
    • The identifier in the X-Client-Dn header is not the case-sensitive identifier of a device in the devices table.
  • The endpoint checks whether the device is eligible for a firmware update.
  • A device is eligible for a firmware update if a deployment is found where the following is true:
    • The device (in the database) and firmware match in both architecture and platform
    • The device's current_version matches each of the version_requirements of the deployment. (Via Version.match?/3)
    • The device has all tags specified in the deployment.
  • Integration tests
  • The endpoint returns the following structure:
{
  "eligible_firmware_update": "http://example.com/path/to/firmware/1.0.1/file.fw"
}

(If not eligible for a firmware update, null is returned:)

{
  "eligible_firmware_update": null
}

Notes:

  • This implementation does not allow for different tenants to have devices with the same identifier. This is an acknowledged major problem with this first version; we'll need to address it before using the product.

Add support for "products"

Currently the web app lists all devices per tenant. A tenant likely will have multiple products. It is expected that users will want to focus on one product at a time. Some way of filtering or grouping firmware, devices, and deployments on a per product basis would be good.

Some notes on products:

  • The .fw files contain a meta-product tag that has the product name. This could be extracted for to categorize firmware, devices, and deployments.
  • The current fwup scripts used with Nerves don't force the meta-product tag to match what's running on devices. This makes it possible to turn one product into another.
  • Companies and individuals change product names. It may be useful to have two or more meta-product names that correspond to one "product" in the UI.

Support rolling updates

Instead of requesting all devices to update simultaneously, it's useful to roll out the updates. This has two benefits:

  1. Should an update break a device or cause a support call, it gives time to pause the deployment.
  2. It can reduce the pressure on any network bottlenecks since the .fw files are large.

Firmware upload signature verification

When a firmware file is uploaded, we verify the firmware is valid and then check if it is signed, and if so, match the verify the signature with they key(s) on the tenant.

The way we determine a firmware is signed is no longer valid - update to use fwup's programmatic interface

Deployment List

Acceptance Criteria

  • Only deployments from the user's tenant should be shown
  • Show Name, criteria and status of the deployments
  • Button to add a new deployment

Remove keys on tenant settings

When on the tenant settings, there should be a remove button or X icon to the side of each key, when clicked it should confirm you want to remove the key and then remove it

Create Deployment

Accessed from the Deployment List

  • Name
  • Set criteria for selecting devices
  • Select target firmware

Device interaction log

It would be nice if the server could maintain an interaction history with each device. This doesn't have to be fancy. It could just contain things like "device connected at time x", "firmware update requested", "device's firmware version is now y". The idea is to have historical information about a device if a bug report is incomplete or there's an issue with firmware updates reverting.

Device View

Acceptance Criteria:

  • When the user clicks on a device name in the Manage Devices page, they're taken to a page that shows information about the device.
  • The page displays a bunch of information about the device.

Let users create device certs via the UI

There are a few ways of creating certificates for devices. This issue covers having a screen that lets users enter in a name or ID for a device and then having the server generate (with the help of nerves_hub_ca) a device certificate. The user would then download the certificate and keys and would install them on the device. I think that this is part of the device creation page, but if another part of the UI makes more sense, it could be there too. We will eventually want to allow users to create certificates for devices as a separate step to creating/registering the device with Nerves Hub. However, that separation could be done as part of another issue if it is involved.

Better handling of firmware metadata

Currently, firmware metadata is being parsed for a few key fields, and then the entire metadata string is being stored in a metadata string field on a firmware record.

The current issue, is that it is very common in the real world for the metadata field to be greater than the database imposed limit of 255 characters.

The proposed fix:

  • A migration that removes the metadata string field, and adds the following relevant fields supplied by @fhunleth:
meta-product
meta-description
meta-version
meta-author
meta-platform
meta-architecture
meta-vcs-identifier
meta-misc
meta-uuid
  • Refactor the firmware_controller and the firmware schema to handle these changes as well.

Guard against accidental device delete and disable

The device delete and disable buttons are on the main device listing screen at the moment. This is fine for now, but it would be nice to move them to either a device detail screen or have a sequence of "are you sure" screens. The idea is to prevent an accidental delete or disable since those should be rare operations in production and they have big consequences to devices.

User Registration

Acceptance Criteria:

  • The user can navigate to a registration page from the login page, and create an account. (When the account is created, an associated tenant is created.)
  • The registration form has email and password fields.
  • Registration can be disabled with a config setting.

Firmware list

Acceptance Criteria

  • Logged in use should only see firmware from their own tenant
  • Show the filename, timestamp, whether or not the firmware is signed and the metadata (extracted from the fwup file)
  • Button to upload a new firmware

Bootstrap vs Materialize

This issue tracks whether we'll use Bootstrap 3, 4 or Materialize for the initial web framework. While the UI should be straightforward, there is an expectation there will be enough client-side validation and and feedback that we might as well start with one.

Document nerves_hub management API

The idea here is to expose an API for CI servers and other systems to interact with the nerves_hub and be able to do the same things that humans can do via the web UI.

Firmware Upload

Acceptance Criteria

  • User can select a firmware file from their computer and upload
  • When uploaded, firmware should be validated (fwup does this?), and metadata extracted
    • If the firmware is not valid, user should be redirected back to the upload page with a message stating it was not valid, and why (if we get that from fwup?)
    • If the firmware is valid, upload the firmware to S3, redirect to firmware list

Need additional detail for S3 upload

Forgot Password Workflow

Acceptance Criteria:

  • The user can click a link on the homepage to go to a Forgot Password form.
  • The form simply contains an email address field.
  • When the user submits the form, it shows a flash message saying "We've sent you an email with instructions to reset your password" -- even if the email address isn't associated with a user.
  • If the email provided is associated with a user, a reset password token is created in the database (associated with that user) and an email is sent to that address.
  • When the user clicks on the link, it sends them to a page that checks the validity of the token. If the token is invalid, they're redirected to the homepage. If the token is valid, they're shown a password field.
  • When the user fills in the password field and hits "submit", their password is reset and they're taken back to the login page.
  • Tokens should expire within 4 days (or more/less? up for discussion)

S3 Firmware Upload module

Create an S3 Firmware Upload module that can be configured to use instead of the Beamware.Firmware.Upload.File module that uploads firmware files to Amazon S3 and generates download links when requested. Should implement both upload_file and download_file like Beamware.Firmware.Upload.File

User Profile

Acceptance Criteria

  • A logged in user can see their email address
  • A logged in user can change their email address
  • A logged in user can change their password
    • Current password required to change password

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.