build_status_server 0.7 → 0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -27,16 +27,20 @@ is listening at the same port (#{udp_server["address"]}:#{udp_server["port"]}
27
27
 
28
28
  puts "Listening on UDP #{udp_server["address"]}:#{udp_server["port"]}" if config.verbose
29
29
 
30
- while true
31
- data, addr = sock.recvfrom(2048)
30
+ begin
31
+ while true
32
+ data, addr = sock.recvfrom(2048)
32
33
 
33
- if process_job(data)
34
- status = process_all_statuses
35
- notify(status)
34
+ if process_job(data)
35
+ status = process_all_statuses
36
+ notify(status)
37
+ end
36
38
  end
39
+ rescue Interrupt
40
+ puts "Good bye."
41
+ sock.close
42
+ exit
37
43
  end
38
-
39
- sock.close
40
44
  end
41
45
 
42
46
  private
@@ -0,0 +1,162 @@
1
+ # TODO
2
+ # move all configuration stuff to Config
3
+ # and just call config[:blaj] instead of if blah
4
+ module BuildStatusServer
5
+ class Server
6
+ attr_reader :config, :store
7
+
8
+ def initialize(options = {})
9
+ @config = Config.new
10
+ config.load(options)
11
+ end
12
+
13
+ def listen
14
+ sock = UDPSocket.new
15
+ udp_server = config.udp_server
16
+
17
+ begin
18
+ sock.bind(udp_server["address"], udp_server["port"])
19
+ rescue Errno::EADDRINUSE
20
+ STDERR.puts <<-EOT
21
+ There appears that another instance is running, or another process
22
+ is listening at the same port (#{udp_server["address"]}:#{udp_server["port"]}
23
+
24
+ EOT
25
+ exit
26
+ end
27
+
28
+ puts "Listening on UDP #{udp_server["address"]}:#{udp_server["port"]}" if config.verbose
29
+
30
+ begin
31
+ while true
32
+ data, addr = sock.recvfrom(2048)
33
+
34
+ if process_job(data)
35
+ status = process_all_statuses
36
+ notify(status)
37
+ end
38
+ end
39
+ rescue Interrupt
40
+ puts "Good bye."
41
+ exit
42
+ end
43
+
44
+ sock.close
45
+ end
46
+
47
+ private
48
+
49
+ def load_store
50
+ @store = begin
51
+ YAML.load_file(config.store_file)
52
+ rescue
53
+ {}
54
+ end
55
+ @store = {} unless store.class == Hash
56
+ end
57
+
58
+
59
+ def process_job(data = "{}")
60
+ job = JSON.parse(data)
61
+
62
+ build_name = job["name"]
63
+
64
+ unless should_process_build(build_name)
65
+ STDOUT.puts "Ignoring #{build_name} (#{config.mask["regex"]}--#{config.mask["policy"]})" if config.verbose
66
+ return false
67
+ end
68
+
69
+ if job.class != Hash or
70
+ job["build"].class != Hash
71
+ STDERR.puts "Pinged with an invalid payload"
72
+ return false
73
+ end
74
+
75
+ phase = job["build"]["phase"]
76
+ status = job["build"]["status"]
77
+
78
+ if phase == "FINISHED"
79
+ STDOUT.puts "Got #{status} for #{build_name} on #{Time.now} [#{job.inspect}]" if config.verbose
80
+ case status
81
+ when "SUCCESS", "FAILURE"
82
+ load_store
83
+ store[build_name] = status
84
+ File.open(config.store_file, "w") { |file| YAML.dump(store, file) }
85
+ return true
86
+ end
87
+ else
88
+ STDOUT.puts "Started for #{build_name} on #{Time.now} [#{job.inspect}]" if config.verbose
89
+ end
90
+
91
+ return false
92
+ end
93
+
94
+ def should_process_build(build_name)
95
+ # If mask exists, then ...
96
+ ! (
97
+ !!config.mask &&
98
+ !!config.mask["regex"] &&
99
+ ((config.mask["policy"] == "include" && build_name !~ config.mask["regex"]) ||
100
+ (config.mask["policy"] != "include" && build_name =~ config.mask["regex"])
101
+ ))
102
+ end
103
+
104
+ def process_all_statuses
105
+ pass = true
106
+
107
+ @store.values.each do |val|
108
+ pass &&= (val == "pass" || val == "SUCCESS")
109
+ end
110
+
111
+ pass
112
+ end
113
+
114
+ def notify(status)
115
+ tcp_client = config.tcp_client
116
+
117
+ attempts = 0
118
+ light = status ? tcp_client["pass"] : tcp_client["fail"]
119
+
120
+ begin
121
+ timeout(5) do
122
+ attempts += 1
123
+ client = TCPSocket.new(tcp_client["host"], tcp_client["port"])
124
+ client.print "GET #{light} HTTP/1.0\n\n"
125
+ answer = client.gets(nil)
126
+ STDOUT.puts answer if config.verbose
127
+ client.close
128
+ end
129
+ rescue Timeout::Error => ex
130
+ STDERR.puts "Error: #{ex} while trying to send #{light}"
131
+ retry unless attempts > 2
132
+ rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH => ex
133
+ STDERR.puts "Error: #{ex} while trying to send #{light}"
134
+ STDERR.puts "Will wait for 2 seconds and try again..."
135
+ sleep 2
136
+ retry unless attempts > 2
137
+ end
138
+ end
139
+ end
140
+ end
141
+
142
+ __END__
143
+
144
+ Example payload:
145
+ {
146
+ "name":"test",
147
+ "url":"job/test/",
148
+ "build":{
149
+ "full_url":"http://cronus.local:3001/job/test/20/",
150
+ "number":20,
151
+ "phase":"FINISHED",
152
+ "status":"SUCCESS",
153
+ "url":"job/test/20/"
154
+ }
155
+ }
156
+
157
+ We're getting this error once in a while:
158
+ /usr/local/lib/ruby/1.8/timeout.rb:64:in `notify': execution expired (Timeout::Error)
159
+ from /home/jcmuller/build_notifier/lib/server.rb:102:in `notify'
160
+ from /home/jcmuller/build_notifier/lib/server.rb:33:in `listen'
161
+ from bin/server:5
162
+
@@ -1,3 +1,3 @@
1
1
  module BuildStatusServer
2
- VERSION = "0.7"
2
+ VERSION = "0.8"
3
3
  end
@@ -1,3 +1,3 @@
1
1
  module BuildStatusServer
2
- VERSION = "0.6"
2
+ VERSION = "0.7"
3
3
  end
metadata CHANGED
@@ -1,12 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: build_status_server
3
3
  version: !ruby/object:Gem::Version
4
- hash: 5
4
+ hash: 27
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 7
9
- version: "0.7"
8
+ - 8
9
+ version: "0.8"
10
10
  platform: ruby
11
11
  authors:
12
12
  - Juan C. Muller
@@ -83,6 +83,7 @@ extra_rdoc_files: []
83
83
  files:
84
84
  - lib/build_status_server/config.rb
85
85
  - lib/build_status_server/server.rb
86
+ - lib/build_status_server/server.rb~
86
87
  - lib/build_status_server/version.rb
87
88
  - lib/build_status_server/version.rb~
88
89
  - lib/build_status_server.rb