Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Github CI #1

Merged
merged 42 commits into from Feb 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
26f358c
initial travis setup
nhoening Jan 28, 2021
e013bae
initial lint and test CI action
nhoening Jan 28, 2021
da76c05
update CI: no bb pipeline, small fixes, add travis badge
nhoening Jan 28, 2021
5d52e09
insist on Python3
nhoening Jan 28, 2021
4cef298
action yml syntax
nhoening Jan 28, 2021
8e8a5c0
action yml syntax
nhoening Jan 28, 2021
4fd9e5d
action yml syntax: python version
nhoening Jan 28, 2021
ea5d2f8
action yml syntax
nhoening Jan 28, 2021
94753f9
simple action
nhoening Jan 28, 2021
13258d9
pre-commit w/o fixed version
nhoening Jan 28, 2021
21d6879
do 3.8 first
nhoening Jan 28, 2021
b30d8d4
single python version for now
nhoening Jan 28, 2021
d3e137d
secret key
nhoening Jan 28, 2021
3fc51c3
pg host 127.0.0.1
nhoening Jan 28, 2021
53bc6de
pg port
nhoening Jan 29, 2021
3bf2221
add pg extensions to test
nhoening Jan 29, 2021
da5780f
alternative for usig pg extensions
nhoening Jan 29, 2021
e7f6526
container is localhost
nhoening Jan 29, 2021
15fe264
container is localhost
nhoening Jan 29, 2021
d782f2c
involve SETUP.sh again
nhoening Jan 29, 2021
f227163
remove job name
nhoening Jan 29, 2021
e31d7ba
postgres container available through 127.0.0.1
nhoening Jan 29, 2021
dc9b948
PGPASSWORD
nhoening Jan 29, 2021
964281a
improve Cbc documentation
nhoening Jan 30, 2021
d27ca5e
install Cbc with sudo
nhoening Jan 30, 2021
1d8265f
clean up; split check from test & add deploy
nhoening Jan 30, 2021
b1f35e5
fix syntax error
nhoening Jan 30, 2021
69ab804
we need to checkout before we can deploy
nhoening Jan 30, 2021
25d1a28
establish deploy workflow
nhoening Feb 1, 2021
62c6f7f
exact job name
nhoening Feb 1, 2021
cc892b9
try running-workflow-name
nhoening Feb 1, 2021
bac7174
use the github ref instead of hardcoding
nhoening Feb 1, 2021
8ec3fd5
use the correct workflow name
nhoening Feb 1, 2021
8edd693
install SSH key and configure remote REPO in env
nhoening Feb 1, 2021
bf1beab
known deployment hosts
nhoening Feb 1, 2021
0659014
try standard key name
nhoening Feb 1, 2021
fb249f4
begin work on ci/README
nhoening Feb 1, 2021
87af229
only deploy to staging when pushes hit on main
nhoening Feb 2, 2021
4ca843c
add/update badges
nhoening Feb 2, 2021
37de689
better details on CI deployment procedure
nhoening Feb 2, 2021
d08676c
no need for Travis actually
nhoening Feb 2, 2021
729c859
small fixes after review
nhoening Feb 3, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
33 changes: 33 additions & 0 deletions .github/workflows/deploy.yml
@@ -0,0 +1,33 @@
name: deploy-to-staging

on:
push:
branches:
- main

jobs:
deploy:
name: "Deploy (main to staging)"
runs-on: ubuntu-latest
steps:
- name: Wait for tests to pass
uses: lewagon/wait-on-check-action@v0.2
with:
ref: ${{ github.ref }}
# check-name: "Test (on Python3.8)" # name of the job we wait for (omit to wait for all checks)
running-workflow-name: "Deploy (main to staging)" # name of the check that will wait for other checks
repo-token: ${{ secrets.GITHUB_TOKEN }}
wait-interval: 20 # seconds
- uses: actions/checkout@v2
with:
fetch-depth: '0'
ref: 'main'
- name: Install SSH key
uses: shimataro/ssh-key-action@v2
with:
key: ${{ secrets.SSH_DEPLOYMENT_KEY }} # private ssh key
known_hosts: ${{ secrets.KNOWN_DEPLOYMENT_HOSTS }} # make via ssh-keyscan -t rsa <your host>
- run: ci/DEPLOY.sh
env:
BRANCH_NAME: main
STAGING_REMOTE_REPO: ${{ secrets.STAGING_REMOTE_REPO }}
50 changes: 50 additions & 0 deletions .github/workflows/lint-and-test.yml
@@ -0,0 +1,50 @@
name: lint-and-test

on: push


jobs:
check:
runs-on: ubuntu-latest
name: Check (on Python3.8)
steps:
- uses: actions/setup-python@v2
with:
python-version: 3.8
- uses: actions/checkout@v2
- uses: pre-commit/action@v2.0.0

test:
needs: check
runs-on: ubuntu-latest
#strategy: # TODO: make work with pre-commit
# matrix:
# python-version: [ '3.8', '3.6' ]
name: "Test (on Python3.8)"
steps:
- uses: actions/setup-python@v2
with:
python-version: 3.8
- uses: actions/checkout@v2
- run: ci/SETUP.sh
- run: make test
env:
PGHOST: 127.0.0.1
PGPORT: 5432
PGUSER: flexmeasures_test
PGDB: flexmeasures_test
PGPASSWORD: flexmeasures_test

services:
# Label used to access the service container
postgres:
# Docker Hub image
image: postgres:12.5
env:
POSTGRES_USER: flexmeasures_test
POSTGRES_PASSWORD: flexmeasures_test
POSTGRES_DB: flexmeasures_test
ports:
- 5432:5432
# needed because the postgres container does not provide a healthcheck
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
12 changes: 6 additions & 6 deletions Makefile
Expand Up @@ -15,41 +15,41 @@ test:
# ---- Documentation ---

update-docs:
pip install sphinx sphinxcontrib.httpdomain
pip3 install sphinx sphinxcontrib.httpdomain
cd documentation; make clean; make html; cd ..

update-docs-pdf:
@echo "NOTE: PDF documentation requires packages (on Debian: latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended)"
@echo "NOTE: Currently, the docs require some pictures which are not in the git repo atm. Ask the devs."
pip install sphinx sphinxcontrib.httpdomain
pip3 install sphinx sphinxcontrib.httpdomain
cd documentation; make clean; make latexpdf; make latexpdf; cd .. # make latexpdf can require two passes

# ---- Installation ---

install: install-deps install-flexmeasures

install-for-dev:
pip install -q pip-tools
pip3 install -q pip-tools
make freeze-deps
pip-sync requirements/app.txt requirements/dev.txt requirements/test.txt
make install-flexmeasures

install-deps:
pip install -q pip-tools
pip3 install -q pip-tools
make freeze-deps
pip-sync requirements/app.txt

install-flexmeasures:
python setup.py develop

freeze-deps:
pip install -q pip-tools
pip3 install -q pip-tools
pip-compile -o requirements/app.txt requirements/app.in
pip-compile -o requirements/dev.txt requirements/dev.in
pip-compile -o requirements/test.txt requirements/test.in

upgrade-deps:
pip install -q pip-tools
pip3 install -q pip-tools
pip-compile --upgrade -o requirements/app.txt requirements/app.in
pip-compile --upgrade -o requirements/dev.txt requirements/dev.in
pip-compile --upgrade -o requirements/test.txt requirements/test.in
Expand Down
9 changes: 8 additions & 1 deletion Readme.md
@@ -1,7 +1,14 @@
# The FlexMeasures Platform

![lint-and-test](https://github.com/SeitaBV/flexmeasures/workflows/lint-and-test/badge.svg)
[![](https://img.shields.io/badge/python-3.6+-blue.svg)](https://www.python.org/downloads/)
nhoening marked this conversation as resolved.
Show resolved Hide resolved
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)

The *FlexMeasures Platform* is a tool for scheduling flexible actions for energy assets.
For this purpose, it performs monitoring, forecastig and scheduling services.
For this purpose, it performs monitoring, forecasting and scheduling services.

Its role is to enhance energy services. Forecasts and schedules are made available via API.


## Build & Run

Expand Down
45 changes: 0 additions & 45 deletions bitbucket-pipelines.yml

This file was deleted.

2 changes: 1 addition & 1 deletion ci/DEPLOY.sh
Expand Up @@ -7,4 +7,4 @@
git remote add staging $STAGING_REMOTE_REPO

# Push the branch being deployed to the git remote. Also push any annotated tags (with a -m message).
git push --follow-tags --set-upstream staging $BITBUCKET_BRANCH
git push --follow-tags --set-upstream staging $BRANCH_NAME
71 changes: 47 additions & 24 deletions ci/README.md
Expand Up @@ -2,7 +2,7 @@

Here you can learn how to get FlexMeasures onto a server.

We talk about serving FlexMeasures in a WSGI setting and deploying on a server via git.
We talk about serving FlexMeasures in a WSGI setting, installing the linear solver and deploying on a (staging) server via git.

TODO: Dockerization

Expand All @@ -14,8 +14,7 @@ Here is an example how to serve this application as WSGI app:

# This file contains the WSGI configuration required to serve up your
# web application.
# It works by setting the variable 'application' to a WSGI handler of some
# description.
# It works by setting the variable 'application' to a WSGI handler of some description.

import sys
import os
Expand All @@ -35,47 +34,71 @@ Here is an example how to serve this application as WSGI app:

## Install the linear solver on the server

To compute schedules, we use a linear optimization solver.
The Cbc solver has to be installed from source, on the server where FlexMeasures runs.
To compute schedules, FlexMeasures uses the [Cbc](https://github.com/coin-or/Cbc) mixed integer linear optimization solver.
It is used through [Pyomo](http://www.pyomo.org), so in principle supporting a [different solver](https://pyomo.readthedocs.io/en/stable/solving_pyomo_models.html#supported-solvers) would be possible.

Cbc needs to be present on the server where FlexMeasures runs, under the `cbc` command.

You can install it on Debian like this:

apt-get install coinor-cbc

If you can't use the package manager on your host, the solver has to be installed from source.
We provide [an example script](ci/install-cbc.sh) to do that, where you can also
pass a directory for the installation.

In case you want to install a later version, adapt the version in the script.


## Automate deployment via Bitbucket Pipelines
nhoening marked this conversation as resolved.
Show resolved Hide resolved
## Automate deployment via Github actions

Github action workflows are in the `.github/workflows` directory. We use them to build and deploy the project to our staging server.

Documenting this might be useful for self-hosters, as well.
The GitHub Actions workflows are triggered by commits being pushed to the repository, but it can also inspire your custom deployment script.

The Bitbucket Pipeline is configured with the `bitbucket-pipelines.yml` file.
It reacts to commits being made to the repository, but it can also inspire your custom deployment script.
In this file we set up the app, run the tests and linters, and if the commit was on the master branch,
we finish with deploying the code to a staging server (see below).
We'll refer to Github Actions as our "CI environment" and our staging server as the "deployment server".

- In `lint-and-test.yml`, we set up the app, then run the tests and linters.
If testing succeeds and if the commit was on the `main` branch, `deploy.yml` deploys the code from the CI environment to the deployment server.

## Deployment on the server via Git
- Of course, the CI environment needs to properly authenticate at the deployment server.

- With the hooks functionality of Git, a post-receive script can then (re-)start the FlexMeasures app on the deployment server.

Let's review these three steps in detail:

### Using git to deploy code (remote upstream)

We support deployment of the FlexMeasures project on a staging server via Git checkout.

The deployment uses git's ability to push code to a remote upstream repository.
We trigger this deployment in `bitbucket-pipelines.yml` (see above)
With the hooks functionality of Git, a post-receive script can then (re)start the FlexMeasures app.
The deployment uses git's ability to push code to a remote upstream repository. This repository needs to be installed on your staging server.

We trigger this deployment in `deploy.yml` and it's being done in `DEPLOY.sh`. There, we add the remote and then push the current branch to it.

We thus need to tell the deployment evnironment two things:

- Add the setting `STAGING_REMOTE_REPO` as an environment variable on the deployment environment (e.g. `deploy.yml` expects it in the Github repository secrets). An example value is `seita@ssh.our-server.com:/home/seita/flexmeasures-staging/flexmeasures.git`.
- Make sure the env variable `BRANCH_NAME` is set, e.g. to "main", so that the deployment environment knows what exact code to push to your deployment server.

### Remote origin
### Authenticate at the deployment server (with an ssh key)

To see how a remote repo is added, see `DEPLOY.sh`. There, we add the remote and also push the current branch there.
The CI environment needs to authenticate at the deployment server using an SSH key pair (use `ssh-keygen` to create one, using no password).

To make this work, we need three things:
To make this work, we need to configure the following:

- Make sure the remote git repo exists (is cloned)
- Add the setting `STAGING_REMOTE_REPO` to the deployment environment (e.g. Bitbucket pipelines). An example value is `seita@ssh.our-server.com:/home/seita/flexmeasures-staging/flexmeasures.git`.
- Set up an SSH key for deployment in the deployment environment, so that the server accepts the code.
- Add the deployment server to `~/.ssh/known_hosts` of the deployment environment, so that the deployment environment knows it's okay to talk to the deployment server (e.g. `deploy.yml` expects it in the Github repository secrets as `KNOWN_DEPLOYMENT_HOSTS`). You can create this entry with `ssh-keyscan -t rsa <your host>`.
- Add the private part of the ssh key pair as key in the deployment environment, so that the deployment server can accept the pushed code. (e.g. as `~/.ssh/id_rsa`). In `deploy.yml`, we expect it as the secret `SSH_DEPLOYMENT_KEY`, which addds the key for us.
- Finally, the public part of the key pair should be in `~/.ssh/authorized_keys` on your deployment server.

### (Re-)start FlexMeasures on the deployment server (install Post-Receive Hook)

### Install Post-Receive Hook
Only pushing the code will not actually deploy the updated FlexMeasures into a usable web app on the deployment server. For this, we need to trigger a script.

Only pushing the code will not deploy the updated FlexMeasures. For this, we need to trigger a script.
Log on to the server (via SSH) and install the Git Post Receive Hook in the remote repo where we deployed the code (see above). This hook will be triggered when a push is received from the deployment environment.
Log on to the server (via SSH) and install a script to (re-)start FlexMeasures as a Git Post Receive Hook in the remote repo where we deployed the code (see above). This hook will be triggered when a push is received from the deployment environment.

The example script below can be a Post Receive Hook (save as `hooks/post-receive` in your remote origin repo and update paths).
It will force checkout the master branch, update dependencies, upgrade the database structure,
It will force checkout the main branch, update dependencies, upgrade the database structure,
update the documentation and finally touch the wsgi.py file.
This last step is often a way to soft restart the running application, but here you need to adapt to your circumstances.

Expand Down
8 changes: 4 additions & 4 deletions ci/SETUP.sh
Expand Up @@ -12,9 +12,7 @@ head -c 24 /dev/urandom > ./instance/secret_key

# Install dependencies
apt-get update
apt-get -y install postgresql-client coinor-cbc
# set PGDB, PGUSER and PGPASSWORD as envs for this
psql -h localhost -p 5432 -c "create extension if not exists cube; create extension if not exists earthdistance;" -U $PGUSER $PGBD;
sudo apt-get -y install postgresql-client coinor-cbc
make install-deps


Expand All @@ -23,7 +21,7 @@ make install-deps
# Hack until this feature is ready: https://bitbucket.org/site/master/issues/15244/build-execution-should-wait-until-all
statusFile=/tmp/postgres-status
while [[ true ]]; do
telnet 127.0.0.1 5432 &> ${statusFile}
telnet $PGHOST $PGPORT &> ${statusFile}
status=$(grep "Connection refused" ${statusFile} | wc -l)
echo "Status: $status"

Expand All @@ -36,3 +34,5 @@ while [[ true ]]; do
break;
fi
done

psql -h $PGHOST -p $PGPORT -c "create extension if not exists cube; create extension if not exists earthdistance;" -U $PGUSER $PGDB;
nhoening marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 1 addition & 1 deletion flexmeasures/utils/config_defaults.py
Expand Up @@ -129,7 +129,7 @@ class TestingConfig(Config):

SECURITY_PASSWORD_SALT = "$2b$19$abcdefghijklmnopqrstuv"
SQLALCHEMY_DATABASE_URI = (
"postgresql://flexmeasures_test:flexmeasures_test@127.0.0.1/flexmeasures_test"
"postgresql://flexmeasures_test:flexmeasures_test@localhost/flexmeasures_test"
)
# SQLALCHEMY_ECHO = True
FLEXMEASURES_TASK_CHECK_AUTH_TOKEN = "test-task-check-token"
Expand Down