Giter Site home page Giter Site logo

leiklier / illumino-web-services Goto Github PK

View Code? Open in Web Editor NEW
1.0 1.0 0.0 1.86 MB

[PRIVATE]: All web services required for the Illumino product family.

Home Page: https://get-illumi.no

JavaScript 55.37% Shell 0.70% Dockerfile 3.32% CSS 6.32% HTML 0.40% TypeScript 33.89%
graphql reactjs docker kubernetes mongodb

illumino-web-services's Introduction

Illumino Web Services

This repository contains all web services required by Illumino. This includes APIs as well as websites. The softwares is organized around a stateless microservices architecture. Each microservice is deployed inside a Docker container, and the containers are orchestrated by Kubernetes.

Author & Maintainer: Leik Lima-Eriksen

Endpoints

Convention:

  • API services use ports 30 000 - 30 499 for exposing services and 30 500 - 30 999 for debuggers.
  • Website services use ports 31 000 - 31 499 for exposing services and 31 500 - 31 999 for debuggers.

NB: Remember to configure port forwarding in //.vscode/settings.json after adding new endpoints. Only service ports should be forwarded, as the debugging is done on the host itself.

[DEV]

Service name Available at TLS enabled? Debugger port
frontend-api localhost:30000/graphql No 30500
embedded-api localhost:30001 No 30501
web-app localhost:31000 No  N/A

[PROD] / [STAG]

Service name Available at TLS enabled?
frontend-api api.get-illumi.no/graphql Yes
embedded-api api.get-illumi.no/embedded Yes
web-app get-illumi.no Yes

Onboarding

The following prerequisities are required on your machine for development purposes:

  • docker-machine, v19.3.x or newer
  • microk8s

Please read the Installation sections for instructions on how to install these.

Installation

First, install microk8s. This package is a distribution of Kubernetes which comes bundled with a couple of handy add-ons. It should be installed via snap:

$ sudo snap install microk8s --classic

In order to avoid having to type sudo each time, add your user to the microk8s group:

$ sudo usermod -a -G microk8s $USER
$ sudo chown -f -R $USER ~/.kube
$ su - $USER

Add the alias for kubectl:

$ echo "alias kubectl='microk8s kubectl'" >> ~/.bashrc

And lastly, install the required add-ons:

$ microk8s enable dns storage
$ microk8s enable ingress
$ microk8s enable registry

NB: You should wait a couple of minutes between typing each of the above commands in order for the installation to succeed.

It may happen that the firewall does not allow pod traffic. This may prevent the pods from sending outbound traffic to the Internet. To check this, run

$ microk8s inspect

It should give you the details on how to correctly configure the firewall if problems are detected.

The next step is to install docker-ce on your machine. This is required for building the Docker images. The configuration of Docker is pretty straight forward:

$ sudo apt update
$ sudo apt install apt-transport-https ca-certificates curl software-properties-common
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable"
$ sudo apt update
$ apt-cache policy docker-ce
$ sudo apt install docker-ce
$ sudo usermod -aG docker ${USER}
$ su - ${USER}

It is also highly recommended to have stern installed. This software makes it easy to output logs from pods. Installation instructions are not provided since it is not available from a package registry. However, it should be fairly easy to install.

Congratulations, you have now successfully configured Kubernetes and Docker!

Deployment - [DEV]

NB: requires an initial build in order to work! Please read the Build section first.

To deploy the cluster on your machine for development purposes, simply run

$ kubectl apply -f cluster/dev

from the root of this repository. This will spin up all the microservices in a minute or two. No additional actions need to be done.

To remove the cluster from your machine, you should run

$ kubectl delete -f cluster/dev

from the root of this repository. This shuts down all the microservices. You may at any time spin it up again by typing the apply command as mentioned above.

Deployment - [PROD] / [STAG]

Since we are using https, we also need to configure a CertManager in addition to the above mentioned requirements. This is responsible for retrieving SSL certificates by LetsEncrypt. CertManager is installed by issuinng the following commands:

$ kubectl create namespace cert-manager
$ kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v0.12.0/cert-manager.yaml

Proceed by starting the ssl-certificate-issuers:

$ kubectl apply -f cluster/_ssl

(should be done from the root of this repository)

Build the images as described in the Build section. Then start the cluster by running

[PROD]:

$ kubectl apply -f cluster/prod

[STAG]:

$ kubectl apply -f cluster/stag

The cluster can be stopped by replacing apply with delete in the above commands.

Build

The docker images are all built by issuing

$ ./docker-build.sh

from the root of this repository. This will create images for both production and development, and all the images are automatically pushed to the local registry available at localhost:32000

Development workflow

When using the dev cluster, the source files are bind mounted inside their respective pods. Also, all pods are configured in such a way that they will restart when files are changing. Therefore, your development workflow should not differ much from what you are used to. Simply just save your source file, and the change is automatically applied!

Using docker does however come with a caveat; since compiled modules are OS dependent, you cannot simply run yarn add inside a directory, since this may result in an incompatibility issue if your OS != Linux. Instead, such a command should be run inside the Pods. Retrieve the correct Pod name (<POD_NAME>) by running

$ kubectl get pods

An interactive shell can be created inside the Pod by running

$ kubectl exec -it <POD_NAME> -- /bin/bash

All dependency files inside the pods are bind mounted to the host OS, and so the changes will be noticed by git as well. However, you need to ./docker-build.sh again if you restart the cluster.

TLDR:

  • Hot reload in all microservices
  • Install packages by running commands inside the Pod.

illumino-web-services's People

Stargazers

 avatar

Watchers

 avatar

illumino-web-services's Issues

Access- / refresh token split

We should transition away from using basic token authentication. This encourages the user to store the JWT in localStorage, which imposes security threats. Instead, an access- / refresh token split is preferred:

  • When authenticating, the server sets a cookie containing the access token.

  • When authenticating, the server sets a cookie containing the refresh token.

  • The client can use the accessToken query which returns an access token if client has refresh token.

  • The access token should be stored as a local variable for maximum security.

  • The refresh token has long expiry (30 days+), whereas the access token has short expiry (2-3 hours max).

Watch only relevant DB changes

As of now, the server watches every update to select collections in order to serve GraphQL subscriptions. The current solution is not scalable because as the user base grows a lot of events need to be filtered. Therefore, the following alternative solution is proposed.

  • Create a pubsub per context
  • In the subscription resolvers, Model.watch(filter)should be called, where filter only allows relevant documents to pass through.

Lazy loading of views (code splitting)

Motivation: Currently, all of our application code is bundled together as a big chunk. The app is not rendered before this whole chunk has been downloaded.

Solution: React provides the React.lazy method for lazy loading components. By using this on all of our views, we only have to download the javascript required for the current view to run. By using this technique together with preloading, we achieve superior performance. Code-splitting is described in more detail on the React developer websites and in the Webpack docs.

Colorwheel for shades of white

Motivation: Users may not always want a color, but instead a nice shade of white - for instance in use when reading or just in order to use the led strip as a lamp.

Solution: When double-tapping on the colorwheel, the default Hue wheel should be replaced by a wheel showing different shades of white (adding more or less warmth to it).

Do not require MAC-address in loginDevice

Requiring MAC-address in loginDevice GraphQL query just makes it inconvenient to manually logging in with a Device. Also, the QR codes become harder to read because the URL that needs to be stored gets very long. It should be sufficient to require only the secret (plus pin if set).

LedStrip feature

We need a new mongoose model / GraphQL type which describes a LedStrip. LedStrips needs to belong to Devices ( = embedded documents in this case ). They should be described by the following:

  • Current intensity (how bright?)
  • Current mode

See if ledStrip is connected

Each ledStrip should have an isConnected attribute which gets updated by the node upon connect/disconnect. This way we can in our app only show the connected ledStrips.

Embedded API

We need an endpoint for the core applications (meaning, the MCUs) to communicate with the API without much overhead. It is suggested that we use WebSockets because of its ease of implementation, and design it as a CLI.

ledStrips: recent colors and favourite colors.

  • Each ledStrip should have an recentColors attribute which is an array consisting of the five most recently appliedd colors, sorted by date. A newly set color gets added as a recentColor only after it has stayed unchanged for at least 30 minutes. This time is calculated by the node.
  • Each device should also have a favoriteColors attribute which is an array consisting of five colors that are chosen to be favourite. These should be able to be deleted by a user.

Logger

The software should log all important events to console, file, and database for debugging and security purposes.

Alarm feature

It should be possible to create user-settable Alarms. These should either trigger once, or at certain intervals (for instance, 'each Tuesday, 7 AM'). In order to accomplish this, the following is considered needed:

  • Alarm mongoose model

HttpOnly Cookies

Refresh tokens passed in cookies should be set to httpOnly. This way clients cannot access them, which makes the API more secure. It may be necessary to write a GraphQL query that lets the client check whether or not a cookie is set (return Boolean).

Enhance security around Device access

Upon login as a Device , one should provide an additional secret to verify that one actually owns the Device. This should be used in loginDevice as well as setDevicePin to prove ownership. The idea here is that the secret can be constructed both by the Device and the API-server. Thus it is possible to determine what the secret for each Device should be, and add this as part of the QR-code printed on top of the physical Device.

The secret should be constructed in this way:

  • Concatenate Device.mac with deployKey.
  • calculate sha256 hash of the concatenated string.
  • extract the last 8 chars of the string.
  • Store the bcrypted version of these chars in Device.secret.

The following steps are required:

  • Add secret to Device mongoose model.
  • Construct and store Device.secret in createDevice. (Maybe do this in a mongoose save-hook?)
  • Verify Device.secret in loginDevice.
  • Owner and Managers should be able to retrieve a Device's secret.
  • Admins should be able to retrieve all Device´s secrets.

Firmware feature

The firmware of Devices should be stored in the API such that Devices can pull new upgrades as they arrive, and in that way upgrade themselves automatically. To accomplish this, the following features are needed:

  • Need a mongoose model for Firmwares.
  • upload new Firmwares.
  • query for the current Firmware belonging to a Device.
  • check whether or not a Device has the latest Firmware installed.
  • a Device should be able to download latest Firmware.
  • a Device should be able to subscribe to new Firmwares, such that it gets a notification when new Firmwares are released.

Remove all unnecessary mongoose populates

In DataLoaders, foreign fields are always populated. This was done in order to avoid errors with ObjectIDs using the Buffer format, which caused problems in GraphQL default type resolvers. However, having these populates causes a lot of unnecessary queries and thus slows down the application. This issue should therefore be addressed. One solution might be to convert ObjectIDs toString('hex').

Preview temperature and humidity in sensor button

Instead of just showing a graph icon on the sensor button, it would be more convenient to display the last measured temperature and humidity. It should be something like this:

------------------------
|                       |
| <temp-icon>: 23*C.    |
|                       |
| <humid-icon>: 38%.    |
|                       |
------------------------

Also, the icons should be either pale red, orange or green depending on whether the values are good or not.

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.