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 +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +43 -7
- data/exe/procsd +0 -0
- data/lib/procsd.rb +1 -0
- data/lib/procsd/cli.rb +54 -14
- data/lib/procsd/templates/service.erb +11 -1
- data/lib/procsd/version.rb +1 -1
- data/procsd.gemspec +2 -0
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2c4a1dba4f8d57cec70cebb0cffd95d3f6e51ab256f534790bac042ec11078e2
|
4
|
+
data.tar.gz: 40ca2c7432f1ab690c61b073d305245a2b74e957627cd286907ee0e5c1ca3c61
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
-
|
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
|
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
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
|
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
|
-
|
43
|
+
execute %W(sudo rm #{path})
|
43
44
|
say "Deleted #{path}"
|
44
45
|
end
|
45
46
|
end
|
46
47
|
|
47
|
-
if
|
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
|
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
|
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
|
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
|
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
|
-
|
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: :
|
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
|
-
|
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
|
-
|
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
|
-
|
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.
|
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
|
-
|
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
|
data/lib/procsd/version.rb
CHANGED
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.
|
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-
|
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
|