procsd 0.1.0 → 0.2.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: bb2d76f653bcd73538afe6175c6e910bf77bbe86930238bfd7ec53f2bef8e939
4
- data.tar.gz: 805808a883ea1f4c8ae03a01a390dda70729dea2a948e16e24c2b392791fa7cb
3
+ metadata.gz: 2c4a1dba4f8d57cec70cebb0cffd95d3f6e51ab256f534790bac042ec11078e2
4
+ data.tar.gz: 40ca2c7432f1ab690c61b073d305245a2b74e957627cd286907ee0e5c1ca3c61
5
5
  SHA512:
6
- metadata.gz: 4e8e6057f5bc9d8a3d466a7f57fb958f0335812a11412ab1b71ef4fa4ea3a77afe37b4d49725f2c144014afcd1ede0f218fc1c3165dbf10df7608c6763848543
7
- data.tar.gz: 32559bb91e97ed3cc238849b5bbc55609cafb27bd0ae25414cdf9fcf91e6205a35b0b6cec65fd9b6339fb153bc5eb8e5a8cfdc3851296bb8df9dad7ae00e6cb1
6
+ metadata.gz: ecbf43025ab6387543cec6775655575af81cb12f590828f4f00fbf5261444d3e06427c252f095fd943493963822f703f87532fe4c8ff7afb6b8c2c8c139cf8e8
7
+ data.tar.gz: 01c8d0561473679da4dcae1203fccf4f8168b72c9e298719459eba1ca4774e934b2c32db3e3536ed6a1d4a40361d264019042f5e73a7f93656da9b5cbb5f6c23
data/CHANGELOG.md ADDED
@@ -0,0 +1,9 @@
1
+ # CHANGELOG
2
+ ## 0.2.0
3
+ * Allow to use erb inside .procsd.yml
4
+ * Add dotenv support
5
+ * Add VERBOSE option to print commands before execution
6
+ * Implement option to provide restart/stop commands in the Procfile (extended syntax)
7
+ * Add list command
8
+ * Add sudo to `status` and `logs` commands to show system messages as well
9
+ * Add --short option to the `status` command
data/README.md CHANGED
@@ -28,9 +28,9 @@ environment:
28
28
  ```
29
29
  > The only required option in `.procsd.yml` is `app` (application's name). Also you can provide custom Systemd directory path (`systemd_dir` option, default is _/etc/systemd/system_)
30
30
 
31
+ Configuration is done.
31
32
 
32
-
33
- Configuration is done. Now it's time to **create** an application (export it to Systemd):
33
+ ### Create an application (export to Systemd)
34
34
  > To disable and remove application from Systemd there is command `$ procsd destroy`.
35
35
 
36
36
  > Note: `create` command needs to provide a few arguments: _--user_ (name of the current user), _--dir_ (application's working directory) and `--path` (user's $PATH). Usually it's fine to provide them like on example below:
@@ -49,8 +49,7 @@ Reloaded configuraion (daemon-reload)
49
49
  App services were created and enabled. Run `start` to start them
50
50
  ```
51
51
 
52
-
53
- **Start** application services:
52
+ ### Start application
54
53
  > Other control commands: `stop` and `restart`
55
54
 
56
55
  ```
@@ -60,7 +59,7 @@ Started app services (sample_app.target)
60
59
  ```
61
60
 
62
61
 
63
- Check the **status**:
62
+ ### Check the status
64
63
  > You can filter processes, like `$ procsd status worker` (show status only for worker processes) or `$ procsd status worker.2` (show status only for worker.2 process)
65
64
 
66
65
  > To show status of the main application target: `$ procsd status --target`
@@ -121,8 +120,18 @@ deploy@server:~/sample_app$ procsd status
121
120
  2018-11-04T01:54:17+0400 sample_app-worker.2[8827]: 2018-11-03T21:54:17.716Z 8827 TID-gniahzm1r INFO: Starting processing, hit Ctrl-C to stop
122
121
  ```
123
122
 
123
+ Also you can see status in a short format:
124
124
 
125
- Now the interesting part, **logs**:
125
+ ```
126
+ deploy@server:~/sample_app$ procsd status --short
127
+
128
+ sample_app-web.1.service loaded active running sample_app-web.1.service
129
+ sample_app-worker.1.service loaded active running sample_app-worker.1.service
130
+ sample_app-worker.2.service loaded active running sample_app-worker.2.service
131
+ ```
132
+
133
+
134
+ ### Check the logs
126
135
  > Like with command `status`, you can filter logs by passing the name of process as an argument: `$ procsd logs web` (show logs only for web processes, if any)
127
136
 
128
137
  ```
@@ -172,6 +181,7 @@ Commands:
172
181
  procsd disable # Disable app target
173
182
  procsd enable # Enable app target
174
183
  procsd help [COMMAND] # Describe available commands or one specific command
184
+ procsd list # List all app services
175
185
  procsd logs # Show app services logs
176
186
  procsd restart # Restart app services
177
187
  procsd start # Start app services
@@ -194,11 +204,37 @@ Procsd following one rule: simplicity. For export it uses static service files (
194
204
  ## Notes
195
205
 
196
206
  * If you want to set environment variables per process, [use format](https://github.com/ddollar/foreman/wiki/Per-Process-Environment-Variables) like Foreman recommends.
207
+ * To print commands before execution, provide env variable `VERBOSE=true` before procsd command. Example:
208
+
209
+ ```
210
+ deploy@server:~/sample_app$ VERBOSE=true procsd logs -n 3
211
+
212
+ > Executing command: journalctl --no-pager --all --no-hostname --output short-iso -n 3 --unit sample_app-web.1.service --unit sample_app-worker.1.service --unit sample_app-worker.2.service
213
+
214
+ -- Logs begin at Sun 2018-10-21 00:38:42 +04, end at Sun 2018-11-04 19:17:01 +04. --
215
+ 2018-11-04T19:11:59+0400 sample_app-worker.2[29907]: 2018-11-04T15:11:59.597Z 29907 TID-gne5aeyuz INFO: Upgrade to Sidekiq Pro for more features and support: http://sidekiq.org
216
+ 2018-11-04T19:11:59+0400 sample_app-worker.2[29907]: 2018-11-04T15:11:59.597Z 29907 TID-gne5aeyuz INFO: Booting Sidekiq 5.2.2 with redis options {:id=>"Sidekiq-server-PID-29907", :url=>nil}
217
+ 2018-11-04T19:11:59+0400 sample_app-worker.2[29907]: 2018-11-04T15:11:59.601Z 29907 TID-gne5aeyuz INFO: Starting processing, hit Ctrl-C to stop
218
+ ```
219
+ * You can use extended format of a Procfile to provide additional restart/stop commands for a process:
220
+ > Keep in mind that syntax below is not supported by Foreman or Heroku
221
+
222
+ > All possible options: `start`, `restart` and `stop`
223
+
224
+ ```yml
225
+ web:
226
+ start: bundle exec rails server -p $PORT
227
+ restart: bundle exec pumactl phased-restart
228
+ worker: bundle exec sidekiq -e production
229
+ ```
230
+
231
+ Why? For example default Ruby on Rails application server [Puma](http://puma.io/) supports [Phased or Rolling restart](https://github.com/puma/puma/blob/master/docs/restart.md#normal-vs-hot-vs-phased-restart) feature. If you provide separate `restart`command for a process, then this command will be called (`$ procsd restart`) by Systemd instead of just killing and starting process again.
232
+
197
233
 
198
234
  ## ToDo
199
235
  * Add Capistrano integration examples
200
236
  * Optional possibility to generate Ngnix config (with out-of-box SSL using [Certbot](https://certbot.eff.org/lets-encrypt/ubuntubionic-nginx)) for an application to use Ngnix as a proxy and serve static files
201
- * Add integration with [Inspeqtor](https://github.com/mperham/inspeqtor) to monitor application services and get alert notifications if someting happened
237
+ * Add integration with [Inspeqtor](https://github.com/mperham/inspeqtor) to monitor application services and get alert notifications if something happened
202
238
 
203
239
 
204
240
  ## License
data/exe/procsd CHANGED
File without changes
data/lib/procsd.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'dotenv/load'
1
2
  require 'thor'
2
3
  require 'procsd/version'
3
4
 
data/lib/procsd/cli.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'yaml'
2
+ require 'erb'
2
3
  require_relative 'generator'
3
4
 
4
5
  module Procsd
@@ -18,7 +19,7 @@ module Procsd
18
19
  gen.export!(services, procsd: @procsd, options: options)
19
20
 
20
21
  enable
21
- if system "sudo", "systemctl", "daemon-reload"
22
+ if execute %w(sudo systemctl daemon-reload)
22
23
  say("Reloaded configuraion (daemon-reload)", :green)
23
24
  end
24
25
 
@@ -39,12 +40,12 @@ module Procsd
39
40
  services.keys.push(target_name).each do |filename|
40
41
  path = File.join(systemd_dir, filename)
41
42
  if File.exist? path
42
- system "sudo", "rm", path
43
+ execute %W(sudo rm #{path})
43
44
  say "Deleted #{path}"
44
45
  end
45
46
  end
46
47
 
47
- if system "sudo", "systemctl", "daemon-reload"
48
+ if execute %w(sudo systemctl daemon-reload)
48
49
  say("Reloaded configuraion (daemon-reload)", :green)
49
50
  end
50
51
 
@@ -62,7 +63,7 @@ module Procsd
62
63
  if target_enabled?
63
64
  say "App target #{target_name} already enabled"
64
65
  else
65
- if system "sudo", "systemctl", "enable", target_name
66
+ if execute %W(sudo systemctl enable #{target_name})
66
67
  say("Enabled app target #{target_name}", :green)
67
68
  end
68
69
  end
@@ -76,7 +77,7 @@ module Procsd
76
77
  if !target_enabled?
77
78
  say "App target #{target_name} already disabled"
78
79
  else
79
- if system "sudo", "systemctl", "disable", target_name
80
+ if execute %W(sudo systemctl disable #{target_name})
80
81
  say("Disabled app target #{target_name}", :green)
81
82
  end
82
83
  end
@@ -90,7 +91,7 @@ module Procsd
90
91
  if target_active?
91
92
  say "Already started/active (#{target_name})"
92
93
  else
93
- if system "sudo", "systemctl", "start", target_name
94
+ if execute %W(sudo systemctl start #{target_name})
94
95
  say("Started app services (#{target_name})", :green)
95
96
  end
96
97
  end
@@ -104,7 +105,7 @@ module Procsd
104
105
  if !target_active?
105
106
  say "Already stopped/inactive (#{target_name})"
106
107
  else
107
- if system "sudo", "systemctl", "stop", target_name
108
+ if execute %W(sudo systemctl stop #{target_name})
108
109
  say("Stopped app services (#{target_name})", :green)
109
110
  end
110
111
  end
@@ -115,18 +116,34 @@ module Procsd
115
116
  preload!
116
117
  say_target_not_exists and return unless target_exist?
117
118
 
118
- if system "sudo", "systemctl", "restart", target_name
119
+ # If one of the child services of a target has `ExecReload` and `ReloadPropagatedFrom`
120
+ # options defined, then use `reload-or-restart` to call all services (not the main target)
121
+ # because https://github.com/systemd/systemd/issues/10638
122
+ success =
123
+ if services.any? { |_, command| command["restart"] }
124
+ execute %w(sudo systemctl reload-or-restart) + services.keys
125
+ else
126
+ execute %W(sudo systemctl restart #{target_name})
127
+ end
128
+
129
+ if success
119
130
  say("Restarted app services (#{target_name})", :green)
120
131
  end
121
132
  end
122
133
 
123
134
  desc "status", "Show app services status"
124
- option :target, type: :string, banner: "Show main target status"
135
+ option :target, type: :boolean, banner: "Show main target status"
136
+ option :short, type: :boolean, banner: "Show services three and their status shortly"
125
137
  def status(service_name = nil)
126
138
  preload!
127
139
  say_target_not_exists and return unless target_exist?
128
140
 
129
- command = %w(systemctl status --no-pager --output short-iso)
141
+ if options["short"]
142
+ command = %w(sudo systemctl list-units --no-pager --no-legend --all)
143
+ else
144
+ command = %w(sudo systemctl status --no-pager --output short-iso)
145
+ end
146
+
130
147
  if options["target"]
131
148
  command << target_name
132
149
  else
@@ -135,7 +152,7 @@ module Procsd
135
152
  command += filtered
136
153
  end
137
154
 
138
- system *command
155
+ execute command
139
156
  end
140
157
 
141
158
  desc "logs", "Show app services logs"
@@ -147,7 +164,7 @@ module Procsd
147
164
  def logs(service_name = nil)
148
165
  preload!
149
166
 
150
- command = %w(journalctl --no-pager --all --no-hostname --output short-iso)
167
+ command = %w(sudo journalctl --no-pager --all --no-hostname --output short-iso)
151
168
  command.push("-n", options.fetch("num", "100"))
152
169
  command.push("-f") if options["tail"]
153
170
  command.push("--system") if options["system"]
@@ -158,7 +175,15 @@ module Procsd
158
175
  say("Can't find any services matching given name: #{service_name}", :red) and return if filtered.empty?
159
176
 
160
177
  filtered.each { |service| command.push("--unit", service) }
161
- system *command
178
+ execute command
179
+ end
180
+
181
+ desc "list", "List all app services"
182
+ def list
183
+ preload!
184
+ say_target_not_exists and return unless target_exist?
185
+
186
+ execute %W(sudo systemctl list-dependencies #{target_name})
162
187
  end
163
188
 
164
189
  desc "--version, -v", "Print the version"
@@ -168,6 +193,11 @@ module Procsd
168
193
 
169
194
  private
170
195
 
196
+ def execute(command)
197
+ say("> Executing command: `#{command.join(' ')}`", :yellow) if ENV["VERBOSE"] == "true"
198
+ system *command
199
+ end
200
+
171
201
  def say_target_not_exists
172
202
  say("App target #{target_name} is not exists", :red)
173
203
  end
@@ -221,9 +251,19 @@ module Procsd
221
251
  raise ConfigurationError, ".procsd.yml config file doesn't exists" unless File.exist? ".procsd.yml"
222
252
 
223
253
  @procfile = YAML.load_file("Procfile")
224
- @procsd = YAML.load_file(".procsd.yml")
254
+ @procsd = YAML.load(ERB.new(File.read ".procsd.yml").result)
225
255
  raise ConfigurationError, "Missing app name in the .procsd.yml file" unless @procsd["app"]
226
256
 
257
+ @procfile.each do |process_name, process_command|
258
+ if process_command.kind_of?(Hash)
259
+ unless process_command["start"]
260
+ raise ConfigurationError, "Missing start command for #{process_name} process in the Procfile"
261
+ end
262
+ else
263
+ @procfile[process_name] = { "start" => process_command }
264
+ end
265
+ end
266
+
227
267
  if formation = @procsd["formation"]
228
268
  @procsd["formation"] = formation.split(",").map { |f| f.split("=") }.to_h
229
269
  @procsd["formation"].each { |k, v| @procsd["formation"][k] = v.to_i }
@@ -1,12 +1,22 @@
1
1
  [Unit]
2
2
  Requires=network.target
3
3
  PartOf=<%= config["target_name"] %>
4
+ <% if config["command"]["restart"] -%>
5
+ ReloadPropagatedFrom=<%= config["target_name"] %>
6
+ <% end -%>
4
7
 
5
8
  [Service]
6
9
  Type=simple
7
10
  User=<%= config["user"] %>
8
11
  WorkingDirectory=<%= config["dir"] %>
9
- ExecStart=/bin/bash -lc '<%= config["command"] %>'
12
+
13
+ ExecStart=/bin/bash -lc '<%= config["command"]["start"] %>'
14
+ <% if stop = config["command"]["stop"] -%>
15
+ ExecStop=/bin/bash -lc '<%= stop %>'
16
+ <% end -%>
17
+ <% if config["command"]["restart"] -%>
18
+ ExecReload=/bin/bash -lc '<%= config["command"]["restart"] %>'
19
+ <% end -%>
10
20
 
11
21
  Restart=always
12
22
  RestartSec=1
@@ -1,3 +1,3 @@
1
1
  module Procsd
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/procsd.gemspec CHANGED
@@ -25,6 +25,8 @@ Gem::Specification.new do |spec|
25
25
  spec.required_ruby_version = ">= 2.3.0"
26
26
 
27
27
  spec.add_dependency "thor"
28
+ spec.add_dependency "dotenv"
29
+
28
30
  spec.add_development_dependency "bundler", "~> 1.16"
29
31
  spec.add_development_dependency "rake", "~> 10.0"
30
32
  spec.add_development_dependency "minitest", "~> 5.0"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: procsd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Victor Afanasev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-11-04 00:00:00.000000000 Z
11
+ date: 2018-11-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: dotenv
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'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: bundler
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -75,6 +89,7 @@ extensions: []
75
89
  extra_rdoc_files: []
76
90
  files:
77
91
  - ".gitignore"
92
+ - CHANGELOG.md
78
93
  - Gemfile
79
94
  - LICENSE.txt
80
95
  - README.md