sv 0.0.5

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fc419ac67937b89b2a0519205e4b38b6346d73b5
4
+ data.tar.gz: 29b88973f788938d4410b970778806da8b9fe7a7
5
+ SHA512:
6
+ metadata.gz: 7622979c1a4afe44cded6315fda8f98c9368e98779edb7776b2c6e13c4bc9d50697fd07fff902b0bb623d9beee65917db38914416f01a1b22f2431ae7f3dcfdc
7
+ data.tar.gz: b661919407a5a9f97a22bf1ce23cc79cc2073008206f187e9b4b694ef9ab7efb4c941462ffd71e5a8de529d22b41f4ea195251967f9623e293fae1bb095876de
data/.gitignore ADDED
@@ -0,0 +1,34 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Specific to RubyMotion:
13
+ .dat*
14
+ .repl_history
15
+ build/
16
+
17
+ ## Documentation cache and generated files:
18
+ /.yardoc/
19
+ /_yardoc/
20
+ /doc/
21
+ /rdoc/
22
+
23
+ ## Environment normalisation:
24
+ /.bundle/
25
+ /lib/bundler/man/
26
+
27
+ # for a library or gem, you might want to ignore these files since the code is
28
+ # intended to run in multiple environments; otherwise, check them in:
29
+ # Gemfile.lock
30
+ # .ruby-version
31
+ # .ruby-gemset
32
+
33
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
34
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in sv.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Neeraj
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Sv
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'sv'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install sv
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it ( https://github.com/[my-github-username]/sv/fork )
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/bin/sv ADDED
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env ruby
2
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
3
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
4
+
5
+ Signal.trap("INT") { exit 1 }
6
+
7
+ require 'optparse'
8
+ require 'sv/error'
9
+ require 'sv/version'
10
+ require 'sv/logger'
11
+ require 'pathname'
12
+ require 'sv/cli/server'
13
+
14
+ logger = ::Sv::Logger.logger
15
+ options = {}
16
+
17
+ opts_parser = OptionParser.new do |opts|
18
+
19
+ banner = []
20
+ banner << "Usage: sv [global options] command [options] args"
21
+ banner << "Commands: start stop start restart status print-config"
22
+
23
+ opts.banner = banner.join("\n")
24
+
25
+ opts.on("-d", "--app-dir [APP DIR]" , "Set app dir") do |d|
26
+ path = Pathname.new(d)
27
+ raise ::Sv::Error, "app_dir path must be absolute" if path.relative?
28
+ options[:app_dir] = path
29
+ end
30
+
31
+ opts.on("-v", "--version", "Show version") do |v|
32
+ puts ::Sv::VERSION
33
+ exit
34
+ end
35
+
36
+ opts.on("--debug", "Show debug messages") do
37
+ options[:debug] = true
38
+ logger.level = ::Logger::DEBUG
39
+ end
40
+
41
+ opts.on("--trace", "Show debug messages and exception stack trace") do
42
+ options[:debug] = true
43
+ options[:trace] = true
44
+ logger.level = ::Logger::DEBUG
45
+ end
46
+
47
+ opts.on_tail("-h", "--help", "Show this message") do
48
+ puts opts
49
+ exit
50
+ end
51
+ end
52
+
53
+ begin
54
+ opts_parser.order!(ARGV)
55
+ app_dir = options[:app_dir] || Dir.pwd
56
+
57
+ if ARGV.size == 0
58
+ puts opts_parser
59
+ exit
60
+ end
61
+ cli = ::Sv::Cli::Server.new(app_dir, argv: ARGV.dup)
62
+ cli.run
63
+
64
+ rescue OptionParser::InvalidOption, OptionParser::MissingArgument, ::Sv::Error => e
65
+ cause = e.cause
66
+ if options[:trace]
67
+ puts cause
68
+ cause ? (raise cause) : (raise e)
69
+ else
70
+ logger.debug "#{cause.message}" if cause
71
+ logger.error "#{e.message}"
72
+ abort
73
+ end
74
+ end
data/lib/sv/api.rb ADDED
@@ -0,0 +1,111 @@
1
+ require 'sv/base'
2
+ require 'sv/error'
3
+ require 'sv/ext/net_http'
4
+ require 'xmlrpc/client'
5
+ require 'ostruct'
6
+
7
+ module Sv
8
+ class Api < ::Sv::Base
9
+
10
+ attr_reader :socket_path
11
+
12
+ def initialize(socket_path)
13
+ @socket_path = socket_path
14
+ end
15
+
16
+ def start_jobs(wait: true)
17
+ wait ? start_jobs_in_foreground : start_jobs_in_background
18
+ end
19
+
20
+ def shutdown
21
+ call "supervisor.shutdown"
22
+ close_connection
23
+ end
24
+
25
+ def start_job(group, name)
26
+ call "supervisor.startProcess", "#{group}:#{name}"
27
+ end
28
+
29
+ def stop_job(group, name)
30
+ call "supervisor.stopProcess" if not job_stopped?(group, name)
31
+ rescue XMLRPC::FaultException => e
32
+ return true if e.faultString == "NOT_RUNNING"
33
+ raise e
34
+ end
35
+
36
+ def job_stopped?(group, name)
37
+ job = call "supervisor.getProcessInfo", "#{group}:#{name}"
38
+ job["state"] == 0 ? true : false
39
+ end
40
+
41
+ def pid
42
+ call "supervisor.getPID"
43
+ end
44
+
45
+ def print_status
46
+ puts "pid #{pid}"
47
+ jobs = self.jobs
48
+ name_width = jobs.map { |j| j.name.size }.max
49
+ template = "%-#{name_width}s %-10s %-7s %-20s\n"
50
+ printf template, "name", "state", "pid", "uptime"
51
+ puts "-"*(name_width + 10 + 7 + 20 + 2)
52
+ jobs.each do |job|
53
+ logger.debug { require 'pp'; PP.pp job.to_h, out="" ; out }
54
+ printf template, job.name, job.statename, job.pid, uptime(job.start)
55
+ end
56
+ end
57
+
58
+ def start_jobs_in_background
59
+ call "supervisor.startAllProcesses", "wait=false"
60
+ end
61
+
62
+ def start_jobs_in_foreground
63
+ jobs.each do |j|
64
+ printf "#{j.name}: starting"
65
+ start_job j.group, j.name
66
+ puts "\r#{j.name}: started "
67
+ end
68
+ end
69
+
70
+ def jobs
71
+ jobs_array = call "supervisor.getAllProcessInfo"
72
+ jobs = jobs_array.map { |j| OpenStruct.new(j) }
73
+ end
74
+
75
+ def close_connection
76
+ @rpc = nil
77
+ end
78
+
79
+
80
+ private
81
+
82
+ def rpc
83
+ @rpc ||= ::XMLRPC::Client.new(socket_path, "/RPC2")
84
+ end
85
+
86
+ def call(*args)
87
+ output = rpc.call(*args)
88
+ return output
89
+ rescue XMLRPC::FaultException => e
90
+ puts
91
+ puts e.message
92
+ raise ::Sv::Error, "error running command #{args[0]}"
93
+ end
94
+
95
+ def uptime(started_at)
96
+ return "-" if started_at.to_i == 0
97
+ uptime = (Time.now.to_i - started_at).to_i
98
+ mm, ss = uptime.divmod(60)
99
+ hh, mm = mm.divmod(60)
100
+ dd, hh = hh.divmod(24)
101
+ if dd == 1
102
+ "%d day, %02d::%02d::%02d" % [dd, hh, mm, ss]
103
+ elsif dd > 1
104
+ "%d days, %02d::%02d::%02d" % [dd, hh, mm, ss]
105
+ else
106
+ "%02d::%02d::%02d" % [hh, mm, ss]
107
+ end
108
+ end
109
+
110
+ end
111
+ end
data/lib/sv/base.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'sv/logger'
2
+ module Sv
3
+ class Base
4
+ include ::Sv::Logger
5
+
6
+ def process_running?
7
+ return false if pid <= 0
8
+ Process.getpgid pid
9
+ return true
10
+ rescue Errno::ESRCH
11
+ return false
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,69 @@
1
+ require 'sv/server'
2
+
3
+ module Sv::Cli
4
+
5
+ class Server
6
+
7
+ attr_reader :app_dir, :argv
8
+
9
+ def initialize(app_dir, argv: ARGV)
10
+ @app_dir = app_dir
11
+ @argv = argv
12
+ end
13
+
14
+ def run
15
+ opts.parse!(argv)
16
+ command = argv.shift.to_sym
17
+ case command
18
+ when :start, :restart
19
+ server.send command, auto_start: options[:auto_start], wait: options[:wait]
20
+ when :'print-config'
21
+ server.send :print_config
22
+ when :stop, :status
23
+ server.send command
24
+ when :help
25
+ help argv.shift
26
+ else
27
+ raise ::Sv::Error, "no such command #{command}"
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def help(command)
34
+ command = command.to_sym if command
35
+ case command
36
+ when :start, :restart
37
+ banner = []
38
+ banner << "sv [global options] #{command} [options]"
39
+ banner = banner.join("\n")
40
+ opts.banner = banner
41
+ puts opts
42
+ else
43
+ puts "no help available for command: #{command}"
44
+ end
45
+ end
46
+
47
+ def server
48
+ @server ||= ::Sv::Server.new(app_dir)
49
+ end
50
+
51
+ def opts
52
+ @opts ||= OptionParser.new do |opts|
53
+ opts.on("-a", "--auto-start" , "auto start jobs") do
54
+ options[:auto_start] = true
55
+ end
56
+
57
+ opts.on("-w", "--wait" , "wait for jobs to start successfully") do
58
+ options[:wait] = true
59
+ end
60
+ end
61
+ end
62
+
63
+ def options
64
+ @options ||= {}
65
+ end
66
+
67
+ end
68
+
69
+ end
data/lib/sv/config.rb ADDED
@@ -0,0 +1,102 @@
1
+ require 'sv/logger'
2
+ require 'sv/error'
3
+ require 'sv/job'
4
+
5
+ module Sv
6
+ class Config
7
+ include Logger
8
+
9
+ attr_reader :app_dir
10
+
11
+ def initialize(app_dir)
12
+ @app_dir = app_dir
13
+ @instances = {}
14
+ @working_dir = app_dir
15
+ end
16
+
17
+ def socket_path
18
+ @socket_path ||= "#{app_dir}/tmp/sockets/supervisor.sock"
19
+ end
20
+
21
+ def pidfile
22
+ @pidfile ||= "#{app_dir}/tmp/pids/supervisor.pid"
23
+ end
24
+
25
+ def logfile
26
+ @logfile ||= "#{app_dir}/log/supervisord.log"
27
+ end
28
+
29
+ def jobs
30
+ @jobs ||= begin
31
+ load_from_file
32
+ jobs_map.values
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def jobs_map
39
+ @jobs_map ||= {}
40
+ end
41
+
42
+ def instances(instances_map)
43
+ @instances = instances_map
44
+ end
45
+
46
+ def job(name, &block)
47
+ name = name.to_sym
48
+ j = jobs_map[name] || Job.new(name)
49
+ j.instance_eval &block
50
+ jobs_map[name] = j
51
+ end
52
+
53
+ def working_dir(working_dir)
54
+ @working_dir = working_dir
55
+ end
56
+
57
+ def load_from_file
58
+ load_jobs("#{app_dir}/config/jobs.yml", optional: true)
59
+ read_config("#{app_dir}/config/jobs.rb", optional: true)
60
+ read_config("#{app_dir}/config/sv.rb")
61
+ set_instances
62
+ set_working_dir
63
+ end
64
+
65
+
66
+ def set_instances
67
+ jobs_map.each do |name, job|
68
+ job.numprocs @instances[name] if @instances.key? name
69
+ end
70
+ end
71
+
72
+ def set_working_dir
73
+ jobs_map.values.each do |job|
74
+ job.working_dir || job.working_dir(@working_dir)
75
+ end
76
+ end
77
+
78
+ def read_config(path, optional: false)
79
+ if not File.readable? path
80
+ raise ::Sv::Error, "config file #{path} missing" if not optional
81
+ return
82
+ end
83
+ instance_eval File.read(path), path
84
+ end
85
+
86
+ def load_jobs(path, optional: false)
87
+ if not File.readable? path
88
+ raise ::Sv::Error, "config file #{path} missing" if not optional
89
+ return
90
+ end
91
+ require 'yaml'
92
+ job_definitions = YAML.load_file(path)
93
+ job_definitions.each do |j|
94
+ name = j['name'].to_sym
95
+ job = Job.new(name)
96
+ job.update(j)
97
+ jobs_map[name] = job
98
+ end
99
+ end
100
+
101
+ end
102
+ end
@@ -0,0 +1,25 @@
1
+ require 'logger'
2
+ require 'sv/ext/string'
3
+ module Sv
4
+ class CustomLogger < ::Logger
5
+
6
+ def initialize(file)
7
+ super(file)
8
+ @level = ::Logger::INFO
9
+ end
10
+
11
+ def format_message(severity, timestamp, progname, msg)
12
+ case severity
13
+ when "INFO"
14
+ "#{msg}\n"
15
+ when "ERROR"
16
+ "#{severity.bold.red} #{msg}\n"
17
+ when "WARN"
18
+ "#{severity.downcase.bold.yellow} #{msg}\n"
19
+ else
20
+ "#{severity.downcase.bold.blue} #{msg}\n"
21
+ end
22
+ end
23
+
24
+ end
25
+ end
data/lib/sv/error.rb ADDED
@@ -0,0 +1,4 @@
1
+ module Sv
2
+ class Error < StandardError
3
+ end
4
+ end
@@ -0,0 +1,19 @@
1
+ require 'net/http'
2
+ require 'pathname'
3
+
4
+ module Net
5
+ class HTTP
6
+ alias_method :orig_connect, :connect
7
+
8
+ def connect
9
+ path = Pathname.new(address)
10
+ if path.exist?
11
+ @socket = Net::BufferedIO.new UNIXSocket.new address
12
+ on_connect
13
+ else
14
+ orig_connect
15
+ end
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,29 @@
1
+ class String
2
+ def colorize(color_code)
3
+ "\e[#{color_code}m#{self}\e[0m"
4
+ end
5
+
6
+ def bold
7
+ "\e[1m#{self}\e[0m"
8
+ end
9
+
10
+ def white
11
+ colorize(37)
12
+ end
13
+
14
+ def green
15
+ colorize(32)
16
+ end
17
+
18
+ def yellow
19
+ colorize(33)
20
+ end
21
+
22
+ def red
23
+ colorize(31)
24
+ end
25
+
26
+ def blue
27
+ colorize(34)
28
+ end
29
+ end
data/lib/sv/job.rb ADDED
@@ -0,0 +1,139 @@
1
+ module Sv
2
+ class Job
3
+
4
+ attr_reader :name
5
+ attr_writer :working_dir
6
+
7
+ def initialize(name)
8
+ set :name, name
9
+ end
10
+
11
+ def name
12
+ attributes.fetch :name
13
+ end
14
+
15
+ def command(*args)
16
+ set_or_get :command, args
17
+ end
18
+
19
+ def working_dir(*args)
20
+ set_or_get :working_dir, args
21
+ end
22
+
23
+ def env(*args)
24
+ set_or_get :env, args
25
+ end
26
+
27
+ def numprocs(*args)
28
+ set_or_get :numprocs, args do |v|
29
+ v.to_i
30
+ end
31
+ end
32
+
33
+ def autorestart(*args)
34
+ set_or_get :autorestart, args
35
+ end
36
+
37
+ def startsecs(*args)
38
+ set_or_get :startsecs, args
39
+ end
40
+
41
+ def startretries(*args)
42
+ set_or_get :startretries, args
43
+ end
44
+
45
+ def stopsignal(*args)
46
+ set_or_get :stopsignal, args
47
+ end
48
+
49
+ def stopwaitsecs(*args)
50
+ set_or_get :stopwaitsecs, args
51
+ end
52
+
53
+ def killasgroup(*args)
54
+ set_or_get :killasgroup, args
55
+ end
56
+
57
+ def redirect_stderr(*args)
58
+ set_or_get :redirect_stderr, args
59
+ end
60
+
61
+ def stdout_logfile(*args)
62
+ set_or_get :stdout_logfile, args
63
+ end
64
+
65
+ def stderr_logfile(*args)
66
+ set_or_get :stderr_logfile, args
67
+ end
68
+
69
+ def update(attrs)
70
+ attrs.each do |key ,value|
71
+ set key, value
72
+ end
73
+ end
74
+
75
+ def render
76
+ return if not attributes.values.all?
77
+ return if attributes[:numprocs] < 1
78
+ File.open(template) do |f|
79
+ erb = ERB.new(f.read, nil, '-')
80
+ erb.result(binding)
81
+ end
82
+ end
83
+
84
+ private
85
+
86
+ def attributes
87
+ @attributes ||= {
88
+ name: nil,
89
+ command: nil,
90
+ working_dir: nil,
91
+ env: "",
92
+ numprocs: 0,
93
+ autorestart: true,
94
+ startsecs: 1,
95
+ startretries: 3,
96
+ stopsignal: :TERM,
97
+ stopwaitsecs: 10,
98
+ killasgroup: true,
99
+ redirect_stderr: true,
100
+ stdout_logfile: "/dev/null",
101
+ stderr_logfile: "/dev/null"
102
+ }
103
+ end
104
+
105
+ def set_or_get(key, args)
106
+ key = key.to_sym
107
+ if args.length == 0
108
+ return attributes.fetch key
109
+ else
110
+ value = args.first
111
+ if block_given?
112
+ value = yield value
113
+ end
114
+ set key, value
115
+ end
116
+ end
117
+
118
+ def set(key, value)
119
+ key = key.to_sym
120
+ if attributes.key? key
121
+ attributes.store key, value
122
+ else
123
+ raise "no such key #{key}"
124
+ end
125
+ end
126
+
127
+
128
+ def template
129
+ @template ||= Pathname.new("#{__dir__}/templates/job.erb")
130
+ end
131
+
132
+ def binding
133
+ attrs = OpenStruct.new(attributes)
134
+ attrs.instance_eval { binding }
135
+ end
136
+
137
+ end
138
+ end
139
+
data/lib/sv/logger.rb ADDED
@@ -0,0 +1,22 @@
1
+ require 'logger'
2
+ require 'sv/custom_logger'
3
+ module Sv
4
+ module Logger
5
+
6
+ def self.logger
7
+ @logger ||= ::Sv::CustomLogger.new(STDOUT)
8
+ end
9
+
10
+ def self.stderr
11
+ @stderr ||= ::Logger.new(STDERR)
12
+ end
13
+
14
+ def logger
15
+ ::Sv::Logger.logger
16
+ end
17
+
18
+ def stderr
19
+ ::Sv::Logger.stderr
20
+ end
21
+ end
22
+ end
data/lib/sv/server.rb ADDED
@@ -0,0 +1,97 @@
1
+ require 'sv/config'
2
+ require 'sv/api'
3
+ require 'sv/supervisor/config'
4
+ require 'sv/status'
5
+
6
+ module Sv
7
+ class Server
8
+
9
+ attr_reader :app_dir
10
+
11
+ def initialize(app_dir)
12
+ @app_dir = app_dir
13
+ end
14
+
15
+ def start(auto_start: false, wait: false)
16
+ init_once
17
+ if server_status.running?
18
+ puts "supervisor already running with pid #{api.pid}"
19
+ return
20
+ end
21
+ system "supervisord -c #{supervisor_config.generated_path}"
22
+ puts "Started"
23
+ api.start_jobs(wait: wait) if auto_start
24
+ end
25
+
26
+ def stop
27
+ init_once
28
+ if server_status.stopped?
29
+ puts "Stopped"
30
+ return
31
+ end
32
+ api.shutdown
33
+ server_status.wait_until_stopped
34
+ puts "Stopped"
35
+ end
36
+
37
+ def restart(auto_start: false, wait: false)
38
+ stop if server_status.running?
39
+ start auto_start: auto_start, wait: wait
40
+ end
41
+
42
+ def start_jobs
43
+ api.start_jobs
44
+ puts api.errors
45
+ end
46
+
47
+ def status
48
+ if server_status.running?
49
+ api.print_status
50
+ else
51
+ puts "Stopped"
52
+ end
53
+ end
54
+
55
+ def print_config
56
+ puts File.read(supervisor_config.generated_path)
57
+ end
58
+
59
+ def required_paths
60
+ paths = [
61
+ "#{app_dir}/tmp/sockets/",
62
+ "#{app_dir}/tmp/pids/",
63
+ "#{app_dir}/log/"
64
+ ]
65
+ paths.each do |path|
66
+ path = Pathname.new(path)
67
+ raise ::Sv::Error, "required path missing #{path}" if not path.exist?
68
+ end
69
+ end
70
+
71
+ private
72
+
73
+ def config
74
+ @config ||= ::Sv::Config.new(app_dir)
75
+ end
76
+
77
+ def api
78
+ @api ||= ::Sv::Api.new(config.socket_path)
79
+ end
80
+
81
+ def server_status
82
+ @server_status ||= ::Sv::Status.new(config.socket_path)
83
+ end
84
+
85
+ def supervisor_config
86
+ @supervisor_config ||= ::Sv::Supervisor::Config.new(config)
87
+ end
88
+
89
+ def init_once
90
+ @init_once ||= begin
91
+ required_paths
92
+ true
93
+ end
94
+ end
95
+
96
+ end
97
+ end
data/lib/sv/status.rb ADDED
@@ -0,0 +1,32 @@
1
+ require 'socket'
2
+
3
+ module Sv
4
+ class Status
5
+
6
+ attr_reader :socket_path
7
+
8
+ def initialize(socket_path)
9
+ @socket_path = socket_path
10
+ end
11
+
12
+ def running?
13
+ s = UNIXSocket.new(socket_path)
14
+ s.close
15
+ return true
16
+ rescue Errno::ECONNREFUSED, Errno::ENOENT
17
+ return false
18
+ end
19
+
20
+ def stopped?
21
+ not running?
22
+ end
23
+
24
+ def wait_until_stopped
25
+ loop do
26
+ break if not running?
27
+ sleep 0.1
28
+ end
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,62 @@
1
+ require 'erb'
2
+ require 'ostruct'
3
+ require 'sv/logger'
4
+
5
+ module Sv::Supervisor
6
+ class Config
7
+
8
+ include ::Sv::Logger
9
+ attr_reader :config
10
+
11
+ def initialize(config)
12
+ @config = config
13
+ end
14
+
15
+ def path
16
+ "#{config.app_dir}/tmp/supervisor.conf"
17
+ end
18
+
19
+ def generated_path
20
+ generate_once
21
+ path
22
+ end
23
+
24
+ def generate_config_file
25
+ erb = ERB.new(File.read(template), nil, '-')
26
+ File.open(path, 'w') do |f|
27
+ f.write erb.result(binding)
28
+ end
29
+ rescue => e
30
+ raise ::Sv::Error, "unable to generate supervisor config"
31
+ end
32
+
33
+ def generate_once
34
+ return if @config_generated
35
+ generate_config_file
36
+ @config_generated = true
37
+ end
38
+
39
+ def template
40
+ "#{__dir__}/../templates/supervisor.conf.erb"
41
+ end
42
+
43
+ def rendered_jobs
44
+ jobs = config.jobs
45
+ jobs.inject("") do |str, job|
46
+ render = job.render
47
+ str << render if render
48
+ str
49
+ end
50
+ end
51
+
52
+ def binding
53
+ opts = OpenStruct.new
54
+ opts.socket_path = config.socket_path
55
+ opts.pidfile = config.pidfile
56
+ opts.logfile = config.logfile
57
+ opts.rendered_jobs = rendered_jobs
58
+ opts.instance_eval { binding }
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,19 @@
1
+ [program:<%= name %>]
2
+ process_name=%(program_name)s_%(process_num)02d
3
+ command=<%= command %>
4
+ directory=<%= working_dir %>
5
+ numprocs=<%= numprocs %>
6
+ autostart=false
7
+ autorestart=<%= autorestart %>
8
+ startsecs=<%= startsecs %>
9
+ startretries=<%= startretries %>
10
+ stopsignal=<%= stopsignal %>
11
+ stopwaitsecs=<%= stopwaitsecs %>
12
+ killasgroup=<%= killasgroup %>
13
+ <% if redirect_stderr -%>
14
+ redirect_stderr=<%= redirect_stderr %>
15
+ <% end -%>
16
+ stdout_logfile=<%= stdout_logfile %>
17
+ stderr_logfile=<%= stderr_logfile %>
18
+ environment=<%= env %>
19
+
@@ -0,0 +1,15 @@
1
+ [unix_http_server]
2
+ file=<%= socket_path %>
3
+
4
+ [supervisord]
5
+ logfile=<%= logfile %>
6
+ loglevel=info
7
+ pidfile=<%= pidfile %>
8
+
9
+ [rpcinterface:supervisor]
10
+ supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
11
+
12
+ [supervisorctl]
13
+ serverurl=unix://<%= socket_path %>
14
+
15
+ <%= rendered_jobs %>
data/lib/sv/version.rb ADDED
@@ -0,0 +1,3 @@
1
+ module Sv
2
+ VERSION = "0.0.5"
3
+ end
data/lib/sv.rb ADDED
@@ -0,0 +1,5 @@
1
+ require "sv/version"
2
+
3
+ module Sv
4
+ # Your code goes here...
5
+ end
data/sv.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'sv/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "sv"
8
+ spec.version = Sv::VERSION
9
+ spec.authors = ["Neeraj"]
10
+ spec.email = ["neeraj.bhunwal@gmail.com"]
11
+ spec.summary = %q{A wrapper for supervisord}
12
+ spec.description = %q{A wrapper for supervisord}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency "rake"
23
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sv
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.5
5
+ platform: ruby
6
+ authors:
7
+ - Neeraj
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: A wrapper for supervisord
42
+ email:
43
+ - neeraj.bhunwal@gmail.com
44
+ executables:
45
+ - sv
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ".gitignore"
50
+ - Gemfile
51
+ - LICENSE.txt
52
+ - README.md
53
+ - Rakefile
54
+ - bin/sv
55
+ - lib/sv.rb
56
+ - lib/sv/api.rb
57
+ - lib/sv/base.rb
58
+ - lib/sv/cli/server.rb
59
+ - lib/sv/config.rb
60
+ - lib/sv/custom_logger.rb
61
+ - lib/sv/error.rb
62
+ - lib/sv/ext/net_http.rb
63
+ - lib/sv/ext/string.rb
64
+ - lib/sv/job.rb
65
+ - lib/sv/logger.rb
66
+ - lib/sv/server.rb
67
+ - lib/sv/status.rb
68
+ - lib/sv/supervisor/config.rb
69
+ - lib/sv/templates/job.erb
70
+ - lib/sv/templates/supervisor.conf.erb
71
+ - lib/sv/version.rb
72
+ - sv.gemspec
73
+ homepage: ''
74
+ licenses:
75
+ - MIT
76
+ metadata: {}
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubyforge_project:
93
+ rubygems_version: 2.2.2
94
+ signing_key:
95
+ specification_version: 4
96
+ summary: A wrapper for supervisord
97
+ test_files: []