sv 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
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: []