capistrano-nomad 0.6.5 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
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