imagefactory-console 0.4.0
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/Rakefile +77 -0
- data/lib/imagefactory.rb +2 -0
- data/lib/imagefactory/base_handler.rb +56 -0
- data/lib/imagefactory/console.rb +251 -0
- data/spec/image_factory/console_spec.rb +217 -0
- data/spec/spec_helper.rb +3 -0
- metadata +72 -0
data/Rakefile
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (C) 2011 Red Hat, Inc.
|
3
|
+
# Written by Jason Guiditta <jguiditt@redhat.com>
|
4
|
+
#
|
5
|
+
# This program is free software; you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation; version 2 of the License.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with this program; if not, write to the Free Software
|
16
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
17
|
+
# MA 02110-1301, USA. A copy of the GNU General Public License is
|
18
|
+
# also available at http://www.gnu.org/copyleft/gpl.html.
|
19
|
+
|
20
|
+
|
21
|
+
require 'rubygems'
|
22
|
+
require 'rake'
|
23
|
+
require 'rake/clean'
|
24
|
+
require 'rake/gempackagetask'
|
25
|
+
require 'rake/rdoctask'
|
26
|
+
require 'rake/testtask'
|
27
|
+
require 'spec/rake/spectask'
|
28
|
+
require 'rake/rpmtask'
|
29
|
+
|
30
|
+
RPMBUILD_DIR = "#{File.expand_path('~')}/rpmbuild"
|
31
|
+
RPM_SPEC = "rubygem-imagefactory-console.spec"
|
32
|
+
|
33
|
+
spec = Gem::Specification.new do |s|
|
34
|
+
s.name = 'imagefactory-console'
|
35
|
+
s.version = '0.4.0'
|
36
|
+
s.has_rdoc = true
|
37
|
+
#s.extra_rdoc_files = ['README', 'COPYING']
|
38
|
+
s.summary = 'QMF Console for Aeolus Image Factory'
|
39
|
+
s.description = s.summary
|
40
|
+
s.author = 'Jason Guiditta'
|
41
|
+
s.email = 'jguiditt@redhat.com'
|
42
|
+
# s.executables = ['your_executable_here']
|
43
|
+
s.files = %w(Rakefile) + Dir.glob("{bin,lib,spec}/**/*")
|
44
|
+
s.require_path = "lib"
|
45
|
+
s.bindir = "bin"
|
46
|
+
end
|
47
|
+
|
48
|
+
Rake::GemPackageTask.new(spec) do |p|
|
49
|
+
p.gem_spec = spec
|
50
|
+
p.need_tar = true
|
51
|
+
p.need_zip = true
|
52
|
+
end
|
53
|
+
|
54
|
+
Rake::RDocTask.new do |rdoc|
|
55
|
+
files =['lib/**/*.rb'] #'README', 'COPYING',
|
56
|
+
rdoc.rdoc_files.add(files)
|
57
|
+
#rdoc.main = "README" # page to start on
|
58
|
+
rdoc.title = "console Docs"
|
59
|
+
rdoc.rdoc_dir = 'doc/rdoc' # rdoc output folder
|
60
|
+
rdoc.options << '--line-numbers'
|
61
|
+
end
|
62
|
+
|
63
|
+
Rake::TestTask.new do |t|
|
64
|
+
t.test_files = FileList['test/**/*.rb']
|
65
|
+
end
|
66
|
+
|
67
|
+
Spec::Rake::SpecTask.new do |t|
|
68
|
+
t.libs << 'lib'
|
69
|
+
t.spec_files = FileList['spec/**/*.rb']
|
70
|
+
t.spec_opts = ['--color', '--format nested']
|
71
|
+
end
|
72
|
+
|
73
|
+
Rake::RpmTask.new(RPM_SPEC) do |rpm|
|
74
|
+
rpm.need_tar = true
|
75
|
+
rpm.package_files.include("lib/*")
|
76
|
+
rpm.topdir = "#{RPMBUILD_DIR}"
|
77
|
+
end
|
data/lib/imagefactory.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (C) 2011 Red Hat, Inc.
|
3
|
+
# Written by Jason Guiditta <jguiditt@redhat.com>
|
4
|
+
#
|
5
|
+
# This program is free software; you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation; version 2 of the License.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with this program; if not, write to the Free Software
|
16
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
17
|
+
# MA 02110-1301, USA. A copy of the GNU General Public License is
|
18
|
+
# also available at http://www.gnu.org/copyleft/gpl.html.
|
19
|
+
|
20
|
+
require 'logger'
|
21
|
+
|
22
|
+
class BaseHandler
|
23
|
+
|
24
|
+
def initialize(logger=nil)
|
25
|
+
logger(logger)
|
26
|
+
end
|
27
|
+
|
28
|
+
def handle(data)
|
29
|
+
logger.debug "====== Type of event: #{data.event}"
|
30
|
+
if data.event == 'STATUS'
|
31
|
+
logger.debug "calling handle status in base handler"
|
32
|
+
handle_status(data)
|
33
|
+
elsif data.event == 'FAILURE'
|
34
|
+
handle_failed(data)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def handle_status(data)
|
39
|
+
logger.debug "{data.event}, #{data.new_status}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def handle_failed(data)
|
43
|
+
logger.error "#{data.to_s}"
|
44
|
+
end
|
45
|
+
|
46
|
+
protected
|
47
|
+
def logger(logger=nil)
|
48
|
+
@logger ||= logger
|
49
|
+
unless @logger
|
50
|
+
@logger = Logger.new(STDOUT)
|
51
|
+
@logger.level = Logger::ERROR
|
52
|
+
@logger.datetime_format = "%Y-%m-%d %H:%M:%S"
|
53
|
+
end
|
54
|
+
return @logger
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,251 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (C) 2011 Red Hat, Inc.
|
3
|
+
# Written by Jason Guiditta <jguiditt@redhat.com>
|
4
|
+
#
|
5
|
+
# This program is free software; you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation; version 2 of the License.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with this program; if not, write to the Free Software
|
16
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
17
|
+
# MA 02110-1301, USA. A copy of the GNU General Public License is
|
18
|
+
# also available at http://www.gnu.org/copyleft/gpl.html.
|
19
|
+
|
20
|
+
# TODO: figure out what I am doing wrong here that I need this line
|
21
|
+
$: << File.expand_path(File.join(File.dirname(__FILE__), "."))
|
22
|
+
require 'cqpid'
|
23
|
+
require 'qmf2'
|
24
|
+
require 'logger'
|
25
|
+
require 'base_handler'
|
26
|
+
|
27
|
+
class ImageFactoryConsole < Qmf2::ConsoleHandler
|
28
|
+
|
29
|
+
attr_accessor :q, :handler
|
30
|
+
|
31
|
+
def initialize(args={})
|
32
|
+
# @retry_limit = args.include?(:retry_limit) ? args[:retry_limit] : 20
|
33
|
+
# @delay = args.include?(:delay) ? args[:delay] : 15
|
34
|
+
host = args.include?(:host) ? args[:host] : "localhost"
|
35
|
+
port = args.include?(:port) ? args[:port] : 5672
|
36
|
+
# url = "amqp://#{host}:#{port}" <- the amqp part here doesnt work yet
|
37
|
+
url = "#{host}:#{port}"
|
38
|
+
opts = {"reconnect"=>"true"}
|
39
|
+
@connection = Cqpid::Connection.new(url, opts)
|
40
|
+
@connection.open
|
41
|
+
@session = Qmf2::ConsoleSession.new(@connection)
|
42
|
+
@session.open
|
43
|
+
@session.set_agent_filter("[and, [eq, _vendor, [quote, 'redhat.com']], [eq, _product, [quote, 'imagefactory']]]")
|
44
|
+
|
45
|
+
if args.include?(:logger)
|
46
|
+
@logger = args[:logger]
|
47
|
+
else
|
48
|
+
@logger = Logger.new(STDOUT)
|
49
|
+
@logger.level = Logger::ERROR
|
50
|
+
@logger.datetime_format = "%Y-%m-%d %H:%M:%S"
|
51
|
+
end
|
52
|
+
@handler = args.include?(:handler)? args[:handler]: BaseHandler.new(@logger)
|
53
|
+
super(@session)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Call this method to initiate a build, and get back an
|
57
|
+
# array of BuildAdaptor objects.
|
58
|
+
# * template => String
|
59
|
+
# Description of what to build. Can be xml, uuid, or url
|
60
|
+
# * targets => Array
|
61
|
+
# Represents the names of the clouds to target (ec2, mock, rackspace, etc)
|
62
|
+
# * image_id => String
|
63
|
+
# The UUID of an image previously built
|
64
|
+
# * build_id => String
|
65
|
+
# The UUID of a previous build of the image
|
66
|
+
# * Returns => an array of BuildAdaptor objects
|
67
|
+
#
|
68
|
+
def build(template, targets, image='', build='')
|
69
|
+
targets = [targets] unless targets.instance_of?(Array)
|
70
|
+
# TODO: return error if there is a problem calling this method or getting
|
71
|
+
# a factory instance
|
72
|
+
begin
|
73
|
+
response = factory.build_image(image, build, template, targets)
|
74
|
+
build_adaptors(response)
|
75
|
+
rescue Exception => e
|
76
|
+
@logger.debug "Encountered error in build_image: #{e}"
|
77
|
+
return e
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Call this method to push an image to a provider, and get back an
|
82
|
+
# array of BuildAdaptor objects.
|
83
|
+
# * providers => Array
|
84
|
+
# Represents the target providers to build for (ec2-us-east, mock1, etc)
|
85
|
+
# * credentials => String
|
86
|
+
# XML block to be used for registration, upload, etc
|
87
|
+
# * image_id => String
|
88
|
+
# The UUID of an image previously built
|
89
|
+
# * build_id => String
|
90
|
+
# The UUID of a previous build of the image
|
91
|
+
# * Returns => an array of BuildAdaptor objects
|
92
|
+
#
|
93
|
+
def push(providers, credentials, image_id, build_id='')
|
94
|
+
providers = [providers] unless providers.instance_of?(Array)
|
95
|
+
# TODO: return error if there is a problem calling this method or getting
|
96
|
+
# a factory instance
|
97
|
+
begin
|
98
|
+
response = factory.push_image(image_id, build_id, providers, credentials)
|
99
|
+
build_adaptors(response)
|
100
|
+
rescue Exception => e
|
101
|
+
@logger.debug "Encountered error in push_image: #{e}"
|
102
|
+
return e
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Call this method to import an image
|
107
|
+
# array of BuildAdaptor objects.
|
108
|
+
# * image => string
|
109
|
+
# The uuid of an existing image
|
110
|
+
# * build => string
|
111
|
+
# the uuid of an existing build, or the empty string
|
112
|
+
# * target_identifier => string
|
113
|
+
# the target specific image ID
|
114
|
+
# * image_desc => string
|
115
|
+
# an xml string description of the image
|
116
|
+
# * target => string
|
117
|
+
# name of the cloud to target
|
118
|
+
# * provider => string
|
119
|
+
# the name of the cloud provider, often a region
|
120
|
+
# Returns => a map including UUIDs as strings for 'target_image', 'build', 'image', 'provider_image'
|
121
|
+
|
122
|
+
def import_image(image, build, target_identifier, image_description, target, provider)
|
123
|
+
# TODO: return error if there is a problem calling this method or getting
|
124
|
+
# a factory instance
|
125
|
+
begin
|
126
|
+
factory.import_image(image, build, target_identifier, image_description, target, provider)
|
127
|
+
rescue Exception => e
|
128
|
+
@logger.debug "Encountered error in import_image: #{e}"
|
129
|
+
return e
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# <b>DEPRECATED:</b> Please use <tt>build</tt> instead.
|
134
|
+
# Call this method to initiate a build, and get back an
|
135
|
+
# BuildAdaptor object.
|
136
|
+
# * descriptor => String
|
137
|
+
# This can be either xml or a url pointing to the xml
|
138
|
+
# * target => String
|
139
|
+
# Represents the target provider type to build for (ec2, mock, etc)
|
140
|
+
# * Returns => a BuildAdaptor object
|
141
|
+
#
|
142
|
+
def build_image(descriptor, target)
|
143
|
+
@logger.warn "[DEPRECATION] 'build_image' is deprecated. Please use 'build' instead."
|
144
|
+
# TODO: return error if there is a problem calling this method or getting
|
145
|
+
# a factory instance
|
146
|
+
begin
|
147
|
+
response = factory.image(descriptor, target)
|
148
|
+
build_adaptor(response)
|
149
|
+
rescue Exception => e
|
150
|
+
@logger.debug "Encountered error in build_image: #{e}"
|
151
|
+
return e
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# <b>DEPRECATED:</b> Please use <tt>push</tt> instead.
|
156
|
+
# Call this method to push an image to a provider, and get back an
|
157
|
+
# BuildAdaptor object.
|
158
|
+
# * image_id => String (uuid)
|
159
|
+
# * provider => String
|
160
|
+
# Represents the target provider to build for (ec2-us-east, mock, etc)
|
161
|
+
# * credentials => String
|
162
|
+
# XML block to be used for registration, upload, etc
|
163
|
+
# * Returns => a BuildAdaptor object
|
164
|
+
#
|
165
|
+
def push_image(image_id, provider, credentials)
|
166
|
+
@logger.warn "[DEPRECATION] 'push_image' is deprecated. Please use 'push' instead."
|
167
|
+
# TODO: return error if there is a problem calling this method or getting
|
168
|
+
# a factory instance
|
169
|
+
begin
|
170
|
+
response = factory.provider_image(image_id, provider, credentials)
|
171
|
+
build_adaptor(response)
|
172
|
+
rescue Exception => e
|
173
|
+
@logger.debug "Encountered error in push_image: #{e}"
|
174
|
+
return e
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
#TODO: enhance both of these methods to handle multiple agents
|
179
|
+
def agent_added(agent)
|
180
|
+
@logger.debug "GOT AN AGENT: #{agent} at #{Time.now.utc}"
|
181
|
+
@q = agent if agent.product == "imagefactory"
|
182
|
+
end
|
183
|
+
|
184
|
+
def agent_deleted(agent, reason)
|
185
|
+
@logger.debug "AGENT GONE: #{agent} at #{Time.now.utc}, because #{reason}"
|
186
|
+
unless @q==nil
|
187
|
+
@q = nil if (@q.product == agent.product && @q.name.eql?(agent.name))
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# TODO: handle agent restart events (this will be more useful when
|
192
|
+
# restarted agent can recover an in-process build
|
193
|
+
def agent_restarted(agent)
|
194
|
+
@logger.debug "AGENT RESTARTED: #{agent.product}"
|
195
|
+
end
|
196
|
+
|
197
|
+
# TODO: handle schema updates. This will be more useful when/if
|
198
|
+
# we make this a more generic console to talk to different agents.
|
199
|
+
def agent_schema_updated(agent)
|
200
|
+
@logger.debug "AGENT SCHEMA UPDATED: #{agent.product}"
|
201
|
+
end
|
202
|
+
|
203
|
+
def event_raised(agent, data, timestamp, severity)
|
204
|
+
@logger.debug "GOT AN EVENT: #{agent}, #{data} at #{timestamp}"
|
205
|
+
@handler.handle(data)
|
206
|
+
end
|
207
|
+
|
208
|
+
def shutdown
|
209
|
+
@logger.debug "Closing connections.."
|
210
|
+
if @session
|
211
|
+
@session.close
|
212
|
+
end
|
213
|
+
@connection.close
|
214
|
+
|
215
|
+
#TODO Replace this with some control flow to manage the cancelling of the console handler, atm
|
216
|
+
# this code swallows error message generated by closing connection, then cancelling console.
|
217
|
+
begin
|
218
|
+
self.cancel
|
219
|
+
rescue QmfError
|
220
|
+
# TODO We should be logging to a file rather than STDOUT, uncomment this code when logging is configured properly
|
221
|
+
# Commented out to clean up user output
|
222
|
+
#@logger.error "Issue Closing Console Handler"
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
private
|
227
|
+
|
228
|
+
def factory
|
229
|
+
@factory ||= @q.query("{class:ImageFactory, package:'com.redhat.imagefactory'}").first
|
230
|
+
end
|
231
|
+
|
232
|
+
def build_adaptors(response)
|
233
|
+
ret = []
|
234
|
+
response['build_adaptors'].each do |imgfacaddr|
|
235
|
+
query = Qmf2::Query.new(Qmf2::DataAddr.new(imgfacaddr))
|
236
|
+
ret << @q.query(query,5).first
|
237
|
+
end
|
238
|
+
ret
|
239
|
+
end
|
240
|
+
|
241
|
+
def build_adaptor(response)
|
242
|
+
@logger.warn "[DEPRECATION] 'build_adaptor' is deprecated. Please use 'build_adaptors' instead."
|
243
|
+
imgfacaddr = Qmf2::DataAddr.new(response['build_adaptor'])
|
244
|
+
query = Qmf2::Query.new(imgfacaddr)
|
245
|
+
@q.query(query,5).first
|
246
|
+
end
|
247
|
+
|
248
|
+
def make_array(a)
|
249
|
+
return a ||= [a] unless a.instance_of?(Array)
|
250
|
+
end
|
251
|
+
end
|
@@ -0,0 +1,217 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module ImageFactory
|
4
|
+
describe ImageFactoryConsole do
|
5
|
+
context "needs a real agent running" do
|
6
|
+
# for now, these all require an actual agent on the bus
|
7
|
+
before(:all) do
|
8
|
+
@logger = Logger.new(STDOUT)
|
9
|
+
@logger.level = Logger::DEBUG
|
10
|
+
@logger.datetime_format = "%Y-%m-%d %H:%M:%S"
|
11
|
+
@i = ImageFactoryConsole.new() # Pass this in for more logging: (:logger => @logger)
|
12
|
+
@i.start
|
13
|
+
# Sadly, this is needed so we wait for an agent to appear.
|
14
|
+
# We might be able to extract this somewhere to hold off
|
15
|
+
# on tests until we get an agent_added notification
|
16
|
+
sleep(5)
|
17
|
+
#TODO: take this snippet and make a fixture of some sort to use in tests
|
18
|
+
#tmpl = '<template> <name>tmpl1</name> <description>foo</description> <os> <name>Fedora</name>
|
19
|
+
# <arch>x86_64</arch> <version>14</version> <install type="url">
|
20
|
+
# <url>http://download.fedoraproject.org/pub/fedora/linux/releases/14/Fedora/x86_64/os/</url> </install>
|
21
|
+
# </os> <repositories> <repository name="custom"> <url>http://repos.fedorapeople.org/repos/aeolus/demo/webapp/</url>
|
22
|
+
# <signed>false</signed> </repository> </repositories> </template>'
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "#q" do
|
26
|
+
it "should get an agent set" do
|
27
|
+
@i.q.should_not be_nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#build_image" do
|
32
|
+
it "should return a build-adaptor with uuid" do
|
33
|
+
@i.build_image("<template></template>", "mock").image_id.should_not be_nil
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "#push_image" do
|
38
|
+
it "should return a build-adaptor with uuid" do
|
39
|
+
@image = @i.build_image("<template></template>", "mock")
|
40
|
+
#@i.handler = BaseHandler.new(@logger)
|
41
|
+
@i.handler.should_not_receive(:handle_failed)
|
42
|
+
@i.push_image(@image.image_id, "mock", "some creds").image_id.should_not be_nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#import_image" do
|
47
|
+
it "should return a build-adaptor with uuid" do
|
48
|
+
@import = @i.import_image("", "", "ami-test", "<image><name>Test Image</name></image>", "ec2", "ec2-us-east-1")
|
49
|
+
is_uuid?(@import['image']).should == true
|
50
|
+
is_uuid?(@import['target_image']).should == true
|
51
|
+
is_uuid?(@import['build']).should == true
|
52
|
+
is_uuid?(@import['provider_image']).should == true
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "#build" do
|
57
|
+
it "should return an array of build-adaptors with uuids" do
|
58
|
+
@i.build("<template></template>", ["mock"]).each do |adaptor|
|
59
|
+
adaptor.image_id.should_not be_nil
|
60
|
+
adaptor.image.should_not be_nil
|
61
|
+
adaptor.build.should_not be_nil
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should work with single target as string" do
|
66
|
+
@i.build("<template></template>", "mock").each do |adaptor|
|
67
|
+
adaptor.image_id.should_not be_nil
|
68
|
+
adaptor.image.should_not be_nil
|
69
|
+
adaptor.build.should_not be_nil
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "#push" do
|
75
|
+
it "should return an array of build-adaptors with uuids" do
|
76
|
+
@i.build("<template></template>", ["mock"]).each do |adaptor|
|
77
|
+
#@i.handler = BaseHandler.new(@logger)
|
78
|
+
@i.handler.should_not_receive(:handle_failed)
|
79
|
+
@i.push(["mock"], "<provider_credentials/>", adaptor.image).each do |a|
|
80
|
+
a.image_id.should_not be_nil
|
81
|
+
a.image.should_not be_nil
|
82
|
+
a.build.should_not be_nil
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should work with single provider as string" do
|
88
|
+
@i.build("<template></template>", "mock").each do |adaptor|
|
89
|
+
#@i.handler = BaseHandler.new(@logger)
|
90
|
+
@i.handler.should_not_receive(:handle_failed)
|
91
|
+
@i.push("mock1", "<provider_credentials/>", adaptor.image).each do |a|
|
92
|
+
a.image_id.should_not be_nil
|
93
|
+
a.image.should_not be_nil
|
94
|
+
a.build.should_not be_nil
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
after(:all) do
|
101
|
+
@i.shutdown
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context "agent is stubbed" do
|
106
|
+
before(:each) do
|
107
|
+
@agent = mock('agent', :null_object => true)
|
108
|
+
@agent.stub(:product).and_return("imagefactory")
|
109
|
+
@agent.stub(:name).and_return("redhat.com:imagefactory:b9e131c7-7905-409e-bfb5-dd4848a776a7")
|
110
|
+
@output = double('output')
|
111
|
+
@i2 = ImageFactoryConsole.new(:logger => @output)
|
112
|
+
end
|
113
|
+
|
114
|
+
describe "#agent_added" do
|
115
|
+
it "logs when a new agent appears" do
|
116
|
+
@output.should_receive(:debug).with(/GOT AN AGENT/).as_null_object
|
117
|
+
@i2.agent_added(@agent)
|
118
|
+
end
|
119
|
+
|
120
|
+
it "stores a reference to that agent if it is a factory" do
|
121
|
+
@output.should_receive(:debug).with(/GOT AN AGENT/)
|
122
|
+
@i2.agent_added(@agent)
|
123
|
+
@i2.q.should respond_to(:product)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
describe "#agent_deleted" do
|
128
|
+
before(:each) do
|
129
|
+
@old_agent = mock('agent', :null_object => true)
|
130
|
+
@old_agent.stub(:product).and_return("imagefactory")
|
131
|
+
@old_agent.stub(:name).and_return("redhat.com:imagefactory:4eb3776e-d91e-4239-9a73-3ab43ecc7e15")
|
132
|
+
@output.should_receive(:debug).with(/GOT AN AGENT/)
|
133
|
+
@i2.agent_added(@agent)
|
134
|
+
end
|
135
|
+
|
136
|
+
it "logs when an agent is removed" do
|
137
|
+
@output.should_receive(:debug).with(/AGENT GONE/).as_null_object
|
138
|
+
@i2.agent_deleted(@agent, "aged")
|
139
|
+
end
|
140
|
+
|
141
|
+
it "removes the agent reference if removed agent is the same as console reference" do
|
142
|
+
@output.should_receive(:debug).with(/AGENT GONE/).as_null_object
|
143
|
+
@i2.agent_deleted(@agent, "aged")
|
144
|
+
@i2.q.should be_nil
|
145
|
+
end
|
146
|
+
|
147
|
+
it "does not remove the agent reference if removed agent is the not same as console reference" do
|
148
|
+
@output.should_receive(:debug).with(/AGENT GONE/).as_null_object
|
149
|
+
@i2.agent_deleted(@old_agent, "aged")
|
150
|
+
@i2.q.should_not be_nil
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
describe "#event_raised" do
|
155
|
+
before(:each) do
|
156
|
+
@data = mock('data', :null_object => true)
|
157
|
+
@data.stub(:event).and_return("STATUS")
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should call handle on an event" do
|
161
|
+
@output.should_receive(:debug).with(/GOT AN EVENT/)
|
162
|
+
|
163
|
+
@i2.handler.should_receive(:handle).once
|
164
|
+
@i2.event_raised(@agent, @data, Time.now, "horrid")
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe "#build_image" do
|
169
|
+
it "should gracefully handle errors" do
|
170
|
+
@output.should_receive(:debug).with(/Encountered error in build_image/)
|
171
|
+
@output.should_receive(:warn).with("[DEPRECATION] 'build_image' is deprecated. Please use 'build' instead.")
|
172
|
+
@i2.q=nil
|
173
|
+
error = @i2.build_image("<template></template>", "mock")
|
174
|
+
error.to_s.should include("undefined method")
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
describe "#push_image" do
|
179
|
+
it "should gracefully handle errors" do
|
180
|
+
@output.should_receive(:debug).with(/Encountered error in push_image/)
|
181
|
+
@output.should_receive(:warn).with("[DEPRECATION] 'push_image' is deprecated. Please use 'push' instead.")
|
182
|
+
@i2.q=nil
|
183
|
+
error = @i2.push_image(123, "mock", "some creds")
|
184
|
+
error.to_s.should include("undefined method")
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
describe "#build" do
|
189
|
+
it "should gracefully handle errors" do
|
190
|
+
@output.should_receive(:debug).with(/Encountered error in build_image/)
|
191
|
+
@i2.q=nil
|
192
|
+
error = @i2.build("<template></template>", "mock")
|
193
|
+
error.to_s.should include("undefined method")
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
describe "#push" do
|
198
|
+
it "should gracefully handle errors" do
|
199
|
+
@output.should_receive(:debug).with(/Encountered error in push_image/)
|
200
|
+
@i2.q=nil
|
201
|
+
error = @i2.push(123, "mock", "some creds")
|
202
|
+
error.to_s.should include("undefined method")
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
after(:each) do
|
207
|
+
@output.should_receive(:debug).with(/Closing/)
|
208
|
+
@i2.shutdown
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
def is_uuid?(test_string)
|
213
|
+
regexp = Regexp.new('^[\w]{8}[-][\w]{4}[-][\w]{4}[-][\w]{4}[-][\w]{12}')
|
214
|
+
regexp.match(test_string) ? true : false
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: imagefactory-console
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 15
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 4
|
9
|
+
- 0
|
10
|
+
version: 0.4.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Jason Guiditta
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-07-22 00:00:00 +01:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: QMF Console for Aeolus Image Factory
|
23
|
+
email: jguiditt@redhat.com
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files: []
|
29
|
+
|
30
|
+
files:
|
31
|
+
- Rakefile
|
32
|
+
- lib/imagefactory.rb
|
33
|
+
- lib/imagefactory/base_handler.rb
|
34
|
+
- lib/imagefactory/console.rb
|
35
|
+
- spec/spec_helper.rb
|
36
|
+
- spec/image_factory/console_spec.rb
|
37
|
+
has_rdoc: true
|
38
|
+
homepage:
|
39
|
+
licenses: []
|
40
|
+
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options: []
|
43
|
+
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
none: false
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
hash: 3
|
52
|
+
segments:
|
53
|
+
- 0
|
54
|
+
version: "0"
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
hash: 3
|
61
|
+
segments:
|
62
|
+
- 0
|
63
|
+
version: "0"
|
64
|
+
requirements: []
|
65
|
+
|
66
|
+
rubyforge_project:
|
67
|
+
rubygems_version: 1.3.7
|
68
|
+
signing_key:
|
69
|
+
specification_version: 3
|
70
|
+
summary: QMF Console for Aeolus Image Factory
|
71
|
+
test_files: []
|
72
|
+
|