1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-06-04 01:18:20 +02:00

chore: Fix formatting all the things

This commit is contained in:
ivaosthu 2018-11-22 11:20:28 +01:00 committed by Ivar Conradi Østhus
parent 9d6715754a
commit 7bffe4d1db
31 changed files with 808 additions and 782 deletions

View File

@ -1,8 +1,8 @@
sudo: false sudo: false
language: node_js language: node_js
node_js: node_js:
- '8' - '8'
- '10' - '10'
env: env:
matrix: matrix:
- DATABASE_URL=postgres://postgres@localhost:5432/unleash_test TEST_DATABASE_URL=postgres://postgres@localhost:5432/unleash_test - DATABASE_URL=postgres://postgres@localhost:5432/unleash_test TEST_DATABASE_URL=postgres://postgres@localhost:5432/unleash_test
@ -10,12 +10,12 @@ env:
secure: HyWYh1dbUfe2yPF9ZdcdA/IVGyNWmJmpuaRvRGnnpO63/5Y0KT6/hyL6nZ4YJ7Wr/KEt4eMJBJsnzaCFtiqNA3cWyyprzXJButw0o8C6dfd/9jOleisuvdqndu92RqDKIIq2EjHVq3sd6B8uGyiOlkMsyFH57O/V+xHW8MYLnaQ= secure: HyWYh1dbUfe2yPF9ZdcdA/IVGyNWmJmpuaRvRGnnpO63/5Y0KT6/hyL6nZ4YJ7Wr/KEt4eMJBJsnzaCFtiqNA3cWyyprzXJButw0o8C6dfd/9jOleisuvdqndu92RqDKIIq2EjHVq3sd6B8uGyiOlkMsyFH57O/V+xHW8MYLnaQ=
before_install: npm install -g greenkeeper-lockfile@1 before_install: npm install -g greenkeeper-lockfile@1
before_script: before_script:
- psql -c 'create database unleash_test;' -U postgres - psql -c 'create database unleash_test;' -U postgres
- greenkeeper-lockfile-update - greenkeeper-lockfile-update
script: yarn run test:coverage script: yarn run test:coverage
after_script: greenkeeper-lockfile-upload after_script: greenkeeper-lockfile-upload
after_success: after_success:
- yarn run test:coverage-report - yarn run test:coverage-report
notifications: notifications:
slack: slack:
secure: MroremSKwtQkwPbrXjgs9hIqKTCDKk7bAIXXzjcS6wXC9uRaFgwFaW8oO3vBxtWa4BL44EQBLE/rboWgqFER62+XgXNgEqGZqrcJHJvby4r+dUNMPI64OZvWdIiydIYxLo8C1C4x5PqBup0xuLq8h/SBnNvA2NLgkjuvzOi+v/Q= secure: MroremSKwtQkwPbrXjgs9hIqKTCDKk7bAIXXzjcS6wXC9uRaFgwFaW8oO3vBxtWa4BL44EQBLE/rboWgqFER62+XgXNgEqGZqrcJHJvby4r+dUNMPI64OZvWdIiydIYxLo8C1C4x5PqBup0xuLq8h/SBnNvA2NLgkjuvzOi+v/Q=

View File

@ -1,19 +1,24 @@
# Changelog # Changelog
## 3.1.2 ## 3.1.2
- fix(clientApi): Add namePrefix paramter to /api/client/features - fix(clientApi): Add namePrefix paramter to /api/client/features
## 3.1.1 ## 3.1.1
- fix(gzip): Add gzip support - fix(gzip): Add gzip support
- fix(package): update unleash-frontend to version 3.1.3 - fix(package): update unleash-frontend to version 3.1.3
## 3.1.0 ## 3.1.0
- fix(package): update unleash-frontend to version 3.1.1 - fix(package): update unleash-frontend to version 3.1.1
## 3.0.6 ## 3.0.6
- fix(log4js): Upgrade log4js to version 3.0.3 and fix default log configuration - fix(log4js): Upgrade log4js to version 3.0.3 and fix default log configuration
## 3.0.5 ## 3.0.5
- fix(package): update log4js to version 3.0.2 - fix(package): update log4js to version 3.0.2
- fix(package): update knex to version 0.15.2 - fix(package): update knex to version 0.15.2
- fix(package): update yargs to version 12.0.1 - fix(package): update yargs to version 12.0.1
@ -24,6 +29,7 @@
- chore(package): update nyc to version 12.0.1 - chore(package): update nyc to version 12.0.1
## 3.0.4 ## 3.0.4
- feat(metrics): Expose toggle updates to prometheus - feat(metrics): Expose toggle updates to prometheus
- chore(package.json): Bump serve-favicon to 2.5.0 - chore(package.json): Bump serve-favicon to 2.5.0
- chore(package.json): Bump joi to 13.0.3 - chore(package.json): Bump joi to 13.0.3
@ -36,31 +42,37 @@
- chore(package.json): Bump commander to 2.15.1 - chore(package.json): Bump commander to 2.15.1
## 3.0.3 ## 3.0.3
- feat(bind): Added option to bind to specific http address - feat(bind): Added option to bind to specific http address
- fix(migration): Unleash should not start if migration fails. - fix(migration): Unleash should not start if migration fails.
## 3.0.2 ## 3.0.2
- fix(package): Update unleash-frontend to version 3.0.1 - fix(package): Update unleash-frontend to version 3.0.1
## 3.0.1 ## 3.0.1
- fix(package): Update db-migrate-pg to version 0.4.0 - fix(package): Update db-migrate-pg to version 0.4.0
- fix(package): update prom-client to version 11.0.0 - fix(package): update prom-client to version 11.0.0
- refactor: use body-parser bundled with express - refactor: use body-parser bundled with express
- fix(package): update express-validator to version 5.0.0 - fix(package): update express-validator to version 5.0.0
## 3.0.0 (10.02.2018) ## 3.0.0 (10.02.2018)
- All changes in all 3.0.0 alpha-releases is included in this version - All changes in all 3.0.0 alpha-releases is included in this version
- fix(package): Upgrade unleash-frontend to version 3.0.0 - fix(package): Upgrade unleash-frontend to version 3.0.0
## 3.0.0-alpha.10 ## 3.0.0-alpha.10
- chore(package.json): Bump unleash-frontend to 3.0.0-alpha.7 - chore(package.json): Bump unleash-frontend to 3.0.0-alpha.7
- fix(store): DB should not override createdAt if set. - fix(store): DB should not override createdAt if set.
## 3.0.0-alpha.9 ## 3.0.0-alpha.9
- Bugfix: more informative name validation errors ([#292](https://github.com/Unleash/unleash/pull/292)) - Bugfix: more informative name validation errors ([#292](https://github.com/Unleash/unleash/pull/292))
## 3.0.0-alpha.8 ## 3.0.0-alpha.8
- [Auth] User-provider ([#261](https://github.com/Unleash/unleash/issues/261)) - [Auth] User-provider ([#261](https://github.com/Unleash/unleash/issues/261))
- [Auth] Document how to secure Unleash ([#234](https://github.com/Unleash/unleash/issues/234)) - [Auth] Document how to secure Unleash ([#234](https://github.com/Unleash/unleash/issues/234))
- [Auth] Admin UI should handle 401 ([#232](https://github.com/Unleash/unleash/issues/232)) - [Auth] Admin UI should handle 401 ([#232](https://github.com/Unleash/unleash/issues/232))
@ -69,16 +81,20 @@
- [Auth] Support sign out ([#288](https://github.com/Unleash/unleash/issues/288)) - [Auth] Support sign out ([#288](https://github.com/Unleash/unleash/issues/288))
## 3.0.0-alpha.7 ## 3.0.0-alpha.7
- Bugfix: Should not allow creation of archived toggle #284 - Bugfix: Should not allow creation of archived toggle #284
## 3.0.0-alpha.6 ## 3.0.0-alpha.6
- Expose vresion number in /api and in user interface. - Expose vresion number in /api and in user interface.
- Housekeeping: Upgrading a lot of dependencies - Housekeeping: Upgrading a lot of dependencies
## 3.0.0-alpha.3 ## 3.0.0-alpha.3
- Bump unleash-frontend - Bump unleash-frontend
## 3.0.0-alpha.2 ## 3.0.0-alpha.2
- Add sdkVersion in client registration - Add sdkVersion in client registration
- disable edit of built-in strategies - disable edit of built-in strategies
- Strip uknown fields in client requests. - Strip uknown fields in client requests.
@ -87,34 +103,42 @@
- Add posibility to inject custom logger provider - Add posibility to inject custom logger provider
## 3.0.0-alpha.1 ## 3.0.0-alpha.1
- upgrade unleash-frontend to 3.0.0-alpha.1 - upgrade unleash-frontend to 3.0.0-alpha.1
- moved api endpoints to /api/admin/* and /api/client/* - moved api endpoints to /api/admin/_ and /api/client/_
- refactored all routes to use a standalone router per file - refactored all routes to use a standalone router per file
- removed v.1 legacy data support - removed v.1 legacy data support
- removed v.1 legacy /features endpoint - removed v.1 legacy /features endpoint
- added prettier and upgraded eslint - added prettier and upgraded eslint
## 2.2.0 ## 2.2.0
- Expose hooks in main export #223 - Expose hooks in main export #223
## 2.1.7 ## 2.1.7
- Bump unleash-frontend to 2.2.6 - Bump unleash-frontend to 2.2.6
## 2.1.6 ## 2.1.6
- Added strategies validation when updating feature toggle - Added strategies validation when updating feature toggle
- Allow node newer than 6 to run the app - Allow node newer than 6 to run the app
## 2.1.4 ## 2.1.4
- Bump unleash-fronted to 2.2.4 - Bump unleash-fronted to 2.2.4
## 2.1.3 ## 2.1.3
- Bugfix for db: timestamps should be with time zone. - Bugfix for db: timestamps should be with time zone.
- Bump unleash-fronted to 2.2.3 - Bump unleash-fronted to 2.2.3
## 2.1.2 ## 2.1.2
- Bugfix for migration: avoid multiple calls on same callback. - Bugfix for migration: avoid multiple calls on same callback.
## 2.1.0 ## 2.1.0
- Provide a set of pre-defined activation strategies. These will automatically be defined by the migrator as long as they don't exist already. - Provide a set of pre-defined activation strategies. These will automatically be defined by the migrator as long as they don't exist already.
- applicationHostname - applicationHostname
- gradualRolloutRandom - gradualRolloutRandom
@ -124,6 +148,7 @@
- userWithId - userWithId
## 2.0.4 ## 2.0.4
- bump unleash-frontend which includes a lot of UI improvements and bug-fixes. - bump unleash-frontend which includes a lot of UI improvements and bug-fixes.
- Fix error message when trying to create a archived feature toggle. - Fix error message when trying to create a archived feature toggle.
@ -145,8 +170,6 @@
**If you are migrating from 1.0.0 to 2.0.0 we recommend reading [the migration guide](https://github.com/Unleash/unleash/blob/master/docs/migration-guide.md)** **If you are migrating from 1.0.0 to 2.0.0 we recommend reading [the migration guide](https://github.com/Unleash/unleash/blob/master/docs/migration-guide.md)**
## 1.0.0 (January 2015) ## 1.0.0 (January 2015)
- Initial public release
- Initial public release

View File

@ -8,19 +8,19 @@ In the interest of fostering an open and welcoming environment, we as contributo
Examples of behavior that contributes to creating a positive environment include: Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language - Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences - Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism - Gracefully accepting constructive criticism
* Focusing on what is best for the community - Focusing on what is best for the community
* Showing empathy towards other community members - Showing empathy towards other community members
Examples of unacceptable behavior by participants include: Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances - The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks - Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment - Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission - Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting - Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities ## Our Responsibilities

View File

@ -1,33 +1,25 @@
# Unleash # Unleash
[![Build Status](https://travis-ci.org/Unleash/unleash.svg?branch=master)](https://travis-ci.org/Unleash/unleash) [![Build Status](https://travis-ci.org/Unleash/unleash.svg?branch=master)](https://travis-ci.org/Unleash/unleash) [![Coverage Status](https://coveralls.io/repos/github/Unleash/unleash/badge.svg?branch=master)](https://coveralls.io/github/Unleash/unleash?branch=master) [![Dependency Status](https://david-dm.org/Unleash/unleash.svg)](https://david-dm.org/Unleash/unleash) [![devDependency Status](https://david-dm.org/Unleash/unleash/dev-status.svg)](https://david-dm.org/Unleash/unleash?type=dev) [![Greenkeeper badge](https://badges.greenkeeper.io/Unleash/unleash.svg)](https://greenkeeper.io/) [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy)
[![Coverage Status](https://coveralls.io/repos/github/Unleash/unleash/badge.svg?branch=master)](https://coveralls.io/github/Unleash/unleash?branch=master)
[![Dependency Status](https://david-dm.org/Unleash/unleash.svg)](https://david-dm.org/Unleash/unleash)
[![devDependency Status](https://david-dm.org/Unleash/unleash/dev-status.svg)](https://david-dm.org/Unleash/unleash?type=dev)
[![Greenkeeper badge](https://badges.greenkeeper.io/Unleash/unleash.svg)](https://greenkeeper.io/)
[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy)
Unleash is a feature toggle system, that gives you a great overview over all feature toggles across Unleash is a feature toggle system, that gives you a great overview over all feature toggles across all your applications and services. It comes with official client implementations for Java, Node.js, Go and Ruby.
all your applications and services. It comes with official client implementations for Java, Node.js, Go and Ruby.
The main motivation for doing feature toggling is to decouple the process for deploying code to production The main motivation for doing feature toggling is to decouple the process for deploying code to production and releasing new features. This helps reducing risk, and allow us to easily manage which features to enable
and releasing new features. This helps reducing risk, and allow us to easily manage which features to enable
> Feature toggles decouple **deployment** of code from **release** of new features > Feature toggles decouple **deployment** of code from **release** of new features
This repo contains the unleash-server, which contains the admin UI and a place to ask for the status of features. This repo contains the unleash-server, which contains the admin UI and a place to ask for the status of features. In order to make use of unleash you will also need a client implementation.
In order to make use of unleash you will also need a client implementation.
<img src="https://github.com/Unleash/unleash/raw/master/docs/assets/dashboard.png" alt="Unleash UI" width="600" /> <img src="https://github.com/Unleash/unleash/raw/master/docs/assets/dashboard.png" alt="Unleash UI" width="600" />
[Online demo version available on heroku](https://unleash.herokuapp.com/#/features). [Online demo version available on heroku](https://unleash.herokuapp.com/#/features).
## Activation strategies ## Activation strategies
It's fine to have a system for turning stuff on and off. But some times we want more granular control,
we want to decide who to the toggle should be enabled for. This is where activation strategies comes in to It's fine to have a system for turning stuff on and off. But some times we want more granular control, we want to decide who to the toggle should be enabled for. This is where activation strategies comes in to the picture. Activation strategies take arbitrary config and allows us to enable a toggle in various ways.
the picture. Activation strategies take arbitrary config and allows us to enable a toggle in various ways.
Common activation strategies includes: Common activation strategies includes:
- Active For users with a specified userId - Active For users with a specified userId
- GradualRollout to X-percent of our users - GradualRollout to X-percent of our users
- Active for our beta users - Active for our beta users
@ -36,9 +28,11 @@ Common activation strategies includes:
Read more about activation strategies in [docs/activation-strategies.md](./docs/activation-strategies.md) Read more about activation strategies in [docs/activation-strategies.md](./docs/activation-strategies.md)
## Client implementations ## Client implementations
We have offical SDK's for Java, Node.js, Go, Ruby and Python. And we will be happy to add implementations in other langugages written by you! These libraries makes it very easy to use Unleash in you application. We have offical SDK's for Java, Node.js, Go, Ruby and Python. And we will be happy to add implementations in other langugages written by you! These libraries makes it very easy to use Unleash in you application.
Official client SDKs: Official client SDKs:
- [unleash/unleash-client-java](https://github.com/unleash/unleash-client-java) - [unleash/unleash-client-java](https://github.com/unleash/unleash-client-java)
- [unleash/unleash-client-node](https://github.com/unleash/unleash-client-node) - [unleash/unleash-client-node](https://github.com/unleash/unleash-client-node)
- [unleash/unleash-client-go](https://github.com/unleash/unleash-client-go) - [unleash/unleash-client-go](https://github.com/unleash/unleash-client-go)
@ -46,6 +40,7 @@ Official client SDKs:
- [unleash/unleash-client-python](https://github.com/Unleash/unleash-client-python) - [unleash/unleash-client-python](https://github.com/Unleash/unleash-client-python)
Clients written by awesome enthusiasts: :fire: Clients written by awesome enthusiasts: :fire:
- [stiano/unleash-client-dotnet](https://github.com/stiano/unleash-client-dotnet) (.Net Core) - [stiano/unleash-client-dotnet](https://github.com/stiano/unleash-client-dotnet) (.Net Core)
- [onybo/unleash-client-core](https://github.com/onybo/unleash-client-core) (.Net Core) - [onybo/unleash-client-core](https://github.com/onybo/unleash-client-core) (.Net Core)
- [rarruda/unleash-client-python](https://github.com/rarruda/unleash-client-python) (Python 3) - [rarruda/unleash-client-python](https://github.com/rarruda/unleash-client-python) (Python 3)
@ -62,22 +57,19 @@ if (unleash.isEnabled("AwesomeFeature")) {
} }
``` ```
# Running Unleash # Running Unleash
## Requirements ## Requirements
You will need a __PostgreSQL__ 9.3+ database instance to be able to run Unleash. You will need a **PostgreSQL** 9.3+ database instance to be able to run Unleash.
When starting Unleash you must specify a database URI (can be set as environment variable DATABASE_URL) When starting Unleash you must specify a database URI (can be set as environment variable DATABASE_URL) which includes a username and password, which has the rights to migrate the database.
which includes a username and password, which has the rights to migrate the database.
_Unleash_ will, at startup, check whether database migration is needed, and perform necessary migrations. _Unleash_ will, at startup, check whether database migration is needed, and perform necessary migrations.
## Using Unleash ## Using Unleash
**The simplest way to get started:** **The simplest way to get started:** (database-url can also be set as a environment variable: DATABASE_URL)
(database-url can also be set as a environment variable: DATABASE_URL)
```bash ```bash
$ npm install unleash-server -g $ npm install unleash-server -g
@ -89,16 +81,19 @@ Unleash started on http://localhost:4242
You can also require Unleash as a lib (recommended) and expand it with more options. Read more about this feature in the [getting started guide](./docs/getting-started.md). You can also require Unleash as a lib (recommended) and expand it with more options. Read more about this feature in the [getting started guide](./docs/getting-started.md).
### Securing Unleash ### Securing Unleash
Unleash also have extension points where you can integrate Unleash with your authentication provider (OAuth 2.0). Read more about [securing unleash](./docs/securing-unleash.md). Unleash also have extension points where you can integrate Unleash with your authentication provider (OAuth 2.0). Read more about [securing unleash](./docs/securing-unleash.md).
## Run with docker ## Run with docker
We have made a separate project which runs unleash inside docker. Please see [unleash-docker](https://github.com/Unleash/unleash-docker) We have made a separate project which runs unleash inside docker. Please see [unleash-docker](https://github.com/Unleash/unleash-docker)
# Developer Guide # Developer Guide
If you want to contribute to this project you are encouraged to send issue request, or provide pull-requests.
Please read the [unleash developer guide](./docs/developer-guide.md) to learn more on how you can contribute. If you want to contribute to this project you are encouraged to send issue request, or provide pull-requests. Please read the [unleash developer guide](./docs/developer-guide.md) to learn more on how you can contribute.
# I want to learn more # I want to learn more
- [Blog: Unleash your features gradually!](http://bytes.schibsted.com/unleash-features-gradually/) - [Blog: Unleash your features gradually!](http://bytes.schibsted.com/unleash-features-gradually/)
- [Presentation: Unleash your features gradually!](http://ivarconr.github.io/feature-toggles-presentation/sch-dev-lunch-2017/#1) - [Presentation: Unleash your features gradually!](http://ivarconr.github.io/feature-toggles-presentation/sch-dev-lunch-2017/#1)
- http://martinfowler.com/bliki/FeatureToggle.html - http://martinfowler.com/bliki/FeatureToggle.html

View File

@ -3,7 +3,6 @@ id: activation_strategy
title: Activation Strategies title: Activation Strategies
--- ---
It is powerful to be able to turn a feature on and off instantaneously, without redeploying the application. The next level of control comes when you are able to enable a feature for specific users or enable it for a small subset of the users. We achieve this level of control with the help of activation strategies. The most simple strategy is the “default” strategy, which basically means that the feature should be enabled to everyone. It is powerful to be able to turn a feature on and off instantaneously, without redeploying the application. The next level of control comes when you are able to enable a feature for specific users or enable it for a small subset of the users. We achieve this level of control with the help of activation strategies. The most simple strategy is the “default” strategy, which basically means that the feature should be enabled to everyone.
The definition of an activation strategy lives in the Unleash API and can be created via the Unleash UI. The implementation of activation strategies lives in the various client implementations. The definition of an activation strategy lives in the Unleash API and can be created via the Unleash UI. The implementation of activation strategies lives in the various client implementations.
@ -11,59 +10,59 @@ The definition of an activation strategy lives in the Unleash API and can be cre
Unleash comes with a few common activation strategies. Some of them require the client to provide the [unleash-context](./unleash-context.md), which gives necessary context for unleash. Unleash comes with a few common activation strategies. Some of them require the client to provide the [unleash-context](./unleash-context.md), which gives necessary context for unleash.
## default ## default
It is the simplest activation strategy and basically means "active for everyone". It is the simplest activation strategy and basically means "active for everyone".
## userWithId ## userWithId
Active for users with a userId defined in the userIds-list. Typically I want to enable a new feature only for myself in production, before I enable it for everyone else. To achieve this we can use the “UserWithIdStrategy”. This strategy allows you to specify a list of user ids that you want to expose the new feature for. (A user id may of course be an email if that is more appropriate in your system.) Active for users with a userId defined in the userIds-list. Typically I want to enable a new feature only for myself in production, before I enable it for everyone else. To achieve this we can use the “UserWithIdStrategy”. This strategy allows you to specify a list of user ids that you want to expose the new feature for. (A user id may of course be an email if that is more appropriate in your system.)
**Parameters** **Parameters**
- userIds - *List of user ids you want the feature toggle be enabled for*
- userIds - _List of user ids you want the feature toggle be enabled for_
## gradualRolloutUserId ## gradualRolloutUserId
Gradually activates feature toggle for logged in users. Stickiness based on the user id.
This strategy guarantees that the same user gets the same experience every time, Gradually activates feature toggle for logged in users. Stickiness based on the user id. This strategy guarantees that the same user gets the same experience every time, across devices. It also guarantees that a user which is among the first 10% will also be among the first 20% of the users. Thus we ensure that users get the same experience. Even if we gradually increase the number of users who are exposed to a particular feature. To achieve this we hash the user id and normalise the hash value to a number between 1 and 100 with a simple modulo operator.
across devices. It also guarantees that a user which is among the first 10% will
also be among the first 20% of the users. Thus we ensure that users get the same
experience. Even if we gradually increase the number of users who are exposed to
a particular feature. To achieve this we hash the user id and normalise the hash
value to a number between 1 and 100 with a simple modulo operator.
![hash_and_normalise](assets/hash_and_normalise.png) ![hash_and_normalise](assets/hash_and_normalise.png)
Starting from v3.x all clients should use the 32-bit [MurmurHash3](https://en.wikipedia.org/wiki/MurmurHash) algorithm to normalize values. Starting from v3.x all clients should use the 32-bit [MurmurHash3](https://en.wikipedia.org/wiki/MurmurHash) algorithm to normalize values. ([issue 247](https://github.com/Unleash/unleash/issues/247))
([issue 247](https://github.com/Unleash/unleash/issues/247))
**Parameters** **Parameters**
- percentage - *The percentage (0-100) you want to enable the feature toggle for.*
- groupId - *Used to define an activation group, which allows you to correlate rollout across feature toggles.* - percentage - _The percentage (0-100) you want to enable the feature toggle for._
- groupId - _Used to define an activation group, which allows you to correlate rollout across feature toggles._
## gradualRolloutSessionId ## gradualRolloutSessionId
Gradually activates feature toggle. Stickiness based on session id. It is almost
identical to the `gradualRolloutUserId` strategy, with the exception that it works Gradually activates feature toggle. Stickiness based on session id. It is almost identical to the `gradualRolloutUserId` strategy, with the exception that it works on session ids. This makes it possible to target all users (not just logged in users), guaranteeing that a user will get the same experience within a session.
on session ids. This makes it possible to target all users (not just logged in
users), guaranteeing that a user will get the same experience within a session.
**Parameters** **Parameters**
- percentage - *The percentage (0-100) you want to enable the feature toggle for.*
- groupId - *Used to define an activation group, which allows you to correlate rollout across feature toggles.* - percentage - _The percentage (0-100) you want to enable the feature toggle for._
- groupId - _Used to define an activation group, which allows you to correlate rollout across feature toggles._
## gradualRolloutRandom ## gradualRolloutRandom
Randomly activates the feature toggle. No stickiness. We have found this rollout strategy
very useful in some scenarios, especially when we enable a feature which is not Randomly activates the feature toggle. No stickiness. We have found this rollout strategy very useful in some scenarios, especially when we enable a feature which is not visible to the user. It is also the strategy we use to sample metrics and error reports.
visible to the user. It is also the strategy we use to sample metrics and error reports.
**Parameters** **Parameters**
- percentage - *The percentage (0-100) you want to enable the feature toggle for.*
- percentage - _The percentage (0-100) you want to enable the feature toggle for._
## remoteAddress ## remoteAddress
Active for remote addresses defined in the IPs list. We sometimes use this strategy to
enable a feature only for IP's in our office network. Active for remote addresses defined in the IPs list. We sometimes use this strategy to enable a feature only for IP's in our office network.
**Parameters** **Parameters**
- IPS - *List of IPs to enable the feature for.*
- IPS - _List of IPs to enable the feature for._
## applicationHostname ## applicationHostname
Active for client instances with a hostName in the hostNames-list. Active for client instances with a hostName in the hostNames-list.
**Parameters** **Parameters**
- hostNames - *List of hostnames to enable the feature toggle for.*
- hostNames - _List of hostnames to enable the feature toggle for._

View File

@ -20,25 +20,23 @@ Defined event types:
**Response** **Response**
```json ```json
{ {
"version": 1, "version": 1,
"events":[ "events": [
{ {
"id":454, "id": 454,
"type":"feature-updated", "type": "feature-updated",
"createdBy":"unknown", "createdBy": "unknown",
"createdAt":"2016-08-24T11:22:01.354Z", "createdAt": "2016-08-24T11:22:01.354Z",
"data": { "data": {
"name":"eid.bankid.mobile", "name": "eid.bankid.mobile",
"description":"", "description": "",
"strategy":"default", "strategy": "default",
"enabled":true, "enabled": true,
"parameters":{} "parameters": {}
}, },
"diffs": [ "diffs": [{ "kind": "E", "path": ["enabled"], "lhs": false, "rhs": true }]
{"kind":"E","path":["enabled"],"lhs":false,"rhs":true}
]
} }
] ]
} }

View File

@ -7,12 +7,10 @@ title: /api/admin/features
`GET: http://unleash.host.com/api/admin/features` `GET: http://unleash.host.com/api/admin/features`
This endpoint is the one all admin ui should use to fetch all available feature toggles This endpoint is the one all admin ui should use to fetch all available feature toggles from the _unleash-server_. The response returns all active feature toggles and their current strategy configuration. A feature toggle will have _at least_ one configured strategy. A strategy will have a `name` and `parameters` map.
from the _unleash-server_. The response returns all active feature toggles and their
current strategy configuration. A feature toggle will have _at least_ one configured strategy.
A strategy will have a `name` and `parameters` map.
**Example response:** **Example response:**
```json ```json
{ {
"version": 2, "version": 2,
@ -53,8 +51,7 @@ A strategy will have a `name` and `parameters` map.
`GET: http://unleash.host.com/api/admin/features/:featureName` `GET: http://unleash.host.com/api/admin/features/:featureName`
Used to fetch details about a specific featureToggle. This is mostly provded to make it easy to Used to fetch details about a specific featureToggle. This is mostly provded to make it easy to debug the API and should not be used by the client implementations.
debug the API and should not be used by the client implementations.
```json ```json
{ {
@ -70,13 +67,13 @@ debug the API and should not be used by the client implementations.
} }
``` ```
### Create a new Feature Toggle ### Create a new Feature Toggle
`POST: http://unleash.host.com/api/admin/features/` `POST: http://unleash.host.com/api/admin/features/`
**Body:** **Body:**
```json
```json
{ {
"name": "Feature.A", "name": "Feature.A",
"description": "lorem ipsum..", "description": "lorem ipsum..",
@ -90,8 +87,7 @@ debug the API and should not be used by the client implementations.
} }
``` ```
Used by the admin-dashboard to create a new feature toggles. The name **must be unique**, Used by the admin-dashboard to create a new feature toggles. The name **must be unique**, otherwise you will get a _403-response_.
otherwise you will get a _403-response_.
Returns 200-respose if the feature toggle was created successfully. Returns 200-respose if the feature toggle was created successfully.
@ -100,7 +96,8 @@ Returns 200-respose if the feature toggle was created successfully.
`PUT: http://unleash.host.com/api/admin/features/:toggleName` `PUT: http://unleash.host.com/api/admin/features/:toggleName`
**Body:** **Body:**
```json
```json
{ {
"name": "Feature.A", "name": "Feature.A",
"description": "lorem ipsum..", "description": "lorem ipsum..",
@ -114,8 +111,7 @@ Returns 200-respose if the feature toggle was created successfully.
} }
``` ```
Used by the admin dashboard to update a feature toggles. The name has to match an Used by the admin dashboard to update a feature toggles. The name has to match an existing features toggle.
existing features toggle.
Returns 200-respose if the feature toggle was updated successfully. Returns 200-respose if the feature toggle was updated successfully.
@ -123,9 +119,7 @@ Returns 200-respose if the feature toggle was updated successfully.
`DELETE: http://unleash.host.com/api/admin/features/:toggleName` `DELETE: http://unleash.host.com/api/admin/features/:toggleName`
Used to archive a feature toggle. A feature toggle can never be totally be deleted, Used to archive a feature toggle. A feature toggle can never be totally be deleted, but can be archived. This is a design decision to make sure that a old feature toggle suddenly reappears becuase someone else re-using the same name.
but can be archived. This is a design decision to make sure that a old feature
toggle suddenly reappears becuase someone else re-using the same name.
## Archive ## Archive
@ -136,6 +130,7 @@ toggle suddenly reappears becuase someone else re-using the same name.
Used to fetch list of archived feature toggles Used to fetch list of archived feature toggles
**Example response:** **Example response:**
```json ```json
{ {
"version": 1, "version": 1,
@ -162,7 +157,8 @@ Used to fetch list of archived feature toggles
`POST http://unleash.host.com/api/admin/archive/revive` `POST http://unleash.host.com/api/admin/archive/revive`
**Body:** **Body:**
```json
```json
{ {
"name": "Feature.A" "name": "Feature.A"
} }

View File

@ -5,15 +5,11 @@ title: /api/admin/metrics
# This document describes the metrics endpoint for admin ui # This document describes the metrics endpoint for admin ui
### Seen-toggles ### Seen-toggles
`GET http://unleash.host.com/api/admin/seen-toggles` `GET http://unleash.host.com/api/admin/seen-toggles`
This enpoints returns a list of applications and what toogles This enpoints returns a list of applications and what toogles unleash has seend for each application. It will only guarantee toggles reported by client applications within the last hour, but will in most cases remember seen-toggles for applications longer
unleash has seend for each application. It will only guarantee
toggles reported by client applications within the last hour, but
will in most cases remember seen-toggles for applications longer
**Example response:** **Example response:**
@ -21,20 +17,12 @@ will in most cases remember seen-toggles for applications longer
[ [
{ {
"appName": "demo-app", "appName": "demo-app",
"seenToggles": [ "seenToggles": ["add-feature-2", "toggle-2", "toggle-3"],
"add-feature-2",
"toggle-2",
"toggle-3"
],
"metricsCount": 127 "metricsCount": 127
}, },
{ {
"appName": "demo-app-2", "appName": "demo-app-2",
"seenToggles": [ "seenToggles": ["add-feature-2", "toggle-2", "toggle-3"],
"add-feature-2",
"toggle-2",
"toggle-3"
],
"metricsCount": 21 "metricsCount": 21
} }
] ]
@ -42,20 +30,15 @@ will in most cases remember seen-toggles for applications longer
**Fields:** **Fields:**
* **appName** - Name of the application seen by unleash-server - **appName** - Name of the application seen by unleash-server
* **seenToggles** - array of toggles names seen by unleash-server for this application - **seenToggles** - array of toggles names seen by unleash-server for this application
* **metricsCount** - number of metrics counted across all toggles for this application. - **metricsCount** - number of metrics counted across all toggles for this application.
### Feature-Toggles metrics ### Feature-Toggles metrics
`GET http://unleash.host.com/api/admin/metrics/feature-toggles` `GET http://unleash.host.com/api/admin/metrics/feature-toggles`
This endpoint gives _last minute_ and _last hour_ metrics for all active toggles. This is based on This endpoint gives _last minute_ and _last hour_ metrics for all active toggles. This is based on metrics reported by client applications. Yes is the number of times a given feature toggle was evaluated to enabled in a client applcation, and no is the number it avaluated to false.
metrics reported by client applications. Yes is the number of times a given feature toggle
was evaluated to enabled in a client applcation, and no is the number it avaluated to false.
**Example response:** **Example response:**
@ -94,28 +77,21 @@ was evaluated to enabled in a client applcation, and no is the number it avaluat
**Fields:** **Fields:**
* **lastHour** - Hour projection collected metrics for all feature toggles. - **lastHour** - Hour projection collected metrics for all feature toggles.
* **lastMinute** - Mintue projection collected metrics for all feature toggles. - **lastMinute** - Mintue projection collected metrics for all feature toggles.
### Applications ### Applications
`GET http://unleash.host.com/api/admin/applications` `GET http://unleash.host.com/api/admin/applications`
This endpoint returns a list of known applications (seen the last two days) and This endpoint returns a list of known applications (seen the last two days) and a link to follow for more datails.
a link to follow for more datails.
```json ```json
{ {
"applications": [ "applications": [
{ {
"appName": "another", "appName": "another",
"strategies": [ "strategies": ["default", "other", "brother"],
"default",
"other",
"brother"
],
"createdAt": "2016-12-09T14:56:36.730Z", "createdAt": "2016-12-09T14:56:36.730Z",
"links": { "links": {
"appDetails": "/api/admin/applications/another" "appDetails": "/api/admin/applications/another"
@ -123,11 +99,7 @@ a link to follow for more datails.
}, },
{ {
"appName": "bow", "appName": "bow",
"strategies": [ "strategies": ["default", "other", "brother"],
"default",
"other",
"brother"
],
"createdAt": "2016-12-09T14:56:36.730Z", "createdAt": "2016-12-09T14:56:36.730Z",
"links": { "links": {
"appDetails": "/api/admin/applications/bow" "appDetails": "/api/admin/applications/bow"
@ -138,23 +110,16 @@ a link to follow for more datails.
``` ```
#### Query Params #### Query Params
You can also specify the query param: _strategyName_, which will return all applications
implementing the given strategy. You can also specify the query param: _strategyName_, which will return all applications implementing the given strategy.
`GET http://unleash.host.com/api/admin/applications?strategyName=someStrategyName` `GET http://unleash.host.com/api/admin/applications?strategyName=someStrategyName`
### Application Details ### Application Details
`GET http://unleash.host.com/api/admin/applications/:appName` `GET http://unleash.host.com/api/admin/applications/:appName`
This endpoint gives insight into details about a client applcation, such as instances, This endpoint gives insight into details about a client applcation, such as instances, strategies implemented and seen toogles.
strategies implemented and seen toogles.
```json ```json
{ {
@ -171,22 +136,15 @@ strategies implemented and seen toogles.
"clientIp": "::ffff:127.0.0.1", "clientIp": "::ffff:127.0.0.1",
"lastSeen": "2016-11-30T16:04:15.991Z", "lastSeen": "2016-11-30T16:04:15.991Z",
"createdAt": "2016-11-30T10:49:11.223Z" "createdAt": "2016-11-30T10:49:11.223Z"
}, }
], ],
"strategies": [ "strategies": [
{ {
"appName": "demo-app", "appName": "demo-app",
"strategies": [ "strategies": ["default", "extra"]
"default",
"extra"
]
} }
], ],
"seenToggles": [ "seenToggles": ["add-feature-2", "toggle-2", "toggle-3"]
"add-feature-2",
"toggle-2",
"toggle-3"
]
} }
``` ```
@ -196,7 +154,6 @@ strategies implemented and seen toogles.
This endpoint gives insight into details about application seen per feature toggle. This endpoint gives insight into details about application seen per feature toggle.
```json ```json
{ {
"my-toggle": [ "my-toggle": [
@ -225,9 +182,7 @@ This endpoint gives insight into details about application seen per feature togg
"createdAt": "2016-12-28T10:39:24.966Z", "createdAt": "2016-12-28T10:39:24.966Z",
"updatedAt": "2017-01-06T15:32:41.932Z", "updatedAt": "2017-01-06T15:32:41.932Z",
"description": "our other app", "description": "our other app",
"strategies": [ "strategies": ["default"],
"default",
],
"url": "http://example.com", "url": "http://example.com",
"color": null, "color": null,
"icon": "desktop" "icon": "desktop"

View File

@ -4,13 +4,14 @@ title: /api/admin/strategies
--- ---
### Fetch Strategies ### Fetch Strategies
`GET: http://unleash.host.com/api/admin/strategies` `GET: http://unleash.host.com/api/admin/strategies`
Used to fetch all defined strategies and their defined paramters. Used to fetch all defined strategies and their defined paramters.
**Response** **Response**
```json ```json
{ {
"version": 1, "version": 1,
"strategies": [ "strategies": [
@ -48,8 +49,9 @@ Used to fetch all defined strategies and their defined paramters.
"required": false "required": false
} }
] ]
}, }
]} ]
}
``` ```
### Create strategy ### Create strategy
@ -81,7 +83,6 @@ Used to fetch all defined strategies and their defined paramters.
Used to create a new Strategy. Name is required and must be unique. It is also required to have a parameters array, but it can be empty. Used to create a new Strategy. Name is required and must be unique. It is also required to have a parameters array, but it can be empty.
### Update strategy ### Update strategy
`PUT: http://unleash.host.com/api/admin/strategies/:name` `PUT: http://unleash.host.com/api/admin/strategies/:name`
@ -109,5 +110,4 @@ Used to create a new Strategy. Name is required and must be unique. It is also r
}, },
``` ```
Used to update a Strategy definition. Name can't be changed. Used to update a Strategy definition. Name can't be changed. **PS! I can be dangerous to change a implemnted strategy as the implementation also might need to be changed**
**PS! I can be dangerous to change a implemnted strategy as the implementation also might need to be changed**

View File

@ -9,23 +9,17 @@ title: /api/client/features
**HEADERS:** **HEADERS:**
* UNLEASH-APPNAME: appName - UNLEASH-APPNAME: appName
* UNLEASH-INSTANCEID: instanceId - UNLEASH-INSTANCEID: instanceId
This endpoint is the one all clients should use to fetch all available feature toggles This endpoint is the one all clients should use to fetch all available feature toggles from the _unleash-server_. The response returns all active feature toggles and their current strategy configuration. A feature toggle will have _at least_ one configured strategy. A strategy will have a `name` and `parameters` map.
from the _unleash-server_. The response returns all active feature toggles and their
current strategy configuration. A feature toggle will have _at least_ one configured strategy.
A strategy will have a `name` and `parameters` map.
> _Note:_ Clients should prefer the `strategies` property. > _Note:_ Clients should prefer the `strategies` property. Legacy properties (`strategy` & `parameters`) will be kept until **version 2** of the format.
> Legacy properties (`strategy` & `parameters`) will be kept until **version 2** of the format.
This endpoint should never return anything besides a valid *20X or 304-response*. It will also This endpoint should never return anything besides a valid _20X or 304-response_. It will also include an `Etag`-header. The value of this header can be used by clients as the value of the `If-None-Match`-header in the request to prevent a data transfer if the client already has the latest response locally.
include an `Etag`-header. The value of this header can be used by clients as the value of
the `If-None-Match`-header in the request to prevent a data transfer if the client already
has the latest response locally.
**Example response:** **Example response:**
```json ```json
{ {
"version": 1, "version": 1,
@ -72,11 +66,9 @@ has the latest response locally.
You may limit the response by sending a `namePrefix` query-parameter. You may limit the response by sending a `namePrefix` query-parameter.
`GET: http://unleash.host.com/api/client/features/:featureName` `GET: http://unleash.host.com/api/client/features/:featureName`
Used to fetch details about a specific feature toggle. This is mainly provided to make it easy to Used to fetch details about a specific feature toggle. This is mainly provided to make it easy to debug the API and should not be used by the client implementations.
debug the API and should not be used by the client implementations.
> _Notice_: You will not get a version property when fetching a specific feature toggle by name. > _Notice_: You will not get a version property when fetching a specific feature toggle by name.

View File

@ -20,12 +20,11 @@ Registers a client instance with the unleash server. The client should send all
} }
``` ```
**Fields:** **Fields:**
* **appName** - Name of the application seen by unleash-server - **appName** - Name of the application seen by unleash-server
* **instanceId** - Instance id for this application (typically hostname, podId or similar) - **instanceId** - Instance id for this application (typically hostname, podId or similar)
* **sdkVersion** - Optional field that describes the sdk version (name:version) - **sdkVersion** - Optional field that describes the sdk version (name:version)
* **strategies** - List of strategies implemented by this application - **strategies** - List of strategies implemented by this application
* **started** - When this client started. Should be reported as [ISO8601](https://en.wikipedia.org/wiki/ISO_8601) time. - **started** - When this client started. Should be reported as [ISO8601](https://en.wikipedia.org/wiki/ISO_8601) time.
* **interval** - At which interval, in milliseconds, will this client be expected to send metrics - **interval** - At which interval, in milliseconds, will this client be expected to send metrics

View File

@ -4,19 +4,22 @@ title: API Documentation
--- ---
## Client API ## Client API
This describes the API provided to unleash-clients. This describes the API provided to unleash-clients.
* [Feature Toggles API](client/feature-toggles-api.md) - [Feature Toggles API](client/feature-toggles-api.md)
* [Register API](client/register-api.md) - [Register API](client/register-api.md)
* [Metrics API](client/metrics-api.md) - [Metrics API](client/metrics-api.md)
## Admin API (internal) ## Admin API (internal)
The internal API used by the Admin UI (unleash-frontend): The internal API used by the Admin UI (unleash-frontend):
* [Feature Toggles API](admin/feature-toggles-api.md) - [Feature Toggles API](admin/feature-toggles-api.md)
* [Strategies API](admin/strategies-api.md) - [Strategies API](admin/strategies-api.md)
* [Events API](admin/events-api.md) - [Events API](admin/events-api.md)
* [Metrics API](admin/metrics-api.md) - [Metrics API](admin/metrics-api.md)
## System API's ## System API's
* [Internal Backstage API](internal-backstage-api.md)
- [Internal Backstage API](internal-backstage-api.md)

View File

@ -7,8 +7,7 @@ title: /internal-backstage/prometheus
`GET http://unleash.host.com/internal-backstage/prometheus` `GET http://unleash.host.com/internal-backstage/prometheus`
Unleash uses prometheus internally to collect metrics. These are Unleash uses prometheus internally to collect metrics. These are available on the given url if the `serverMetrics` option is enabled (default=true).
available on the given url if the `serverMetrics` option is enabled (default=true).
[Read more about Prometheus](https://prometheus.io/) [Read more about Prometheus](https://prometheus.io/)
@ -21,4 +20,3 @@ You can use this query in grafana to achive this:
``` ```
delta(feature_toggle_update_total{toggle="Demo"}[1m]) != bool 0? delta(feature_toggle_update_total{toggle="Demo"}[1m]) != bool 0?
``` ```

View File

@ -3,34 +3,31 @@ id: client_specification
title: Client Specification title: Client Specification
--- ---
# Client Specification 1.0 # Client Specification 1.0
This document attempts to guide developers in implementing a Unleash Client SDK. This document attempts to guide developers in implementing a Unleash Client SDK.
## System Overview ## System Overview
Unleash is comprised of three parts: Unleash is comprised of three parts:
- **Unleash API** - The service holding all feature toggles and their configurations. Configurations declare which activation strategies to use and which parameters they should get. - **Unleash API** - The service holding all feature toggles and their configurations. Configurations declare which activation strategies to use and which parameters they should get.
- **Unleash UI** - The dashboard used to manage feature toggles, define new strategies, look at metrics, etc. - **Unleash UI** - The dashboard used to manage feature toggles, define new strategies, look at metrics, etc.
- **Unleash SDK** - Used by clients to check if a feature is enabled or disabled. The SDK also collects metrics and sends them to the Unleash API. Activation Strategies are also implemented in the SDK. Unleash currently provides official SDKs for Java and Node.js - **Unleash SDK** - Used by clients to check if a feature is enabled or disabled. The SDK also collects metrics and sends them to the Unleash API. Activation Strategies are also implemented in the SDK. Unleash currently provides official SDKs for Java and Node.js
![system_overview](https://raw.githubusercontent.com/Unleash/unleash/master/docs/assets/unleash-diagram.png "System Overview") ![system_overview](https://raw.githubusercontent.com/Unleash/unleash/master/docs/assets/unleash-diagram.png 'System Overview')
In order to be super fast, the client SDK caches all feature toggles and their current configuration in memory. The activation strategies are also implemented in the SDK. This makes it really fast to check if a toggle is on or off because it is just a simple function operating on local state, without the need to poll data from the database. In order to be super fast, the client SDK caches all feature toggles and their current configuration in memory. The activation strategies are also implemented in the SDK. This makes it really fast to check if a toggle is on or off because it is just a simple function operating on local state, without the need to poll data from the database.
## The Basics ## The Basics
All client implementations should strive to have a simple and consistent user API.
It should be a simple method, called isEnabled, to check if a feature toggle is enabled All client implementations should strive to have a simple and consistent user API. It should be a simple method, called isEnabled, to check if a feature toggle is enabled or not. The method should return a `boolean` value, true or false.
or not. The method should return a `boolean` value, true or false.
```javascript ```javascript
unleash.isEnabled("myAwesomeToggle") unleash.isEnabled('myAwesomeToggle');
``` ```
The basic `isEnabled` method should also accept a default value. This should be used if The basic `isEnabled` method should also accept a default value. This should be used if the client does not know anything about that that toggle name. If the user does not specify a default value, false should be returned for unknown feature toggles.
the client does not know anything about that that toggle name. If the user does not specify
a default value, false should be returned for unknown feature toggles.
**Calling unleash with default value:** **Calling unleash with default value:**
@ -39,9 +36,8 @@ boolean value = unleash.isEnabled("unknownFeatureToggle", false);
//value==false because default value was used. //value==false because default value was used.
``` ```
### Implementation of isEnabled ### Implementation of isEnabled
A feature toggle is defined as: A feature toggle is defined as:
```json ```json
@ -67,7 +63,7 @@ A feature toggle is defined as:
"parameters": { "parameters": {
"userIdList": "123,221,998" "userIdList": "123,221,998"
} }
} }
``` ```
A simple demo of the isEnable function in JavaScript-style (most implementation will probably be more functional): A simple demo of the isEnable function in JavaScript-style (most implementation will probably be more functional):
@ -77,63 +73,45 @@ function isEnabled(name, unleashContext = {}, defaultValue = false) {
const toggle = toggleRepository.get(name); const toggle = toggleRepository.get(name);
let enabled = false; let enabled = false;
if ( !toggle ) { if (!toggle) {
return defaultValue; return defaultValue;
} else if ( ! toggle.isEnabled) { } else if (!toggle.isEnabled) {
return false; return false;
} else { } else {
for(let i=0;i<toggle.strategies.length;i++) { for (let i = 0; i < toggle.strategies.length; i++) {
let strategyDef = toggle.strategies[i]; let strategyDef = toggle.strategies[i];
let strategyImpl = strategyImplRepository.get(strategyDef.name); let strategyImpl = strategyImplRepository.get(strategyDef.name);
if(strategyImpl.isEnabled(toggle.parameters, unleashContext)) { if (strategyImpl.isEnabled(toggle.parameters, unleashContext)) {
return true; return true;
} }
} }
return false; return false;
} }
} }
``` ```
## Activation Strategies ## Activation Strategies
Activation strategies are defined and configured in the unleash-service. It is up to the client
to provide the actual implementation of each activation strategy.
Unleash also ships with a few built-in strategies and it is expected that client SDK's implement Activation strategies are defined and configured in the unleash-service. It is up to the client to provide the actual implementation of each activation strategy.
these. Read more about these [activation strategies](activation-strategies.md). For the built-in
strategies to work as expected the client should also allow the user to define a Unleash also ships with a few built-in strategies and it is expected that client SDK's implement these. Read more about these [activation strategies](activation-strategies.md). For the built-in strategies to work as expected the client should also allow the user to define a [unleash-context](unleash-context.md). The context should be possible to pass in as part of the `isEnabled` call.
[unleash-context](unleash-context.md). The context should be possible to pass in as part of
the `isEnabled` call.
### Extension points ### Extension points
Client implementation should also provide a defined interface to make it easier for
the user to implement their own activation strategies, and register those in the unleash client.
Client implementation should also provide a defined interface to make it easier for the user to implement their own activation strategies, and register those in the unleash client.
## Fetching feature toggles (polling) ## Fetching feature toggles (polling)
The client implementation should fetch toggles in the background, as regular polling.
In thread based environment (e.g. Java) this needs to be done on a separate thread.
The default poll interval should be **15 seconds**, and it should be configurable.
The client implementation should fetch toggles in the background, as regular polling. In thread based environment (e.g. Java) this needs to be done on a separate thread. The default poll interval should be **15 seconds**, and it should be configurable.
## Client registration ## Client registration
Client implementation should at initialization register with the unleash-server.
The should send a registration as specified in the [api documentation](api/client/register-api.md).
The registration must include all fields specified.
Client implementation should at initialization register with the unleash-server. The should send a registration as specified in the [api documentation](api/client/register-api.md). The registration must include all fields specified.
## Metrics ## Metrics
Clients are expected to send metrics back to Unleash API at regular intervals. The metrics is a list
of used toggles and how many times they evaluated to *yes* or *no* in the current period.
Read more about how to send the metrics in the [metrics-api](api/client/metrics-api.md) documentation.
Clients are expected to send metrics back to Unleash API at regular intervals. The metrics is a list of used toggles and how many times they evaluated to _yes_ or _no_ in the current period. Read more about how to send the metrics in the [metrics-api](api/client/metrics-api.md) documentation.
## Backup Feature Toggles ## Backup Feature Toggles
The SDK also persists the latest known state to a local file at the instance where the client is running.
It will persist a local copy every time the client detects changes from the API. Having a local backup of
the latest known state minimises the consequence of clients not being able to to talk to Unleash API at
startup. This is required because network is unreliable.
The SDK also persists the latest known state to a local file at the instance where the client is running. It will persist a local copy every time the client detects changes from the API. Having a local backup of the latest known state minimises the consequence of clients not being able to to talk to Unleash API at startup. This is required because network is unreliable.

View File

@ -3,8 +3,7 @@ id: database_backup
title: Database Backup title: Database Backup
--- ---
When upgrading to a new major version of Unleash it is advised to do a When upgrading to a new major version of Unleash it is advised to do a full database backup to ease rollback in case of failures.
full database backup to ease rollback in case of failures.
1. Create a database backup: 1. Create a database backup:

View File

@ -3,43 +3,41 @@ id: database_schema
title: Database Schema title: Database Schema
--- ---
This document describes our current database schema used in PostgreSQL. We use db-migrate to migrate (create tables, add columns etc) the database.
This document describes our current database schema used in PostgreSQL.
We use db-migrate to migrate (create tables, add columns etc) the database.
## Table: _migrations_ ## Table: _migrations_
Used by db-migrate module to keep track of migrations. Used by db-migrate module to keep track of migrations.
| NAME | TYPE | SIZE | NULLABLE | COLUMN_DEF | | NAME | TYPE | SIZE | NULLABLE | COLUMN_DEF |
| ----------- | --------- | ----------- | -------- | -------------------------------------- | | ------ | --------- | ---- | -------- | -------------------------------------- |
| id | serial | 10 | 0 | nextval('migrations_id_seq'::regclass) | | id | serial | 10 | 0 | nextval('migrations_id_seq'::regclass) |
| name | varchar | 255 | 0 | (null) | | name | varchar | 255 | 0 | (null) |
| run_on | timestamp | 29 | 0 | (null) | | run_on | timestamp | 29 | 0 | (null) |
## Table: _events_ ## Table: _events_
| NAME | TYPE | SIZE | NULLABLE | COLUMN_DEF | | NAME | TYPE | SIZE | NULLABLE | COLUMN_DEF |
| ----------- | --------- | ----------- | -------- | ---------------------------------- | | ---------- | --------- | ---------- | -------- | ---------------------------------- |
| id | serial | 10 | 0 | nextval('events_id_seq'::regclass) | | id | serial | 10 | 0 | nextval('events_id_seq'::regclass) |
| created_at | timestamp | 29 | 1 | now() | | created_at | timestamp | 29 | 1 | now() |
| type | varchar | 255 | 0 | (null) | | type | varchar | 255 | 0 | (null) |
| created_by | varchar | 255 | 0 | (null) | | created_by | varchar | 255 | 0 | (null) |
| data | json | 2147483647 | 1 | (null) | | data | json | 2147483647 | 1 | (null) |
## Table: _strategies_ ## Table: _strategies_
| NAME | TYPE | SIZE | NULLABLE | COLUMN_DEF | | NAME | TYPE | SIZE | NULLABLE | COLUMN_DEF |
| ------------------- | --------- | ----------- | -------- | ---------- | | ------------------- | --------- | ---------- | -------- | ---------- |
| created_at | timestamp | 29 | 1 | now() | | created_at | timestamp | 29 | 1 | now() |
| name | varchar | 255 | 0 | (null) | | name | varchar | 255 | 0 | (null) |
| description | text | 2147483647 | 1 | (null) | | description | text | 2147483647 | 1 | (null) |
| parameters_template | json | 2147483647 | 1 | (null) | | parameters_template | json | 2147483647 | 1 | (null) |
## Table: _features_ ## Table: _features_
| **NAME** | **TYPE** | **SIZE** | **NULLABLE** | **COLUMN_DEF** | **COMMENT** | | **NAME** | **TYPE** | **SIZE** | **NULLABLE** | **COLUMN_DEF** | **COMMENT** |
| ------------- | --------- | ----------- | ------------ | -------------- | ----------- | | ----------- | --------- | ---------- | ------------ | -------------- | ----------- |
| created_at | timestamp | 29 | 1 | now() | | | created_at | timestamp | 29 | 1 | now() | |
| name | varchar | 255 | 0 | (null) | | | name | varchar | 255 | 0 | (null) | |
| enabled | int4 | 10 | 1 | 0 | | | enabled | int4 | 10 | 1 | 0 | |
@ -47,7 +45,6 @@ Used by db-migrate module to keep track of migrations.
| archived | int4 | 10 | 1 | 0 | | | archived | int4 | 10 | 1 | 0 | |
| strategies | json | 2147483647 | 1 | (null) | | | strategies | json | 2147483647 | 1 | (null) | |
## Table: _client_strategies_ ## Table: _client_strategies_
| COLUMN_NAME | TYPE_NAME | COLUMN_SIZE | NULLABLE | COLUMN_DEF | | COLUMN_NAME | TYPE_NAME | COLUMN_SIZE | NULLABLE | COLUMN_DEF |
@ -56,7 +53,6 @@ Used by db-migrate module to keep track of migrations.
| updated_at | timestamp | 29 | 1 | now() | | updated_at | timestamp | 29 | 1 | now() |
| strategies | json | 2147483647 | 1 | (null) | | strategies | json | 2147483647 | 1 | (null) |
## Table: _client_instances_ ## Table: _client_instances_
| COLUMN_NAME | TYPE_NAME | COLUMN_SIZE | NULLABLE | COLUMN_DEF | | COLUMN_NAME | TYPE_NAME | COLUMN_SIZE | NULLABLE | COLUMN_DEF |

View File

@ -3,10 +3,9 @@ id: developer_guide
title: Developer guide title: Developer guide
--- ---
## PostgreSQL ## PostgreSQL
To run and develop unleash you need to have PostgreSQL database (PostgreSQL v.9.5.x or newer) locally.
To run and develop unleash you need to have PostgreSQL database (PostgreSQL v.9.5.x or newer) locally.
### Create a local unleash databases in postgres ### Create a local unleash databases in postgres
@ -30,9 +29,8 @@ export TEST_DATABASE_URL=postgres://unleash_user:passord@localhost:5432/unleash_
``` ```
## PostgreSQL with docker ## PostgreSQL with docker
If you dont want to install PostgreSQL locally you can spin up an instance with docker.
We have created a script to ease this process: `scripts/docker-postgres.sh`
If you dont want to install PostgreSQL locally you can spin up an instance with docker. We have created a script to ease this process: `scripts/docker-postgres.sh`
## Commands ## Commands
@ -58,6 +56,7 @@ npm test
We use database migrations to track database changes. We use database migrations to track database changes.
### Making a schema change ### Making a schema change
In order to run migrations you will set the environment variable for DATABASE_URL In order to run migrations you will set the environment variable for DATABASE_URL
`export DATABASE_URL=postgres://unleash_user:passord@localhost:5432/unleash` `export DATABASE_URL=postgres://unleash_user:passord@localhost:5432/unleash`
@ -76,14 +75,18 @@ Example of a typical migration:
/* eslint camelcase: "off" */ /* eslint camelcase: "off" */
'use strict'; 'use strict';
exports.up = function (db, cb) { exports.up = function(db, cb) {
db.createTable('examples', { db.createTable(
'examples',
{
id: { type: 'int', primaryKey: true, notNull: true }, id: { type: 'int', primaryKey: true, notNull: true },
created_at: { type: 'timestamp', defaultValue: 'now()' }, created_at: { type: 'timestamp', defaultValue: 'now()' },
}, cb); },
cb,
);
}; };
exports.down = function (db, cb) { exports.down = function(db, cb) {
return db.dropTable('examples', cb); return db.dropTable('examples', cb);
}; };
``` ```
@ -95,7 +98,6 @@ Test your migrations:
> npm run db-migrate -- down > npm run db-migrate -- down
``` ```
## Publishing / Releasing new packages ## Publishing / Releasing new packages
Please run `npm run nsp` nad `npm run test` checks before publishing. Please run `npm run nsp` nad `npm run test` checks before publishing.

View File

@ -5,14 +5,14 @@ title: Getting Started
## Requirements ## Requirements
You will need Node.js >= 8.0.0 and a __PostreSQL__ 9.5+ database instance to be able to run Unleash. You will need Node.js >= 8.0.0 and a **PostreSQL** 9.5+ database instance to be able to run Unleash.
When starting Unleash you must specify a database uri (can be set as environment variable DATABASE_URL) When starting Unleash you must specify a database uri (can be set as environment variable DATABASE_URL) which includes a username and password, that have rights to migrate the database.
which includes a username and password, that have rights to migrate the database.
On startup _Unleash_ will perform necessary migrations if needed. On startup _Unleash_ will perform necessary migrations if needed.
## Start Unleash ## Start Unleash
### 1. The simplest way to get started: ### 1. The simplest way to get started:
```bash ```bash
@ -23,17 +23,22 @@ Unleash started on http://localhost:4242
``` ```
### 2. Or programmatically: ### 2. Or programmatically:
You can also depend on unleash You can also depend on unleash
```js ```js
const unleash = require('unleash-server'); const unleash = require('unleash-server');
unleash.start({ unleash
.start({
databaseUrl: 'postgres://unleash_user:passord@localhost:5432/unleash', databaseUrl: 'postgres://unleash_user:passord@localhost:5432/unleash',
port: 4242 port: 4242,
}).then(unleash => { })
console.log(`Unleash started on http://localhost:${unleash.app.get('port')}`); .then(unleash => {
}); console.log(
`Unleash started on http://localhost:${unleash.app.get('port')}`,
);
});
``` ```
Available unleash options includes: Available unleash options includes:
@ -51,6 +56,7 @@ Available unleash options includes:
- `custom` - Use this when you implement your own custom authentication logic. - `custom` - Use this when you implement your own custom authentication logic.
### 3. Docker ### 3. Docker
You can also use the [hosted docker image](https://hub.docker.com/r/unleashorg/unleash-server/) to start the Unleash server You can also use the [hosted docker image](https://hub.docker.com/r/unleashorg/unleash-server/) to start the Unleash server
```sh ```sh
@ -66,13 +72,13 @@ By default, `unleash` uses [log4js](https://github.com/nomiddlename/log4js-node)
A logger provider is a function which takes the name of a logger and returns a logger implementation. For instance, the following code snippet shows how a logger provider for the global `console` object could be written: A logger provider is a function which takes the name of a logger and returns a logger implementation. For instance, the following code snippet shows how a logger provider for the global `console` object could be written:
```javascript ```javascript
function consoleLoggerProvider (name) { function consoleLoggerProvider(name) {
// do something with the name // do something with the name
return { return {
debug: console.log, debug: console.log,
info: console.log, info: console.log,
warn: console.log, warn: console.log,
error: console.error error: console.error,
}; };
} }
``` ```
@ -81,7 +87,7 @@ The logger interface with its `debug`, `info`, `warn` and `error` methods expect
### How do I set a logger provider? ### How do I set a logger provider?
Custom logger providers need to be set *before requiring the `unleash-server` module*. The following example shows how this can be done: Custom logger providers need to be set _before requiring the `unleash-server` module_. The following example shows how this can be done:
```javascript ```javascript
// first configure the logger provider // first configure the logger provider

View File

@ -6,6 +6,7 @@ title: Google Auth Hook
This part of the tutorial shows how to create a sign-in flow for users and integrate with Unleash server project. The implementation assumes that I am working in `localhost` with `4242` port. This part of the tutorial shows how to create a sign-in flow for users and integrate with Unleash server project. The implementation assumes that I am working in `localhost` with `4242` port.
This is a simple `index.js` server file. This is a simple `index.js` server file.
```javascript ```javascript
const unleash = require('unleash-server'); const unleash = require('unleash-server');
@ -15,7 +16,7 @@ if (process.env.DATABASE_URL_FILE) {
unleash.start(options).then(unleash => { unleash.start(options).then(unleash => {
console.log(`Unleash started on http://localhost:${unleash.app.get('port')}`); console.log(`Unleash started on http://localhost:${unleash.app.get('port')}`);
});; });
``` ```
### Creating a web application client ID ### Creating a web application client ID
@ -31,6 +32,7 @@ unleash.start(options).then(unleash => {
5. Type the **Name**. 5. Type the **Name**.
6. Under **Authorized redirect URIs** enter the following URLs, one at a time. 6. Under **Authorized redirect URIs** enter the following URLs, one at a time.
``` ```
http://localhost:4242/api/auth/callback http://localhost:4242/api/auth/callback
``` ```
@ -39,58 +41,67 @@ http://localhost:4242/api/auth/callback
8. Copy the **CLIENT ID** and **CLIENT SECRET** and save them for later use. 8. Copy the **CLIENT ID** and **CLIENT SECRET** and save them for later use.
### Add dependencies ### Add dependencies
Add two dependencies [`passport`](https://www.npmjs.com/package/passport) and [`passport-google-oauth20`](https://www.npmjs.com/package/passport-google-oauth20) inside `index.js` file Add two dependencies [`passport`](https://www.npmjs.com/package/passport) and [`passport-google-oauth20`](https://www.npmjs.com/package/passport-google-oauth20) inside `index.js` file
```js ```js
const unleash = require('unleash-server'); const unleash = require('unleash-server');
const passport = require('passport'); const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20').Strategy; const GoogleStrategy = require('passport-google-oauth20').Strategy;
``` ```
### Configure the Google strategy for use by Passport.js ### Configure the Google strategy for use by Passport.js
OAuth 2-based strategies require a `verify` function which receives the credential (`accessToken`) for accessing the Google API on the user's behalf, along with the user's profile. The function must invoke `cb` with a user object, which will be set at `req.user` in route handlers after authentication. OAuth 2-based strategies require a `verify` function which receives the credential (`accessToken`) for accessing the Google API on the user's behalf, along with the user's profile. The function must invoke `cb` with a user object, which will be set at `req.user` in route handlers after authentication.
```js ```js
const GOOGLE_CLIENT_ID = '...'; const GOOGLE_CLIENT_ID = '...';
const GOOGLE_CLIENT_SECRET = '...'; const GOOGLE_CLIENT_SECRET = '...';
const GOOGLE_CALLBACK_URL = 'http://localhost:4242/api/auth/callback'; const GOOGLE_CALLBACK_URL = 'http://localhost:4242/api/auth/callback';
passport.use(new GoogleStrategy( passport.use(
new GoogleStrategy(
{ {
clientID: GOOGLE_CLIENT_ID, clientID: GOOGLE_CLIENT_ID,
clientSecret: GOOGLE_CLIENT_SECRET, clientSecret: GOOGLE_CLIENT_SECRET,
callbackURL: GOOGLE_CALLBACK_URL callbackURL: GOOGLE_CALLBACK_URL,
}, },
function(accessToken, refreshToken, profile, cb) { function(accessToken, refreshToken, profile, cb) {
// Extract the minimal profile information we need from the profile object // Extract the minimal profile information we need from the profile object
// and connect with Unleash to get name and email. // and connect with Unleash to get name and email.
cb(null, new unleash.User({ cb(
null,
new unleash.User({
name: profile.displayName, name: profile.displayName,
email: profile.emails[0].value, email: profile.emails[0].value,
})); }),
} );
)); },
),
);
``` ```
Add `googleAdminAuth()` function and other options Add `googleAdminAuth()` function and other options
```js ```js
function googleAdminAuth(app) {} function googleAdminAuth(app) {}
let options = { let options = {
enableLegacyRoutes: false, enableLegacyRoutes: false,
adminAuthentication: 'custom', adminAuthentication: 'custom',
preRouterHook: googleAdminAuth preRouterHook: googleAdminAuth,
}; };
unleash.start(options).then(unleash => { unleash.start(options).then(unleash => {
console.log(`Unleash started on http://localhost:${unleash.app.get('port')}`); console.log(`Unleash started on http://localhost:${unleash.app.get('port')}`);
});; });
``` ```
### In `googleAdminAuth` function ### In `googleAdminAuth` function
Configure `passport` package. Configure `passport` package.
```js ```js
function googleAdminAuth(app) { function googleAdminAuth(app) {
app.use(passport.initialize()); app.use(passport.initialize());
@ -102,32 +113,39 @@ function googleAdminAuth(app) {
``` ```
Implement a preRouter hook for `/api/admin/login`. It's neccesary for login with Google. Implement a preRouter hook for `/api/admin/login`. It's neccesary for login with Google.
```js ```js
function googleAdminAuth(app) { function googleAdminAuth(app) {
// ... // ...
app.get('/api/admin/login', passport.authenticate('google', { scope: ['profile', 'email'] })); app.get(
'/api/admin/login',
passport.authenticate('google', { scope: ['profile', 'email'] }),
);
// ... // ...
} }
``` ```
Implement a preRouter hook for `/api/auth/callback`. It's a callback when the login is executed. Implement a preRouter hook for `/api/auth/callback`. It's a callback when the login is executed.
```js ```js
function googleAdminAuth(app) { function googleAdminAuth(app) {
// ... // ...
app.get('/api/auth/callback', app.get(
'/api/auth/callback',
passport.authenticate('google', { passport.authenticate('google', {
failureRedirect: '/api/admin/error-login', failureRedirect: '/api/admin/error-login',
}), }),
(req, res) => { (req, res) => {
// Successful authentication, redirect to your app. // Successful authentication, redirect to your app.
res.redirect('/'); res.redirect('/');
} },
); );
// ... // ...
} }
``` ```
Implement a preRouter hook for `/api/admin`. Implement a preRouter hook for `/api/admin`.
```js ```js
function googleAdminAuth(app) { function googleAdminAuth(app) {
// ... // ...
@ -143,8 +161,9 @@ function googleAdminAuth(app) {
path: '/api/admin/login', path: '/api/admin/login',
type: 'custom', type: 'custom',
message: `You have to identify yourself in order to use Unleash. Click the button and follow the instructions.`, message: `You have to identify yourself in order to use Unleash. Click the button and follow the instructions.`,
}) }),
).end(); )
.end();
} }
}); });
// ... // ...
@ -152,7 +171,9 @@ function googleAdminAuth(app) {
``` ```
### The complete code ### The complete code
The `index.js` server file. The `index.js` server file.
```js ```js
'use strict'; 'use strict';
@ -164,19 +185,24 @@ const GOOGLE_CLIENT_ID = '...';
const GOOGLE_CLIENT_SECRET = '...'; const GOOGLE_CLIENT_SECRET = '...';
const GOOGLE_CALLBACK_URL = 'http://localhost:4242/api/auth/callback'; const GOOGLE_CALLBACK_URL = 'http://localhost:4242/api/auth/callback';
passport.use(new GoogleStrategy( passport.use(
new GoogleStrategy(
{ {
clientID: GOOGLE_CLIENT_ID, clientID: GOOGLE_CLIENT_ID,
clientSecret: GOOGLE_CLIENT_SECRET, clientSecret: GOOGLE_CLIENT_SECRET,
callbackURL: GOOGLE_CALLBACK_URL callbackURL: GOOGLE_CALLBACK_URL,
}, },
function(accessToken, refreshToken, profile, cb) { function(accessToken, refreshToken, profile, cb) {
cb(null, new unleash.User({ cb(
null,
new unleash.User({
name: profile.displayName, name: profile.displayName,
email: profile.emails[0].value, email: profile.emails[0].value,
})); }),
} );
)); },
),
);
function googleAdminAuth(app) { function googleAdminAuth(app) {
app.use(passport.initialize()); app.use(passport.initialize());
@ -184,14 +210,18 @@ function googleAdminAuth(app) {
passport.serializeUser((user, done) => done(null, user)); passport.serializeUser((user, done) => done(null, user));
passport.deserializeUser((user, done) => done(null, user)); passport.deserializeUser((user, done) => done(null, user));
app.get('/api/admin/login', passport.authenticate('google', { scope: ['profile', 'email'] })); app.get(
app.get('/api/auth/callback', '/api/admin/login',
passport.authenticate('google', { scope: ['profile', 'email'] }),
);
app.get(
'/api/auth/callback',
passport.authenticate('google', { passport.authenticate('google', {
failureRedirect: '/api/admin/error-login', failureRedirect: '/api/admin/error-login',
}), }),
(req, res) => { (req, res) => {
res.redirect('/'); res.redirect('/');
} },
); );
app.use('/api/admin/', (req, res, next) => { app.use('/api/admin/', (req, res, next) => {
@ -205,8 +235,9 @@ function googleAdminAuth(app) {
path: '/api/admin/login', path: '/api/admin/login',
type: 'custom', type: 'custom',
message: `You have to identify yourself in order to use Unleash. Click the button and follow the instructions.`, message: `You have to identify yourself in order to use Unleash. Click the button and follow the instructions.`,
}) }),
).end(); )
.end();
} }
}); });
} }
@ -214,7 +245,7 @@ function googleAdminAuth(app) {
let options = { let options = {
enableLegacyRoutes: false, enableLegacyRoutes: false,
adminAuthentication: 'custom', adminAuthentication: 'custom',
preRouterHook: googleAdminAuth preRouterHook: googleAdminAuth,
}; };
if (process.env.DATABASE_URL_FILE) { if (process.env.DATABASE_URL_FILE) {
@ -223,5 +254,5 @@ if (process.env.DATABASE_URL_FILE) {
unleash.start(options).then(unleash => { unleash.start(options).then(unleash => {
console.log(`Unleash started on http://localhost:${unleash.app.get('port')}`); console.log(`Unleash started on http://localhost:${unleash.app.get('port')}`);
});; });
``` ```

View File

@ -5,8 +5,8 @@ title: Migration Guide
Generally the intention is that `unleash-server` should always provide support for clients one lower major version. This should make possible to upgrade `unleash` gradually. Generally the intention is that `unleash-server` should always provide support for clients one lower major version. This should make possible to upgrade `unleash` gradually.
## Upgrading from v2.x to v3.x ## Upgrading from v2.x to v3.x
The notable change introduced in Unleash v3.x is a strict separation of api paths for client requests and admin requests. This makes it easier to implement different authentication mechanisms for the admin UI and all unleash-clients. You can read more about [securing unleash](https://github.com/Unleash/unleash/blob/master/docs/securing-unleash.md). The notable change introduced in Unleash v3.x is a strict separation of api paths for client requests and admin requests. This makes it easier to implement different authentication mechanisms for the admin UI and all unleash-clients. You can read more about [securing unleash](https://github.com/Unleash/unleash/blob/master/docs/securing-unleash.md).
The recommended approach is to first upgrade the `unleash-server` to v3 (which still supports v2 clients). After this is done you should upgrade all your clients to v3. The recommended approach is to first upgrade the `unleash-server` to v3 (which still supports v2 clients). After this is done you should upgrade all your clients to v3.
@ -16,16 +16,18 @@ After upgrading all your clients you should consider turning off legacy routes,
## Upgrading from v1.0 to v2.0 ## Upgrading from v1.0 to v2.0
### Caveat 1: Not used db-migrate to migrate the unleash database? ### Caveat 1: Not used db-migrate to migrate the unleash database?
In FINN we used, for internal reasons, liquebase to migrate our database. In FINN we used, for internal reasons, liquebase to migrate our database.
Because unleash from version 2.0 migrates the database internally, with db-migrate, Because unleash from version 2.0 migrates the database internally, with db-migrate, you need to make sure that all previous migrations for version 1 exists, so unleash does not try to create tables that already exists.
you need to make sure that all previous migrations for version 1 exists, so unleash
does not try to create tables that already exists.
#### How to check? #### How to check?
If you don't have a "migrations" table with _7 unique migrations_ you are affected by this. If you don't have a "migrations" table with _7 unique migrations_ you are affected by this.
#### How to fix? #### How to fix?
Before starting unleash version 2 you have to run the SQL located under `scripts/fix-migrations-version-1.sql` Before starting unleash version 2 you have to run the SQL located under `scripts/fix-migrations-version-1.sql`
### Caveat 2: databaseUrl (not database*Uri*) ### Caveat 2: databaseUrl (not database*Uri*)
Using unleash as a lib and injecting your own config? Then you should know that we changed the databaseUri config param name to **databaseUrl**. This to align it with the environment variable (DATABASE_URL), avoiding multiple names for same config param. Using unleash as a lib and injecting your own config? Then you should know that we changed the databaseUri config param name to **databaseUrl**. This to align it with the environment variable (DATABASE_URL), avoiding multiple names for same config param.

View File

@ -3,31 +3,35 @@ id: securing_unleash
title: Securing Unleash title: Securing Unleash
--- ---
The Unleash API is split in two different paths: `/api/client` and `/api/admin`. The Unleash API is split in two different paths: `/api/client` and `/api/admin`. This makes it easy to have different authentication strategy for the admin interface and the client-api used by the applications integrating with Unleash.
This makes it easy to have different authentication strategy for the admin interface and the client-api used by the applications integrating with Unleash.
## General settings ## General settings
Unleash uses an encrypted cookie to maintain a user session. This allows users to be logged in across instances of Unleash. To protect this cookie you should specify the `secret` option when starting unleash.- Unleash uses an encrypted cookie to maintain a user session. This allows users to be logged in across instances of Unleash. To protect this cookie you should specify the `secret` option when starting unleash.-
## Securing the Admin API ## Securing the Admin API
In order to secure the Admin API you have to tell Unleash that you are using a custom admin authentication and implement your authentication logic as a preHook. You should also set the secret option to a protected secret in your system. In order to secure the Admin API you have to tell Unleash that you are using a custom admin authentication and implement your authentication logic as a preHook. You should also set the secret option to a protected secret in your system.
```javascript ```javascript
const unleash = require('unleash-server'); const unleash = require('unleash-server');
const myCustomAdminAuth = require('./auth-hook'); const myCustomAdminAuth = require('./auth-hook');
unleash.start({ unleash
.start({
databaseUrl: 'postgres://unleash_user:passord@localhost:5432/unleash', databaseUrl: 'postgres://unleash_user:passord@localhost:5432/unleash',
secret: 'super-duper-secret', secret: 'super-duper-secret',
adminAuthentication: 'custom', adminAuthentication: 'custom',
preRouterHook: myCustomAdminAuth preRouterHook: myCustomAdminAuth,
}).then(unleash => { })
console.log(`Unleash started on http://localhost:${unleash.app.get('port')}`); .then(unleash => {
}); console.log(
`Unleash started on http://localhost:${unleash.app.get('port')}`,
);
});
``` ```
Additionally, you can trigger the admin interface to prompt the user to sign in by configuring your middleware to return a `401` status on Additionally, you can trigger the admin interface to prompt the user to sign in by configuring your middleware to return a `401` status on protected routes. The response body must contain a `message` and a `path` used to redirect the user to the proper login route.
protected routes. The response body must contain a `message` and a `path` used to redirect the user to the proper login route.
```json ```json
{ {
@ -37,13 +41,14 @@ protected routes. The response body must contain a `message` and a `path` used t
``` ```
Examples on custom authentication hooks: Examples on custom authentication hooks:
- [google-auth-hook.js](https://github.com/Unleash/unleash/blob/master/examples/google-auth-hook.js) - [google-auth-hook.js](https://github.com/Unleash/unleash/blob/master/examples/google-auth-hook.js)
- [basic-auth-hook.js](https://github.com/Unleash/unleash/blob/master/examples/basic-auth-hook.js) - [basic-auth-hook.js](https://github.com/Unleash/unleash/blob/master/examples/basic-auth-hook.js)
We also have a version of Unleash deployed on Heroku which uses Google OAuth 2.0: We also have a version of Unleash deployed on Heroku which uses Google OAuth 2.0: https://secure-unleash.herokuapp.com
https://secure-unleash.herokuapp.com
## Securing the Client API ## Securing the Client API
A common way to support client access is to use pre shared secrets. This can be solved by having clients send a shared key in a http header with every client request to the Unleash API. All official Unleash clients should support this. A common way to support client access is to use pre shared secrets. This can be solved by having clients send a shared key in a http header with every client request to the Unleash API. All official Unleash clients should support this.
In the [Java client](https://github.com/Unleash/unleash-client-java#custom-http-headers) this looks like: In the [Java client](https://github.com/Unleash/unleash-client-java#custom-http-headers) this looks like:
@ -63,7 +68,8 @@ On the unleash server side you need to implement a preRouter hook which verifies
const unleash = require('unleash-server'); const unleash = require('unleash-server');
const sharedSecret = '12312Random'; const sharedSecret = '12312Random';
unleash.start({ unleash
.start({
databaseUrl: 'postgres://unleash_user:passord@localhost:5432/unleash', databaseUrl: 'postgres://unleash_user:passord@localhost:5432/unleash',
enableLegacyRoutes: false, enableLegacyRoutes: false,
preRouterHook: app => { preRouterHook: app => {
@ -74,13 +80,15 @@ unleash.start({
next(); next();
} }
}); });
} },
}).then(unleash => { })
console.log(`Unleash started on http://localhost:${unleash.app.get('port')}`); .then(unleash => {
}); console.log(
`Unleash started on http://localhost:${unleash.app.get('port')}`,
);
});
``` ```
[client-auth-unleash.js](https://github.com/Unleash/unleash/blob/master/examples/client-auth-unleash.js) [client-auth-unleash.js](https://github.com/Unleash/unleash/blob/master/examples/client-auth-unleash.js)
PS! Remember to disable legacy route by setting the `enableLegacyRoutes` option to false. This will require all your clients to be on v3.x. PS! Remember to disable legacy route by setting the `enableLegacyRoutes` option to false. This will require all your clients to be on v3.x.

View File

@ -3,10 +3,7 @@ id: unleash_context
title: Unleash Context title: Unleash Context
--- ---
In order to standardise a few activation strategies we also needed to standardise a unleash context, which contains some fields that varies per requests, needed to implement the activation strategies.
In order to standardise a few activation strategies we also needed to
standardise a unleash context, which contains some fields that varies
per requests, needed to implement the activation strategies.
The unleash context is defined by these fields: The unleash context is defined by these fields:
@ -15,12 +12,8 @@ The unleash context is defined by these fields:
- remoteAddress: String, - remoteAddress: String,
- properties: Map<String, String> - properties: Map<String, String>
All fields are optional, but if they are not set you will not be able to use All fields are optional, but if they are not set you will not be able to use certain activation strategies.
certain activation strategies.
E.g. the userWithId-strategy obviously depends on the userId field. E.g. the userWithId-strategy obviously depends on the userId field.
The properties field is more generic and can be used to provide more abritary The properties field is more generic and can be used to provide more abritary data to the strategies. A common usage is to add more metadata, e.g. that the current user is a beta user, and thus the betaUser-strategy will use this info in its implementation.
data to the strategies. A common usage is to add more metadata, e.g. that the
current user is a beta user, and thus the betaUser-strategy will use this info
in its implementation.

View File

@ -7,71 +7,85 @@
{ {
"name": "userWithId", "name": "userWithId",
"description": "Active for users with a userId defined in the userIds-list", "description": "Active for users with a userId defined in the userIds-list",
"parameters": [{ "parameters": [
{
"name": "userIds", "name": "userIds",
"type": "list", "type": "list",
"description": "", "description": "",
"required": false "required": false
}] }
]
}, },
{ {
"name": "applicationHostname", "name": "applicationHostname",
"description": "Active for client instances with a hostName in the hostNames-list.", "description": "Active for client instances with a hostName in the hostNames-list.",
"parameters": [{ "parameters": [
{
"name": "hostNames", "name": "hostNames",
"type": "list", "type": "list",
"description": "List of hostnames to enable the feature toggle for.", "description": "List of hostnames to enable the feature toggle for.",
"required": false "required": false
}] }
]
}, },
{ {
"name": "gradualRolloutRandom", "name": "gradualRolloutRandom",
"description": "Randomly activate the feature toggle. No stickiness.", "description": "Randomly activate the feature toggle. No stickiness.",
"parameters": [{ "parameters": [
{
"name": "percentage", "name": "percentage",
"type": "percentage", "type": "percentage",
"description": "", "description": "",
"required": false "required": false
}] }
]
}, },
{ {
"name": "gradualRolloutSessionId", "name": "gradualRolloutSessionId",
"description": "Gradually activate feature toggle. Stickiness based on session id.", "description": "Gradually activate feature toggle. Stickiness based on session id.",
"parameters": [{ "parameters": [
{
"name": "percentage", "name": "percentage",
"type": "percentage", "type": "percentage",
"description": "", "description": "",
"required": false "required": false
},{ },
{
"name": "groupId", "name": "groupId",
"type": "string", "type": "string",
"description": "Used to define a activation groups, which allows you to correlate across feature toggles.", "description": "Used to define a activation groups, which allows you to correlate across feature toggles.",
"required": true "required": true
}] }
]
}, },
{ {
"name": "gradualRolloutUserId", "name": "gradualRolloutUserId",
"description": "Gradually activate feature toggle for logged in users. Stickiness based on user id.", "description": "Gradually activate feature toggle for logged in users. Stickiness based on user id.",
"parameters": [{ "parameters": [
{
"name": "percentage", "name": "percentage",
"type": "percentage", "type": "percentage",
"description": "", "description": "",
"required": false "required": false
},{ },
{
"name": "groupId", "name": "groupId",
"type": "string", "type": "string",
"description": "Used to define a activation groups, which allows you to correlate across feature toggles.", "description": "Used to define a activation groups, which allows you to correlate across feature toggles.",
"required": true "required": true
}] }
]
}, },
{ {
"name": "remoteAddress", "name": "remoteAddress",
"description": "Active for remote addresses defined in the IPs list.", "description": "Active for remote addresses defined in the IPs list.",
"parameters": [{ "parameters": [
{
"name": "IPs", "name": "IPs",
"type": "list", "type": "list",
"description": "List of IPs to enable the feature toggle for.", "description": "List of IPs to enable the feature toggle for.",
"required": true "required": true
}] }
]
} }
] ]

View File

@ -8,10 +8,12 @@
{ {
"name": "usersWithEmail", "name": "usersWithEmail",
"description": "Active for users defined in the comma-separated emails-parameter.", "description": "Active for users defined in the comma-separated emails-parameter.",
"parameters": [{ "parameters": [
{
"name": "emails", "name": "emails",
"type": "string" "type": "string"
}] }
]
} }
], ],
"applications": [ "applications": [
@ -21,9 +23,7 @@
}, },
{ {
"appName": "demo-app-2", "appName": "demo-app-2",
"strategies": ["default", "strategies": ["default", "extra"],
"extra"
],
"description": "hello" "description": "hello"
} }
], ],
@ -48,66 +48,78 @@
"name": "featureX", "name": "featureX",
"description": "the #1 feature", "description": "the #1 feature",
"enabled": true, "enabled": true,
"strategies": [{ "strategies": [
{
"name": "default", "name": "default",
"parameters": {} "parameters": {}
}] }
]
}, },
{ {
"name": "featureY", "name": "featureY",
"description": "soon to be the #1 feature", "description": "soon to be the #1 feature",
"enabled": false, "enabled": false,
"strategies": [{ "strategies": [
{
"name": "baz", "name": "baz",
"parameters": { "parameters": {
"foo": "bar" "foo": "bar"
} }
}] }
]
}, },
{ {
"name": "featureZ", "name": "featureZ",
"description": "terrible feature", "description": "terrible feature",
"enabled": true, "enabled": true,
"strategies": [{ "strategies": [
{
"name": "baz", "name": "baz",
"parameters": { "parameters": {
"foo": "rab" "foo": "rab"
} }
}] }
]
}, },
{ {
"name": "featureArchivedX", "name": "featureArchivedX",
"description": "the #1 feature", "description": "the #1 feature",
"enabled": true, "enabled": true,
"archived": true, "archived": true,
"strategies": [{ "strategies": [
{
"name": "default", "name": "default",
"parameters": {} "parameters": {}
}] }
]
}, },
{ {
"name": "featureArchivedY", "name": "featureArchivedY",
"description": "soon to be the #1 feature", "description": "soon to be the #1 feature",
"enabled": false, "enabled": false,
"archived": true, "archived": true,
"strategies": [{ "strategies": [
{
"name": "baz", "name": "baz",
"parameters": { "parameters": {
"foo": "bar" "foo": "bar"
} }
}] }
]
}, },
{ {
"name": "featureArchivedZ", "name": "featureArchivedZ",
"description": "terrible feature", "description": "terrible feature",
"enabled": true, "enabled": true,
"archived": true, "archived": true,
"strategies": [{ "strategies": [
{
"name": "baz", "name": "baz",
"parameters": { "parameters": {
"foo": "rab" "foo": "rab"
} }
}] }
]
} }
] ]
} }

View File

@ -4,11 +4,11 @@ It's hosted on https://unleash.github.io/
# What's In This Document # What's In This Document
* [Get Started in 5 Minutes](#get-started-in-5-minutes) - [Get Started in 5 Minutes](#get-started-in-5-minutes)
* [Directory Structure](#directory-structure) - [Directory Structure](#directory-structure)
* [Editing Content](#editing-content) - [Editing Content](#editing-content)
* [Adding Content](#adding-content) - [Adding Content](#adding-content)
* [Full Documentation](#full-documentation) - [Full Documentation](#full-documentation)
# Get Started in 5 Minutes # Get Started in 5 Minutes
@ -18,6 +18,7 @@ It's hosted on https://unleash.github.io/
# Install dependencies # Install dependencies
$ npm install $ npm install
``` ```
2. Run your dev server: 2. Run your dev server:
```sh ```sh
@ -103,6 +104,7 @@ For more information about adding new docs, click [here](https://docusaurus.io/d
1. Add links to docs, custom pages or external links by editing the headerLinks field of `website/siteConfig.js`: 1. Add links to docs, custom pages or external links by editing the headerLinks field of `website/siteConfig.js`:
`website/siteConfig.js` `website/siteConfig.js`
```javascript ```javascript
{ {
headerLinks: [ headerLinks: [
@ -127,6 +129,7 @@ For more information about the navigation bar, click [here](https://docusaurus.i
1. If you want your page to show up in your navigation header, you will need to update `website/siteConfig.js` to add to the `headerLinks` element: 1. If you want your page to show up in your navigation header, you will need to update `website/siteConfig.js` to add to the `headerLinks` element:
`website/siteConfig.js` `website/siteConfig.js`
```javascript ```javascript
{ {
headerLinks: [ headerLinks: [

View File

@ -1,13 +1,37 @@
{ {
"documentation": { "documentation": {
<<<<<<< HEAD
"User documentation": ["getting_started", "client_sdk", "securing_unleash", "unleash_context", "activation_strategy", "client_specification", "migration_guide"], "User documentation": ["getting_started", "client_sdk", "securing_unleash", "unleash_context", "activation_strategy", "client_specification", "migration_guide"],
"Developer Guide": ["developer_guide", "database_schema", "database_backup"], "Developer Guide": ["developer_guide", "database_schema", "database_backup"],
=======
"Getting Started": [
"getting_started",
"securing_unleash",
"unleash_context",
"activation_strategy",
"client_specification",
"migration_guide"
],
"Developer Guide": [
"developer_guide",
"database_schema",
"database_backup"
],
>>>>>>> chore: Fix formatting all the things
"Guides": ["guides/google_auth"] "Guides": ["guides/google_auth"]
}, },
"api": { "api": {
"Client": ["api/client/features", "api/client/register", "api/client/metrics"], "Client": [
"Admin": ["api/admin/features", "api/admin/strategies", "api/admin/metrics", "api/admin/events" ], "api/client/features",
"Internal": ["api/internal" ] "api/client/register",
"api/client/metrics"
],
"Admin": [
"api/admin/features",
"api/admin/strategies",
"api/admin/metrics",
"api/admin/events"
],
"Internal": ["api/internal"]
} }
} }