dlss-capistrano-docker 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7b180b31a5354ceec3029befccbdeac4ba5c86321eb75a1beb369d0c24a5ebbd
4
+ data.tar.gz: 30865848d3ef1b7c5e86565641aed355c011cf85e5219999c112a1d234d353eb
5
+ SHA512:
6
+ metadata.gz: f90641ba2d8b8c60c7f22e45dfc477f163732e9aeb3b89244b5b1563e09f10913c51cdb59464dc8d015c7b5f558655d01d7b9729fbe11b541603ab0504828a53
7
+ data.tar.gz: dddb973eaecac7511a4a6128cdf6a0e2b065226e0e8c40547204b191ae101cb5eb3010669551831ce1a8685fb10b8e86f5854ada8044815f3d548c59c71524c8
data/.gitignore ADDED
@@ -0,0 +1,56 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+
13
+ # Used by dotenv library to load environment variables.
14
+ # .env
15
+
16
+ # Ignore Byebug command history file.
17
+ .byebug_history
18
+
19
+ ## Specific to RubyMotion:
20
+ .dat*
21
+ .repl_history
22
+ build/
23
+ *.bridgesupport
24
+ build-iPhoneOS/
25
+ build-iPhoneSimulator/
26
+
27
+ ## Specific to RubyMotion (use of CocoaPods):
28
+ #
29
+ # We recommend against adding the Pods directory to your .gitignore. However
30
+ # you should judge for yourself, the pros and cons are mentioned at:
31
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
32
+ #
33
+ # vendor/Pods/
34
+
35
+ ## Documentation cache and generated files:
36
+ /.yardoc/
37
+ /_yardoc/
38
+ /doc/
39
+ /rdoc/
40
+
41
+ ## Environment normalization:
42
+ /.bundle/
43
+ /vendor/bundle
44
+ /lib/bundler/man/
45
+
46
+ # for a library or gem, you might want to ignore these files since the code is
47
+ # intended to run in multiple environments; otherwise, check them in:
48
+ # Gemfile.lock
49
+ # .ruby-version
50
+ # .ruby-gemset
51
+
52
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
53
+ .rvmrc
54
+
55
+ # Used by RuboCop. Remote config files pulled in from inherit_from directive.
56
+ # .rubocop-https?--*
data/.rubocop.yml ADDED
@@ -0,0 +1,178 @@
1
+ AllCops:
2
+ TargetRubyVersion: 3.1
3
+ SuggestExtensions: false
4
+ DisplayCopNames: true
5
+ Include:
6
+ - './Rakefile' # rake only
7
+ - '**/*.rb'
8
+ - '**/*.rake' # rake only
9
+
10
+ Bundler/GemComment:
11
+ OnlyFor:
12
+ - restrictive_version_specifiers
13
+ - branch
14
+
15
+ # Configuration parameters: AllowURI, URISchemes.
16
+ Layout/LineLength:
17
+ Max: 120
18
+
19
+ # consider if refactoring will improve adherence to SOLID and/or improve readability
20
+ # Sometimes splitting the class up won't improve readablity, it just makes reader jump around in the code.
21
+ Metrics/ClassLength:
22
+ Max: 150 # default 100
23
+
24
+ # consider if refactoring will improve adherence to SOLID and/or improve readability
25
+ # Sometimes splitting the method up won't improve readablity, it just makes reader jump around in the code.
26
+ # Good method names help.
27
+ Metrics/MethodLength:
28
+ Max: 15 # default 10
29
+
30
+ # capistrano tasks tend to be long.
31
+ Metrics/BlockLength:
32
+ Enabled: false
33
+
34
+ # "> 0", "== 0", "< 0" are not less readable than ".positive?", ".zero?" or ".negative?"
35
+ Style/NumericPredicate:
36
+ Enabled: false
37
+
38
+ Style/RegexpLiteral:
39
+ Enabled: false
40
+
41
+ Style/SymbolArray:
42
+ MinSize: 4 # default 2
43
+
44
+ Style/WordArray:
45
+ MinSize: 4 # default 2
46
+
47
+ Gemspec/DeprecatedAttributeAssignment: # new in 1.30
48
+ Enabled: true
49
+ Gemspec/RequireMFA: # new in 1.23
50
+ Enabled: true
51
+ Layout/LineContinuationLeadingSpace: # new in 1.31
52
+ Enabled: true
53
+ Layout/LineContinuationSpacing: # new in 1.31
54
+ Enabled: true
55
+ Layout/LineEndStringConcatenationIndentation: # new in 1.18
56
+ Enabled: true
57
+ Layout/SpaceBeforeBrackets: # new in 1.7
58
+ Enabled: true
59
+ Lint/AmbiguousAssignment: # new in 1.7
60
+ Enabled: true
61
+ Lint/AmbiguousOperatorPrecedence: # new in 1.21
62
+ Enabled: true
63
+ Lint/AmbiguousRange: # new in 1.19
64
+ Enabled: true
65
+ Lint/ConstantOverwrittenInRescue: # new in 1.31
66
+ Enabled: true
67
+ Lint/DeprecatedConstants: # new in 1.8
68
+ Enabled: true
69
+ Lint/DuplicateBranch: # new in 1.3
70
+ Enabled: true
71
+ Lint/DuplicateRegexpCharacterClassElement: # new in 1.1
72
+ Enabled: true
73
+ Lint/EmptyBlock: # new in 1.1
74
+ Enabled: true
75
+ Lint/EmptyClass: # new in 1.3
76
+ Enabled: true
77
+ Lint/EmptyInPattern: # new in 1.16
78
+ Enabled: true
79
+ Lint/IncompatibleIoSelectWithFiberScheduler: # new in 1.21
80
+ Enabled: true
81
+ Lint/LambdaWithoutLiteralBlock: # new in 1.8
82
+ Enabled: true
83
+ Lint/NoReturnInBeginEndBlocks: # new in 1.2
84
+ Enabled: true
85
+ Lint/NonAtomicFileOperation: # new in 1.31
86
+ Enabled: true
87
+ Lint/NumberedParameterAssignment: # new in 1.9
88
+ Enabled: true
89
+ Lint/OrAssignmentToConstant: # new in 1.9
90
+ Enabled: true
91
+ Lint/RedundantDirGlobSort: # new in 1.8
92
+ Enabled: true
93
+ Lint/RefinementImportMethods: # new in 1.27
94
+ Enabled: true
95
+ Lint/RequireRangeParentheses: # new in 1.32
96
+ Enabled: true
97
+ Lint/RequireRelativeSelfPath: # new in 1.22
98
+ Enabled: true
99
+ Lint/SymbolConversion: # new in 1.9
100
+ Enabled: true
101
+ Lint/ToEnumArguments: # new in 1.1
102
+ Enabled: true
103
+ Lint/TripleQuotes: # new in 1.9
104
+ Enabled: true
105
+ Lint/UnexpectedBlockArity: # new in 1.5
106
+ Enabled: true
107
+ Lint/UnmodifiedReduceAccumulator: # new in 1.1
108
+ Enabled: true
109
+ Lint/UselessRuby2Keywords: # new in 1.23
110
+ Enabled: true
111
+ Naming/BlockForwarding: # new in 1.24
112
+ Enabled: true
113
+ Security/CompoundHash: # new in 1.28
114
+ Enabled: true
115
+ Security/IoMethods: # new in 1.22
116
+ Enabled: true
117
+ Style/ArgumentsForwarding: # new in 1.1
118
+ Enabled: true
119
+ Style/CollectionCompact: # new in 1.2
120
+ Enabled: true
121
+ Style/DocumentDynamicEvalDefinition: # new in 1.1
122
+ Enabled: true
123
+ Style/EmptyHeredoc: # new in 1.32
124
+ Enabled: true
125
+ Style/EndlessMethod: # new in 1.8
126
+ Enabled: true
127
+ Style/EnvHome: # new in 1.29
128
+ Enabled: true
129
+ Style/FetchEnvVar: # new in 1.28
130
+ Enabled: true
131
+ Style/FileRead: # new in 1.24
132
+ Enabled: true
133
+ Style/FileWrite: # new in 1.24
134
+ Enabled: true
135
+ Style/HashConversion: # new in 1.10
136
+ Enabled: true
137
+ Style/HashExcept: # new in 1.7
138
+ Enabled: true
139
+ Style/IfWithBooleanLiteralBranches: # new in 1.9
140
+ Enabled: true
141
+ Style/InPatternThen: # new in 1.16
142
+ Enabled: true
143
+ Style/MagicCommentFormat: # new in 1.35
144
+ Enabled: true
145
+ Style/MapCompactWithConditionalBlock: # new in 1.30
146
+ Enabled: true
147
+ Style/MapToHash: # new in 1.24
148
+ Enabled: true
149
+ Style/MultilineInPatternThen: # new in 1.16
150
+ Enabled: true
151
+ Style/NegatedIfElseCondition: # new in 1.2
152
+ Enabled: true
153
+ Style/NestedFileDirname: # new in 1.26
154
+ Enabled: true
155
+ Style/NilLambda: # new in 1.3
156
+ Enabled: true
157
+ Style/NumberedParameters: # new in 1.22
158
+ Enabled: true
159
+ Style/NumberedParametersLimit: # new in 1.22
160
+ Enabled: true
161
+ Style/ObjectThen: # new in 1.28
162
+ Enabled: true
163
+ Style/OpenStructUse: # new in 1.23
164
+ Enabled: true
165
+ Style/QuotedSymbols: # new in 1.16
166
+ Enabled: true
167
+ Style/RedundantArgument: # new in 1.4
168
+ Enabled: true
169
+ Style/RedundantInitialize: # new in 1.27
170
+ Enabled: true
171
+ Style/RedundantSelfAssignmentBranch: # new in 1.19
172
+ Enabled: true
173
+ Style/SelectByRegexp: # new in 1.22
174
+ Enabled: true
175
+ Style/StringChars: # new in 1.12
176
+ Enabled: true
177
+ Style/SwapValues: # new in 1.1
178
+ Enabled: true
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Dependencies are defined in dlss-capistrano-docker.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,67 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ dlss-capistrano-docker (1.0.0)
5
+ capistrano (~> 3.0)
6
+ capistrano-one_time_key
7
+ capistrano-shared_configs
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ airbrussh (1.4.1)
13
+ sshkit (>= 1.6.1, != 1.7.0)
14
+ ast (2.4.2)
15
+ byebug (11.1.3)
16
+ capistrano (3.17.1)
17
+ airbrussh (>= 1.0.0)
18
+ i18n
19
+ rake (>= 10.0.0)
20
+ sshkit (>= 1.9.0)
21
+ capistrano-one_time_key (0.1.0)
22
+ capistrano (~> 3.0)
23
+ capistrano-shared_configs (0.2.2)
24
+ concurrent-ruby (1.1.10)
25
+ i18n (1.12.0)
26
+ concurrent-ruby (~> 1.0)
27
+ json (2.6.2)
28
+ net-scp (1.2.1)
29
+ net-ssh (>= 2.6.5)
30
+ net-ssh (7.0.1)
31
+ parallel (1.22.1)
32
+ parser (3.1.2.1)
33
+ ast (~> 2.4.1)
34
+ rainbow (3.1.1)
35
+ rake (13.0.6)
36
+ regexp_parser (2.5.0)
37
+ rexml (3.2.5)
38
+ rubocop (1.36.0)
39
+ json (~> 2.3)
40
+ parallel (~> 1.10)
41
+ parser (>= 3.1.2.1)
42
+ rainbow (>= 2.2.2, < 4.0)
43
+ regexp_parser (>= 1.8, < 3.0)
44
+ rexml (>= 3.2.5, < 4.0)
45
+ rubocop-ast (>= 1.20.1, < 2.0)
46
+ ruby-progressbar (~> 1.7)
47
+ unicode-display_width (>= 1.4.0, < 3.0)
48
+ rubocop-ast (1.21.0)
49
+ parser (>= 3.1.1.0)
50
+ ruby-progressbar (1.11.0)
51
+ sshkit (1.21.3)
52
+ net-scp (>= 1.1.2)
53
+ net-ssh (>= 2.8.0)
54
+ unicode-display_width (2.3.0)
55
+
56
+ PLATFORMS
57
+ x86_64-darwin-21
58
+
59
+ DEPENDENCIES
60
+ bundler
61
+ byebug
62
+ dlss-capistrano-docker!
63
+ rake (>= 12.3.3)
64
+ rubocop (~> 1.0)
65
+
66
+ BUNDLED WITH
67
+ 2.3.22
data/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # dlss-capistrano-docker
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/dlss-capistrano-docker.svg)](https://badge.fury.io/rb/dlss-capistrano-docker)
4
+
5
+ This gem provides Capistrano Docker deployment tasks used by Stanford Libraries' Digital Library Systems and Services group.
6
+
7
+ It requires that the services to be run on a server be specified by a docker compose configuration file.
8
+
9
+ ## Included Tasks
10
+ * `ssh`: establishes an SSH connection to the host running in environment, and changes into the current deployment directory.
11
+ * `honeybadger:notify`: notifies Honeybadger of deploy using curl (thus, ruby is not required on host).
12
+ * `docker:login`: log into Docker Hub. Logging in is required to avoid strict image download limits.
13
+ * `docker:logout`: log out of Docker Hub.
14
+ * `docker:prune`: prune docker artifacts to avoid filling disk space.
15
+ * `docker_compose:migrate`: migrate the database.
16
+ * `docker_compose:seed`: seed the database.
17
+ * `docker_compose:build`: build images for the services.
18
+ * `docker_compose:setup_rabbit`: create channel, queues, etc for RabbitMQ.
19
+ * `docker_compose:restart`: down then up services.
20
+ * `docker_compose:up`: stop services.
21
+ * `docker_compose:down`: tear down services.
22
+ * `docker_compose:copy_assets`: copy assets from a container to the server so they can be served by Apache.
23
+ * `docker_compose:dereference_linked_files`: turn linked files into actual files.
24
+ * `docker_compose:dereference_linked_dirs`: turn linked directories into actual directories containing actual files.
25
+
26
+ ## Hooks
27
+ Hooks into the Capistrano lifecycle are provided for most of these tasks. These hooks can be controlled with variables, e.g., `docker_hub_use_hooks` to control the hooks for `docker:login` and `docker:logout`.
28
+
29
+ In addition to tasks included in this gem, a hook is provided for `shared_configs:update`.
30
+
31
+ ## Usage
32
+ For an example of any of the following, see https://github.com/sul-dlss/happy-heron
33
+
34
+ ### `Gemfile`
35
+ * Add `gem 'dlss-capistrano-docker', require: false` to the deployment group.
36
+ * Remove any gems that are removed from `Capfile` below.
37
+ * Move puma gem from development/test dependencies to the application dependencies. (Puma will be used as the application server instead of Passenger.)
38
+
39
+ ### `Capfile`
40
+ * Remove any of the following:
41
+ ```
42
+ require 'capistrano/bundler'
43
+ require 'capistrano/rails'
44
+ require 'capistrano/honeybadger'
45
+ require 'capistrano/passenger'
46
+ require 'whenever/capistrano'
47
+ require 'dlss/capistrano'
48
+ ```
49
+ * Add `require 'dlss/docker/capistrano`
50
+
51
+ ### `config/deploy.rb`
52
+ * For `:linked_files` remove `config/database.yml` and `config/secrets.yml` if present. Both of these will be provided by environment variables.
53
+ * For `:linked_dirs` remove `tmp/pids`, `tmp/cache`, `tmp/sockets`, `public/system` if present. `log` and `config/settings` should remain.
54
+ * Remove any sidekiq, sneakers, passenger, whenever, or shared_configs related settings.
55
+ * Add `set :docker_compose_file, 'docker-compose.prod.yml'` to reference the production docker-compose file.
56
+ * Optionally, add `set :docker_compose_seed_use_hooks, true` to perform seeding.
57
+ * Optionally, add `set :docker_compose_rabbitmq_use_hooks, true` to perform Rabbitmq setup.
58
+ * Note that there are other settings supported by this gem for additional configuration.
59
+
60
+ ### `config/deploy/<environment>.rb`
61
+ * Each server should have the `app` role and any roles that correspond with profiles in the docker-compose file. This is what controls what services are run on the server.
62
+
63
+ ### `config/puma.rb`
64
+ * Change `RAILS_MAX_THREAD` to `PUMA_MAX_THREAD` and `RAILS_MIN_THREAD` to `PUMA_MIN_THREAD`.
65
+ * Enable workers with `workers ENV.fetch('PUMA_WORKERS', 2)`
66
+ * Enable preload with `preload_app!`.
67
+
68
+ ### `config/schedule.rb`
69
+ * Add `set :job_template, nil` to execute with sh instead of bash.
70
+
71
+ ### `Dockerfile`
72
+ * When possible, base the image on Alpine (e.g., `FROM ruby:3.1-alpine`).
73
+ * Processes should run as the application user (e.g., `h2`) not root, with user id and group id set to match the server.
74
+ * If using Whenever, install Supercronic (which does not have to run as root) and write the crontab file during the build with `RUN sh -c 'bundle exec whenever . | tee -a config/crontab'`.
75
+ * When possible, write to both a log file and stdout.
76
+ * Precompile assets (`RUN bin/rails assets:precompile`) as part of the build. `SECRET_KEY_BASE` will need to be available for precompiling.
77
+
78
+ ### `docker-compose.prod.yml`
79
+ * Duplicate configuration can be shared with fragments (e.g., `&environment` / `*environment`).
80
+ * The command for a container can be overridden with `command:`, e.g., `command: bin/bundle exec rake sneakers:run 2>&1 | tee -a log/sneakers.log`.
81
+ * Each service should be assigned to one or more profiles. These correspond to capistrano roles. For example:
82
+ ```
83
+ profiles:
84
+ - cron
85
+ ```
86
+ * Containers should link in the shared logs directory. For example:
87
+ ```
88
+ volumes:
89
+ - /opt/app/h2/happy-heron/shared/log:/app/log
90
+ ```
91
+ * Environment variables provided by the server should be passed through to the container. For example:
92
+ ```
93
+ environment:
94
+ - HONEYBADGER_API_KEY
95
+ ```
96
+
97
+ ### `.dockerignore`
98
+ Ignore `public.assets`
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'bundler'
4
+
5
+ Dir.glob('lib/tasks/*.rake').each { |r| import r }
6
+
7
+ begin
8
+ Bundler.setup(:default, :development)
9
+ rescue Bundler::BundlerError => e
10
+ $stderr.puts e.message
11
+ $stderr.puts "Run `bundle install` to install missing gems"
12
+ exit e.status_code
13
+ end
14
+
15
+ require "bundler/gem_tasks"
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib/', __FILE__)
3
+ $:.unshift lib unless $:.include?(lib)
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "dlss-capistrano-docker"
7
+ s.version = '1.0.0'
8
+
9
+ s.platform = Gem::Platform::RUBY
10
+ s.authors = ['Justin Littman']
11
+ s.email = ['justinlittman@stanford.edu']
12
+ s.summary = "Capistrano recipes for use in SUL/DLSS projects for docker deployment"
13
+ s.homepage = 'https://github.com/sul-dlss/dlss-capistrano-docker'
14
+ s.license = "Apache-2.0"
15
+
16
+ s.required_ruby_version = '>= 3.0', '< 4'
17
+
18
+ # All dependencies are runtime dependencies, since this gem's "runtime" is
19
+ # the dependent gem's development-time.
20
+ s.add_dependency "capistrano", "~> 3.0"
21
+ s.add_dependency "capistrano-one_time_key"
22
+ s.add_dependency "capistrano-shared_configs"
23
+
24
+ s.add_development_dependency 'bundler'
25
+ s.add_development_dependency 'byebug'
26
+ s.add_development_dependency 'rake', '>= 12.3.3'
27
+ s.add_development_dependency 'rubocop', '~> 1.0'
28
+
29
+ s.files = `git ls-files`.split($/)
30
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
31
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
32
+ s.metadata['rubygems_mfa_required'] = 'true'
33
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Capistrano plugin hook to set default values
4
+ namespace :load do
5
+ task :defaults do
6
+ set :docker_prune_use_hooks, fetch(:docker_prune_use_hooks, true)
7
+ set :docker_hub_use_hooks, fetch(:docker_hub_use_hooks, true)
8
+ end
9
+ end
10
+
11
+ # Integrate hooks into Capistrano
12
+ namespace :deploy do
13
+ before :starting, :add_docker_hooks do
14
+ invoke 'docker:add_prune_hooks' if fetch(:docker_prune_use_hooks)
15
+ invoke 'docker:add_hub_hooks' if fetch(:docker_hub_use_hooks)
16
+ end
17
+ end
18
+
19
+ namespace :docker do
20
+ task :add_prune_hooks do
21
+ # Cleaning up docker on start so that images/logs are available for troubleshooting.
22
+ after 'deploy:starting', 'docker:prune'
23
+ end
24
+
25
+ task :add_hub_hooks do
26
+ after 'deploy:starting', 'docker:login'
27
+ after 'deploy:finishing', 'docker:logout'
28
+ end
29
+
30
+ desc 'Log in to Docker Hub'
31
+ task :login do
32
+ on roles(:app) do
33
+ execute(:docker, 'login', '-u', '$DOCKER_USERNAME', '-p', '$DOCKER_PASSWORD')
34
+ end
35
+ end
36
+
37
+ desc 'Log out of Docker Hub'
38
+ task :logout do
39
+ on roles(:app) do
40
+ execute(:docker, 'logout')
41
+ end
42
+ end
43
+
44
+ desc 'Prune unused images/containers'
45
+ task :prune do
46
+ on roles(:app) do
47
+ execute(:docker, 'system', 'prune', '-af')
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,198 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Capistrano plugin hook to set default values
4
+ namespace :load do
5
+ task :defaults do
6
+ set :docker_compose_file, fetch(:docker_compose_file, 'docker-compose.yml')
7
+
8
+ set :docker_compose_migrate_use_hooks, fetch(:docker_compose_migrate_use_hooks, true)
9
+ set :migration_role, fetch(:migration_role, :db)
10
+ set :migration_servers, -> { primary(fetch(:migration_role)) }
11
+ set :migration_command, fetch(:migration_command, 'db:migrate')
12
+
13
+ set :docker_compose_seed_use_hooks, fetch(:docker_compose_seed_use_hooks, false)
14
+ set :seed_command, fetch(:migration_command, 'db:seed')
15
+
16
+ set :docker_compose_build_use_hooks, fetch(:docker_compose_build_use_hooks, true)
17
+ set :build_roles, fetch(:build_roles, [:app])
18
+ set :dereference_files, fetch(:dereference_files)
19
+ set :dereference_dirs, fetch(:dereference_dirs, [])
20
+
21
+ set :docker_compose_rabbitmq_use_hooks, fetch(:docker_compose_rabbit_use_hooks, false)
22
+ set :rabbitmq_role, fetch(:rabbitmq_role, :app)
23
+ set :rabbitmq_servers, -> { primary(fetch(:rabbitmq_role)) }
24
+ set :rabbitmq_command, fetch(:rabbitmq_command, 'rabbitmq:setup')
25
+
26
+ set :docker_compose_restart_use_hooks, fetch(:docker_compose_restart_use_hooks, true)
27
+
28
+ set :copy_assets_role, fetch(:copy_assets_role, :app)
29
+ set :assets_path, fetch(:assets_path, 'public/assets')
30
+ set :docker_compose_copy_assets_use_hooks, fetch(:docker_compose_copy_assets_use_hooks, true)
31
+ end
32
+ end
33
+
34
+ # Integrate hooks into Capistrano
35
+ namespace :deploy do
36
+ before :starting, :add_docker_hooks do
37
+ invoke 'docker_compose:add_migrate_hooks' if fetch(:docker_compose_migrate_use_hooks)
38
+ invoke 'docker_compose:add_seed_hooks' if fetch(:docker_compose_seed_use_hooks)
39
+ invoke 'docker_compose:add_build_hooks' if fetch(:docker_compose_build_use_hooks)
40
+ invoke 'docker_compose:add_rabbitmq_hooks' if fetch(:docker_compose_rabbitmq_use_hooks)
41
+ invoke 'docker_compose:add_restart_hooks' if fetch(:docker_compose_restart_use_hooks)
42
+ invoke 'docker_compose:add_copy_assets_hooks' if fetch(:docker_compose_copy_assets_use_hooks)
43
+ end
44
+ end
45
+
46
+ namespace :docker_compose do
47
+ task :add_migrate_hooks do
48
+ after 'deploy:publishing', 'docker_compose:migrate'
49
+ end
50
+
51
+ task :add_seed_hooks do
52
+ after 'deploy:publishing', 'docker_compose:seed'
53
+ end
54
+
55
+ task :add_build_hooks do
56
+ after 'deploy:updating', 'docker_compose:build'
57
+ end
58
+
59
+ task :add_rabbitmq_hooks do
60
+ after 'deploy:publishing', 'docker_compose:setup_rabbitmq'
61
+ end
62
+
63
+ task :add_restart_hooks do
64
+ after 'deploy:publishing', 'docker_compose:restart'
65
+ end
66
+
67
+ task :add_copy_assets_hooks do
68
+ after 'deploy:publishing', 'docker_compose:copy_assets'
69
+ end
70
+
71
+ desc 'Migrate database'
72
+ task :migrate do
73
+ on fetch(:migration_servers) do
74
+ within current_path do
75
+ execute(:docker, 'compose', '-f', fetch(:docker_compose_file), 'run', 'app', 'bin/rails',
76
+ fetch(:migration_command))
77
+ end
78
+ info 'Db migrated'
79
+ end
80
+ end
81
+
82
+ desc 'Seed database'
83
+ task :seed do
84
+ on fetch(:migration_servers) do
85
+ within current_path do
86
+ execute(:docker, 'compose', '-f', fetch(:docker_compose_file), 'run', 'app', 'bin/rails',
87
+ fetch(:seed_command))
88
+ end
89
+ info 'Db migrated'
90
+ end
91
+ end
92
+
93
+ desc 'Build images'
94
+ # Docker build does not dereference symlinks.
95
+ task build: [:dereference_linked_files, :dereference_linked_dirs] do
96
+ on roles(fetch(:build_roles)) do
97
+ info 'Building images'
98
+ within release_path do
99
+ execute(:docker, 'compose', '-f', fetch(:docker_compose_file), 'build')
100
+ end
101
+ info 'Docker images built'
102
+ end
103
+ end
104
+
105
+ desc 'Setup RabbitMQ'
106
+ task :setup_rabbitmq do
107
+ on fetch(:rabbitmq_servers) do
108
+ within current_path do
109
+ execute(:docker, 'compose', '-f', fetch(:docker_compose_file), 'run', 'app', 'bin/rake',
110
+ fetch(:rabbitmq_command))
111
+ end
112
+ info 'RabbitMQ setup'
113
+ end
114
+ end
115
+
116
+ desc 'Restart containers (down then up)'
117
+ task restart: [:down, :up]
118
+
119
+ desc 'Start containers'
120
+ task :up do
121
+ on roles(:app) do |server|
122
+ cmd = cmd_with_profiles(server)
123
+ cmd.concat(['up', '-d'])
124
+ within current_path do
125
+ execute(*cmd)
126
+ info 'Containers started'
127
+ end
128
+ end
129
+ end
130
+
131
+ desc 'Tear down containers'
132
+ task :down do
133
+ on roles(:app) do |server|
134
+ cmd = cmd_with_profiles(server)
135
+ cmd.concat(['down'])
136
+ within current_path do
137
+ execute(*cmd)
138
+ info 'Containers down'
139
+ end
140
+ end
141
+ end
142
+
143
+ desc 'Copy assets'
144
+ task :copy_assets do
145
+ assets_path = fetch(:assets_path)
146
+ on roles(fetch(:copy_assets_role)) do
147
+ within current_path do
148
+ # Can't do a direct copy to public/assets because it is a symlink.
149
+ execute(:docker, 'compose', '-f', fetch(:docker_compose_file), 'cp',
150
+ 'app:/app/public/assets', '.')
151
+ execute(:rm, '-fr', "#{assets_path}/*")
152
+ execute(:mkdir, assets_path)
153
+ execute(:cp, 'assets/*', "#{assets_path}/")
154
+ end
155
+ info 'Assets copied'
156
+ end
157
+ end
158
+
159
+ desc 'Dereference linked files'
160
+ task :dereference_linked_files do
161
+ dereference_files = fetch(:dereference_files) || fetch(:linked_files, [])
162
+ next if dereference_files.empty?
163
+
164
+ on roles(fetch(:build_roles)) do
165
+ dereference_files.each do |file|
166
+ target = release_path.join(file)
167
+ source = shared_path.join(file)
168
+ execute :rm, target if test "[ -L #{target} ]"
169
+ execute :cp, source, target
170
+ end
171
+ end
172
+ end
173
+
174
+ desc 'Dereference linked directories'
175
+ task :dereference_linked_dirs do
176
+ dereference_dirs = fetch(:dereference_dirs)
177
+ next if dereference_dirs.empty?
178
+
179
+ on roles(fetch(:build_roles)) do
180
+ dereference_dirs.each do |dir|
181
+ target = release_path.join(dir)
182
+ source = shared_path.join(dir)
183
+ next unless test "[ -L #{target} ]"
184
+
185
+ execute :rm, target
186
+ execute :cp, '-r', source, target
187
+ end
188
+ end
189
+ end
190
+
191
+ def cmd_with_profiles(server)
192
+ cmd = [:docker, 'compose', '-f', fetch(:docker_compose_file)]
193
+ server.roles.each do |role|
194
+ cmd.concat(['--profile', role.to_s])
195
+ end
196
+ cmd
197
+ end
198
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Capistrano plugin hook to set default values
4
+ namespace :load do
5
+ task :defaults do
6
+ set :honeybadger_use_hooks, fetch(:honeybadger_use_hooks, true)
7
+ end
8
+ end
9
+
10
+ # Integrate hooks into Capistrano
11
+ namespace :deploy do
12
+ before :starting, :add_honeybadger_hooks do
13
+ invoke 'honeybadger:add_hooks' if fetch(:honeybadger_use_hooks)
14
+ end
15
+ end
16
+
17
+ namespace :honeybadger do
18
+ task :add_hooks do
19
+ after 'deploy:finishing', 'honeybadger:notify'
20
+ end
21
+
22
+ # Replaces honeybadger:deploy to use curl instead of invoking ruby.
23
+ # Adapted from https://github.com/honeybadger-io/honeybadger-ruby/blob/master/vendor/capistrano-honeybadger/lib/capistrano/tasks/deploy.cap
24
+ desc 'Notify Honeybadger of a deploy (using the API via curl)'
25
+ task notify: %i[deploy:set_current_revision] do
26
+ fetch(:honeybadger_server) do
27
+ if (s = primary(:app))
28
+ set(:honeybadger_server, s.select?({ exclude: :no_release }) ? s : nil)
29
+ end
30
+ end
31
+
32
+ if (server = fetch(:honeybadger_server))
33
+ revision = fetch(:current_revision)
34
+
35
+ on server do |_host|
36
+ info 'Notifying Honeybadger of deploy.'
37
+
38
+ honeybadger_config = nil
39
+ within release_path do
40
+ honeybadger_config = capture(:cat, 'config/honeybadger.yml')
41
+ end
42
+ remote_api_key = YAML.safe_load(honeybadger_config)['api_key']
43
+ remote_api_key = capture(:echo, '$HONEYBADGER_API_KEY') if remote_api_key.nil?
44
+
45
+ options = {
46
+ 'deploy[environment]' => fetch(:honeybadger_env, fetch(:rails_env, 'production')),
47
+ 'deploy[local_username]' => fetch(:honeybadger_user, ENV['USER'] || ENV.fetch('USERNAME', nil)),
48
+ 'deploy[revision]' => revision,
49
+ 'deploy[repository]' => fetch(:repo_url),
50
+ 'api_key' => fetch(:honeybadger_api_key, ENV.fetch('HONEYBADGER_API_KEY', nil)) || remote_api_key
51
+ }
52
+ data = options.to_a.map { |pair| pair.join('=') }.join('&')
53
+ execute(:curl, '--no-progress-meter', '--data', "\"#{data}\"", 'https://api.honeybadger.io/v1/deploys')
54
+ info 'Honeybadger notification complete.'
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Capistrano plugin hook to set default values
4
+ namespace :load do
5
+ task :defaults do
6
+ set :shared_configs_use_hooks, fetch(:shared_configs_use_hooks, true)
7
+ end
8
+ end
9
+
10
+ # Integrate hooks into Capistrano
11
+ namespace :deploy do
12
+ before :starting, :add_shared_configs_hooks do
13
+ invoke 'shared_configs:add_hooks' if fetch(:shared_configs_use_hooks)
14
+ end
15
+ end
16
+
17
+ namespace :shared_configs do
18
+ task :add_hooks do
19
+ before 'deploy:updating', 'shared_configs:update'
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ desc 'ssh to the current directory on the server'
4
+ task :ssh do
5
+ on roles(:app), primary: true do |host|
6
+ command = "cd #{fetch(:deploy_to)}/current && exec $SHELL -l"
7
+ puts command if fetch(:log_level) == :debug
8
+ exec "ssh -l #{host.user} #{host.hostname} -p #{host.port || 22} -t '#{command}'"
9
+ end
10
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'capistrano/one_time_key'
4
+ require 'capistrano/shared_configs'
5
+
6
+ Dir.glob("#{__dir__}/capistrano/tasks/*.rake").each { |r| import r }
metadata ADDED
@@ -0,0 +1,158 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dlss-capistrano-docker
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Justin Littman
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-09-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: capistrano
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: capistrano-one_time_key
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: capistrano-shared_configs
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: byebug
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: 12.3.3
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: 12.3.3
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.0'
111
+ description:
112
+ email:
113
+ - justinlittman@stanford.edu
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".gitignore"
119
+ - ".rubocop.yml"
120
+ - Gemfile
121
+ - Gemfile.lock
122
+ - README.md
123
+ - Rakefile
124
+ - dlss-capistrano-docker.gemspec
125
+ - lib/dlss/docker/capistrano.rb
126
+ - lib/dlss/docker/capistrano/tasks/docker.rake
127
+ - lib/dlss/docker/capistrano/tasks/docker_compose.rake
128
+ - lib/dlss/docker/capistrano/tasks/honeybadger.rake
129
+ - lib/dlss/docker/capistrano/tasks/shared_configs.rake
130
+ - lib/dlss/docker/capistrano/tasks/ssh.rake
131
+ homepage: https://github.com/sul-dlss/dlss-capistrano-docker
132
+ licenses:
133
+ - Apache-2.0
134
+ metadata:
135
+ rubygems_mfa_required: 'true'
136
+ post_install_message:
137
+ rdoc_options: []
138
+ require_paths:
139
+ - lib
140
+ required_ruby_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '3.0'
145
+ - - "<"
146
+ - !ruby/object:Gem::Version
147
+ version: '4'
148
+ required_rubygems_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ requirements: []
154
+ rubygems_version: 3.3.7
155
+ signing_key:
156
+ specification_version: 4
157
+ summary: Capistrano recipes for use in SUL/DLSS projects for docker deployment
158
+ test_files: []