winter 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -13,6 +13,9 @@
13
13
  # under the License.
14
14
 
15
15
  require 'winter/logger'
16
+ require 'fileutils'
17
+ require 'digest/md5'
18
+ require 'net/http'
16
19
 
17
20
  module Winter
18
21
 
@@ -37,15 +40,100 @@ module Winter
37
40
  @verbose = false
38
41
  @destination = '.'
39
42
  end
43
+
44
+ def get
45
+ if ! File.directory?(@destination)
46
+ $LOG.debug "Create the destination folder if its not already there."
47
+ FileUtils.mkdir_p @destination
48
+ end
49
+ #Try and get file in a couple different ways. If we succeed then move on.
50
+ #Artifacts in your local .m2 ALWAYS take precedence over a remote artifact...
51
+ #Unless we fail so hard we end up using mvn as a last ditched effort.
52
+ success = getLocalM2
53
+ success = getRestArtifactory if ! success and ! @offline
54
+ success = getMaven if ! success and system( 'which mvn > /dev/null' )
55
+ if ! success
56
+ $LOG.info "[failed] #{outputFilename}"
57
+ end
58
+ return success
59
+ end
60
+
61
+ def artifactory_path
62
+ "#{@group.gsub(/\./,'/')}/#{@artifact}/#{@version}/#{@artifact}-#{@version}.#{@package}"
63
+ end
40
64
 
41
- def getMaven
42
- dest_file = File.join(@destination,outputFilename)
65
+ def dest_file
66
+ File.join(@destination,outputFilename)
67
+ end
68
+
69
+ def restRequest(uri)
70
+ response = Net::HTTP.get_response(uri)
71
+ return response.body if response.is_a?(Net::HTTPSuccess)
72
+ $LOG.debug "#{outputFilename}: Rest request to #{uri.inspect} #{response.inspect}"
73
+ raise "Rest request got a bad response code back [#{response.code}]"
74
+ end
75
+
76
+ def getRestArtifactory
77
+ log_prefix = '[remote] '
78
+ $LOG.debug "#{log_prefix}#{outputFilename}: Attempting to fetch via the artifactory rest api."
79
+ #Loop through all the repos until something works
80
+ @repositories.each { |repo|
81
+ begin
82
+ open(dest_file,"wb") { |file|
83
+ file.write(restRequest(URI.parse("#{repo}/#{artifactory_path}")))
84
+ }
85
+ rescue SocketError,RuntimeError => e # :( Maybe do better handling later.
86
+ $LOG.error "#{log_prefix}#{outputFilename}: Unable to fetch Artifact from #{repo}/#{artifactory_path}"
87
+ $LOG.debug e
88
+ next
89
+ end
90
+ #Check to make sure the md5sum of what we downloaded matches what's in the artifactory.
91
+ begin
92
+ artifactory_md5 = restRequest(URI.parse("#{repo}/#{artifactory_path}.md5"))
93
+ my_md5 = Digest::MD5.file("#{dest_file}").hexdigest
94
+ rescue SocketError, RuntimeError => e # :( Do better handling later.
95
+ $LOG.error "#{log_prefix}#{outputFilename}: Blew up while attempting to get md5s."
96
+ else
97
+ if artifactory_md5 == my_md5
98
+ $LOG.debug "#{log_prefix}#{outputFilename}: Successfully fetched via artifactory rest api."
99
+ $LOG.info "#{log_prefix}#{outputFilename}"
100
+ return true
101
+ end
102
+ $LOG.error "#{log_prefix}#{outputFilename}: Comparing remote MD5 #{artifactory_md5} to local md5 #{my_md5} (#{dest_file})"
103
+ $LOG.error "#{log_prefix}#{outputFilename}: Comparison failed. Deleting the 'bad' jar and moving on."
104
+ FileUtils.rm(dest_file)
105
+ end
106
+ }
107
+ return false
108
+ end
109
+
110
+ def getLocalM2
111
+ log_prefix = "[local] "
112
+ begin
113
+ artifact = "#{ENV["HOME"]}/.m2/repository/#{artifactory_path}"
114
+ $LOG.debug "#{log_prefix}#{outputFilename}: Copying #{artifact} to #{dest_file}"
115
+ FileUtils.cp(artifact,dest_file)
116
+ rescue Errno::ENOENT
117
+ $LOG.debug "#{log_prefix}#{outputFilename}: #{artifact} does not exist."
118
+ rescue SystemCallError => e
119
+ $LOG.error "#{log_prefix}#{outputFilename}: Failed to copy file from local m2 repository."
120
+ $LOG.error e
121
+ else #Yay we got it
122
+ $LOG.debug "#{log_prefix}#{outputFilename}: Successfully copied from local m2 repository."
123
+ $LOG.info "#{log_prefix}#{outputFilename}"
124
+ return true
125
+ end
126
+ return false
127
+ end
43
128
 
129
+ #Depricated because its slow and expensive to use... leaving it here for now.
130
+ def getMaven
131
+ log_prefix = "[maven] "
44
132
  c = "mvn org.apache.maven.plugins:maven-dependency-plugin:2.5:get "
45
133
  c << " -DremoteRepositories=#{@repositories.join(',').shellescape}"
46
134
  c << " -Dtransitive=#{@transative}"
47
135
  c << " -Dartifact=#{@group.shellescape}:#{@artifact.shellescape}:#{@version.shellescape}:#{@package.shellescape}"
48
- c << " -Ddest=#{dest_file.shellescape}"
136
+ c << " -Ddest=#{dest_file.shellescape} &>/dev/null"
49
137
 
50
138
  if @offline
51
139
  c << " --offline"
@@ -56,13 +144,12 @@ module Winter
56
144
  c << " -q"
57
145
  end
58
146
 
59
- $LOG.debug c
60
147
  result = system( c )
61
148
  if result == false
62
- $LOG.error("Failed to retrieve artifact: #{@group}:#{@artifact}:#{@version}:#{@package}")
149
+ $LOG.error("#{log_prefix}#{outputFilename}: Failed to retrieve artifact. -- #{c}")
63
150
  else
64
- $LOG.info "#{@group}:#{@artifact}:#{@version}:#{@package}"
65
- $LOG.debug dest_file
151
+ $LOG.info "#{log_prefix}#{@group}:#{@artifact}:#{@version}:#{@package}"
152
+ $LOG.debug "#{log_prefix}#{dest_file}"
66
153
  end
67
154
  return result
68
155
  end
@@ -144,7 +144,9 @@ module Winter
144
144
  end
145
145
 
146
146
  def conf( dir )
147
- process_templates( dir, File.join(WINTERFELL_DIR,RUN_DIR,@name,'conf') )
147
+ #We strip off the final / to normalize the input.
148
+ #If we don't do that then process_templates will end up with crazy file names.
149
+ process_templates( dir.sub(/\/$/,""), File.join(WINTERFELL_DIR,RUN_DIR,@name,'conf') )
148
150
  end
149
151
 
150
152
  def read( file )
@@ -60,30 +60,32 @@ module Winter
60
60
  #I hate waiting so this is going to become faster.
61
61
  max_threads = 10 #make this configurable later.
62
62
  active_threads = 0
63
+ error = false
63
64
  Signal.trap("CHLD") do
64
65
  #Reap everything you possibly can.
65
66
  begin
66
- pid = waitpid(-1, Process::WNOHANG)
67
- #puts "reaped #{pid}" if pid
68
- active_threads -= 1 if pid
67
+ pid, status = waitpid2(-1, Process::WNOHANG)
68
+ if pid
69
+ active_threads -= 1
70
+ error = true if status.exitstatus > 0
71
+ end
69
72
  rescue Errno::ECHILD
70
73
  break
71
74
  end while pid
72
75
  end
73
76
 
74
- error = false
75
77
  dependencies.each do |dep|
76
78
  while (active_threads >= max_threads) do
77
79
  $LOG.debug "Total active threads: #{active_threads}"
78
- #$LOG.debug "threads: #{active_threads}"
79
80
  sleep 1
80
81
  end
81
- #File.join(@destination,"#{@artifact}-#{@version}.#{@package}")
82
82
  if !File.exists?(File.join(dep.destination,dep.outputFilename))
83
83
  active_threads += 1
84
84
  fork do
85
- result = dep.getMaven
86
- error = true if result == false
85
+ #Get the dependency and Vomit up an error code if we fail
86
+ #If we don't do this then the main proc has no idea the build
87
+ # was garbage
88
+ exit 1 unless dep.get
87
89
  end
88
90
  else
89
91
  $LOG.info "Already have #{dep.outputFilename}"
@@ -34,6 +34,7 @@ module Winter
34
34
  rescue Exception=>e
35
35
  $LOG.error "Could not fetch winter configuration from : #{url}"
36
36
  $LOG.debug e
37
+ exit(-1)
37
38
  end
38
39
 
39
40
  extract_jar file
@@ -61,6 +62,7 @@ module Winter
61
62
  rescue Exception=>e
62
63
  $LOG.error "#{file} is corrupt or invalid."
63
64
  $LOG.debug e
65
+ exit(-1)
64
66
  end
65
67
 
66
68
  cleanup file
@@ -70,86 +70,39 @@ module Winter
70
70
  @directives.merge! dsl[:directives]
71
71
 
72
72
  java_cmd = generate_java_invocation
73
- java_cmd << " > #{@config['console']} 2>&1"
73
+
74
+ if @config['daemonize']
75
+ java_cmd << " 2>&1 " #"don't eat the log thats evil"
76
+ else
77
+ java_cmd << " > #{@config['console']} 2>&1"
78
+ end
74
79
  $LOG.debug java_cmd
75
80
 
76
- # execute
81
+ #
77
82
  if( File.exists?(File.join(@service_dir, "pid")) )
78
83
  $LOG.error "PID file already exists. Is the process running?"
79
84
  exit
80
85
  end
81
- pid_file = File.open(File.join(@service_dir, "pid"), "w")
82
86
 
83
87
  # Normally, we'd just use Process.daemon for ruby 1.9, but for some
84
88
  # reason the OSGi container we're using crashes when the CWD is changed
85
89
  # to '/'. So, we'll just leave the CWD alone.
86
90
  #Process.daemon(Dir.getwd,nil)
87
-
91
+
92
+ exec(java_cmd) if @config['daemonize'] #Let the child eat winter so things are awesome for daemontools
93
+ #We never hit the past this point if we went to daemonize mode.
94
+
95
+ #If we're not trying to run as a daemon just fork and let the subprocess be eaten
88
96
  java_pid = fork do
89
97
  exec(java_cmd)
90
98
  end
91
99
 
100
+ pid_file = File.open(File.join(@service_dir, "pid"), "w")
92
101
  pid = java_pid
93
- pid = Process.pid if @config['daemonize']
94
102
  pid_file.write(pid)
95
103
  pid_file.close
96
104
 
97
105
  $LOG.info "Started #{@config['service']} (#{pid})"
98
-
99
- if( @config['daemonize'] )
100
- stay_resident(java_pid,winterfile)
101
- end
102
- end
103
-
104
- def stay_resident( child_pid, winterfile )
105
- interrupted = false
106
-
107
- #TERM, CONT STOP HUP ALRM INT and KILL
108
- Signal.trap("EXIT") do
109
- $LOG.debug "EXIT Terminating... #{$$}"
110
- interrupted = true
111
- begin
112
- stop winterfile
113
- # not working...
114
- # Process.getpgid child_pid
115
- # Process.kill child_pid #skipped if process is alredy dead
116
- rescue
117
- $LOG.debug "Child pid (#{child_pid}) is already gone."
118
- end
119
- end
120
- Signal.trap("HUP") do
121
- $LOG.debug "HUP Terminating... #{$$}"
122
- interrupted = true
123
- end
124
- Signal.trap("TERM") do
125
- $LOG.debug "TERM Terminating... #{$$}"
126
- interrupted = true
127
- end
128
- Signal.trap("KILL") do
129
- $LOG.debug "KILL Terminating... #{$$}"
130
- interrupted = true
131
- end
132
- Signal.trap("CONT") do
133
- $LOG.debug "CONT Terminating... #{$$}"
134
- interrupted = true
135
- end
136
- Signal.trap("ALRM") do
137
- $LOG.debug "ALRM Terminating... #{$$}"
138
- interrupted = true
139
- end
140
- Signal.trap("INT") do
141
- $LOG.debug "INT Terminating... #{$$}"
142
- interrupted = true
143
- end
144
- Signal.trap("CHLD") do
145
- $LOG.debug "CHLD Terminating... #{$$}"
146
- interrupted = true
147
- end
148
- #Process.detach(pid)
149
-
150
- while 1
151
- exit 0 if interrupted
152
- end
153
106
  end
154
107
 
155
108
  def find_java
@@ -172,7 +125,7 @@ module Winter
172
125
  felix_jar = File.join(@felix.destination,"#{@felix.artifact}-#{@felix.version}.#{@felix.package}")
173
126
 
174
127
  # start building the command
175
- cmd = [ "#{java_bin.shellescape} -server" ]
128
+ cmd = [ "exec #{java_bin.shellescape} -server" ]
176
129
  cmd << (@config["64bit"]==true ? " -d64 -XX:+UseCompressedOops":'')
177
130
  cmd << " -XX:MaxPermSize=256m -XX:NewRatio=3"
178
131
  cmd << " -Xmx#{@config['jvm.mx']}"
@@ -31,14 +31,17 @@ module Winter
31
31
  service = f_pid.sub( %r{#{WINTERFELL_DIR}/#{RUN_DIR}/([^/]+)/pid}, '\1')
32
32
  pid_file = File.open(f_pid, "r")
33
33
  pid = pid_file.read().to_i
34
-
35
- begin
36
- Process.getpgid( pid )
37
- running = "Running"
38
- rescue Errno::ESRCH
39
- running = "Dangling pid file : #{f_pid}"
34
+
35
+ if pid <= 0
36
+ running = "A pid of zero was found... something bad is going on"
37
+ else
38
+ begin
39
+ Process.getpgid( pid )
40
+ running = "Running"
41
+ rescue Errno::ESRCH
42
+ running = "Dangling pid file : #{f_pid}"
43
+ end
40
44
  end
41
-
42
45
  services["#{service} (#{pid})"] = "#{running}"
43
46
  end
44
47
 
@@ -31,23 +31,39 @@ module Winter
31
31
 
32
32
  @service_dir = File.join(File.split(winterfile)[0],RUN_DIR,service)
33
33
  f_pid = File.join(@service_dir, "pid")
34
-
35
34
  if File.exists?(f_pid)
36
- pid = nil;
35
+ pid = nil
36
+ pid_string = nil
37
37
  File.open(f_pid, "r") do |f|
38
- pid = f.read().to_i
38
+ pid_string = f.read()
39
+ pid = pid_string.to_i
39
40
  end
40
41
 
41
- begin
42
- pgid = Process.getpgid pid
43
- pgid *= -1 if !config['daemonize']
44
- Process.kill("TERM", pgid)
45
- rescue => e
46
- $LOG.debug( e )
47
- $LOG.info( "Process #{pid} does not exist. Removing pid file." )
42
+ #Send a TERM to the container if we have a non bogus pid
43
+ if pid > 0
44
+ begin
45
+ $LOG.info("Attempting to terminate #{pid}")
46
+ Process.kill("TERM", pid)
47
+ rescue => e
48
+ $LOG.debug( e )
49
+ $LOG.info("Unable to control process with pid #{pid}.")
50
+ $LOG.info("Either your user has insufficent rights, or the process doesn't exist")
51
+ end
52
+
53
+ #Wait for things to stop.
54
+ begin
55
+ $LOG.info("Waiting for the process with pid #{pid} to stop")
56
+ sleep 1 while Process.kill(0,pid)
57
+ rescue => e
58
+ $LOG.info("The container seems to have exited.")
59
+ end
60
+ else
61
+ $LOG.info("An invalid pid value was found in the pid file. (\"#{pid_string}\" was parsed as #{pid})")
48
62
  end
49
-
63
+
64
+ #If things worked (Or we couldn't find a pid)... then we're good to delete.
50
65
  begin
66
+ $LOG.info("Removing the pid file")
51
67
  File.unlink(f_pid)
52
68
  rescue
53
69
  $LOG.error( "Error deleting PID file." )
@@ -13,5 +13,5 @@
13
13
  # under the License.
14
14
 
15
15
  module Winter
16
- VERSION = "0.0.3"
16
+ VERSION = "0.1.0"
17
17
  end
@@ -34,7 +34,8 @@ describe Winter do
34
34
  begin
35
35
  lambda {
36
36
  cli = Winter::CLI.new
37
- cli.fetch 'com.liveops.sample', 'winter', '1.0.0-SNAPSHOT'
37
+ cli.fetch 'com.liveops.sample', 'sample', '1.0.0-SNAPSHOT'
38
+ #cli.fetch 'http://artifactory:8081/artifactory/libs-all/', 'sample', '1.0.0-SNAPSHOT'
38
39
  }.should_not raise_error
39
40
  end
40
41
  end
@@ -66,7 +67,7 @@ describe Winter do
66
67
  it "Build a service from a manifest" do
67
68
  begin
68
69
  lambda {
69
- args = ["build", "spec/sample_data/Winterfile", "--clean", "--local"]
70
+ args = ["build", "spec/sample_data/Winterfile", "--clean"]
70
71
  cli = Winter::CLI.start( args )
71
72
  }.should_not raise_error
72
73
  Dir["run/default/libs"].include? "maven-dependency-plugin-2.5.jar"
@@ -79,7 +80,7 @@ describe Winter do
79
80
  context "start, status and stop " do
80
81
  before "build service to get artifacts." do
81
82
  lambda {
82
- args = ["build", "spec/sample_data/Winterfile", "--clean", "--local"]
83
+ args = ["build", "spec/sample_data/Winterfile", "--clean"]
83
84
  cli = Winter::CLI.start( args )
84
85
  }.should_not raise_error
85
86
  end
@@ -90,12 +91,8 @@ describe Winter do
90
91
  lambda {
91
92
  Winter::CLI.start ["start"]
92
93
  Winter::CLI.start ["status"]
93
- #Winter::CLI.start ["stop"]
94
+ Winter::CLI.start ["stop"]
94
95
  }.should_not raise_error
95
- #lambda {
96
- # puts "TRYING STOP"
97
- # Winter::CLI.start ["stop"]
98
- #}.should_not raise_error
99
96
  end
100
97
  end
101
98
  end
@@ -113,7 +110,7 @@ describe Winter do
113
110
 
114
111
  after do
115
112
  Dir.chdir(File.split("spec/sample_data/Winterfile")[0]) do
116
- #Winter::CLI.start ["stop"]
113
+ Winter::CLI.start ["stop"]
117
114
  end
118
115
 
119
116
  FileUtils.rm_r( "spec/sample_data/run" )
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.required_ruby_version = '>= 1.9.1'
22
22
 
23
- spec.add_runtime_dependency "thor", "~> 0.18.0"
23
+ spec.add_runtime_dependency "thor", "~> 0.14.0"
24
24
  spec.add_development_dependency "bundler", "~> 1.3"
25
25
  spec.add_development_dependency "rake"
26
26
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: winter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-01-30 00:00:00.000000000 Z
12
+ date: 2014-04-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: thor
@@ -18,7 +18,7 @@ dependencies:
18
18
  requirements:
19
19
  - - ~>
20
20
  - !ruby/object:Gem::Version
21
- version: 0.18.0
21
+ version: 0.14.0
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
- version: 0.18.0
29
+ version: 0.14.0
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: bundler
32
32
  requirement: !ruby/object:Gem::Requirement