collins_client 0.2.7
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +15 -0
- data/Gemfile.lock +50 -0
- data/README.md +46 -0
- data/Rakefile +66 -0
- data/VERSION +1 -0
- data/collins_client.gemspec +73 -0
- data/lib/collins/address.rb +74 -0
- data/lib/collins/api.rb +119 -0
- data/lib/collins/api/admin.rb +19 -0
- data/lib/collins/api/asset.rb +184 -0
- data/lib/collins/api/asset_state.rb +85 -0
- data/lib/collins/api/attributes.rb +76 -0
- data/lib/collins/api/ip_address.rb +87 -0
- data/lib/collins/api/logging.rb +137 -0
- data/lib/collins/api/management.rb +84 -0
- data/lib/collins/api/tag.rb +46 -0
- data/lib/collins/api/util.rb +28 -0
- data/lib/collins/api/util/errors.rb +45 -0
- data/lib/collins/api/util/parameters.rb +44 -0
- data/lib/collins/api/util/requests.rb +136 -0
- data/lib/collins/api/util/responses.rb +46 -0
- data/lib/collins/asset.rb +311 -0
- data/lib/collins/asset_client.rb +57 -0
- data/lib/collins/client.rb +100 -0
- data/lib/collins/errors.rb +56 -0
- data/lib/collins/ipmi.rb +41 -0
- data/lib/collins/logging.rb +33 -0
- data/lib/collins/monkeypatch.rb +24 -0
- data/lib/collins/option.rb +220 -0
- data/lib/collins/power.rb +99 -0
- data/lib/collins/profile.rb +73 -0
- data/lib/collins/simple_callback.rb +141 -0
- data/lib/collins/state.rb +50 -0
- data/lib/collins/util.rb +145 -0
- data/lib/collins_client.rb +7 -0
- metadata +100 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module Collins; module Api
|
4
|
+
|
5
|
+
module Admin
|
6
|
+
|
7
|
+
def repopulate_solr! wait_for_completion = true
|
8
|
+
parameters = {
|
9
|
+
:waitForCompletion => wait_for_completion
|
10
|
+
}
|
11
|
+
http_get("/api/admin/solr", parameters) do |response|
|
12
|
+
parse_response response, :expects => 200
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end; end
|
19
|
+
|
@@ -0,0 +1,184 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module Collins; module Api
|
4
|
+
|
5
|
+
module Asset
|
6
|
+
|
7
|
+
def create! asset_or_tag, options = {}
|
8
|
+
asset = get_asset_or_tag asset_or_tag
|
9
|
+
parameters = {
|
10
|
+
:generate_ipmi => get_option(:generate_ipmi, options, false),
|
11
|
+
:status => get_option(:status, options, asset.status),
|
12
|
+
:type => get_option(:type, options, asset.type)
|
13
|
+
}
|
14
|
+
parameters = select_non_empty_parameters parameters
|
15
|
+
logger.debug("Creating asset #{asset.tag} with parameters #{parameters.inspect}")
|
16
|
+
http_put("/api/asset/#{asset.tag}", parameters) do |response|
|
17
|
+
parse_response response, :expects => 201, :as => :asset
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def delete! asset_or_tag, options = {}
|
22
|
+
asset = get_asset_or_tag asset_or_tag
|
23
|
+
parameters = {
|
24
|
+
:reason => get_option(:reason, options, nil)
|
25
|
+
}
|
26
|
+
parameters = select_non_empty_parameters parameters
|
27
|
+
logger.debug("Deleting asset #{asset.tag} with parameters #{parameters.inspect}")
|
28
|
+
http_delete("/api/asset/#{asset.tag}", parameters, asset.location) do |response|
|
29
|
+
parse_response response, :expects => 200, :as => :status, :raise => strict?, :default => false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def exists? asset_or_tag, status = nil
|
34
|
+
begin
|
35
|
+
asset = get(asset_or_tag)
|
36
|
+
if asset && status && asset.status.downcase == status.downcase then
|
37
|
+
true
|
38
|
+
elsif asset && status.nil? then
|
39
|
+
true
|
40
|
+
else
|
41
|
+
false
|
42
|
+
end
|
43
|
+
rescue Collins::RequestError => e
|
44
|
+
if e.code.to_i == 404 then
|
45
|
+
false
|
46
|
+
else
|
47
|
+
# if strict? is true, should still return a boolean for exists?
|
48
|
+
logger.info("Exception getting asset: #{e.class} #{e}")
|
49
|
+
false
|
50
|
+
end
|
51
|
+
rescue Exception => e
|
52
|
+
if e.class.to_s == "WebMock::NetConnectNotAllowedError" then
|
53
|
+
raise e
|
54
|
+
end
|
55
|
+
# if strict? is true, should still return a boolean for exists?
|
56
|
+
logger.info("Exception getting asset: #{e.class} - #{e}")
|
57
|
+
false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def get asset_or_tag, options = {}
|
62
|
+
asset = get_asset_or_tag asset_or_tag
|
63
|
+
parameters = {
|
64
|
+
:location => get_option(:location, options, nil)
|
65
|
+
}
|
66
|
+
parameters = select_non_empty_parameters parameters
|
67
|
+
logger.debug("Getting asset #{asset.tag} with params #{parameters.inspect}")
|
68
|
+
http_get("/api/asset/#{asset.tag}", parameters, asset.location) do |response|
|
69
|
+
parse_response response, :as => :asset, :expects => 200, :raise => strict?, :default => false
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Find assets matching the specified criteria
|
74
|
+
#
|
75
|
+
# In general the options hash corresponds to asset key/value pairs. Reserved keys in the selector
|
76
|
+
# are treated with care. These keys are in {Collins::Asset::Find::DATE\_PARAMS} and in
|
77
|
+
# {Collins::Asset::Find::GENERAL\_PARAMS}. All other keys are assumed to be asset attributes.
|
78
|
+
# @param [Hash] options Query options
|
79
|
+
# @return [Array<Collins::Asset>] An array of assets matching the query
|
80
|
+
# @raise [UnexpectedResponseError] If the HTTP response code is not a 200
|
81
|
+
def find options = {}
|
82
|
+
solrquery = options.delete(:query)
|
83
|
+
if solrquery != nil then
|
84
|
+
return search solrquery, options[:size], options.sort
|
85
|
+
end
|
86
|
+
use_api_version "1.1"
|
87
|
+
query = asset_hash_to_find_query options
|
88
|
+
params = query.to_a.map do |param|
|
89
|
+
key, val = param
|
90
|
+
if val.is_a?(Array) then
|
91
|
+
val.map{|v| "#{key}=#{asset_escape_attribute(v)}"}.join("&")
|
92
|
+
else
|
93
|
+
"#{key}=#{asset_escape_attribute(val)}"
|
94
|
+
end
|
95
|
+
end.reject{|s| s.empty?}
|
96
|
+
logger.debug("Finding assets using params #{params.inspect}")
|
97
|
+
http_get("/api/assets", params) do |response|
|
98
|
+
parse_response response, :expects => 200, :as => :paginated do |json|
|
99
|
+
json.map { |j| Collins::Asset.from_json(j) }
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def search query, size = 50, sort = "ASC", sort_field = "tag"
|
105
|
+
use_api_version "1.2"
|
106
|
+
if query.start_with? "\"" and query.end_with? "\"" then
|
107
|
+
query = query[1..-2]
|
108
|
+
end
|
109
|
+
params = {
|
110
|
+
:query => query,
|
111
|
+
:size => size,
|
112
|
+
:sort => sort,
|
113
|
+
:sort_field => sort_field
|
114
|
+
}
|
115
|
+
logger.debug("perform asset search using query #{query}")
|
116
|
+
http_get("/api/assets",params) do |response|
|
117
|
+
parse_response response, :expects => 200, :as => :paginated do |json|
|
118
|
+
json.map { |j| Collins::Asset.from_json(j) }
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def find_similar asset_or_tag, size = 50, sort = "ASC", sort_type = "distance", only_unallocated = true
|
124
|
+
asset = get_asset_or_tag asset_or_tag
|
125
|
+
params = {
|
126
|
+
:size => size,
|
127
|
+
:sort => sort,
|
128
|
+
:sortType => sort_type,
|
129
|
+
:onlyUnallocated => only_unallocated
|
130
|
+
}
|
131
|
+
logger.debug("Finding similar assets for #{asset.tag}")
|
132
|
+
http_get("/api/asset/#{asset.tag}/similar", params) do |response|
|
133
|
+
parse_response response, :expects => 200, :as => :paginated do |json|
|
134
|
+
json.map { |j| Collins::Asset.from_json(j) }
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
private
|
140
|
+
def asset_escape_attribute value
|
141
|
+
URI.escape(value.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
|
142
|
+
end
|
143
|
+
|
144
|
+
def asset_hash_to_find_query opts = {}
|
145
|
+
options = opts.clone
|
146
|
+
hash = {:attribute => []}
|
147
|
+
okeys = options.keys
|
148
|
+
Collins::Asset::Find::DATE_PARAMS.each do |query_key|
|
149
|
+
okeys.each do |user_key|
|
150
|
+
if query_key.to_s.downcase == user_key.to_s.downcase then
|
151
|
+
hash[query_key.to_sym] = Collins::Asset.format_date_string(options.delete(user_key))
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
Collins::Asset::Find::GENERAL_PARAMS.each do |query_key|
|
156
|
+
okeys.each do |user_key|
|
157
|
+
if query_key.to_s.downcase == user_key.to_s.downcase then
|
158
|
+
hash[query_key.to_sym] = options.delete(user_key)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
options.each do |k,v|
|
163
|
+
hash[:attribute] << "#{k};#{regex_to_string(v)}"
|
164
|
+
end
|
165
|
+
hash
|
166
|
+
end
|
167
|
+
|
168
|
+
def regex_to_string value
|
169
|
+
if is_regex? value then
|
170
|
+
rewrite_regex value
|
171
|
+
else
|
172
|
+
value
|
173
|
+
end
|
174
|
+
end
|
175
|
+
def is_regex? value
|
176
|
+
value.is_a?(Regexp)
|
177
|
+
end
|
178
|
+
def rewrite_regex value
|
179
|
+
value.inspect[1..-2] # turn /lkasd/ into lkasd
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
|
184
|
+
end; end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module Collins; module Api
|
2
|
+
|
3
|
+
module AssetState
|
4
|
+
def state_test; @state_test end
|
5
|
+
def state_test= v; @state_test = v end
|
6
|
+
module_function :state_test, :state_test=
|
7
|
+
|
8
|
+
def state_create! name, label, description, status = nil
|
9
|
+
name = validate_state_name name
|
10
|
+
parameters = {
|
11
|
+
:label => label,
|
12
|
+
:description => description,
|
13
|
+
:status => status
|
14
|
+
}
|
15
|
+
if not ::Collins::Api::AssetState.state_test then
|
16
|
+
parameters = select_non_empty_parameters parameters
|
17
|
+
end
|
18
|
+
logger.debug("Creating state with name #{name}")
|
19
|
+
http_put("/api/state/#{name}", parameters) do |r|
|
20
|
+
parse_response r, :expects => 201, :as => :status, :raise => strict?, :default => false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
def state_delete! name
|
24
|
+
name = validate_state_name name
|
25
|
+
logger.debug("Deleting state with name #{name}")
|
26
|
+
http_delete("/api/state/#{name}") do |r|
|
27
|
+
parse_response r, :expects => 202, :as => :data, :raise => strict?, :default => 0 do |js|
|
28
|
+
js["DELETED"].to_s.to_i
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
def state_update! name, options = {}
|
33
|
+
name = validate_state_name name
|
34
|
+
parameters = {
|
35
|
+
:label => options[:label],
|
36
|
+
:description => options[:description],
|
37
|
+
:name => options[:name],
|
38
|
+
:status => options[:status]
|
39
|
+
}
|
40
|
+
if not ::Collins::Api::AssetState.state_test then
|
41
|
+
parameters = select_non_empty_parameters parameters
|
42
|
+
end
|
43
|
+
logger.debug("Updating state with name #{name} params #{parameters}")
|
44
|
+
http_post("/api/state/#{name}", parameters) do |r|
|
45
|
+
parse_response r, :expects => 200, :as => :status, :raise => strict?, :default => false
|
46
|
+
end
|
47
|
+
end
|
48
|
+
def state_get name
|
49
|
+
name = validate_state_name name
|
50
|
+
logger.debug("Fetching state with name #{name}")
|
51
|
+
http_get("/api/state/#{name}") do |r|
|
52
|
+
empty = ::Collins::AssetState.new({})
|
53
|
+
parse_response r, :expects => 200, :as => :data, :default => empty, :raise => false do |js|
|
54
|
+
::Collins::AssetState.from_json(js)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
def state_get_all
|
59
|
+
http_get("/api/states") do |r|
|
60
|
+
parse_response r, :expects => 200, :as => :data, :default => [], :raise => false do |js|
|
61
|
+
js.map do |state|
|
62
|
+
::Collins::AssetState.from_json(state)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
def validate_state_name name
|
70
|
+
if ::Collins::Api::AssetState.state_test then
|
71
|
+
return name
|
72
|
+
end
|
73
|
+
name_opt = ::Collins::Option(name).map {|x| x.to_s.strip}.filter_not {|x| x.empty?}.filter {|x|
|
74
|
+
x.size > 1 && x.size <= 32
|
75
|
+
}
|
76
|
+
if name_opt.empty? then
|
77
|
+
raise ::Collins::ExpectationFailedError.new("name must be between 2 and 32 characters")
|
78
|
+
else
|
79
|
+
name_opt.get
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end # end module AssetState
|
84
|
+
|
85
|
+
end; end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Collins; module Api
|
2
|
+
|
3
|
+
module Attributes
|
4
|
+
def delete_attribute! asset_or_tag, attribute, group_id = nil
|
5
|
+
asset = get_asset_or_tag asset_or_tag
|
6
|
+
parameters = {
|
7
|
+
:groupId => group_id
|
8
|
+
}
|
9
|
+
parameters = select_non_empty_parameters parameters
|
10
|
+
logger.debug("Deleting attribute #{attribute} on #{asset.tag} with params #{parameters.inspect}")
|
11
|
+
http_delete("/api/asset/#{asset.tag}/attribute/#{attribute}", parameters, asset.location) do |response|
|
12
|
+
parse_response response, :expects => 202, :as => :status, :raise => strict?, :default => false
|
13
|
+
end
|
14
|
+
end
|
15
|
+
def set_attribute! asset_or_tag, key, value, group_id = nil
|
16
|
+
asset = get_asset_or_tag asset_or_tag
|
17
|
+
parameters = {
|
18
|
+
:attribute => "#{key};#{value}",
|
19
|
+
:groupId => group_id
|
20
|
+
}
|
21
|
+
parameters = select_non_empty_parameters parameters
|
22
|
+
logger.debug("Setting attribute #{key} to #{value} on #{asset.tag}")
|
23
|
+
http_post("/api/asset/#{asset.tag}", parameters, asset.location) do |response|
|
24
|
+
parse_response response, :expects => 200, :as => :status, :raise => strict?, :default => false
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Set the status of an asset
|
29
|
+
# @overload set_status!(asset_or_tag, status, reason = 'Set via API', state = nil)
|
30
|
+
# Set the status, reason and optionally state of asset
|
31
|
+
# @param [String,Collins::Asset] asset_or_tag The asset or tag
|
32
|
+
# @param [String] status the status of the asset
|
33
|
+
# @param [String] reason the reason for the change
|
34
|
+
# @param [String] state the asset state
|
35
|
+
# @overload set_status!(asset_or_tag, hash)
|
36
|
+
# Set the status, reason, and optionally state of asset
|
37
|
+
# @param [String,Collins::Asset] asset_or_tag The asset or tag
|
38
|
+
# @param [Hash] hash the options to set
|
39
|
+
# @option hash [String] :status The asset status
|
40
|
+
# @option hash [String] :reason The reason for the change
|
41
|
+
# @option hash [String] :state The asset state
|
42
|
+
# @return Boolean
|
43
|
+
def set_status! asset_or_tag, *varargs
|
44
|
+
status = state = nil
|
45
|
+
reason = 'Set via ruby client'
|
46
|
+
asset = get_asset_or_tag asset_or_tag
|
47
|
+
if varargs.size == 0 then
|
48
|
+
raise ::Collins::ExpectationFailedError.new("set_status! requires a status")
|
49
|
+
elsif varargs.size == 1 and varargs[0].is_a?(Hash) then
|
50
|
+
hash = symbolize_hash(varargs[0], :downcase => true)
|
51
|
+
status = hash[:status]
|
52
|
+
reason = hash.fetch(:reason, reason)
|
53
|
+
state = hash[:state]
|
54
|
+
elsif varargs.size == 1 and (varargs[0].is_a?(String) or varargs[0].is_a?(Symbol)) then
|
55
|
+
status = varargs[0].to_s
|
56
|
+
elsif varargs.size > 1 then
|
57
|
+
status = varargs[0]
|
58
|
+
reason = varargs[1]
|
59
|
+
state = varargs[2] if varargs.size > 2
|
60
|
+
else
|
61
|
+
raise ::Collins::ExpectationFailedError.new("set_status! called with invalid parameters")
|
62
|
+
end
|
63
|
+
parameters = {
|
64
|
+
:status => status,
|
65
|
+
:reason => reason,
|
66
|
+
:state => state
|
67
|
+
}
|
68
|
+
parameters = select_non_empty_parameters parameters
|
69
|
+
logger.debug("Setting status to #{status} on #{asset.tag}")
|
70
|
+
http_post("/api/asset/#{asset.tag}/status", parameters, asset.location) do |response|
|
71
|
+
parse_response response, :expects => 200, :as => :status, :raise => strict?, :default => false
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end # module Attributes
|
75
|
+
|
76
|
+
end; end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'collins/address'
|
2
|
+
|
3
|
+
module Collins; module Api
|
4
|
+
|
5
|
+
module IpAddress
|
6
|
+
def ipaddress_allocate! asset_or_tag, address_pool, count = 1
|
7
|
+
asset = get_asset_or_tag asset_or_tag
|
8
|
+
logger.debug("Allocating #{count} addresses for #{asset.tag} in pool #{address_pool}")
|
9
|
+
parameters = {
|
10
|
+
:count => count,
|
11
|
+
:pool => address_pool
|
12
|
+
}
|
13
|
+
http_put("/api/asset/#{asset.tag}/address", parameters, asset.location) do |response|
|
14
|
+
parse_response response, :expects => 201, :default => [] do |json|
|
15
|
+
Collins::Address.from_json(json["data"]["ADDRESSES"])
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def ipaddress_update! asset_or_tag, old_address = nil, options = {}
|
21
|
+
asset = get_asset_or_tag asset_or_tag
|
22
|
+
logger.debug("Updating IP address for #{asset.tag}")
|
23
|
+
parameters = {
|
24
|
+
:old_address => old_address,
|
25
|
+
:address => get_option(:address, options, nil),
|
26
|
+
:gateway => get_option(:gateway, options, nil),
|
27
|
+
:netmask => get_option(:netmask, options, nil),
|
28
|
+
:pool => get_option(:pool, options, nil)
|
29
|
+
}
|
30
|
+
parameters = select_non_empty_parameters parameters
|
31
|
+
http_post("/api/asset/#{asset.tag}/address", parameters, asset.location) do |response|
|
32
|
+
parse_response response, :expects => [200,201], :default => false, :raise => strict?
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def ipaddress_delete! asset_or_tag, pool = nil
|
37
|
+
asset = get_asset_or_tag asset_or_tag
|
38
|
+
logger.debug("Deleting addresses for asset #{asset.tag} in pool #{pool}")
|
39
|
+
parameters = {
|
40
|
+
:pool => pool
|
41
|
+
}
|
42
|
+
parameters = select_non_empty_parameters parameters
|
43
|
+
http_delete("/api/asset/#{asset.tag}/addresses", parameters, asset.location) do |response|
|
44
|
+
parse_response response, :expects => 200, :default => false, :raise => strict? do |json|
|
45
|
+
json["data"]["DELETED"].to_s.to_i
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def ipaddress_pools show_all = true
|
51
|
+
logger.debug("Finding IP address pools")
|
52
|
+
http_get("/api/address/pools", {:all => show_all}) do |response|
|
53
|
+
parse_response response, :expects => 200, :default => [], :raise => strict? do |json|
|
54
|
+
json["data"]["POOLS"]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def addresses_for_asset asset_or_tag
|
60
|
+
asset = get_asset_or_tag asset_or_tag
|
61
|
+
logger.debug("Getting IP addresses for asset #{asset.tag}")
|
62
|
+
http_get("/api/asset/#{asset.tag}/addresses", {}, asset.location) do |response|
|
63
|
+
parse_response response, :expects => 200, :default => [], :raise => strict? do |json|
|
64
|
+
Collins::Address.from_json(json["data"]["ADDRESSES"])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def asset_at_address address
|
70
|
+
logger.debug("Finding asset at address #{address}")
|
71
|
+
http_get("/api/asset/with/address/#{address}") do |response|
|
72
|
+
parse_response response, :expects => 200, :default => nil, :raise => strict?, :as => :bare_asset
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def assets_in_pool pool
|
77
|
+
logger.debug("Finding assets in pool #{pool}")
|
78
|
+
http_get("/api/assets/with/addresses/in/#{pool}") do |response|
|
79
|
+
parse_response response, :expects => 200, :default => [], :raise => strict? do |json|
|
80
|
+
json["data"]["ASSETS"].map{|j| Collins::Asset.from_json(j, true)}
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end # module IpAddress
|
86
|
+
|
87
|
+
end; end
|