ocular 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +15 -0
- data/examples/ssh-example.rb +11 -0
- data/lib/blocktest.rb +40 -0
- data/lib/ocular.rb +2 -0
- data/lib/ocular/dsl/logging.rb +117 -0
- data/lib/ocular/dsl/runcontext.rb +28 -0
- data/lib/ocular/dsl/ssh.rb +16 -0
- data/lib/ocular/event/eventbase.rb +28 -0
- data/lib/ocular/event/eventfactory.rb +47 -0
- data/lib/ocular/mixin/from_file.rb +49 -0
- data/lib/ocular/ocular.rb +7 -0
- data/lib/ocular/version.rb +3 -0
- data/spec/blocktest_spec.rb +70 -0
- data/spec/spec_helper.rb +6 -0
- metadata +91 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: de167ed33e75bba8f6482de164f5b1f7c1fea60a
|
4
|
+
data.tar.gz: f9ce4d9717736477221e9a456bfafcd1d6a4d0f9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 260602dd6cef56943d98f5a6271dfd5cded3753a222c1e14d3ba6eb437e45e048f1074b63a09e6e18684c415aeb1856a0dc8837680c1f0b512cf0f078e2b637f
|
7
|
+
data.tar.gz: 84e6e806f943dff204d98a39dcf125dbf9a8cf61f7db2f1a0c5b53c2bcb5a7afe6f1fa28e1c68cd9c739a5d9732b7e51b73b12c796d6ad095a8c305ed38215e2
|
data/README.md
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# ocular
|
2
|
+
Framework to automate responses for infrastructure events.
|
3
|
+
|
4
|
+
Ocular allows to easily create small scripts which are triggered from multiple different event sources and which can then execute scripts commanding all kinds of infrastructure, do remote command execution, execute AWS API calls, modify databases and so on.
|
5
|
+
|
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
|
+
|
8
|
+
Planned event sources:
|
9
|
+
- HTTP calls
|
10
|
+
- RabbitMQ messages
|
11
|
+
- SQS/SNS messages
|
12
|
+
- Graphite item triggers
|
13
|
+
- Zabbix alerts
|
14
|
+
- Timers
|
15
|
+
|
data/lib/blocktest.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# game.rb
|
2
|
+
|
3
|
+
module MixinTest
|
4
|
+
|
5
|
+
def setMixingTestValue(val)
|
6
|
+
@mixingTestValue = val
|
7
|
+
end
|
8
|
+
|
9
|
+
def getMixingTestValue
|
10
|
+
return @mixingTestValue
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
class BlockTest
|
16
|
+
|
17
|
+
attr_accessor :testValue
|
18
|
+
|
19
|
+
include MixinTest
|
20
|
+
|
21
|
+
def initialize(&block)
|
22
|
+
@callback = block
|
23
|
+
end
|
24
|
+
|
25
|
+
def testMethod(val)
|
26
|
+
@testValue = val
|
27
|
+
end
|
28
|
+
|
29
|
+
def call(&block)
|
30
|
+
block.call
|
31
|
+
end
|
32
|
+
|
33
|
+
def ieval(&block)
|
34
|
+
self.instance_eval(&block)
|
35
|
+
end
|
36
|
+
|
37
|
+
def ievaldef
|
38
|
+
self.instance_eval(&@callback)
|
39
|
+
end
|
40
|
+
end
|
data/lib/ocular.rb
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
class Ocular
|
4
|
+
module DSL
|
5
|
+
module Logging
|
6
|
+
|
7
|
+
def debug(message = nil, &block)
|
8
|
+
@logger.add(Logger::Severity::DEBUG, message, @run_id, &block)
|
9
|
+
end
|
10
|
+
alias log debug
|
11
|
+
|
12
|
+
def info(message = nil, &block)
|
13
|
+
add(Severity::INFO, nil, message, &block)
|
14
|
+
end
|
15
|
+
|
16
|
+
def warn(message = nil, &block)
|
17
|
+
add(Severity::INFO, nil, message, &block)
|
18
|
+
end
|
19
|
+
|
20
|
+
def error(message = nil, &block)
|
21
|
+
add(Severity::INFO, nil, message, &block)
|
22
|
+
end
|
23
|
+
|
24
|
+
def fatal(message = nil, &block)
|
25
|
+
add(Severity::INFO, nil, message, &block)
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
# Most of the Logger class is copied from the Ruby Logger class source code.
|
32
|
+
class Logger
|
33
|
+
|
34
|
+
# Logging severity.
|
35
|
+
module Severity
|
36
|
+
# Low-level information, mostly for developers.
|
37
|
+
DEBUG = 0
|
38
|
+
# Generic (useful) information about system operation.
|
39
|
+
INFO = 1
|
40
|
+
# A warning.
|
41
|
+
WARN = 2
|
42
|
+
# A handleable error condition.
|
43
|
+
ERROR = 3
|
44
|
+
# An unhandleable error that results in a program crash.
|
45
|
+
FATAL = 4
|
46
|
+
# An unknown message that should always be logged.
|
47
|
+
UNKNOWN = 5
|
48
|
+
end
|
49
|
+
|
50
|
+
def initialize()
|
51
|
+
@level = Severity::DEBUG
|
52
|
+
@formatter = Logger::Formatter.new
|
53
|
+
end
|
54
|
+
|
55
|
+
def add(severity, message = nil, run_id = nil, &block)
|
56
|
+
severity ||= Severity::UNKNOWN
|
57
|
+
if severity < @level
|
58
|
+
return true
|
59
|
+
end
|
60
|
+
|
61
|
+
if message.nil?
|
62
|
+
if block_given?
|
63
|
+
message = yield
|
64
|
+
else
|
65
|
+
message = progname
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
puts format_message(format_severity(severity), Time.now, run_id, message)
|
70
|
+
true
|
71
|
+
end
|
72
|
+
|
73
|
+
SEV_LABEL = %w(DEBUG INFO WARN ERROR FATAL ANY).each(&:freeze).freeze
|
74
|
+
|
75
|
+
def format_severity(severity)
|
76
|
+
SEV_LABEL[severity] || 'ANY'
|
77
|
+
end
|
78
|
+
|
79
|
+
def format_message(severity, datetime, progname, msg)
|
80
|
+
@formatter.call(severity, datetime, progname, msg)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Default formatter for log messages.
|
84
|
+
class Formatter
|
85
|
+
Format = "%s, [%s#%d] %5s -- %s: %s\n".freeze
|
86
|
+
|
87
|
+
attr_accessor :datetime_format
|
88
|
+
|
89
|
+
def initialize
|
90
|
+
@datetime_format = nil
|
91
|
+
end
|
92
|
+
|
93
|
+
def call(severity, time, progname, msg)
|
94
|
+
Format % [severity[0..0], format_datetime(time), $$, severity, progname, msg2str(msg)]
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def format_datetime(time)
|
100
|
+
time.strftime(@datetime_format || "%Y-%m-%dT%H:%M:%S.%6N ".freeze)
|
101
|
+
end
|
102
|
+
|
103
|
+
def msg2str(msg)
|
104
|
+
case msg
|
105
|
+
when ::String
|
106
|
+
msg
|
107
|
+
when ::Exception
|
108
|
+
"#{ msg.message } (#{ msg.class })\n" <<
|
109
|
+
(msg.backtrace || []).join("\n")
|
110
|
+
else
|
111
|
+
msg.inspect
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
require 'securerandom'
|
3
|
+
|
4
|
+
class Ocular
|
5
|
+
module DSL
|
6
|
+
class RunContext
|
7
|
+
attr_accessor :run_id
|
8
|
+
attr_accessor :proxy
|
9
|
+
attr_accessor :class_name
|
10
|
+
|
11
|
+
include Ocular::DSL::Logging
|
12
|
+
include Ocular::DSL::SSH
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@run_id = SecureRandom.uuid()
|
16
|
+
@logger = Ocular::DSL::Logger.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def method_missing(method_sym, *arguments, &block)
|
20
|
+
if self.proxy
|
21
|
+
self.proxy.send(method_sym, *arguments, &block)
|
22
|
+
else
|
23
|
+
raise NoMethodError("undefined method `#{method_sym}` in event #{self.class_name}")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'ocular/mixin/from_file'
|
2
|
+
require 'ocular/dsl/ssh'
|
3
|
+
require 'ocular/dsl/logging'
|
4
|
+
|
5
|
+
class Ocular
|
6
|
+
module DSL
|
7
|
+
|
8
|
+
class EventBase
|
9
|
+
include Ocular::DSL::SSH
|
10
|
+
include Ocular::DSL::Logging
|
11
|
+
|
12
|
+
attr_accessor :proxy
|
13
|
+
|
14
|
+
|
15
|
+
def initialize(&block)
|
16
|
+
@callback = block
|
17
|
+
end
|
18
|
+
|
19
|
+
def exec(run_context)
|
20
|
+
puts "Running #{run_context}"
|
21
|
+
run_context.proxy = self.proxy
|
22
|
+
run_context.instance_eval(&@callback)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'ocular/event/eventbase.rb'
|
2
|
+
|
3
|
+
class Ocular
|
4
|
+
module Event
|
5
|
+
class DefinitionProxy
|
6
|
+
attr_accessor :events
|
7
|
+
attr_accessor :klass_name
|
8
|
+
|
9
|
+
def initialize(klass_name)
|
10
|
+
self.klass_name = klass_name
|
11
|
+
@events = []
|
12
|
+
@logger = Ocular::DSL::Logger.new
|
13
|
+
end
|
14
|
+
|
15
|
+
include Ocular::Mixin::FromFile
|
16
|
+
include Ocular::DSL::Logging
|
17
|
+
|
18
|
+
def onEvent(factory_class, &block)
|
19
|
+
eventbase = Ocular::DSL::EventBase.new(&block)
|
20
|
+
eventbase.proxy = self
|
21
|
+
@events << eventbase
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class EventFactory
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
@files = {}
|
29
|
+
end
|
30
|
+
|
31
|
+
def load_from_file(file)
|
32
|
+
proxy = DefinitionProxy.new(file)
|
33
|
+
proxy.from_file(file)
|
34
|
+
@files[file] = proxy
|
35
|
+
return proxy
|
36
|
+
end
|
37
|
+
|
38
|
+
def load_from_block(name, &block)
|
39
|
+
proxy = DefinitionProxy.new(name)
|
40
|
+
proxy.instance_eval(&block)
|
41
|
+
@files[name] = proxy
|
42
|
+
return proxy
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
#
|
2
|
+
# OriginalAuthor:: Adam Jacob (<adam@opscode.com>)
|
3
|
+
# OriginalAuthor:: Christopher Walters (<cw@opscode.com>)
|
4
|
+
# Copyright:: Copyright (c) 2008 Opscode, Inc.
|
5
|
+
# License:: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
class Ocular
|
20
|
+
module Mixin
|
21
|
+
module FromFile
|
22
|
+
|
23
|
+
# Loads a given ruby file, and runs instance_eval against it in the context of the current
|
24
|
+
# object.
|
25
|
+
#
|
26
|
+
# Raises an IOError if the file cannot be found, or is not readable.
|
27
|
+
def from_file(filename)
|
28
|
+
if File.exists?(filename) && File.readable?(filename)
|
29
|
+
self.instance_eval(IO.read(filename), filename, 1)
|
30
|
+
else
|
31
|
+
raise IOError, "Cannot open or read #{filename}!"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Loads a given ruby file, and runs class_eval against it in the context of the current
|
36
|
+
# object.
|
37
|
+
#
|
38
|
+
# Raises an IOError if the file cannot be found, or is not readable.
|
39
|
+
def class_from_file(filename)
|
40
|
+
if File.exists?(filename) && File.readable?(filename)
|
41
|
+
self.class_eval(IO.read(filename), filename, 1)
|
42
|
+
else
|
43
|
+
raise IOError, "Cannot open or read #{filename}!"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
#require_relative "../lib/game.rb"
|
2
|
+
require 'blocktest'
|
3
|
+
|
4
|
+
def globalMethodForTesting(val)
|
5
|
+
$globalMethodVariable = val
|
6
|
+
end
|
7
|
+
|
8
|
+
RSpec.describe BlockTest do
|
9
|
+
describe "#call" do
|
10
|
+
it "can call a block" do
|
11
|
+
test = BlockTest.new
|
12
|
+
a = false
|
13
|
+
test.call do
|
14
|
+
a = true
|
15
|
+
end
|
16
|
+
expect(a).to eq(true)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#ieval" do
|
21
|
+
it "can instance_eval a block" do
|
22
|
+
test = BlockTest.new
|
23
|
+
a = false
|
24
|
+
test.ieval do
|
25
|
+
a = true
|
26
|
+
end
|
27
|
+
expect(a).to eq(true)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "can call a BlockTest method" do
|
31
|
+
test = BlockTest.new
|
32
|
+
test.ieval do
|
33
|
+
testMethod(2)
|
34
|
+
end
|
35
|
+
expect(test.testValue).to eq(2)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "can call a BlockTest method while calling global methods" do
|
39
|
+
test = BlockTest.new
|
40
|
+
test.ieval do
|
41
|
+
globalMethodForTesting(3)
|
42
|
+
end
|
43
|
+
expect($globalMethodVariable).to eq(3)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "can call a mixin function" do
|
47
|
+
test = BlockTest.new
|
48
|
+
test.ieval do
|
49
|
+
setMixingTestValue(6)
|
50
|
+
end
|
51
|
+
expect(test.getMixingTestValue).to eq(6)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "#ievaldef" do
|
56
|
+
it "can execute callback from initialise" do
|
57
|
+
a = false
|
58
|
+
test = BlockTest.new do
|
59
|
+
a = true
|
60
|
+
end
|
61
|
+
test.ievaldef
|
62
|
+
expect(a).to eq(true)
|
63
|
+
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ocular
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Juho Mäkinen
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-02-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rye
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.9.13
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.9.13
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 3.4.0
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 3.4.0
|
41
|
+
description: |+
|
42
|
+
Framework to automate responses for infrastructure events.
|
43
|
+
|
44
|
+
Ocular allows to easily create small scripts which are triggered from multiple different event sources and which can then execute scripts commanding all kinds of infrastructure, do remote command execution, execute AWS API calls, modify databases and so on.
|
45
|
+
|
46
|
+
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.
|
47
|
+
|
48
|
+
email: juho@unity3d.com
|
49
|
+
executables: []
|
50
|
+
extensions: []
|
51
|
+
extra_rdoc_files: []
|
52
|
+
files:
|
53
|
+
- README.md
|
54
|
+
- examples/ssh-example.rb
|
55
|
+
- lib/blocktest.rb
|
56
|
+
- lib/ocular.rb
|
57
|
+
- lib/ocular/dsl/logging.rb
|
58
|
+
- lib/ocular/dsl/runcontext.rb
|
59
|
+
- lib/ocular/dsl/ssh.rb
|
60
|
+
- lib/ocular/event/eventbase.rb
|
61
|
+
- lib/ocular/event/eventfactory.rb
|
62
|
+
- lib/ocular/mixin/from_file.rb
|
63
|
+
- lib/ocular/ocular.rb
|
64
|
+
- lib/ocular/version.rb
|
65
|
+
- spec/blocktest_spec.rb
|
66
|
+
- spec/spec_helper.rb
|
67
|
+
homepage: http://github.com/garo/ocular
|
68
|
+
licenses:
|
69
|
+
- Apache 2.0
|
70
|
+
metadata: {}
|
71
|
+
post_install_message:
|
72
|
+
rdoc_options: []
|
73
|
+
require_paths:
|
74
|
+
- lib
|
75
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
requirements: []
|
86
|
+
rubyforge_project:
|
87
|
+
rubygems_version: 2.4.5.1
|
88
|
+
signing_key:
|
89
|
+
specification_version: 4
|
90
|
+
summary: Tool to create simple operational scripts
|
91
|
+
test_files: []
|