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.
- 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
|