• Stars
    star
    100
  • Rank 340,703 (Top 7 %)
  • Language
    Haskell
  • License
    MIT License
  • Created over 10 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Deploy tool for Haskell applications, like Capistrano for Rails

Build Draft Release

Hapistrano

Description

Hapistrano is a deployment library for Haskell applications similar to Ruby's Capistrano.

Purpose

We created Hapistrano because:

  • Deploys should be simple, but as close to atomic as possible (eg, they shouldn't require much application downtime).
  • Rollback should be trivial to achieve to bring the application back to the last-deployed state.
  • Deploys shouldn't fail because of dependency problems.

How it Works

Hapistrano (like Capistrano for Ruby) deploys applications to a new directory marked with a timestamp on the remote host. It creates this new directory quickly by placing a git repository for caching purposes on the remote server.

When the build process completes, it switches a symlink to the current release directory, and optionally restarts the web server.

By default, Hapistrano keeps the last five releases on the target host filesystem and deletes previous releases to avoid filling up the disk.

Usage

Hapistrano 0.4.0.0 looks for a configuration file called hap.yaml that typically looks like this:

deploy_path: '/var/projects/my-project'
host: [email protected]
port: 2222
# To perform version control operations
repo: 'https://github.com/stackbuilders/hapistrano.git'
revision: origin/master
# To copy the contents of the directory
local_directory: '/tmp/my-project'
build_script:
  - stack setup
  - stack build
restart_command: systemd restart my-app-service

The following parameters are required:

  • deploy_path β€” the root of the deploy target on the remote host.
  • Related to the source of the repository, you have the following options:
    • Git repository default β€” consists of two parameters. When these are set, hapistrano will perform version control related operations. Note: Only GitHub is supported.
      • repo β€” the origin repository.
      • revision β€” the SHA1 or branch to deploy. If a branch, you will need to specify it as origin/branch_name due to the way that the cache repo is configured.
    • local_directory β€” when this parameter is set, hapistrano will copy the contents of the directory.

The following parameters are optional:

  • host β€” the target host, if missing, localhost will be assumed (which is useful for testing and playing with hap locally). You can specify the user that is going to connect to the server here. Example: [email protected].
  • port β€” SSH port number to use. If missing, 22 will be used.
  • shell β€” Shell to use. Currently supported: zsh ans bash. If missing, Bash will be used.
  • ssh_args β€” Optional ssh arguments. Only -p is passed via the port variable.
  • build_script β€” instructions how to build the application in the form of shell commands.
  • restart_command β€” if you need to restart a remote web server after a successful rollback, specify the command that you use in this variable. It will be run after both deploy and rollback.
  • vc_action - Controls if version control related activity should take place. It defaults to true. When you don't want activity like cloning, fetching etc. to take place, set this to false.
  • linux - Specify, whether or not, the target system where Hapistrano will deploy to is a GNU/Linux or other UNIX (g.e. BSD, Mac). This is set to true by default so unless the target system is not GNU/Linux, this should not be necessary. The platform where Hapistrano is running won't affect the available options for commands (g.e. A Mac deploying to an Ubuntu machine, doesn't need this flag)
  • release_format - The release timestamp format, the '--release-format' argument passed via the CLI takes precedence over this value. If neither CLI nor configuration file value is specified, it defaults to 'short'
  • keep_releases - The number of releases to keep, the '--keep-releases' argument passed via the CLI takes precedence over this value. If neither CLI nor configuration file value is specified, it defaults to '5'
  • keep_one_failed - A boolean specifying whether to keep all failed releases or just one (the latest failed release), the '--keep-one-failed' flag passed via the CLI takes precedence over this value. If neither CLI nor configuration file value is specified, it defaults to false (i.e. keep all failed releases).
  • linked_files:- Listed files that will be symlinked from the {deploy_path}/shared folder into each release directory during deployment. Can be used for configuration files that need to be persisted (e.g. dotenv files). NOTE: The directory structure must be similar in your release directories in case you need to link a file inside a nested directory (e.g. shared/foo/file.txt).
  • linked_dirs:- Listed directories that will be symlinked from the {deploy_path}/shared folder into each release directory during deployment. Can be used for data directories that need to be persisted (e.g. upload directories). NOTE: Do not add a slash / at the end of the directory (e.g. foo/) because we use parseRelFile to create the symlink.
  • run_locally:- Instructions to run locally on your machine in the form of shell commands. Example:
run_locally:
  - pwd
  - bash deploy.sh

Note how we are even able to execute a bash script named deploy.sh above. Be sure to use set -e in your bash script to avoid headaches. Hapistrano will stop the execution on non-zero exit codes. Without the usage of set -e, there is a possibility that your bash script may return a zero exit code even if your intermediate command resulted in an error.

After creating a configuration file as above, deploying is as simple as:

$ hap deploy

Rollback is also trivial:

$ hap rollback # to rollback to previous successful deploy
$ hap rollback -n 2 # go two deploys back in time, etc.
  • maintenance_directory:- The name of the directory on which the maintenance file will be placed. {deploy_path}/{maintenance_directory}. The default directory name is maintenance
  • maintenance_filename:- The name of the file that is going to be created in the maintenance_directory. It has to have the .html extension to be seen in the browser. {deploy_path}/{maintenance_directory}/{maintenance_filename}. The default filename is maintenance.html

Environment Variables

Configuration files are parsed using loadYamlSettings, therefore, variable substitution is supported. Considering the following configuration file:

revision: "_env:HAPISTRANO_REVISION:origin/master
...

The revision value could be overwritten as follows:

HAPISTRANO_REVISION=origin/feature_branch hap deploy

What to do when compiling on server is not viable

Sometimes the target machine (server) is not capable of compiling your application because e.g. it has not enough memory and GHC exhausts it all. You can copy pre-compiled files from local machine or CI server using copy_files and copy_dirs parameters:

copy_files:
  - src: '/home/stackbuilders/my-file.txt'
    dest: 'my-file.txt'
copy_dirs:
  - src: .stack-work
    dest: .stack-work

src maybe absolute or relative, it's path to file or directory on local machine, dest may only be relative (it's expanded relatively to cloned repo) and specifies where to put the files/directories on target machine. Directories and files with clashing names will be overwritten. Directories are copied recursively.

Deploying to multiple machines concurrently

Beginning with Hapistrano 0.3.1.0 it's possible to deploy to several machines concurrently. The only things you need to do is to adjust your configuration file and use targets parameter instead of host and port, like this:

targets:
  - host: myserver-a.com
    port: 2222
  - host: myserver-b.com
# the rest is the same

Additionally, starting with 0.4.9.0 it is possible to run commands only on the lead target during a concurrent deploying process ensuring that certain tasks only get executed once. The lead target is considered the first entry in the targets list:

targets:
  - host: app1.example.com # lead server
  - host: app2.example.com

build_script:
  - command: ./run_database_migrations
    only_lead: true
  - ./build
# the rest is the same

A few things to note here:

  • host item is required for every target, but port may be omitted and then it defaults to 22.

  • The deployment will run concurrently and finish when interactions with all targets have finished either successfully or not. If at least one interaction was unsuccessful, the hap tool will exit with non-zero exit code.

  • The log is printed in such a way that messages from several machines get intermixed, but it's guaranteed that they won't overlap (printing itself is sequential) and the headers will tell you exactly which machine was executing which command.

If you don't specify host and targets, hap will assume localhost as usually, which is mainly useful for testing.

Docker

Starting with version 0.4.4.0 all new Docker images would be published to [GitHub's Container Registry][ghcr], while the old versions remain available on [Docker Hub][dockerhub]. To download the latest version available, change the image reference as follows:

- stackbuilders/hapistrano:latest
+ ghcr.io/stackbuilders/hapistrano:latest

GH Actions

Check the documentation here

Development

Requirements

  • Install Zsh
  • Use GHCup to install:
    • GHC 8.10.x or 9.0.x (it is recommended to try both for backward compatibility)
    • Cabal 3.x

Alternatively, install only Nix following the instructions detailed here.

Getting Started

Update package index:

cabal update

Enable tests:

cabal configure --enable-tests

Install project dependencies:

cabal build --only-dependencies

Compile the project:

cabal build

Run tests:

cabal test

Enable/disable maintenance mode

Present a maintenance page to visitors. Disables your application's web interface by writing a {maintenance_filename} file to each web server. The servers must be configured to detect the presence of this file, and if it is present, always display it instead of performing the request.

The maintenance page will just say the site is down for maintenance, and will be back shortly.

To enable maintenance mode run:

hap maintenance enable

Disabling maintenance mode will remove the file from the {maintenance_directory} it can be done with the following command:

hap maintenance disable

Notes

  • Hapistrano is not supported on Windows. Please check: Issue #96.

License

MIT, see the LICENSE file.

Contributing

Do you want to contribute to this project? Please take a look at our contributing guideline to know how you can help us build it.


Stack Builders Check out our libraries | Join our team

More Repositories

1

react-native-spotlight-tour

A highly customizable tour feature with an awesome spotlight effect
TypeScript
86
star
2

tutorials

Stack Builders Tutorials.
Haskell
70
star
3

dotenv-hs

Load environment variables from dotenv files for Haskell
Haskell
59
star
4

inflections-hs

Rails-like inflections for Haskell
Haskell
36
star
5

stache

Mustache templates for Haskell
Haskell
28
star
6

assertive-ts

A type-safe fluent assertion library written in TypeScript and inspired by Jest assertions and the popular AssertJ
TypeScript
24
star
7

scalendar

DEPRECATED: Haskell Library to deal with resource availability in a Calendar
Haskell
24
star
8

openssh-github-keys

DEPRECATED: Control SSH access to your servers via GitHub teams
Haskell
20
star
9

hspec-golden

Golden tests with Hspec
Haskell
19
star
10

atomic-write

Writes files atomically in Haskell while preserving permissions
Haskell
18
star
11

railblazer

Quick Rails app configuration
Ruby
18
star
12

octohat

API wrapper for Github's API in Haskell with tests
Haskell
17
star
13

twitter-feed

DEPRECATED: Haskell library for retrieving and linkifying a Twitter user timeline.
Haskell
17
star
14

cloud-haskell-chat

Chat Server with Cloud Haskell
Haskell
12
star
15

cassava-megaparsec

Megaparsec parser of CSV files that plays nicely with Cassava
Haskell
9
star
16

propel

Push to your project the right way
Ruby
8
star
17

nonsense

Demo: https://stackbuilders.github.io/nonsense/
Elm
8
star
18

stub_shell

Stub shell environment for your rspec test suite.
Ruby
7
star
19

rollbar-haskell

A group of libraries written in Haskell to communicate with Rollbar API.
Haskell
7
star
20

sshd-lint

Checks a sshd_config file for adherence to security best practices
Haskell
7
star
21

semantic-release-hackage

A sematic-release plugin to publish Haskell packages to Hackage
TypeScript
7
star
22

sb-debian-base

Generic Ansible setup role for Debian and Ubuntu servers
Jinja
6
star
23

ansible-role-certbot

Ansible role to create Let's Encrypt certificates using the Certbot tool.
Shell
6
star
24

pivotal_planning_poker

Planning poker for distributed teams using Pivotal Tracker.
Ruby
6
star
25

clearnexus-chrome-extension

DEPRECATED: Clearnexus Chrome Extension
PureScript
5
star
26

cis194-templates

cis194 Haskell course templates
Haskell
5
star
27

dbcleaner

DEPRECATED: A simple database cleaner library for testing
Haskell
5
star
28

compose-2019

Compose 2019 Conference Example
OCaml
5
star
29

embrace-ambiguity

Make incomplete or incorrect Haskell programs compile!
Haskell
5
star
30

valid_data

Check whether the rows in your database are valid according to your ActiveRecord validations
Ruby
5
star
31

ansible-aws

Deploy a basic AWS infrastructure with Ansible
JavaScript
4
star
32

datetime

DEPRECATED: Fork of the DateTime library on Hackage to compile on GHC 7.10
Haskell
4
star
33

quickcheck-manual

A QuickCheck manual
Haskell
3
star
34

harvest-api

DEPRECATED: Haskell bindings to the Harvest API
Haskell
3
star
35

bfg

The BFG.
Haskell
2
star
36

bookshelf

A bookshelf.
Haskell
2
star
37

hubot

Hubot
CoffeeScript
2
star
38

high-spec

The code for the specific endpoints blog post
ATS
2
star
39

turbulent-sniffle

Behold a turbulent sniffle!
Haskell
2
star
40

dr-hakyll

Dr. Hakyll
Haskell
2
star
41

passenger-check

Nagios check for Passenger status (Haskell)
Haskell
2
star
42

easy-feed

Straightforward and efficient generation of feeds in Haskell.
Haskell
2
star
43

weak-strong

The Weak and the Strong
Agda
2
star
44

react-native-with-typescript

Quito Lambda - React Native and TypeScript
Haskell
2
star
45

token-bucket

A TCP-based token bucket server written in Haskell
Haskell
2
star
46

nodejs-with-nix

NodeJS + nix
Nix
2
star
47

pull_panel

Manage pull requests in multiple apps and organizations
JavaScript
2
star
48

nuxt-utm

Nuxt 3 module for capturing and tracking UTM parameters from URLs, with additional contextual data collection.
TypeScript
2
star
49

haskell-playground

Code snippets about non-strict vs. not purely lazy evaluation in Haskell.
Haskell
1
star
50

aws-base

AWS Base Role
1
star
51

haskell-deploy

Haskell deploy script from Circle CI to Debian
Shell
1
star
52

nano-chat

Nano Chat Example
JavaScript
1
star
53

nano-chat-ansible

Nano Chat - Ansible
1
star
54

persistent-crud

Persistent Crud
Haskell
1
star
55

hst-statistics

hst-statistics
Haskell
1
star
56

react-native-quito-lambda

https://www.meetup.com/Quito-Lambda-Meetup/events/250149099/
JavaScript
1
star
57

run-length

run-length
Haskell
1
star
58

tiny-python-fullstack

Tiny Python Backend
TypeScript
1
star
59

conway-cljs

Conway's game of life in clojurescript
Clojure
1
star
60

workdays

Workday calculations in Haskell.
Haskell
1
star
61

parseerror-eq

Simple library to adds an Eq instance to Parsec's ParseError type if it's needed
Haskell
1
star
62

.github

Stack Builders' Github profile info
1
star
63

corasick-park

Server for velociraptor-speed substitutions using the Aho-Corasick algorithm.
Haskell
1
star
64

ansible-role-asdf

Installs asdf on Linux
Jinja
1
star
65

keyword-args

Parses a configuration file containing keywords and arguments separated by spaces
Haskell
1
star
66

rock-paper-scissors

Multiplayer Rock, Paper, Scissors game made with Typescript & Socket.io
TypeScript
1
star