ocular 0.1.16 → 0.1.17

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9e7bdc14065534d11c655212e482f3e63f5fe1e3
4
- data.tar.gz: 80bee22324973ce182d65d5c7518949e826bc1d1
3
+ metadata.gz: f2b13556c63053b9d7f15e8382b3803295edc3d4
4
+ data.tar.gz: 8862213d31cabfaee4332bcb33bcacf63601e5d7
5
5
  SHA512:
6
- metadata.gz: 839537f3335286e0269274211824b3dd8560f4857ec4a04789d43796ef2d71637ea99f74357d7cac72b91051e3eeb1e5f23a14d05332ba837d3da9efaf3f928e
7
- data.tar.gz: 55a4b0fdf8c52dcf925740ef367061ceb372c59f677dfc06c1580506f5b18d07310fd2e4ff4d942c813aa1ccb9e162d99ed2676413d63132ece867b832fdf210
6
+ metadata.gz: 1be07d88abd000eb2cb6c70b92b9790b33720d8d72554393f8e0f0bc21ac07a43abc8c511b7f807ed98c40a728f46bbc7613a7d0fd73e9994104a59a0089d91d
7
+ data.tar.gz: bb7edaf144bac5bc7433505b6c05b23e9027f27656c8bbd32a257fff9a319cafc3395947e499831ebdba9a8236b3f1b21ff7bd7a5c020527ad30b14433201c4d
data/README.md CHANGED
@@ -5,11 +5,26 @@ Ocular allows to easily create small scripts which are triggered from multiple d
5
5
 
6
6
  The goal is that a new script could be written really quickly to automate a previously manual infrastructure maintenance job instead of doing the manual job yet another time. Scripts are written in Ruby with a simple Ocular DSL which allows the script to easily respond to multitude different events.
7
7
 
8
- Planned event sources:
8
+ Currently implemented event sources:
9
9
  - HTTP calls
10
10
  - RabbitMQ messages
11
+ - Timers
12
+
13
+ Planned event sources:
11
14
  - SQS/SNS messages
12
- - Graphite item triggers
13
15
  - Zabbix alerts
14
- - Timers
16
+ - NATS broadcast messages
17
+ - salt-stack event bus
18
+
19
+ Currently implemented clients to external services (ie. what you can easily do once your event has been triggered):
20
+ - MySQL
21
+ - etcd
22
+ - RabbitMQ
23
+ - AWS/EC2
24
+ - Kafka (for logging)
25
+ - SSH for remote execution
15
26
 
27
+ Planned clients to external services:
28
+ - Graphite
29
+ - Zabbix configuration
30
+ - salt-stack remote state execution
data/lib/ocular/daemon.rb CHANGED
@@ -37,7 +37,6 @@ class Ocular
37
37
  end
38
38
 
39
39
  def start_input_handlers()
40
- puts "derp"
41
40
  @eventfactory.start_input_handlers()
42
41
  end
43
42
 
@@ -1,5 +1,6 @@
1
1
  require 'logger'
2
2
  require 'etcd'
3
+ require 'pp'
3
4
 
4
5
  class Ocular
5
6
  module DSL
@@ -29,6 +30,67 @@ class Ocular
29
30
  return @@__etcd_instance
30
31
  end
31
32
 
33
+ def ttl_lock(key, ttl:10)
34
+ id = @run_id
35
+ if !id
36
+ id = Process.pid.to_s
37
+ Socket.ip_address_list.each do |addr|
38
+ next if addr.ip_address == "127.0.0.1"
39
+ next if addr.ip_address.start_with?("::1")
40
+ next if addr.ip_address.start_with?("fe80::1")
41
+ id += "-" + addr.ip_address
42
+ end
43
+ end
44
+
45
+ client = etcd()
46
+
47
+ current_lock = locked?(key)
48
+
49
+ if current_lock != id and current_lock != nil
50
+ return nil # Somebody else has lock, can't lock by ourself
51
+ end
52
+
53
+ if current_lock == id and current_lock != nil
54
+ begin
55
+ client.test_and_set("/ocular/locks/#{key}", value: id, prevValue: id, ttl: ttl)
56
+ return id
57
+ rescue ::Etcd::NodeExist => e
58
+ return nil
59
+ end
60
+
61
+ else
62
+ begin
63
+ client.create("/ocular/locks/#{key}", value: id, ttl: ttl)
64
+ return id
65
+ rescue ::Etcd::NodeExist => e
66
+ return nil
67
+ end
68
+ end
69
+ end
70
+
71
+ def unlock(key)
72
+ client = etcd()
73
+ begin
74
+ client.delete("/ocular/locks/#{key}")
75
+ rescue ::Etcd::KeyNotFound
76
+
77
+ end
78
+ return true
79
+ end
80
+
81
+ def locked?(key)
82
+ client = etcd()
83
+ begin
84
+ ret = client.get("/ocular/locks/#{key}")
85
+ if ret.node and ret.node.expiration == nil
86
+ warn("Key #{key} has been locked permanently with value '#{ret.node.value}'!")
87
+ end
88
+ return ret.node.value # Key is locked
89
+ rescue ::Etcd::KeyNotFound => e
90
+ return nil
91
+ end
92
+ end
93
+
32
94
  end
33
95
 
34
96
  end
@@ -46,7 +46,13 @@ class Ocular
46
46
  r.error = error
47
47
  end
48
48
 
49
- Marshal.dump(r, writer)
49
+ begin
50
+ Marshal.dump(r, writer)
51
+ rescue TypeError => e
52
+ ::Ocular.logger.error "TypeError when trying to marshal event handler return value. Reason: #{e}"
53
+ ::Ocular.logger.error "This is usually because you forgot that the last function return value is returned from the handler function. The current type of the returned value is #{r.response.class}. Please make sure your handler returns a proper value which doesn't reference any sockets or otherwise complex unserializable objects."
54
+ ::Ocular.logger.error "The value of the returned value is :#{r.response.pretty_inspect}"
55
+ end
50
56
  writer.close
51
57
  end
52
58
  writer.close
@@ -29,22 +29,28 @@ class Ocular
29
29
  attr_reader :cron_enabled
30
30
 
31
31
  def initialize(settings_factory)
32
- settings = settings_factory[:cron]
32
+ settings = settings_factory.fetch(:cron, {})
33
33
  @cron_enabled = true
34
34
 
35
+ pp settings
35
36
  if settings[:lock]
36
37
  @cron_enabled = false
37
38
  end
38
39
 
40
+ if settings[:enabled] == false
41
+ ::Ocular.logger.info "Cron is disabled from settings"
42
+ @cron_enabled = false
43
+ end
44
+
39
45
  @scheduler = ::Rufus::Scheduler.new
40
46
  ::Ocular.logger.debug "Starting Rufus cron scheduler"
41
47
 
42
- if settings[:lock]
48
+ if settings[:lock] and @cron_enabled == true
49
+ Ocular.logger.debug "Enabling cron locking at pid #{Process.pid.to_s}"
43
50
  @scheduler.every(settings[:lock_delay] || "10s", :overlap => false) do
44
- etcd = ::Ocular::DSL::Etcd.etcd()
51
+ c = Class.new.extend(Ocular::DSL::Etcd)
45
52
 
46
- ret = etcd.get(settings[:lock])
47
- pp ret
53
+ @cron_enabled = c.ttl_lock("cron_input", ttl:20)
48
54
  end
49
55
  end
50
56
  end
@@ -59,7 +65,7 @@ class Ocular
59
65
 
60
66
  def disable()
61
67
  @cron_enabled = false
62
- end
68
+ end
63
69
 
64
70
  def enable()
65
71
  @cron_enabled = true
@@ -445,7 +445,9 @@ class Ocular
445
445
  context.params = indifferent_params(context.request.params)
446
446
 
447
447
  context.response['Content-Type'] = nil
448
- invoke(context) { |context| dispatch(context) }
448
+ invoke(context) do |context|
449
+ dispatch(context)
450
+ end
449
451
 
450
452
  unless context.response['Content-Type']
451
453
  context.response['Content-Type'] = "text/html"
@@ -469,7 +471,6 @@ class Ocular
469
471
 
470
472
  def invoke(context)
471
473
  res = catch(:halt) { yield(context) }
472
-
473
474
  if Array === res and Fixnum === res.first
474
475
  res = res.dup
475
476
  status(context, res.shift)
@@ -488,7 +489,11 @@ class Ocular
488
489
  context.response.status = error.http_status
489
490
 
490
491
  if error.respond_to? :to_s
491
- puts error.to_s
492
+ str = error.to_s
493
+ if !str.end_with?("\n")
494
+ str += "\n"
495
+ end
496
+ context.response.body = str
492
497
  end
493
498
  else
494
499
  context.response.status = 500
@@ -603,7 +608,7 @@ class Ocular
603
608
  pattern, keys = compile("/check")
604
609
 
605
610
  (@routes["GET"] ||= []) << build_signature(pattern, keys) do |context|
606
- [200, "OK"]
611
+ [200, "OK\n"]
607
612
  end
608
613
  end
609
614
 
@@ -71,8 +71,14 @@ class Ocular
71
71
  context.delivery_info = delivery_info
72
72
  context.metadata = metadata
73
73
  context.payload = payload
74
- eventbase.exec(context)
75
- ch.acknowledge(delivery_info.delivery_tag, false)
74
+ begin
75
+ eventbase.exec(context)
76
+ ch.acknowledge(delivery_info.delivery_tag, false)
77
+ rescue
78
+ sleep 1
79
+ warn "Error on RabbitMQ event processing on context #{context}"
80
+ ch.reject(delivery_info.delivery_tag, true)
81
+ end
76
82
  end
77
83
 
78
84
  id = queue + "-" + block.to_s
@@ -28,7 +28,7 @@ class Ocular
28
28
  end
29
29
 
30
30
  def self.load_from_file(filename)
31
- #puts "Loaded settings from #{filename}"
31
+ ::Ocular.logger.debug "Loaded settings from #{filename}"
32
32
  @settings = ::Ocular::deep_symbolize(YAML::load_file(filename))
33
33
  end
34
34
 
@@ -1,3 +1,3 @@
1
1
  class Ocular
2
- Version = "0.1.16"
2
+ Version = "0.1.17"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ocular
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.16
4
+ version: 0.1.17
5
5
  platform: ruby
6
6
  authors:
7
7
  - Juho Mäkinen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-04-22 00:00:00.000000000 Z
11
+ date: 2016-05-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rye