capistrano-nomad 0.6.5 → 0.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 659b43a201195b9cefc001ff096e0edc07967303695f19466e612061028f81d7
4
- data.tar.gz: 236271b31a3cae45ba09828afb8cc27854eee2ce2329166dfde818683610c193
3
+ metadata.gz: d227d6f15f433cd6410884afc5572cf9c7e115a7365e00e244d3b95ca320f148
4
+ data.tar.gz: a0cdd0e131319cd0f1a17a926afe70619d24550018de9731c96a610b075300c2
5
5
  SHA512:
6
- metadata.gz: bce586af52de2b0d1d679bb7dcbb7b1d8ccf9fb23bfa8296ff9fb2cff379deb8a35071b75164e7750918f7c1d52364340beb40877fbacd41cbd70bb758af1e40
7
- data.tar.gz: ace5161204cdc20b739a462971ba9a2d18d194205ecc4ef2beb68e7820da0e4a02e9b711317babd5e76bf368892b358b9c8f2abdcd82dcca92303faa79bcc77a
6
+ metadata.gz: fd4aec6aecd6698d4ed23d4e1a2c3d3e8ded18467c1a4d8daee191e29304e2f91f85ca7d604681dba4ec6cb885308f0fb6985fb4e9d952e459fc7859a3b3917a
7
+ data.tar.gz: 6009d60f5bd99e35fdb2961f6b9d860ea9db40ac844cebacf87b21ae58381eeefd35022fb58c7a6b88fa74da7e3acff3ee26a0f9a71a92e1b61495102bf53a21
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- capistrano-nomad (0.6.5)
4
+ capistrano-nomad (0.7.0)
5
5
  activesupport (<= 7.0.8)
6
6
  byebug
7
7
  capistrano (~> 3.0)
data/README.md CHANGED
@@ -48,24 +48,38 @@ end)
48
48
 
49
49
  # Make helpers available to all template .erb files
50
50
  nomad_template_helpers do
51
- def restart_stanza
51
+ def restart_stanza(interval = "1m")
52
52
  <<-EOF
53
-
53
+ restart {
54
+ interval = "#{interval}"
55
+ attempts = 3
56
+ mode = "delay"
57
+ }
54
58
  EOF
55
59
  end
56
60
  end
57
61
 
58
- # Docker image types
62
+ # Use hosted Docker image
63
+ nomad_docker_image_type :postgres,
64
+ alias_digest: "postgres:5.0.0"
65
+
66
+ # Use Docker image that will be built locally relative to project and push
59
67
  nomad_docker_image_type :backend,
60
68
  path: "local/path/backend",
61
69
  alias: ->(image_type:) { "gcr.io/axsuul/#{image_type}" },
62
70
  target: "release",
63
71
  build_args: { foo: "bar" }
72
+
73
+ # Use Docker image that will be built locally from an absolute path and push
64
74
  nomad_docker_image_type :redis,
65
75
  path: "/absolute/path/redis",
66
76
  alias: "gcr.io/axsuul/redis"
67
- nomad_docker_image_type :postgres,
68
- alias_digest: "postgres:5.0.0"
77
+
78
+ # Use Docker image that will be built remotely on server
79
+ nomad_docker_image_type :restic,
80
+ path: "containers/restic",
81
+ alias: "my-project/restic:local",
82
+ strategy: :remote_build
69
83
 
70
84
  # Jobs
71
85
  nomad_job :backend, docker_image_types: [:backend], var_files: [:rails]
@@ -80,20 +94,20 @@ nomad_namespace :analytics do
80
94
  end
81
95
  ```
82
96
 
83
- Deploy all with
97
+ Deploy all jobs
84
98
 
85
99
  ```shell
86
100
  cap production nomad:all:deploy
87
101
  ```
88
102
 
89
- Deploy jobs individually with
103
+ Deploy individual jobs
90
104
 
91
105
  ```shell
92
106
  cap production nomad:app:deploy
93
107
  cap production nomad:analytics:grafana:deploy
94
108
  ```
95
109
 
96
- Manage jobs with
110
+ Manage jobs
97
111
 
98
112
  ```shell
99
113
  cap production nomad:app:stop
@@ -102,7 +116,7 @@ cap production nomad:analytics:grafana:restart
102
116
  cap production nomad:postgres:status
103
117
  ```
104
118
 
105
- Open console with
119
+ Open console
106
120
 
107
121
  ```shell
108
122
  cap production nomad:app:console
@@ -110,7 +124,7 @@ cap production nomad:app:console TASK=custom-task-name
110
124
  cap production nomad:analytics:grafana:console
111
125
  ```
112
126
 
113
- Show logs with
127
+ Display logs
114
128
 
115
129
  ```shell
116
130
  cap production nomad:app:logs
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = "capistrano-nomad"
5
- spec.version = "0.6.5"
5
+ spec.version = "0.7.0"
6
6
  spec.authors = ["James Hu"]
7
7
 
8
8
  spec.summary = "Capistrano plugin for deploying and managing Nomad jobs"
@@ -5,3 +5,7 @@ end
5
5
  def capistrano_nomad_deep_symbolize_hash_keys(hash)
6
6
  JSON.parse(JSON[hash], symbolize_names: true)
7
7
  end
8
+
9
+ def capistrano_nomad_run_remotely(&block)
10
+ on(roles(:manager), &block)
11
+ end
@@ -21,7 +21,7 @@ end
21
21
  def capistrano_nomad_read_docker_image_types_manifest
22
22
  manifest = {}
23
23
 
24
- on(roles(:manager)) do |_host|
24
+ capistrano_nomad_run_remotely do
25
25
  # Ensure file exists
26
26
  execute("mkdir -p #{shared_path}")
27
27
  execute("touch #{capistrano_nomad_docker_image_types_manifest_path}")
@@ -37,7 +37,7 @@ def capistrano_nomad_read_docker_image_types_manifest
37
37
  end
38
38
 
39
39
  def capistrano_nomad_update_docker_image_types_manifest(image_type, properties = {})
40
- on(roles(:manager)) do |_host|
40
+ capistrano_nomad_run_remotely do
41
41
  # Read and update manifest
42
42
  manifest = capistrano_nomad_read_docker_image_types_manifest
43
43
  manifest[image_type] = (manifest[image_type] || {}).merge(properties.stringify_keys)
@@ -90,12 +90,7 @@ def capistrano_nomad_build_docker_image_for_type(image_type)
90
90
  args << "--build-arg #{key}=#{value}"
91
91
  end
92
92
 
93
- run_locally do
94
- # If any of these files exist then we're in the middle of rebase so we should interrupt
95
- if ["rebase-merge", "rebase-apply"].any? { |f| File.exist?("#{capistrano_nomad_git.dir.path}/.git/#{f}") }
96
- raise StandardError, "Still in the middle of git rebase, interrupting docker image build"
97
- end
98
-
93
+ docker_build_command = lambda do |path|
99
94
  image_alias_args = args.dup
100
95
 
101
96
  [capistrano_nomad_build_docker_image_alias(image_type)]
@@ -104,7 +99,30 @@ def capistrano_nomad_build_docker_image_for_type(image_type)
104
99
  image_alias_args << "--tag #{tag}"
105
100
  end
106
101
 
107
- execute("docker build #{image_alias_args.join(' ')} #{capistrano_nomad_root.join(attributes[:path])}")
102
+ "docker build #{image_alias_args.join(' ')} #{path}"
103
+ end
104
+
105
+ case attributes[:strategy]
106
+
107
+ # We need to build Docker container locally
108
+ when :local_build, :local_push
109
+ run_locally do
110
+ # If any of these files exist then we're in the middle of rebase so we should interrupt
111
+ if ["rebase-merge", "rebase-apply"].any? { |f| File.exist?("#{capistrano_nomad_git.dir.path}/.git/#{f}") }
112
+ raise StandardError, "Still in the middle of git rebase, interrupting docker image build"
113
+ end
114
+
115
+ execute(docker_build_command.call(capistrano_nomad_root.join(attributes[:path])))
116
+ end
117
+
118
+ # We need to build Docker container remotely
119
+ when :remote_build, :remote_push
120
+ remote_path = Pathname.new(release_path).join(attributes[:path])
121
+ capistrano_nomad_upload(local_path: attributes[:path], remote_path: remote_path)
122
+
123
+ capistrano_nomad_run_remotely do
124
+ execute(docker_build_command.call(remote_path))
125
+ end
108
126
  end
109
127
  end
110
128
 
@@ -112,6 +130,8 @@ def capistrano_nomad_push_docker_image_for_type(image_type, is_manifest_updated:
112
130
  attributes = fetch(:nomad_docker_image_types)[image_type]
113
131
  alias_digest = attributes&.dig(:alias_digest)
114
132
 
133
+ return false unless [:local_push, :remote_push].include?(attributes[:strategy])
134
+
115
135
  run_locally do
116
136
  # Don't push Docker image if alias digest is already passed in
117
137
  unless alias_digest
@@ -1,6 +1,14 @@
1
+ require "active_support/core_ext/hash"
2
+
1
3
  def nomad_docker_image_type(image_type, attributes = {})
2
4
  docker_image_types = fetch(:nomad_docker_image_types) || {}
3
- docker_image_types[image_type] = attributes
5
+ docker_image_types[image_type] = attributes.reverse_merge(
6
+ # In case image doesn't get pushed, this will still be populated
7
+ alias_digest: attributes[:alias],
8
+
9
+ # By default build and push Docker image locally
10
+ strategy: :local_push,
11
+ )
4
12
 
5
13
  set(:nomad_docker_image_types, docker_image_types)
6
14
  end
@@ -96,7 +96,7 @@ def capistrano_nomad_run_nomad_command(kind, *args)
96
96
  end
97
97
 
98
98
  def capistrano_nomad_execute_nomad_command(*args)
99
- on(roles(:manager)) do |host|
99
+ capistrano_nomad_run_remotely do |host|
100
100
  run_interactively(host) do
101
101
  capistrano_nomad_run_nomad_command(:execute, *args)
102
102
  end
@@ -106,7 +106,7 @@ end
106
106
  def capistrano_nomad_capture_nomad_command(*args)
107
107
  output = nil
108
108
 
109
- on(roles(:manager)) do |_host|
109
+ capistrano_nomad_run_remotely do
110
110
  output = capistrano_nomad_run_nomad_command(:capture, *args)
111
111
  end
112
112
 
@@ -152,7 +152,7 @@ def capistrano_nomad_find_job_task_details(name, namespace: nil, task: nil)
152
152
  end
153
153
 
154
154
  def capistrano_nomad_exec_within_job(name, command, namespace: nil, task: nil)
155
- on(roles(:manager)) do
155
+ capistrano_nomad_run_remotely do
156
156
  if (task_details = capistrano_nomad_find_job_task_details(name, namespace: namespace, task: task))
157
157
  capistrano_nomad_execute_nomad_command(
158
158
  :alloc,
@@ -174,40 +174,55 @@ def capistrano_nomad_exec_within_job(name, command, namespace: nil, task: nil)
174
174
  end
175
175
  end
176
176
 
177
- def capistrano_nomad_upload_file(local_path:, remote_path:, erb_vars: {})
178
- docker_image_types = fetch(:nomad_docker_image_types)
179
- docker_image_types_manifest = capistrano_nomad_read_docker_image_types_manifest
180
-
181
- # Merge manifest into image types
182
- docker_image_types_manifest.each do |manifest_image_type, manifest_attributes|
183
- docker_image_types[manifest_image_type]&.merge!(manifest_attributes) || {}
184
- end
185
-
186
- # Parse manifest files using ERB
187
- erb = ERB.new(File.open(local_path).read, trim_mode: "-")
188
-
189
- final_erb_vars = {
190
- git_commit_id: fetch(:current_revision) || capistrano_nomad_git_commit_id,
191
- docker_image_types: docker_image_types,
192
- }
193
-
194
- # Add global ERB vars
195
- final_erb_vars.merge!(fetch(:nomad_template_vars) || {})
196
-
197
- # Add job-specific ERB vars
198
- final_erb_vars.merge!(erb_vars)
177
+ def capistrano_nomad_upload(local_path:, remote_path:, erb_vars: {})
178
+ # If directory upload everything within the directory
179
+ if File.directory?(local_path)
180
+ Dir.glob("#{local_path}/*").each do |path|
181
+ capistrano_nomad_upload(local_path: path, remote_path: "#{remote_path}/#{File.basename(path)}")
182
+ end
183
+ else
184
+ io =
185
+ if File.extname(local_path) == ".erb"
186
+ docker_image_types = fetch(:nomad_docker_image_types)
187
+ docker_image_types_manifest = capistrano_nomad_read_docker_image_types_manifest
188
+
189
+ # Merge manifest into image types
190
+ docker_image_types_manifest.each do |manifest_image_type, manifest_attributes|
191
+ docker_image_types[manifest_image_type]&.merge!(manifest_attributes) || {}
192
+ end
193
+
194
+ # Parse manifest files using ERB
195
+ erb = ERB.new(File.open(local_path).read, trim_mode: "-")
196
+
197
+ final_erb_vars = {
198
+ git_commit_id: fetch(:current_revision) || capistrano_nomad_git_commit_id,
199
+ docker_image_types: docker_image_types,
200
+ }
201
+
202
+ # Add global ERB vars
203
+ final_erb_vars.merge!(fetch(:nomad_template_vars) || {})
204
+
205
+ # Add job-specific ERB vars
206
+ final_erb_vars.merge!(erb_vars)
207
+
208
+ # We use a custom namespace class so that we can include helper methods into the namespace to make them available
209
+ # for template to access
210
+ namespace = CapistranoNomadErbNamespace.new(
211
+ context: self,
212
+ vars: final_erb_vars,
213
+ )
214
+
215
+ StringIO.new(erb.result(namespace.instance_eval { binding }))
216
+ else
217
+ File.open(local_path)
218
+ end
199
219
 
200
- # We use a custom namespace class so that we can include helper methods into the namespace to make them available for
201
- # template to access
202
- namespace = CapistranoNomadErbNamespace.new(
203
- context: self,
204
- vars: final_erb_vars,
205
- )
206
- erb_io = StringIO.new(erb.result(namespace.instance_eval { binding }))
220
+ capistrano_nomad_run_remotely do
221
+ # Ensure parent directory exists
222
+ execute(:mkdir, "-p", File.dirname(remote_path))
207
223
 
208
- on(roles(:manager)) do
209
- execute(:mkdir, "-p", File.dirname(remote_path))
210
- upload!(erb_io, remote_path)
224
+ upload!(io, remote_path)
225
+ end
211
226
  end
212
227
  end
213
228
 
@@ -253,7 +268,7 @@ def capistrano_nomad_upload_jobs(names, *args)
253
268
  uniq_var_files = names.map { |n| capistrano_nomad_fetch_job_var_files(n, *args) }.flatten.uniq
254
269
 
255
270
  uniq_var_files.each do |var_file|
256
- capistrano_nomad_upload_file(
271
+ capistrano_nomad_upload(
257
272
  local_path: capistrano_nomad_build_local_var_file_path(var_file, *args),
258
273
  remote_path: capistrano_nomad_build_release_var_file_path(var_file, *args),
259
274
  )
@@ -269,7 +284,7 @@ def capistrano_nomad_upload_jobs(names, *args)
269
284
  # Can set a custom template instead
270
285
  file_basename = nomad_job_options[:template] || name
271
286
 
272
- capistrano_nomad_upload_file(
287
+ capistrano_nomad_upload(
273
288
  local_path: capistrano_nomad_build_local_job_path(file_basename, *args),
274
289
  remote_path: capistrano_nomad_build_release_job_path(name, *args),
275
290
  erb_vars: erb_vars,
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capistrano-nomad
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.5
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Hu
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-11-19 00:00:00.000000000 Z
11
+ date: 2023-11-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport