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