collins_client 0.2.7

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.
@@ -0,0 +1,56 @@
1
+ module Collins
2
+
3
+ class CollinsError < StandardError; end
4
+ class ExpectationFailedError < CollinsError; end
5
+ class UnexpectedResponseError < CollinsError; end
6
+ class RequestError < CollinsError
7
+ attr_accessor :code, :uri
8
+ def initialize message, code
9
+ super(message)
10
+ @code = code.to_i
11
+ end
12
+ def description verbose = false
13
+ <<-D
14
+ #{message}
15
+ Response Code: #{code}
16
+ URI: #{uri}
17
+ D
18
+ end
19
+ end
20
+
21
+ class RichRequestError < RequestError
22
+ attr_accessor :class_of, :remote_description, :remote_message, :stacktrace
23
+ def initialize message, code, description, details = {}
24
+ super(message, code)
25
+ @code = code
26
+ @remote_description = description
27
+ @class_of = details["classOf"]
28
+ @remote_message = details["message"]
29
+ @stacktrace = details["stackTrace"]
30
+ end
31
+ def get_remote_stacktrace verbose
32
+ if verbose then
33
+ stacktrace
34
+ else
35
+ "Suppressed"
36
+ end
37
+ end
38
+ def description verbose = false
39
+ <<-D
40
+ #{message}
41
+ Response Code: #{code}
42
+ URI: #{uri}
43
+ Remote Description: #{remote_description}
44
+ Remote Exception Class: #{class_of}
45
+ Remote Message:
46
+ #{remote_message}
47
+
48
+ Remote Backtrace:
49
+ #{get_remote_stacktrace(verbose)}
50
+ D
51
+ end
52
+ end
53
+
54
+ class AuthenticationError < CollinsError; end
55
+
56
+ end
@@ -0,0 +1,41 @@
1
+ module Collins
2
+
3
+ class Ipmi
4
+
5
+ include Collins::Util
6
+
7
+ attr_accessor :address, :asset_id, :gateway, :id, :netmask, :password, :username
8
+
9
+ def self.from_json json
10
+ Collins::Ipmi.new json
11
+ end
12
+
13
+ def initialize opts = {}
14
+ hash = symbolize_hash(opts).inject({}) do |result, (k,v)|
15
+ key = k.to_s.downcase.sub(/^ipmi_/, "").to_sym
16
+ result[key] = v
17
+ result
18
+ end
19
+ @address = hash[:address].to_s
20
+ @asset_id = hash[:asset_id].to_s.to_i
21
+ @gateway = hash[:gateway].to_s
22
+ @id = hash[:id].to_s.to_i
23
+ @netmask = hash[:netmask].to_s
24
+ @password = hash[:password].to_s
25
+ @username = hash[:username].to_s
26
+ end
27
+
28
+ def empty?
29
+ @id == 0
30
+ end
31
+
32
+ def to_s
33
+ if empty? then
34
+ "Ipmi(None)"
35
+ else
36
+ "Ipmi(id = #{id}, asset_id = #{asset_id}, address = #{address}, gateway = #{gateway}, netmask = #{netmask}, username = #{username}, password = #{password})"
37
+ end
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,33 @@
1
+ require 'collins/monkeypatch'
2
+ require 'collins/option'
3
+
4
+ module Collins; module Util
5
+
6
+ module Logging
7
+
8
+ DEFAULT_LOG_FORMAT = "%Y-%m-%d %H:%M:%S.%L"
9
+
10
+ def get_logger options = {}
11
+ return options[:logger] if options[:logger]
12
+ trace = Collins::Option(options[:trace]).get_or_else(false)
13
+ debug = Collins::Option(options[:debug]).get_or_else(false)
14
+ progname = Collins::Option(options[:progname] || options[:program]).get_or_else('unknown')
15
+ logfile = Collins::Option(options[:logfile]).get_or_else(STDOUT)
16
+ logger = Logger.new(logfile)
17
+ if trace then
18
+ logger.level = Logger::TRACE
19
+ elsif debug then
20
+ logger.level = Logger::DEBUG
21
+ else
22
+ logger.level = Logger::INFO
23
+ end
24
+ logger.progname = File.basename(progname)
25
+ logger.formatter = Proc.new do |severity, datetime, progname, message|
26
+ date_s = datetime.strftime(Collins::Util::Logging::DEFAULT_LOG_FORMAT)
27
+ "#{severity} [#{date_s}] #{progname}: #{message}\n"
28
+ end
29
+ logger
30
+ end
31
+ end
32
+
33
+ end; end
@@ -0,0 +1,24 @@
1
+ require 'logger'
2
+
3
+ class Logger
4
+
5
+ module Severity
6
+ TRACE = -1
7
+ end
8
+
9
+ def trace?; @level <= TRACE; end
10
+
11
+ def trace(progname = nil, &block)
12
+ add(TRACE, nil, progname, &block)
13
+ end
14
+
15
+ private
16
+ def format_severity severity
17
+ if severity == TRACE then
18
+ 'TRACE'
19
+ else
20
+ SEV_LABEL[severity] || 'ANY'
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,220 @@
1
+ module Collins
2
+
3
+ # Convenience method for creating an `Option`
4
+ def self.Option value
5
+ if value.nil? then
6
+ ::Collins::None()
7
+ else
8
+ ::Collins::Some(value)
9
+ end
10
+ end
11
+ # Convenience method for creating a `None`
12
+ def self.None
13
+ ::Collins::None.new
14
+ end
15
+ # Convenience method for creating a `Some`
16
+ def self.Some value
17
+ ::Collins::Some.new(value)
18
+ end
19
+
20
+ # Represents optional values. Instances of `Option` are either an instance of `Some` or `None`
21
+ # @note This is pretty much a straight rip off of the scala version
22
+ # @example
23
+ # name = get_parameter("name")
24
+ # upper = Option(name).map{|s| s.strip}.filter{|s|s.size > 0}.map{|s|s.upcase}
25
+ # puts(upper.get_or_else(""))
26
+ class Option
27
+
28
+ # @return [Boolean] True if the value is undefined
29
+ def empty?
30
+ raise NotImplementedError.new("empty? not implemented")
31
+ end
32
+
33
+ # @return [Boolean] True if the value is defined
34
+ def defined?
35
+ !empty?
36
+ end
37
+
38
+ # @return [Object] Value, if defined
39
+ # @raise [NameError] if value is undefined
40
+ def get
41
+ raise NotImplementedError.new("get not implemented")
42
+ end
43
+
44
+ # The value associated with this option, or the default
45
+ #
46
+ # @example
47
+ # # Raises an exception
48
+ # Option(nil).get_or_else { raise Exception.new("Stuff") }
49
+ # # Returns -1
50
+ # Option("23").map {|i| i.to_i}.filter{|i| i > 25}.get_or_else -1
51
+ #
52
+ # @param [Object] default A default value to use if the option value is undefined
53
+ # @yield [] Provide a default with a block instead of a parameter
54
+ # @return [Object] If None, default, otherwise the value
55
+ def get_or_else *default
56
+ if empty? then
57
+ if block_given? then
58
+ yield
59
+ else
60
+ default.first
61
+ end
62
+ else
63
+ get
64
+ end
65
+ end
66
+
67
+ # Return this `Option` if non-empty, otherwise return the result of evaluating the default
68
+ # @example
69
+ # Option(nil).or_else { "foo" } == Some("foo")
70
+ # @return [Option<Object>]
71
+ def or_else *default
72
+ if empty? then
73
+ res = if block_given? then
74
+ yield
75
+ else
76
+ default.first
77
+ end
78
+ if res.is_a?(Option) then
79
+ res
80
+ else
81
+ ::Collins::Option(res)
82
+ end
83
+ else
84
+ self
85
+ end
86
+ end
87
+
88
+ # Return true if non-empty and predicate is true for the value
89
+ # @return [Boolean] test passed
90
+ def exists? &predicate
91
+ !empty? && predicate.call(get)
92
+ end
93
+
94
+ # Apply the block specified to the value if non-empty
95
+ # @return [NilClass]
96
+ def foreach &f
97
+ if self.defined? then
98
+ f.call(get)
99
+ end
100
+ nil
101
+ end
102
+
103
+ # If the option value is defined, apply the specified block to that value
104
+ #
105
+ # @example
106
+ # Option("15").map{|i| i.to_i}.get == 15
107
+ #
108
+ # @yieldparam [Object] block The current value
109
+ # @yieldreturn [Object] The new value
110
+ # @return [Option<Object>] Optional value
111
+ def map &block
112
+ if empty? then
113
+ None.new
114
+ else
115
+ Some.new(block.call(get))
116
+ end
117
+ end
118
+
119
+ # Same as map, but flatten the results
120
+ #
121
+ # This is useful when operating on an object that will return an `Option`.
122
+ #
123
+ # @example
124
+ # Option(15).flat_map {|i| Option(i).filter{|i2| i2 > 0}} == Some(15)
125
+ #
126
+ # @see #map
127
+ # @return [Option<Object>] Optional value
128
+ def flat_map &block
129
+ if empty? then
130
+ None.new
131
+ else
132
+ res = block.call(get)
133
+ if res.is_a?(Some) then
134
+ res
135
+ else
136
+ Some.new(res)
137
+ end
138
+ end
139
+ end
140
+
141
+ # Convert to `None` if predicate fails
142
+ #
143
+ # Returns this option if it is non-empty *and* applying the predicate to this options returns
144
+ # true. Otherwise return `None`.
145
+ #
146
+ # @yieldparam [Object] predicate The current value
147
+ # @yieldreturn [Boolean] result of testing value
148
+ # @return [Option<Object>] `None` if predicate fails, or already `None`
149
+ def filter &predicate
150
+ if empty? || predicate.call(get) then
151
+ self
152
+ else
153
+ None.new
154
+ end
155
+ end
156
+
157
+ # Inverse of `filter` operation.
158
+ #
159
+ # Returns this option if it is non-empty *and* applying the predicate to this option returns
160
+ # false. Otherwise return `None`.
161
+ #
162
+ # @see #filter
163
+ # @return [Option<Object>]
164
+ def filter_not &predicate
165
+ if empty? || !predicate.call(get) then
166
+ self
167
+ else
168
+ None.new
169
+ end
170
+ end
171
+ end
172
+
173
+ # Represents a missing value
174
+ class None < Option
175
+ # Always true for `None`
176
+ # @see Option#empty?
177
+ def empty?
178
+ true
179
+ end
180
+ # Always raises a NameError
181
+ # @raise [NameError]
182
+ def get
183
+ raise NameError.new("None.get")
184
+ end
185
+ def eql? other
186
+ self.class.equal?(other.class)
187
+ end
188
+ alias == eql?
189
+ end
190
+
191
+ # Represents a present value
192
+ #
193
+ # A number of equality and comparison methods are implemented so that `Some` values are compared
194
+ # using the value of `x`.
195
+ class Some < Option
196
+ def initialize value
197
+ @x = value
198
+ end
199
+ def empty?
200
+ false
201
+ end
202
+ def get
203
+ x
204
+ end
205
+ def eql? other
206
+ self.class.equal?(other.class) && x.eql?(other.x)
207
+ end
208
+ alias == eql?
209
+ def hash
210
+ x.hash
211
+ end
212
+ def <=>(other)
213
+ self.class == other.class ?
214
+ (x <=> other.x) : nil
215
+ end
216
+ protected
217
+ attr_reader :x
218
+ end
219
+
220
+ end
@@ -0,0 +1,99 @@
1
+ require 'collins/errors'
2
+
3
+ module Collins
4
+
5
+ class InvalidPowerStatus < CollinsError; end
6
+
7
+ class PowerUnit
8
+ include Collins::Util
9
+
10
+ attr_accessor :key, :value, :type, :label, :position, :is_required, :unique
11
+
12
+ def initialize model = {}
13
+ hash = symbolize_hash(model).inject({}) do |result, (k,v)|
14
+ result[k.downcase] = v
15
+ result
16
+ end
17
+ @key = hash[:key].to_s
18
+ @value = hash[:value].to_s
19
+ @type = hash[:type].to_s
20
+ @label = hash[:label].to_s
21
+ @position = hash[:position].to_s.to_i
22
+ @is_required = hash[:is_required]
23
+ @unique = hash[:unique]
24
+ end
25
+
26
+ def is_required?
27
+ @is_required == true
28
+ end
29
+ def unique?
30
+ @unique == true
31
+ end
32
+ end
33
+
34
+ class Power
35
+
36
+ include Collins::Util
37
+
38
+ attr_accessor :unit_id, :units
39
+
40
+ class << self
41
+ def from_json json
42
+ return [] if (json.nil? or json.empty?)
43
+ if not json.is_a?(Array) then
44
+ json = [json]
45
+ end
46
+ json.map { |j| Collins::Power.new j }
47
+ end
48
+ def normalize_action action
49
+ case action.to_s.downcase.to_sym
50
+ when :off, :poweroff
51
+ "powerOff"
52
+ when :on, :poweron
53
+ "powerOn"
54
+ when :powersoft
55
+ "powerSoft"
56
+ when :soft, :rebootsoft
57
+ "rebootSoft"
58
+ when :hard, :reboothard
59
+ "rebootHard"
60
+ when :status, :powerstate
61
+ "powerState"
62
+ when :verify
63
+ "verify"
64
+ when :identify
65
+ "identify"
66
+ else
67
+ raise InvalidPowerStatus.new("#{action} is not a valid power status")
68
+ end
69
+ end
70
+ end
71
+
72
+ def initialize model = {}
73
+ hash = symbolize_hash(model).inject({}) do |result, (k,v)|
74
+ result[k.downcase] = v
75
+ result
76
+ end
77
+ @unit_id = hash[:unit_id].to_s.to_i
78
+ @units = (hash[:units] || []).map {|u| Collins::PowerUnit.new(u)}
79
+ end
80
+
81
+ def keys
82
+ units.map{|u| u.key }
83
+ end
84
+ def values
85
+ units.map{|u| u.value}
86
+ end
87
+ def types
88
+ units.map{|u| u.type}
89
+ end
90
+ def labels
91
+ units.map{|u| u.label}
92
+ end
93
+ def positions
94
+ units.map{|u| u.position}
95
+ end
96
+
97
+ end
98
+
99
+ end