aboutsummaryrefslogtreecommitdiffstats
path: root/.kamal/hooks
diff options
context:
space:
mode:
Diffstat (limited to '.kamal/hooks')
-rwxr-xr-x.kamal/hooks/docker-setup.sample3
-rwxr-xr-x.kamal/hooks/post-deploy.sample14
-rwxr-xr-x.kamal/hooks/post-proxy-reboot.sample3
-rwxr-xr-x.kamal/hooks/pre-build.sample51
-rwxr-xr-x.kamal/hooks/pre-connect.sample47
-rwxr-xr-x.kamal/hooks/pre-deploy.sample109
-rwxr-xr-x.kamal/hooks/pre-proxy-reboot.sample3
7 files changed, 230 insertions, 0 deletions
diff --git a/.kamal/hooks/docker-setup.sample b/.kamal/hooks/docker-setup.sample
new file mode 100755
index 0000000..2fb07d7
--- /dev/null
+++ b/.kamal/hooks/docker-setup.sample
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+echo "Docker set up on $KAMAL_HOSTS..."
diff --git a/.kamal/hooks/post-deploy.sample b/.kamal/hooks/post-deploy.sample
new file mode 100755
index 0000000..75efafc
--- /dev/null
+++ b/.kamal/hooks/post-deploy.sample
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+# A sample post-deploy hook
+#
+# These environment variables are available:
+# KAMAL_RECORDED_AT
+# KAMAL_PERFORMER
+# KAMAL_VERSION
+# KAMAL_HOSTS
+# KAMAL_ROLE (if set)
+# KAMAL_DESTINATION (if set)
+# KAMAL_RUNTIME
+
+echo "$KAMAL_PERFORMER deployed $KAMAL_VERSION to $KAMAL_DESTINATION in $KAMAL_RUNTIME seconds"
diff --git a/.kamal/hooks/post-proxy-reboot.sample b/.kamal/hooks/post-proxy-reboot.sample
new file mode 100755
index 0000000..1435a67
--- /dev/null
+++ b/.kamal/hooks/post-proxy-reboot.sample
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+echo "Rebooted kamal-proxy on $KAMAL_HOSTS"
diff --git a/.kamal/hooks/pre-build.sample b/.kamal/hooks/pre-build.sample
new file mode 100755
index 0000000..f87d811
--- /dev/null
+++ b/.kamal/hooks/pre-build.sample
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+# A sample pre-build hook
+#
+# Checks:
+# 1. We have a clean checkout
+# 2. A remote is configured
+# 3. The branch has been pushed to the remote
+# 4. The version we are deploying matches the remote
+#
+# These environment variables are available:
+# KAMAL_RECORDED_AT
+# KAMAL_PERFORMER
+# KAMAL_VERSION
+# KAMAL_HOSTS
+# KAMAL_ROLE (if set)
+# KAMAL_DESTINATION (if set)
+
+if [ -n "$(git status --porcelain)" ]; then
+ echo "Git checkout is not clean, aborting..." >&2
+ git status --porcelain >&2
+ exit 1
+fi
+
+first_remote=$(git remote)
+
+if [ -z "$first_remote" ]; then
+ echo "No git remote set, aborting..." >&2
+ exit 1
+fi
+
+current_branch=$(git branch --show-current)
+
+if [ -z "$current_branch" ]; then
+ echo "Not on a git branch, aborting..." >&2
+ exit 1
+fi
+
+remote_head=$(git ls-remote $first_remote --tags $current_branch | cut -f1)
+
+if [ -z "$remote_head" ]; then
+ echo "Branch not pushed to remote, aborting..." >&2
+ exit 1
+fi
+
+if [ "$KAMAL_VERSION" != "$remote_head" ]; then
+ echo "Version ($KAMAL_VERSION) does not match remote HEAD ($remote_head), aborting..." >&2
+ exit 1
+fi
+
+exit 0
diff --git a/.kamal/hooks/pre-connect.sample b/.kamal/hooks/pre-connect.sample
new file mode 100755
index 0000000..18e61d7
--- /dev/null
+++ b/.kamal/hooks/pre-connect.sample
@@ -0,0 +1,47 @@
+#!/usr/bin/env ruby
+
+# A sample pre-connect check
+#
+# Warms DNS before connecting to hosts in parallel
+#
+# These environment variables are available:
+# KAMAL_RECORDED_AT
+# KAMAL_PERFORMER
+# KAMAL_VERSION
+# KAMAL_HOSTS
+# KAMAL_ROLE (if set)
+# KAMAL_DESTINATION (if set)
+# KAMAL_RUNTIME
+
+hosts = ENV["KAMAL_HOSTS"].split(",")
+results = nil
+max = 3
+
+elapsed = Benchmark.realtime do
+ results = hosts.map do |host|
+ Thread.new do
+ tries = 1
+
+ begin
+ Socket.getaddrinfo(host, 0, Socket::AF_UNSPEC, Socket::SOCK_STREAM, nil, Socket::AI_CANONNAME)
+ rescue SocketError
+ if tries < max
+ puts "Retrying DNS warmup: #{host}"
+ tries += 1
+ sleep rand
+ retry
+ else
+ puts "DNS warmup failed: #{host}"
+ host
+ end
+ end
+
+ tries
+ end
+ end.map(&:value)
+end
+
+retries = results.sum - hosts.size
+nopes = results.count { |r| r == max }
+
+puts "Prewarmed %d DNS lookups in %.2f sec: %d retries, %d failures" % [ hosts.size, elapsed, retries, nopes ]
diff --git a/.kamal/hooks/pre-deploy.sample b/.kamal/hooks/pre-deploy.sample
new file mode 100755
index 0000000..1b280c7
--- /dev/null
+++ b/.kamal/hooks/pre-deploy.sample
@@ -0,0 +1,109 @@
+#!/usr/bin/env ruby
+
+# A sample pre-deploy hook
+#
+# Checks the Github status of the build, waiting for a pending build to complete for up to 720 seconds.
+#
+# Fails unless the combined status is "success"
+#
+# These environment variables are available:
+# KAMAL_RECORDED_AT
+# KAMAL_PERFORMER
+# KAMAL_VERSION
+# KAMAL_HOSTS
+# KAMAL_COMMAND
+# KAMAL_SUBCOMMAND
+# KAMAL_ROLE (if set)
+# KAMAL_DESTINATION (if set)
+
+# Only check the build status for production deployments
+if ENV["KAMAL_COMMAND"] == "rollback" || ENV["KAMAL_DESTINATION"] != "production"
+ exit 0
+end
+
+require "bundler/inline"
+
+# true = install gems so this is fast on repeat invocations
+gemfile(true, quiet: true) do
+ source "https://rubygems.org"
+
+ gem "octokit"
+ gem "faraday-retry"
+end
+
+MAX_ATTEMPTS = 72
+ATTEMPTS_GAP = 10
+
+def exit_with_error(message)
+ $stderr.puts message
+ exit 1
+end
+
+class GithubStatusChecks
+ attr_reader :remote_url, :git_sha, :github_client, :combined_status
+
+ def initialize
+ @remote_url = `git config --get remote.origin.url`.strip.delete_prefix("https://github.com/")
+ @git_sha = `git rev-parse HEAD`.strip
+ @github_client = Octokit::Client.new(access_token: ENV["GITHUB_TOKEN"])
+ refresh!
+ end
+
+ def refresh!
+ @combined_status = github_client.combined_status(remote_url, git_sha)
+ end
+
+ def state
+ combined_status[:state]
+ end
+
+ def first_status_url
+ first_status = combined_status[:statuses].find { |status| status[:state] == state }
+ first_status && first_status[:target_url]
+ end
+
+ def complete_count
+ combined_status[:statuses].count { |status| status[:state] != "pending"}
+ end
+
+ def total_count
+ combined_status[:statuses].count
+ end
+
+ def current_status
+ if total_count > 0
+ "Completed #{complete_count}/#{total_count} checks, see #{first_status_url} ..."
+ else
+ "Build not started..."
+ end
+ end
+end
+
+
+$stdout.sync = true
+
+puts "Checking build status..."
+attempts = 0
+checks = GithubStatusChecks.new
+
+begin
+ loop do
+ case checks.state
+ when "success"
+ puts "Checks passed, see #{checks.first_status_url}"
+ exit 0
+ when "failure"
+ exit_with_error "Checks failed, see #{checks.first_status_url}"
+ when "pending"
+ attempts += 1
+ end
+
+ exit_with_error "Checks are still pending, gave up after #{MAX_ATTEMPTS * ATTEMPTS_GAP} seconds" if attempts == MAX_ATTEMPTS
+
+ puts checks.current_status
+ sleep(ATTEMPTS_GAP)
+ checks.refresh!
+ end
+rescue Octokit::NotFound
+ exit_with_error "Build status could not be found"
+end
diff --git a/.kamal/hooks/pre-proxy-reboot.sample b/.kamal/hooks/pre-proxy-reboot.sample
new file mode 100755
index 0000000..061f805
--- /dev/null
+++ b/.kamal/hooks/pre-proxy-reboot.sample
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+echo "Rebooting kamal-proxy on $KAMAL_HOSTS..."