#rest #web-services #service #rocket-framework #query-api #coding #challenge

nightly bin+lib password-as-service

a very poorly considered http/rest service

4 releases

0.1.4 May 10, 2019
0.1.3 May 7, 2019
0.1.2 May 7, 2019
0.1.1 May 7, 2019

#17 in #coding

MIT license

3MB
834 lines

Contains (ELF exe, 4.5MB) bin/lin64/passwd-as-service, (Mach-o exe, 2.5MB) bin/osx64/passwd-as-service, (DOS exe, 2MB) bin/win64/passwd-as-service.exe

passwd-as-service

crate source docs

Passwd-as-service is a webservice that provides a query API into the /etc/passwd and /etc/group files. It's not meant to be a 'real' service; it's a didactic coding sample meant for potential employers, based off a coding challenge from Brain Corp. See the file api.pdf for details on the exact challenge.

Documentation

Clone the source and run cargo doc --open, or visit the docs on docs.rs

Installation

  • Install Rust using rustup.

  • Install the nightly toolchain

    rustup install nightly
    
  • Install via crates.io

    cargo +nightly install password-as-service
    

    Alternatively, prebuilt binaries for 64-bit OSX, Windows, and Linux Ubuntu/Debianare available in [./bin].

Configuration

[ROCKET_PORT=PORT] passwd-as-service [PATH_TO_USERS] [PATH_TO_GROUPS]
  • ROCKET_PORT is the port to serve from. This can also be set as an environment variable.
  • PATH_TO_USERS is the location of the users file: defaults to "/etc/passwd".
  • PATH_TO_GROUPS is the location of the users file: defaults to "/etc/group" You must use both of PATH_TO_USERS and PATH_TO_GROUPS, or neither.

Testing

  • Clone the repository

    cd ~/rust
    git clone gitlab.com/efronlicht/passwd-as-service
    
  • Navigate to the project directory

    cd ~/rust/passwd-ass-service
    
  • Run Tests

    Cargo

    cargo test
    

Test Coverage (Ubuntu/Debian)

  • Install Tarpaulin:

    # install the lib-ssl development libraries
    apt-get install libssl-dev pkg-config cmake zlib1g-dev
    # set cargo to use rust's `nightly` toolchain
    rustup default nightly
    # OR:
    rustup override set nightly
    # install tarpaulin
    RUSTFLAGS="--cfg procmacro2_semver_exempt" cargo install cargo-tarpaulin
    
  • Get Coverage

    $ cargo tarpaulin
    
      [INFO tarpaulin] Running Tarpaulin
      [INFO tarpaulin] Building project
      [INFO tarpaulin] Launching test
      [INFO tarpaulin] running /home/efron/rust/passwd-as-service/target/debug/deps/bin-f54ce995ec16a011
    
      running 0 tests
    
      test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
    
      [INFO tarpaulin] Launching test
      [INFO tarpaulin] running /home/efron/rust/passwd-as-service/target/debug/deps/lib-1087fab0c4512719
    
      running 6 tests
      ......
      test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
    
      [INFO tarpaulin] Coverage Results:
      || Tested/Total Lines:
      || src/api/mod.rs: 14/14
      || src/api/tests.rs: 84/86
      || src/lib.rs: 6/20
      || src/main.rs: 0/3
      || src/model/group.rs: 11/18
      || src/model/user.rs: 24/26
      ||
      83.23% coverage, 139/167 lines covered
    

Design Decisions

Language: Rust

  • Positives
    • Extremely strong static typing and guarantees about concurrency. No race conditions.
    • No garbage collection and powerful optimizing compiler make it run blazing fast.
    • Easy to compile to a portable binary and deploy in containers.
    • Best-in-class good documentation and code quality tools
    • Deployment is easy, and low usage of resources makes running on rented servers cheap.
    • Cargo is an extremely good package and dependency manger.
    • My personal favorite programming language.
  • Negatives
    • High learning curve.
    • Difficult to write.
    • Immature ecosystem for web development comparied to competitors like JavaScript, Go, & Python.
    • Strictness not always necessary for 'quick and dirty' jobs.
    • Slow compilation times.

Database: None, w/ a level of in-memory caching.

This is a toy project, dealing with very small amounts of data. Even the largest linux system is unlikely to have more than ten thousand users or groups; we simply don't need a relational database to query this kind of data. We have a single source of truth (the flat files /etc/passwd/ and /etc/group themselves.

  • Positives

    • Removes a lot of overhead and disk usage.
    • Cheaper containerization: Most relational databases clock out at over 200mb and can use considerable memory that's a lot of resources for something we simply don't need.
    • Much simpler deployment; we can just distribute a binary, with zero dependencies.
  • Negatives:

    • Relational databasses like PostgreSQL and MYSQL are pretty much made for this kind of query.
    • If the project expands we'll probably need to use a database eventually.
    • Reinventing the wheel.

Framework: Rocket.

Rocket is an extremely exciting framework for writing servers in Rust.

Positives

  • Very little boilerplate.
  • Strong typing & powerful custom macros allow you to create readable, testable APIs.
  • Very fast.

Negatives

  • Immature.
  • Requires nightly rust.
  • Changes to Rust could leave the Rocket stranded.

Deployment: Statically linked binaries

Positives:
  • Fast
  • Portable
  • Much smaller than wrapping an entire interpreter.
  • Can't inject DLLs (because there are no dynamic libararies)
Negatives
  • Must be recompiled every time, unlike interpreted languages.
  • Larger than using dynamic links.

Continuous Integration & Source Control: Git w/. Gitlab

Upsides:

  • Simpler than most
  • Git is the most common source control tool by a country mile
  • Gitlab's continuous integration is much better for small or medium sized projects than the heavyweight solutions used for most github projects.

Negatives:

  • Github is much more discoverable.

Dependencies

~10–20MB
~309K SLoC