foreman_reserve 0.1.6 → 0.1.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.
- checksums.yaml +4 -4
- data/README.rdoc +43 -9
- data/VERSION +1 -1
- data/app/controllers/foreman_reserve/api/hosts_controller.rb +142 -83
- data/app/models/foreman_reserve/host_extensions.rb +24 -15
- data/foreman_reserve.gemspec +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: edaeb4e6dd24d5ca57297860ae94f8e49f47ac39
|
4
|
+
data.tar.gz: 79c1507a10634769373a92ba9f9d256d862ae155
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1c929a0f33b04449f517359cd7cb292cf1abb9e41fb1968e114e6fd6b1ed3d814c653da9be2715a26fe0510c4691eee39c47b77209627ffcddf03aa5a6c1da55
|
7
|
+
data.tar.gz: 63c57ee74c1a651740656ed52defbc1ee28de60e869e04e1b755424693ceecd7153c42f97ac52c38b8fc26aea2c37e41ad18145f02acb2a187822e258bbe5b9d
|
data/README.rdoc
CHANGED
@@ -1,39 +1,73 @@
|
|
1
1
|
= foreman_reserve
|
2
2
|
|
3
|
+
{<img src="https://badge.fury.io/rb/foreman_reserve.png" alt="Gem Version" />}[http://badge.fury.io/rb/foreman_reserve]
|
4
|
+
|
3
5
|
This gem will added a route to the API to return the name of available host(s)
|
4
6
|
|
5
7
|
= Installation:
|
6
8
|
|
7
|
-
gem
|
9
|
+
You have to make sure that the gem is available to foreman, to do that the
|
10
|
+
recommended way is to add a new file to <i>$FOREMAN_DIR/bundler.d</i> named
|
11
|
+
<i>foreman_reserve.rb</i> with the next content:
|
12
|
+
|
13
|
+
* You can use the git code to get the latest:
|
14
|
+
|
15
|
+
gem 'foreman_reserve', :git => "https://github.com/david-caro/foreman_reserve.git"
|
16
|
+
|
17
|
+
* Or the gem from rubygems:
|
18
|
+
|
19
|
+
gem 'foreman_reserve'
|
20
|
+
|
21
|
+
After that you'll need to create the bundle for foreman, as foreman user run
|
22
|
+
from the <i>$FOREMAN_DIR</i>:
|
23
|
+
|
24
|
+
<tt>>$ bunde --deploy</tt>
|
25
|
+
|
26
|
+
|
27
|
+
== Foreman 1.1
|
8
28
|
|
9
29
|
In order to work, the foreman application must be the following two lines commented out.
|
10
30
|
|
11
31
|
config/routes.rb
|
12
|
-
|
32
|
+
# match '*a', :to => 'errors#routing'
|
13
33
|
|
14
34
|
config/routes/v1.rb
|
15
|
-
|
35
|
+
# match '*other', :to => 'home#route_error'
|
16
36
|
|
17
37
|
= Usage
|
18
38
|
|
39
|
+
To make a host 'reservable', you need to make sure it has a parameter named
|
40
|
+
<b>RESERVED</b>, that parameter will be used to store the current reservation
|
41
|
+
status, you can safely add the parameter to a hostgroup for the hsot to inherit
|
42
|
+
from.
|
43
|
+
|
19
44
|
To return 1 host:
|
20
|
-
|
45
|
+
|
46
|
+
<tt>>$ curl -u admin:secret -H 'accept:application/json' http://0.0.0.0:3000/api/hosts_reserve</tt>
|
21
47
|
|
22
48
|
To return multiple hosts, pass a parameter called 'amount'
|
23
49
|
|
24
|
-
curl -u admin:secret -H 'accept:application/json' http://0.0.0.0:3000/api/hosts_reserve?amount=3
|
50
|
+
<tt>>$ curl -u admin:secret -H 'accept:application/json' http://0.0.0.0:3000/api/hosts_reserve?amount=3</tt>
|
25
51
|
|
26
52
|
Filter using a specific query: (name ~ virt%)
|
27
53
|
|
28
|
-
curl -u admin:secret -H 'accept:application/json' 'http://0.0.0.0:3000/api/hosts_reserve?query=name%20~%20virt%25'
|
54
|
+
<tt>>$ curl -u admin:secret -H 'accept:application/json' 'http://0.0.0.0:3000/api/hosts_reserve?query=name%20~%20virt%25'</tt>
|
29
55
|
|
30
56
|
Release a specific host:
|
31
57
|
|
32
|
-
curl -u admin:secret -H 'accept:application/json' 'http://0.0.0.0:3000/api/hosts_release?host_name=myreservedhost'
|
58
|
+
<tt>>$ curl -u admin:secret -H 'accept:application/json' 'http://0.0.0.0:3000/api/hosts_release?host_name=myreservedhost'</tt>
|
33
59
|
|
34
60
|
Release a group of hosts using a query: (name ~ virt%)
|
35
61
|
|
36
|
-
curl -u admin:secret -H 'accept:application/json' 'http://0.0.0.0:3000/api/hosts_reserve?query=name%20~%20virt%25'
|
62
|
+
<tt>>$ curl -u admin:secret -H 'accept:application/json' 'http://0.0.0.0:3000/api/hosts_reserve?query=name%20~%20virt%25'</tt>
|
63
|
+
|
64
|
+
== foreman-python
|
65
|
+
|
66
|
+
In order to use from python, there's a python module that already includes
|
67
|
+
this plugin calls, you can find it on pypi or on github:
|
68
|
+
|
69
|
+
* https://github.com/david-caro/python-foreman
|
70
|
+
* https://pypi.python.org/pypi/python-foreman
|
37
71
|
|
38
72
|
== Contributing to foreman_reserve
|
39
73
|
|
@@ -47,6 +81,6 @@ curl -u admin:secret -H 'accept:application/json' 'http://0.0.0.0:3000/api/hosts
|
|
47
81
|
|
48
82
|
== Copyright
|
49
83
|
|
50
|
-
Copyright (c)
|
84
|
+
Copyright (c) 2013 Joseph Mitchell Magen and David Caro. See LICENSE.txt for
|
51
85
|
further details.
|
52
86
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.7
|
@@ -3,103 +3,149 @@ module Api
|
|
3
3
|
class ForemanReserveController < Api::V1::BaseController
|
4
4
|
unloadable
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
6
|
+
# Get the list of reserved hosts
|
7
|
+
# @param query [String] Query to filter the hosts with
|
8
|
+
def get_reserved(query='')
|
9
|
+
hosts = User.current.admin? ? Host::Managed : Host::Managed.my_hosts
|
10
|
+
hosts.search_for(query)
|
11
|
+
hosts.each do |host|
|
12
|
+
params = host.info()['parameters']
|
13
|
+
if params and
|
14
|
+
params.key?('RESERVED') and
|
15
|
+
params['RESERVED'] != 'false'
|
16
|
+
host
|
17
|
+
end
|
15
18
|
end
|
16
19
|
end
|
17
|
-
end
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
21
|
+
# Get the list of available hosts
|
22
|
+
# @param query [String] Query to filter the hosts with
|
23
|
+
def get_free(query='')
|
24
|
+
hosts = User.current.admin? ? Host::Managed : Host::Managed.my_hosts
|
25
|
+
hosts.search_for(query)
|
26
|
+
hosts.each do |host|
|
27
|
+
params = host.info()['parameters']
|
28
|
+
if params and
|
29
|
+
params.has_key('RESERVED') and
|
30
|
+
params['RESERVED'] == 'false'
|
31
|
+
host
|
32
|
+
end
|
28
33
|
end
|
29
34
|
end
|
30
|
-
end
|
31
35
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
36
|
+
# Return not found
|
37
|
+
# @param exception [String] Message to show
|
38
|
+
def not_found(exception = nil)
|
39
|
+
logger.debug "not found: #{exception}" if exception
|
40
|
+
respond_to do |format|
|
41
|
+
format.html { render "common/404", :status => 404 }
|
42
|
+
format.json { head :status => 404}
|
43
|
+
format.yaml { head :status => 404}
|
44
|
+
end
|
45
|
+
true
|
46
|
+
end
|
41
47
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
48
|
+
# <b>API METHOD</b>: Reserve one or more hosts, will return 404 if the
|
49
|
+
# given query gives no results and 406 (Not acceptable) if not enough free
|
50
|
+
# hosts
|
51
|
+
#
|
52
|
+
# <b>Query parameters:</b>
|
53
|
+
#
|
54
|
+
# * <tt><b>amount</b> (Int)</tt> <i>(defaults to: <tt>1</tt>)</i> ---
|
55
|
+
# Amount of hosts to reserve
|
56
|
+
# * <tt><b>reason</b> (String)</tt> <i>(defaults to: <tt>true</tt>)</i> ---
|
57
|
+
# Reason to reserve the hosts under, this is the string that will be
|
58
|
+
# put in the <i>RESERVED</i> host parameter
|
59
|
+
# * <tt><b>query</b> (String)</tt> <i>(defaults to: <tt>''</tt>)</i> ---
|
60
|
+
# Query to filter the list of hosts with
|
61
|
+
def reserve
|
62
|
+
amount = (params[:amount] || 1).to_i
|
63
|
+
reason = params[:reason] || 'true'
|
64
|
+
## Lock to avoid reserving the same host twice
|
65
|
+
unless File.exists? "/tmp/foreman_reserve.lock"
|
66
|
+
File.open("/tmp/foreman_reserve.lock", 'w') {}
|
67
|
+
end
|
68
|
+
lock = File.new("/tmp/foreman_reserve.lock")
|
69
|
+
begin
|
70
|
+
lock.flock(File::LOCK_EX)
|
71
|
+
potential_hosts = get_free(params[:query])
|
72
|
+
return not_found if potential_hosts.empty?
|
73
|
+
return not_acceptable if potential_hosts.count < amount
|
74
|
+
@hosts = potential_hosts[0..(amount-1)].each do |host|
|
75
|
+
logger.error host.class.name
|
76
|
+
logger.error host.class.instance_methods(false)
|
77
|
+
logger.error Host.class.instance_methods(false)
|
78
|
+
host.reserve!(reason)
|
79
|
+
end
|
80
|
+
ensure
|
81
|
+
lock.flock(File::LOCK_UN)
|
82
|
+
end
|
83
|
+
respond_to do |format|
|
84
|
+
format.json {render :json => @hosts }
|
85
|
+
format.yaml {render :text => @hosts.to_yaml}
|
86
|
+
format.html {not_found }
|
60
87
|
end
|
61
|
-
ensure
|
62
|
-
lock.flock(File::LOCK_UN)
|
63
|
-
end
|
64
|
-
respond_to do |format|
|
65
|
-
format.json {render :json => @hosts }
|
66
|
-
format.yaml {render :text => @hosts.to_yaml}
|
67
|
-
format.html {not_found }
|
68
88
|
end
|
69
|
-
end
|
70
89
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
+
# <b>API METHOD</b>: Release one or more hosts, will return 406 if there
|
91
|
+
# are less than <tt>amount</tt> reserved hosts
|
92
|
+
#
|
93
|
+
# <b>Query parameters:</b>
|
94
|
+
#
|
95
|
+
# * <tt><b>amount</b> (Int)</tt> <i>(defaults to: <tt>1</tt>)</i> ---
|
96
|
+
# Amount of hosts to release
|
97
|
+
# * <tt><b>host_name</b> (String)</tt>
|
98
|
+
# <i>(defaults to: <tt>''</tt>)</i> ---
|
99
|
+
# If given, will also filter by that host name
|
100
|
+
# * <tt><b>query</b> (String)</tt> <i>(defaults to: <tt>''</tt>)</i> ---
|
101
|
+
# Query to filter the list of hosts with
|
102
|
+
def release
|
103
|
+
host_name = (params[:host_name] || '')
|
104
|
+
query = params[:query]
|
105
|
+
amount = (params[:amount] || 0 ).to_i
|
106
|
+
if host_name != ''
|
107
|
+
query = "#{query} AND name = #{host_name}"
|
108
|
+
end
|
109
|
+
reserved_hosts = get_reserved(query)
|
110
|
+
return not_found if reserved_hosts.empty?
|
111
|
+
if amount != 0
|
112
|
+
return not_acceptable if reserved_hosts.count < amount
|
113
|
+
@hosts = reserved_hosts[0..(amount-1)].each { |host| host.release! }
|
114
|
+
else
|
115
|
+
@hosts = reserved_hosts.each { |host| host.release! }
|
116
|
+
end
|
117
|
+
respond_to do |format|
|
118
|
+
format.json {render :json => @hosts.map(&:name) }
|
119
|
+
format.yaml {render :text => @hosts.to_yaml}
|
120
|
+
format.html {not_found }
|
121
|
+
end
|
90
122
|
end
|
91
|
-
end
|
92
123
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
124
|
+
# <b>API METHOD</b>: Show the list of resrved hosts
|
125
|
+
#
|
126
|
+
# <b>Query parameters:</b>
|
127
|
+
#
|
128
|
+
# * <tt><b>query</b> (String)</tt> <i>(defaults to: <tt>''</tt>)</i> ---
|
129
|
+
# Query to filter the list of hosts with
|
130
|
+
def show_reserved
|
131
|
+
hosts = get_reserved(params[:query])
|
132
|
+
return not_found if hosts.empty?
|
133
|
+
respond_to do |format|
|
134
|
+
format.json {render :json => hosts }
|
135
|
+
format.yaml {render :text => hosts.to_yaml}
|
136
|
+
format.html {not_found }
|
137
|
+
end
|
100
138
|
end
|
101
|
-
end
|
102
139
|
|
140
|
+
# <b>API METHOD</b>: Show the list of available hosts, will return 406
|
141
|
+
# (Not acceptable) if <tt>amount</tt> given and not enough free hosts found
|
142
|
+
#
|
143
|
+
# <b>Query parameters:</b>
|
144
|
+
#
|
145
|
+
# * <tt><b>amount</b> (Int)</tt> <i>(defaults to: <tt>0</tt>)</i> ---
|
146
|
+
# Amount of hosts to show, 0 for all
|
147
|
+
# * <tt><b>query</b> (String)</tt> <i>(defaults to: <tt>''</tt>)</i> ---
|
148
|
+
# Query to filter the list of hosts with
|
103
149
|
def show_available
|
104
150
|
amount = (params[:amount] || 0).to_i
|
105
151
|
hosts = get_free(params[:query])
|
@@ -115,6 +161,18 @@ module Api
|
|
115
161
|
end
|
116
162
|
end
|
117
163
|
|
164
|
+
# <b>API METHOD</b>: Update the reserved reason
|
165
|
+
#
|
166
|
+
# <b>Query parameters:</b>
|
167
|
+
#
|
168
|
+
# * <tt><b>amount</b> (Int)</tt> <i>(defaults to: <tt>0</tt>)</i> ---
|
169
|
+
# Amount of hosts to show, 0 for all
|
170
|
+
# * <tt><b>reason</b> (String)</tt>
|
171
|
+
# <i>(defaults to: <tt>true</tt>)</i> ---
|
172
|
+
# New reason to reserve the hosts under, this is the string that will
|
173
|
+
# be put in the <i>RESERVED</i> host parameter
|
174
|
+
# * <tt><b>query</b> (String)</tt> <i>(defaults to: <tt>''</tt>)</i> ---
|
175
|
+
# Query to filter the list of hosts with
|
118
176
|
def update_reason
|
119
177
|
amount = (params[:amount] || 0).to_i
|
120
178
|
reason = params[:reason] || 'true'
|
@@ -134,6 +192,7 @@ module Api
|
|
134
192
|
end
|
135
193
|
end
|
136
194
|
|
195
|
+
# Return HTTP 406 (Not acceptable)
|
137
196
|
def not_acceptable
|
138
197
|
head :status => 406
|
139
198
|
end
|
@@ -1,24 +1,33 @@
|
|
1
1
|
module ForemanReserve
|
2
2
|
module HostExtensions
|
3
3
|
extend ActiveSupport::Concern
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
4
|
+
module InstanceMethods
|
5
|
+
|
6
|
+
# Reserve the host
|
7
|
+
#
|
8
|
+
# @param reason [String] Reason to reserve the host under
|
9
|
+
def reserve!(reason = 'true')
|
10
|
+
param = "RESERVED"
|
11
|
+
if p=host_parameters.find_by_name(param)
|
12
|
+
p.update_attribute(:value, reason)
|
13
|
+
else
|
14
|
+
host_parameters.create!(:name => param, :value => reason)
|
12
15
|
end
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
16
|
+
end
|
17
|
+
|
18
|
+
# Release the host
|
19
|
+
def release!
|
20
|
+
param = "RESERVED"
|
21
|
+
if p=host_parameters.find_by_name(param)
|
22
|
+
p.update_attribute(:value, "false")
|
18
23
|
end
|
19
|
-
def as_json(options={})
|
20
|
-
super(:methods => [:host_parameters])
|
21
24
|
end
|
25
|
+
|
26
|
+
# Return a json represenatation of the host
|
27
|
+
def as_json(options={})
|
28
|
+
super(:methods => [:host_parameters])
|
29
|
+
end
|
30
|
+
|
22
31
|
end
|
23
32
|
end
|
24
33
|
end
|
data/foreman_reserve.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = "foreman_reserve"
|
5
|
-
s.version = "0.1.
|
5
|
+
s.version = "0.1.7"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Joseph Mitchell Magen", "David Caro"]
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foreman_reserve
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joseph Mitchell Magen
|
@@ -116,3 +116,4 @@ signing_key:
|
|
116
116
|
specification_version: 3
|
117
117
|
summary: Plugin engine for Foreman to allocate hosts
|
118
118
|
test_files: []
|
119
|
+
has_rdoc:
|