nifty 0.0.1 → 0.2.2
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.md +79 -12
- data/bin/nifty +2 -0
- data/config/nifty.yml +18 -0
- data/config/templates/image.erb +38 -0
- data/config/templates/template.erb +26 -0
- data/lib/nifty/backend.rb +55 -0
- data/lib/nifty/backends/opennebula.rb +109 -0
- data/lib/nifty/backends/utils/opennebula/datastore_handler.rb +36 -0
- data/lib/nifty/backends/utils/opennebula/group_handler.rb +23 -0
- data/lib/nifty/backends/utils/opennebula/handler.rb +60 -0
- data/lib/nifty/backends/utils/opennebula/helper.rb +44 -0
- data/lib/nifty/backends/utils/opennebula/image_handler.rb +209 -0
- data/lib/nifty/backends/utils/opennebula/template_handler.rb +91 -0
- data/lib/nifty/backends/utils/opennebula.rb +9 -0
- data/lib/nifty/backends/utils.rb +2 -0
- data/lib/nifty/backends.rb +5 -0
- data/lib/nifty/command_executioner.rb +202 -0
- data/lib/nifty/errors/api_call_timeout_error.rb +1 -0
- data/lib/nifty/errors/argument_error.rb +1 -0
- data/lib/nifty/errors/backend_error.rb +1 -0
- data/lib/nifty/errors/backends/opennebula/authentication_error.rb +1 -0
- data/lib/nifty/errors/backends/opennebula/resource_not_found_error.rb +1 -0
- data/lib/nifty/errors/backends/opennebula/resource_retrieval_error.rb +1 -0
- data/lib/nifty/errors/backends/opennebula/resource_state_error.rb +1 -0
- data/lib/nifty/errors/backends/opennebula/stub_error.rb +1 -0
- data/lib/nifty/errors/backends/opennebula/user_not_authorized_error.rb +1 -0
- data/lib/nifty/errors/backends/opennebula.rb +5 -0
- data/lib/nifty/errors/backends/opennebula_error.rb +1 -0
- data/lib/nifty/errors/backends.rb +4 -0
- data/lib/nifty/errors/command_execution_error.rb +1 -0
- data/lib/nifty/errors/event/converter_error.rb +1 -0
- data/lib/nifty/errors/event/loader_error.rb +1 -0
- data/lib/nifty/errors/event.rb +5 -0
- data/lib/nifty/errors/events/event_error.rb +1 -0
- data/lib/nifty/errors/events/expiration_event_error.rb +1 -0
- data/lib/nifty/errors/events/registration_event_error.rb +1 -0
- data/lib/nifty/errors/events.rb +4 -0
- data/lib/nifty/errors/standard_error.rb +1 -0
- data/lib/nifty/errors/transfer_method_error.rb +1 -0
- data/lib/nifty/errors/transfer_methods/destination_not_directory_error.rb +1 -0
- data/lib/nifty/errors/transfer_methods/destination_not_writable_error.rb +1 -0
- data/lib/nifty/errors/transfer_methods/image_file_not_readable_error.rb +1 -0
- data/lib/nifty/errors/transfer_methods.rb +4 -0
- data/lib/nifty/errors.rb +10 -0
- data/lib/nifty/event/converter.rb +29 -0
- data/lib/nifty/event/loader.rb +27 -0
- data/lib/nifty/event/processor.rb +96 -0
- data/lib/nifty/event.rb +6 -0
- data/lib/nifty/events/event.rb +32 -0
- data/lib/nifty/events/opennebula/event.rb +23 -0
- data/lib/nifty/events/opennebula/expiration_event.rb +32 -0
- data/lib/nifty/events/opennebula/metadata_update_event.rb +12 -0
- data/lib/nifty/events/opennebula/registration_event.rb +113 -0
- data/lib/nifty/events/opennebula/utils/events_common.rb +69 -0
- data/lib/nifty/events/opennebula/utils.rb +4 -0
- data/lib/nifty/events/opennebula.rb +6 -0
- data/lib/nifty/events.rb +5 -0
- data/lib/nifty/exit_codes.rb +8 -0
- data/lib/nifty/settings.rb +18 -0
- data/lib/nifty/transfer_method.rb +69 -0
- data/lib/nifty/transfer_methods/opennebula/cp.rb +52 -0
- data/lib/nifty/transfer_methods/opennebula/noop.rb +27 -0
- data/lib/nifty/transfer_methods/opennebula.rb +4 -0
- data/lib/nifty/transfer_methods.rb +4 -0
- data/lib/nifty/version.rb +1 -1
- data/lib/nifty.rb +20 -2
- data/nifty.gemspec +7 -0
- data/schema/appliance.json +295 -0
- data/templates/image.erb +8 -0
- data/templates/template.erb +13 -0
- metadata +166 -3
@@ -0,0 +1,209 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
require 'erb'
|
3
|
+
require 'tilt/erb'
|
4
|
+
|
5
|
+
# Handler for OpenNebula ImagePool
|
6
|
+
#
|
7
|
+
# @author Michal Kimle
|
8
|
+
class Nifty::Backends::Utils::Opennebula::ImageHandler < Nifty::Backends::Utils::Opennebula::Handler
|
9
|
+
|
10
|
+
IMAGE_STATE_READY = 'READY'
|
11
|
+
IMAGE_STATE_DISABLED = 'DISABLED'
|
12
|
+
IMAGE_STATE_USED = 'USED'
|
13
|
+
IMAGE_STATE_ERROR = 'ERROR'
|
14
|
+
TIME_FORMAT = '%Y%m%d%H%M%S'
|
15
|
+
ATTRIBUTE_EXPIRATION = 'NIFTY_EXPIRATION'
|
16
|
+
ATTRIBUTE_OUTDATED = 'NIFTY_OUTDATED'
|
17
|
+
ATTRIBUTE_APPLIANCE_VERSION = 'NIFTY_APPLIANCE_VERSION'
|
18
|
+
|
19
|
+
# Constructor
|
20
|
+
#
|
21
|
+
# @see Nifty::Backends::Utils::Opennebula::Handler#initialize
|
22
|
+
def initialize(client)
|
23
|
+
super(client)
|
24
|
+
@pool = OpenNebula::ImagePool.new(client)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns all images for given appliance id
|
28
|
+
#
|
29
|
+
# @param [String] appliance_id
|
30
|
+
# @return [Array] array of images
|
31
|
+
def images(appliance_id)
|
32
|
+
reload!
|
33
|
+
|
34
|
+
pool.find_all { |image| image["TEMPLATE/#{ATTRIBUTE_APPLIANCE_ID}"] == appliance_id }
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns all expired images (have attribute NIFTY_EXPIRATION)
|
38
|
+
#
|
39
|
+
# @return [Array] array of expired images
|
40
|
+
def expired_images()
|
41
|
+
reload!
|
42
|
+
|
43
|
+
pool.find_all { |image| image["TEMPLATE/#{ATTRIBUTE_EXPIRATION}"] }
|
44
|
+
end
|
45
|
+
|
46
|
+
def images_by_version(version)
|
47
|
+
reload!
|
48
|
+
|
49
|
+
pool.find_all { |image| image["TEMPLATE/#{ATTRIBUTE_APPLIANCE_VERSION}"] == version }
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns image with given id if exists
|
53
|
+
#
|
54
|
+
# @param [Fixnum] id
|
55
|
+
# @return [OpenNebula::Image] image with given id
|
56
|
+
def image_exist?(id)
|
57
|
+
reload!
|
58
|
+
|
59
|
+
pool.find { |image| image.id == id }
|
60
|
+
end
|
61
|
+
|
62
|
+
# Deletes image
|
63
|
+
#
|
64
|
+
# @param [OpenNebula::Image] image
|
65
|
+
# @raise [Nifty::Errors::ApiCallTimeoutError] if image isn't deleted within a timeout
|
66
|
+
def delete_image(image)
|
67
|
+
id = image.id
|
68
|
+
|
69
|
+
if image.state_str == IMAGE_STATE_USED
|
70
|
+
logger.warn("Image with id #{id.inspect} cannot be removed, still in use")
|
71
|
+
return
|
72
|
+
end
|
73
|
+
|
74
|
+
Nifty::Backends::Utils::Opennebula::Helper.handle_opennebula_error { image.info! }
|
75
|
+
logger.debug("Deleting image with id #{id.inspect}")
|
76
|
+
Nifty::Backends::Utils::Opennebula::Helper.handle_opennebula_error { image.delete }
|
77
|
+
|
78
|
+
Timeout::timeout(Nifty::API_CALL_TIMEOUT) do
|
79
|
+
while(image_exist?(id))
|
80
|
+
sleep(Nifty::API_POLLING_WAIT)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
rescue Timeout::Error
|
84
|
+
fail Nifty::Errors::ApiCallTimeoutError, "Image with id #{id.inspect} was not deleted within timeout"
|
85
|
+
end
|
86
|
+
|
87
|
+
# Disables image
|
88
|
+
#
|
89
|
+
# @param [OpenNebula::Image] image
|
90
|
+
# @raise [Nifty::Errors::ApiCallTimeoutError] if image isn't disabled within a timeout
|
91
|
+
def disable_image(image)
|
92
|
+
image_state = image.state_str
|
93
|
+
id = image.id
|
94
|
+
|
95
|
+
if image_state == IMAGE_STATE_DISABLED
|
96
|
+
logger.debug("Image with id #{id.inspect} is already disabled, skipping")
|
97
|
+
return
|
98
|
+
end
|
99
|
+
|
100
|
+
unless image_state == IMAGE_STATE_READY || image_state == IMAGE_STATE_ERROR
|
101
|
+
logger.warn("Image with id #{id.inspect} cannot be disabled")
|
102
|
+
return
|
103
|
+
end
|
104
|
+
|
105
|
+
Nifty::Backends::Utils::Opennebula::Helper.handle_opennebula_error { image.disable }
|
106
|
+
|
107
|
+
Nifty::Backends::Utils::Opennebula::Helper.handle_opennebula_error { image.info! }
|
108
|
+
Timeout::timeout(Nifty::API_CALL_TIMEOUT) do
|
109
|
+
until(image.state_str == IMAGE_STATE_DISABLED)
|
110
|
+
sleep(Nifty::API_POLLING_WAIT)
|
111
|
+
Nifty::Backends::Utils::Opennebula::Helper.handle_opennebula_error { image.info! }
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Expires image
|
117
|
+
# Renames image and add attribute NIFTY_EXPIRATION to image with timestamp as a value
|
118
|
+
#
|
119
|
+
# @param [OpenNebula::Image] image
|
120
|
+
def expire_image(image)
|
121
|
+
Nifty::Backends::Utils::Opennebula::Helper.handle_opennebula_error { image.info! }
|
122
|
+
id = image.id
|
123
|
+
|
124
|
+
if image["TEMPLATE/#{ATTRIBUTE_EXPIRATION}"]
|
125
|
+
logger.debug("Image with id #{id.inspect} is already expired, skipping")
|
126
|
+
return
|
127
|
+
end
|
128
|
+
|
129
|
+
disable_image(image)
|
130
|
+
|
131
|
+
logger.debug("Expiring image with id #{id.inspect}")
|
132
|
+
|
133
|
+
expiration_time = Time.now.strftime(TIME_FORMAT)
|
134
|
+
expiration_attribute = "#{ATTRIBUTE_EXPIRATION} = \"#{expiration_time}\""
|
135
|
+
|
136
|
+
Nifty::Backends::Utils::Opennebula::Helper.handle_opennebula_error { image.rename("EXPIRED_#{expiration_time}_#{image.name}") }
|
137
|
+
Nifty::Backends::Utils::Opennebula::Helper.handle_opennebula_error { image.update(expiration_attribute, true) }
|
138
|
+
end
|
139
|
+
|
140
|
+
# Outdates image
|
141
|
+
# Adds atribute marking the image is outdated
|
142
|
+
#
|
143
|
+
# @param [OpenNebula::Image] image
|
144
|
+
def outdate_image(image)
|
145
|
+
Nifty::Backends::Utils::Opennebula::Helper.handle_opennebula_error { image.info! }
|
146
|
+
|
147
|
+
id = image.id
|
148
|
+
|
149
|
+
if image["TEMPLATE/#{ATTRIBUTE_OUTDATED}"]
|
150
|
+
logger.debug("Image with id #{id.inspect} is already outdated, skipping")
|
151
|
+
return
|
152
|
+
end
|
153
|
+
|
154
|
+
logger.debug("Outdating image with id #{id.inspect}")
|
155
|
+
|
156
|
+
outdate_time = Time.now.strftime(TIME_FORMAT)
|
157
|
+
outdate_attribute = "#{ATTRIBUTE_OUTDATED} = \"#{outdate_time}\""
|
158
|
+
Nifty::Backends::Utils::Opennebula::Helper.handle_opennebula_error { image.update(outdate_attribute, true) }
|
159
|
+
end
|
160
|
+
|
161
|
+
# Registers a new image
|
162
|
+
#
|
163
|
+
# @param [String] template template for image
|
164
|
+
# @param [OpenNebula::Datastore] datastore datastore to register image to
|
165
|
+
# @raise [Nifty::Errors::ApiCallTimeoutError] if image isn't ready within a timeout
|
166
|
+
def register_image(template, datastore)
|
167
|
+
image_alloc = ::OpenNebula::Image.build_xml
|
168
|
+
image = ::OpenNebula::Image.new(image_alloc, client)
|
169
|
+
|
170
|
+
logger.debug("Registering image with template\n#{template}")
|
171
|
+
Nifty::Backends::Utils::Opennebula::Helper.handle_opennebula_error { image.allocate(template, datastore.id) }
|
172
|
+
|
173
|
+
begin
|
174
|
+
Timeout::timeout(Nifty::API_CALL_TIMEOUT) do
|
175
|
+
Nifty::Backends::Utils::Opennebula::Helper.handle_opennebula_error { image.info! }
|
176
|
+
|
177
|
+
until(image.state_str == IMAGE_STATE_READY)
|
178
|
+
sleep(Nifty::API_POLLING_WAIT)
|
179
|
+
Nifty::Backends::Utils::Opennebula::Helper.handle_opennebula_error { image.info! }
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
image
|
184
|
+
rescue Timeout::Error
|
185
|
+
image.delete
|
186
|
+
fail Nifty::Errors::ApiCallTimeoutError, "Image with id #{image.id.inspect} didn't become ready within timeout"
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# Prepares a template for an image
|
191
|
+
#
|
192
|
+
# @param [String] template_dir directory with templates
|
193
|
+
# @param [Hash] data used while populating a template
|
194
|
+
# @return [String] final template for an image
|
195
|
+
def self.prepare_template(template_dir, data)
|
196
|
+
template_location = File.join(template_dir, "image.erb")
|
197
|
+
fail Nifty::Errors::ArgumentError, "Missing file 'image.erb' in template directory '#{template_dir}'" unless File.exist?(template_location)
|
198
|
+
|
199
|
+
template = Tilt::ERBTemplate.new(template_location)
|
200
|
+
template_content = template.render(Object.new, data)
|
201
|
+
|
202
|
+
template = Tilt::ERBTemplate.new(File.join(Nifty::GEM_DIR, 'templates', 'image.erb'))
|
203
|
+
nifty_template_content = template.render(Object.new, data)
|
204
|
+
|
205
|
+
whole_template_content = template_content + nifty_template_content
|
206
|
+
logger.debug "Populated image template:\n#{whole_template_content}"
|
207
|
+
whole_template_content
|
208
|
+
end
|
209
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
require 'erb'
|
3
|
+
require 'tilt/erb'
|
4
|
+
require 'set'
|
5
|
+
|
6
|
+
# Handler for OpenNebula TemplatePool
|
7
|
+
#
|
8
|
+
# @author Michal Kimle
|
9
|
+
class Nifty::Backends::Utils::Opennebula::TemplateHandler < Nifty::Backends::Utils::Opennebula::Handler
|
10
|
+
|
11
|
+
# Constructor
|
12
|
+
#
|
13
|
+
# @see Nifty::Backends::Utils::Opennebula::Handler#initialize
|
14
|
+
def initialize(client)
|
15
|
+
super(client)
|
16
|
+
@pool = OpenNebula::TemplatePool.new(client)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns all templates for given appliance id
|
20
|
+
#
|
21
|
+
# @param [String] appliance_id
|
22
|
+
# @return [Array] array of templates
|
23
|
+
def templates(appliance_id)
|
24
|
+
reload!
|
25
|
+
|
26
|
+
pool.find_all{ |template| template["TEMPLATE/#{ATTRIBUTE_APPLIANCE_ID}"] == appliance_id }
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns template with given id if exists
|
30
|
+
#
|
31
|
+
# @param [Fixnum] id
|
32
|
+
# @return [OpenNebula::Template] template with given id
|
33
|
+
def template_exist?(id)
|
34
|
+
reload!
|
35
|
+
|
36
|
+
pool.find { |template| template.id == id }
|
37
|
+
end
|
38
|
+
|
39
|
+
# Deletes template
|
40
|
+
#
|
41
|
+
# @param [OpenNebula::Template] template
|
42
|
+
# @raise [Nifty::Errors::ApiCallTimeoutError] if template isn't deleted within a timeout
|
43
|
+
def delete_template(template)
|
44
|
+
template.info!
|
45
|
+
id = template.id
|
46
|
+
|
47
|
+
logger.debug("Deleting template with id #{id.inspect}")
|
48
|
+
Nifty::Backends::Utils::Opennebula::Helper.handle_opennebula_error { template.delete }
|
49
|
+
|
50
|
+
Timeout::timeout(Nifty::API_CALL_TIMEOUT) do
|
51
|
+
while(template_exist?(id))
|
52
|
+
sleep(Nifty::API_POLLING_WAIT)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
rescue Timeout::Error
|
56
|
+
fail Nifty::Errors::ApiCallTimeoutError, "Template with id #{template.id.inspect} was not deleted within timeout"
|
57
|
+
end
|
58
|
+
|
59
|
+
# Registers a new template
|
60
|
+
#
|
61
|
+
# @param [String] template_template template for template
|
62
|
+
def register_template(template_template)
|
63
|
+
template_alloc = ::OpenNebula::Template.build_xml
|
64
|
+
template = ::OpenNebula::Template.new(template_alloc, client)
|
65
|
+
|
66
|
+
logger.debug("Registering template with template\n#{template_template}")
|
67
|
+
Nifty::Backends::Utils::Opennebula::Helper.handle_opennebula_error { template.allocate(template_template) }
|
68
|
+
|
69
|
+
template
|
70
|
+
end
|
71
|
+
|
72
|
+
# Prepares a template for a template
|
73
|
+
#
|
74
|
+
# @param [String] template_dir directory with templates
|
75
|
+
# @param [Hash] data used while populating a template
|
76
|
+
# @return [String] final template for a template
|
77
|
+
def self.prepare_template(template_dir, data)
|
78
|
+
template_location = File.join(template_dir, "template.erb")
|
79
|
+
fail Nifty::Errors::ArgumentError, "Missing file 'template.erb' in template directory '#{template_dir}'" unless File.exist?(template_location)
|
80
|
+
|
81
|
+
template = Tilt::ERBTemplate.new(template_location)
|
82
|
+
template_content = template.render(Object.new, data)
|
83
|
+
|
84
|
+
template = Tilt::ERBTemplate.new(File.join(Nifty::GEM_DIR, 'templates', 'template.erb'))
|
85
|
+
nifty_template_content = template.render(Object.new, data)
|
86
|
+
|
87
|
+
whole_template_content = template_content + nifty_template_content
|
88
|
+
logger.debug "Populated template template:\n#{whole_template_content}"
|
89
|
+
whole_template_content
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# Namespace for OpenNebula's backend utilities
|
2
|
+
module Nifty::Backends::Utils::Opennebula; end
|
3
|
+
|
4
|
+
require 'nifty/backends/utils/opennebula/helper'
|
5
|
+
require 'nifty/backends/utils/opennebula/handler'
|
6
|
+
require 'nifty/backends/utils/opennebula/group_handler'
|
7
|
+
require 'nifty/backends/utils/opennebula/image_handler'
|
8
|
+
require 'nifty/backends/utils/opennebula/template_handler'
|
9
|
+
require 'nifty/backends/utils/opennebula/datastore_handler'
|
@@ -0,0 +1,5 @@
|
|
1
|
+
# Namespace for all the backends
|
2
|
+
module Nifty::Backends
|
3
|
+
require File.join(File.dirname(__FILE__), self.name.demodulize.underscore, 'utils')
|
4
|
+
Dir.glob(File.join(File.dirname(__FILE__), self.name.demodulize.underscore, '*.rb')) { |backend_file| require backend_file.chomp('.rb') }
|
5
|
+
end
|
@@ -0,0 +1,202 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'yell'
|
3
|
+
|
4
|
+
class Nifty::CommandExecutioner < Thor
|
5
|
+
class << self
|
6
|
+
# Force Thor to exit with a non-zero return value on failure (after `exit` is called).
|
7
|
+
#
|
8
|
+
# @return [TrueClass, FalseClass] true if thor fail, false otherwise
|
9
|
+
def exit_on_failure?
|
10
|
+
true
|
11
|
+
end
|
12
|
+
|
13
|
+
# List all available transfer methods for the backend
|
14
|
+
#
|
15
|
+
# @param [Nifty::Backend] backend
|
16
|
+
# @return [Array] array of transfer method classes that support the backend
|
17
|
+
def available_transfer_methods(backend)
|
18
|
+
unless Nifty::TransferMethods.constants.include? backend.camelize.to_sym
|
19
|
+
fail Nifty::CommandExecutionError, "No backend with name '#{backend}'"
|
20
|
+
end
|
21
|
+
|
22
|
+
clazz = "Nifty::TransferMethods::#{backend.camelize}".constantize
|
23
|
+
constants = clazz.constants.map { |sym| sym.to_s.downcase }
|
24
|
+
constants.select! do |constant|
|
25
|
+
unknown = clazz.const_get(constant.camelize)
|
26
|
+
|
27
|
+
unknown.respond_to?('transfer_method?') && unknown.transfer_method?
|
28
|
+
end
|
29
|
+
|
30
|
+
constants.sort
|
31
|
+
end
|
32
|
+
|
33
|
+
# List all available backends
|
34
|
+
#
|
35
|
+
# @return [Array] array of all available backend classes
|
36
|
+
def available_backends
|
37
|
+
constants = Nifty::Backends.constants.map { |sym| sym.to_s.downcase }
|
38
|
+
constants.select! do |constant|
|
39
|
+
unknown = Nifty::Backends.const_get(constant.camelize)
|
40
|
+
|
41
|
+
unknown.respond_to?('backend?') && unknown.backend?
|
42
|
+
end
|
43
|
+
|
44
|
+
constants.sort
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# global options
|
49
|
+
class_option :"appliance-dir",
|
50
|
+
:required => true,
|
51
|
+
:default => Nifty::Settings['appliance-dir'],
|
52
|
+
:type => :string,
|
53
|
+
:aliases => '-a',
|
54
|
+
:desc => 'Directory from where appliance descriptors will be loaded'
|
55
|
+
class_option :"transfer-method",
|
56
|
+
:required => true,
|
57
|
+
:default => Nifty::Settings['transfer']['method'],
|
58
|
+
:type => :string,
|
59
|
+
:aliases => '-m',
|
60
|
+
:desc => 'Transfer method for image upload'
|
61
|
+
class_option :"transfer-destination",
|
62
|
+
:default => Nifty::Settings['transfer']['destination'],
|
63
|
+
:type => :string,
|
64
|
+
:aliases => '-t',
|
65
|
+
:desc => 'Image upload destination'
|
66
|
+
class_option :"logging-level",
|
67
|
+
:required => true,
|
68
|
+
:default => Nifty::Settings['logging']['level'],
|
69
|
+
:type => :string,
|
70
|
+
:enum => Yell::Severities
|
71
|
+
class_option :"logging-file",
|
72
|
+
:default => Nifty::Settings['logging']['file'],
|
73
|
+
:type => :string,
|
74
|
+
:desc => 'File to write log to'
|
75
|
+
class_option :debug,
|
76
|
+
:default => Nifty::Settings['debug'],
|
77
|
+
:type => :boolean,
|
78
|
+
:desc => 'Runs nifty in debug mode'
|
79
|
+
|
80
|
+
desc 'version', 'Prints NIFTY\'s version'
|
81
|
+
def version
|
82
|
+
$stdout.puts Nifty::VERSION
|
83
|
+
end
|
84
|
+
|
85
|
+
desc 'backends', 'Lists all available backends with their description'
|
86
|
+
def backends
|
87
|
+
backends = self.class.available_backends
|
88
|
+
longest = backends.map { |backend| backend.length }.sort.last
|
89
|
+
backends.each do |backend|
|
90
|
+
$stdout.puts "%-#{longest + 2}s" % "#{backend}" + "# #{Nifty::Backends.const_get(backend.camelize).description}"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
available_backends.each do |backend|
|
95
|
+
backend_clazz = Nifty::Backends.const_get(backend.camelize)
|
96
|
+
options = backend_clazz.options
|
97
|
+
options.each do |name, parameters|
|
98
|
+
parameters[:default] = Nifty::Settings[backend][name.to_s] unless parameters[:default]
|
99
|
+
method_option name, parameters
|
100
|
+
end
|
101
|
+
|
102
|
+
class_eval %Q^
|
103
|
+
desc '#{backend}', 'Runs NIFTY with backend #{backend}'
|
104
|
+
def #{backend}
|
105
|
+
start('#{backend}', options)
|
106
|
+
end
|
107
|
+
|
108
|
+
desc '#{backend}-transfer-methods', 'Lists all available transfer methods with their description for #{backend.inspect} backend'
|
109
|
+
def #{backend}_transfer_methods
|
110
|
+
methods = self.class.available_transfer_methods '#{backend}'
|
111
|
+
longest = methods.map { |method| method.length }.sort.last
|
112
|
+
methods.each do |method|
|
113
|
+
$stdout.puts "%-\#{longest + 2}s" % "\#{method}" + "# \#{Nifty::TransferMethods::#{backend.camelize}.const_get(method.camelize).description}"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
^
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
# Starts NIFTY with selected backend
|
122
|
+
#
|
123
|
+
# @param [String] backend backend's name
|
124
|
+
# @param [Hash] options options from command line
|
125
|
+
def start(backend, options)
|
126
|
+
parameters = options.to_hash.deep_symbolize_keys
|
127
|
+
init_log parameters
|
128
|
+
|
129
|
+
backend = Nifty::Backends.const_get(backend.camelize)
|
130
|
+
logger.debug "Selected backend '#{backend.inspect}'"
|
131
|
+
|
132
|
+
transfer_method = construct_transfer_method(backend, parameters)
|
133
|
+
logger.debug "Selected transfer method '#{transfer_method.inspect}'"
|
134
|
+
|
135
|
+
logger.debug "Parameters: #{parameters}"
|
136
|
+
|
137
|
+
processor = Nifty::Event::Processor.new(backend, transfer_method, parameters)
|
138
|
+
exit processor.process_events
|
139
|
+
end
|
140
|
+
|
141
|
+
# Inits logging according to the settings
|
142
|
+
#
|
143
|
+
# @param [Hash] parameters
|
144
|
+
# @option parameters [String] logging-level
|
145
|
+
# @option parameters [String] logging-file file to log to
|
146
|
+
# @option parameters [TrueClass, FalseClass] debug debug mode
|
147
|
+
# @return [Type] description of returned object
|
148
|
+
def init_log(parameters)
|
149
|
+
parameters[:"logging-level"] = 'DEBUG' if parameters[:debug]
|
150
|
+
|
151
|
+
Yell.new :stdout, :name => Object, :level => parameters[:"logging-level"].downcase, :format => Yell::DefaultFormat
|
152
|
+
Object.send :include, Yell::Loggable
|
153
|
+
|
154
|
+
if parameters[:"logging-file"]
|
155
|
+
unless (File.exist?(parameters[:"logging-file"]) && File.writable?(parameters[:"logging-file"])) || (File.writable?(File.dirname(parameters[:"logging-file"])))
|
156
|
+
logger.error "File #{parameters[:"logging-file"]} isn't writable"
|
157
|
+
return
|
158
|
+
end
|
159
|
+
|
160
|
+
logger.adapter :file, parameters[:"logging-file"]
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# Returns class representing transfer method of specified name
|
165
|
+
#
|
166
|
+
# @param [Nifty::Backend] backend
|
167
|
+
# @param [String] transfer_method_name name of the transfer method
|
168
|
+
# @return [Nifty::TransferMethod] transfer method class
|
169
|
+
def transfer_method_constant(backend, transfer_method_name)
|
170
|
+
transfer_methods = "Nifty::TransferMethods::#{backend.name.demodulize}".constantize
|
171
|
+
backend_name = backend.name.demodulize.underscore
|
172
|
+
error_msg = "No such transfer method '#{transfer_method_name}' for backend '#{backend_name}'"
|
173
|
+
unless transfer_methods.constants.include?(transfer_method_name.camelize.to_sym)
|
174
|
+
$stdout.puts error_msg
|
175
|
+
exit Nifty::ExitCodes::NO_TRANSFER_METHOD_ERROR_EXIT_CODE
|
176
|
+
end
|
177
|
+
|
178
|
+
transfer_method = transfer_methods.const_get(transfer_method_name.camelize)
|
179
|
+
unless transfer_method.respond_to?('backend') && transfer_method.backend == backend
|
180
|
+
$stdout.puts error_msg
|
181
|
+
exit
|
182
|
+
end
|
183
|
+
|
184
|
+
transfer_method
|
185
|
+
end
|
186
|
+
|
187
|
+
# Returns transfer method according to settings
|
188
|
+
#
|
189
|
+
# @param [Nifty::Backend] backend
|
190
|
+
# @param [Hash] parameters
|
191
|
+
# @option parameters [String] transfer-method name of the transfer method
|
192
|
+
# @option parameters [String] transfer-destination destination fo the transfer method
|
193
|
+
# @return [Nifty::TransferMethod] instance of specified transfer method
|
194
|
+
def construct_transfer_method(backend, parameters)
|
195
|
+
transfer_method_const = transfer_method_constant(backend, parameters[:"transfer-method"])
|
196
|
+
|
197
|
+
transfer_method_const.new(parameters[:"transfer-destination"])
|
198
|
+
rescue Nifty::Errors::TransferMethodError => ex
|
199
|
+
$stdout.puts ex.message
|
200
|
+
exit Nifty::ExitCodes::TRANSFER_METHOD_ERROR_EXIT_CODE
|
201
|
+
end
|
202
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
class Nifty::Errors::ApiCallTimeoutError < Nifty::Errors::StandardError; end
|
@@ -0,0 +1 @@
|
|
1
|
+
class Nifty::Errors::ArgumentError < Nifty::Errors::StandardError; end
|
@@ -0,0 +1 @@
|
|
1
|
+
class Nifty::Errors::BackendError < Nifty::Errors::StandardError; end
|
@@ -0,0 +1 @@
|
|
1
|
+
class Nifty::Errors::Backends::Opennebula::AuthenticationError < Nifty::Errors::Backends::OpennebulaError; end
|
@@ -0,0 +1 @@
|
|
1
|
+
class Nifty::Errors::Backends::Opennebula::ResourceNotFoundError < Nifty::Errors::Backends::OpennebulaError; end
|
@@ -0,0 +1 @@
|
|
1
|
+
class Nifty::Errors::Backends::Opennebula::ResourceRetrievalError < Nifty::Errors::Backends::OpennebulaError; end
|
@@ -0,0 +1 @@
|
|
1
|
+
class Nifty::Errors::Backends::Opennebula::ResourceStateError < Nifty::Errors::Backends::OpennebulaError; end
|
@@ -0,0 +1 @@
|
|
1
|
+
class Nifty::Errors::Backends::Opennebula::StubError < Nifty::Errors::Backends::OpennebulaError; end
|
@@ -0,0 +1 @@
|
|
1
|
+
class Nifty::Errors::Backends::Opennebula::UserNotAuthorizedError < Nifty::Errors::Backends::OpennebulaError; end
|
@@ -0,0 +1,5 @@
|
|
1
|
+
module Nifty::Errors::Backends::Opennebula
|
2
|
+
require File.join(File.dirname(__FILE__), 'opennebula_error')
|
3
|
+
require File.join(File.dirname(__FILE__), self.name.demodulize.underscore, 'authentication_error')
|
4
|
+
Dir.glob(File.join(File.dirname(__FILE__), self.name.demodulize.underscore, '*.rb')) { |error_file| require error_file.chomp('.rb') }
|
5
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
class Nifty::Errors::Backends::OpennebulaError < Nifty::Errors::BackendError; end
|
@@ -0,0 +1 @@
|
|
1
|
+
class Nifty::Errors::CommandExecutionError < Nifty::Errors::StandardError; end
|
@@ -0,0 +1 @@
|
|
1
|
+
class Nifty::Errors::Event::ConverterError < Nifty::Errors::StandardError; end
|
@@ -0,0 +1 @@
|
|
1
|
+
class Nifty::Errors::Event::LoaderError < Nifty::Errors::StandardError; end
|
@@ -0,0 +1,5 @@
|
|
1
|
+
module Nifty::Errors::Event
|
2
|
+
require File.join(File.dirname(__FILE__), 'event', 'loader_error')
|
3
|
+
require File.join(File.dirname(__FILE__), 'event', 'converter_error')
|
4
|
+
Dir.glob(File.join(File.dirname(__FILE__), self.name.demodulize.underscore, '*.rb')) { |error_file| require error_file.chomp('.rb') }
|
5
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
class Nifty::Errors::Events::EventError < Nifty::Errors::StandardError; end
|
@@ -0,0 +1 @@
|
|
1
|
+
class Nifty::Errors::Events::ExpirationEventError < Nifty::Errors::Events::EventError; end
|
@@ -0,0 +1 @@
|
|
1
|
+
class Nifty::Errors::Events::RegistrationEventError < Nifty::Errors::Events::EventError; end
|
@@ -0,0 +1 @@
|
|
1
|
+
class Nifty::Errors::StandardError < ::StandardError; end
|
@@ -0,0 +1 @@
|
|
1
|
+
class Nifty::Errors::TransferMethodError < Nifty::Errors::ArgumentError; end
|
@@ -0,0 +1 @@
|
|
1
|
+
class Nifty::Errors::TransferMethods::DestinationNotDirectoryError < Nifty::Errors::TransferMethodError; end
|
@@ -0,0 +1 @@
|
|
1
|
+
class Nifty::Errors::TransferMethods::DestinationNotWritableError < Nifty::Errors::TransferMethodError; end
|
@@ -0,0 +1 @@
|
|
1
|
+
class Nifty::Errors::TransferMethods::ImageFileNotReadableError < Nifty::Errors::TransferMethodError; end
|
data/lib/nifty/errors.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
# Namespace for all the exceptions
|
2
|
+
module Nifty::Errors
|
3
|
+
require File.join(File.dirname(__FILE__), 'errors', 'standard_error')
|
4
|
+
require File.join(File.dirname(__FILE__), 'errors', 'argument_error')
|
5
|
+
require File.join(File.dirname(__FILE__), 'errors', 'event')
|
6
|
+
require File.join(File.dirname(__FILE__), 'errors', 'backends')
|
7
|
+
require File.join(File.dirname(__FILE__), 'errors', 'transfer_methods')
|
8
|
+
require File.join(File.dirname(__FILE__), 'errors', 'events')
|
9
|
+
Dir.glob(File.join(File.dirname(__FILE__), self.name.demodulize.underscore, '*.rb')) { |error_file| require error_file.chomp('.rb') }
|
10
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# Converts appliances into events
|
2
|
+
#
|
3
|
+
# @author Michal Kimle
|
4
|
+
class Nifty::Event::Converter
|
5
|
+
# Converts appliance into event
|
6
|
+
#
|
7
|
+
# @param [Cloud::Appliance::Descriptor::Appliance] appliance
|
8
|
+
# @param [Nifty::Backend] backend
|
9
|
+
# @param [Nifty::TransferMethod] transfer_method
|
10
|
+
# @param [Hash] parameters
|
11
|
+
# @raise [Nifty::Errors::Event::ConverterError] when something goes wrong while conversion
|
12
|
+
# @return [Nifty::Event] description of returned object
|
13
|
+
def self.convert_appliance(appliance, backend, transfer_method, parameters)
|
14
|
+
events_module = "Nifty::Events::#{backend.name.demodulize}".constantize
|
15
|
+
|
16
|
+
logger.debug "Converting appliance #{appliance.inspect}"
|
17
|
+
event_type = "#{appliance.action}_event".camelize
|
18
|
+
|
19
|
+
fail Nifty::Errors::Event::ConverterError, "No such event type for action #{appliance.action.inspect}" unless events_module.constants.include?(event_type.to_sym)
|
20
|
+
event_class = events_module.const_get(event_type)
|
21
|
+
|
22
|
+
fail Nifty::Errors::Event::ConverterError, "Class #{event_class.inspect} doesn't represent an event" unless (event_class.respond_to?('event?') && event_class.event? && event_class.public_instance_methods.include?(:run))
|
23
|
+
|
24
|
+
event = backend.create_event(event_class, appliance, transfer_method, parameters)
|
25
|
+
logger.debug "Converted event: #{event.inspect}"
|
26
|
+
|
27
|
+
event
|
28
|
+
end
|
29
|
+
end
|