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 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