cloudkeeper-one 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.gitmodules +3 -0
- data/.rspec +2 -0
- data/.rubocop.yml +48 -0
- data/.travis.yml +22 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +17 -0
- data/README.md +98 -0
- data/Rakefile +17 -0
- data/bin/cloudkeeper-one +5 -0
- data/cloudkeeper-one.gemspec +44 -0
- data/config/cloudkeeper-one.yml +23 -0
- data/config/templates/image.erb +20 -0
- data/config/templates/template.erb +19 -0
- data/lib/cloudkeeper/one/appliance_actions/list.rb +68 -0
- data/lib/cloudkeeper/one/appliance_actions/registration.rb +73 -0
- data/lib/cloudkeeper/one/appliance_actions/removal.rb +57 -0
- data/lib/cloudkeeper/one/appliance_actions/update.rb +34 -0
- data/lib/cloudkeeper/one/appliance_actions/utils/image_download.rb +43 -0
- data/lib/cloudkeeper/one/appliance_actions/utils/template_preparation.rb +36 -0
- data/lib/cloudkeeper/one/appliance_actions/utils/templates/attributes.erb +23 -0
- data/lib/cloudkeeper/one/appliance_actions/utils.rb +10 -0
- data/lib/cloudkeeper/one/appliance_actions.rb +11 -0
- data/lib/cloudkeeper/one/cli.rb +185 -0
- data/lib/cloudkeeper/one/core_connector.rb +106 -0
- data/lib/cloudkeeper/one/errors/actions/action_error.rb +9 -0
- data/lib/cloudkeeper/one/errors/actions/listing_error.rb +9 -0
- data/lib/cloudkeeper/one/errors/actions/registration_error.rb +9 -0
- data/lib/cloudkeeper/one/errors/actions/update_error.rb +9 -0
- data/lib/cloudkeeper/one/errors/actions.rb +12 -0
- data/lib/cloudkeeper/one/errors/argument_error.rb +7 -0
- data/lib/cloudkeeper/one/errors/invalid_configuration_error.rb +7 -0
- data/lib/cloudkeeper/one/errors/multi_error.rb +25 -0
- data/lib/cloudkeeper/one/errors/network_connection_error.rb +7 -0
- data/lib/cloudkeeper/one/errors/opennebula/api_call_timeout_error.rb +9 -0
- data/lib/cloudkeeper/one/errors/opennebula/authentication_error.rb +9 -0
- data/lib/cloudkeeper/one/errors/opennebula/missing_pool_error.rb +9 -0
- data/lib/cloudkeeper/one/errors/opennebula/opennebula_error.rb +9 -0
- data/lib/cloudkeeper/one/errors/opennebula/resource_not_found_error.rb +9 -0
- data/lib/cloudkeeper/one/errors/opennebula/resource_retrieval_error.rb +9 -0
- data/lib/cloudkeeper/one/errors/opennebula/resource_state_error.rb +9 -0
- data/lib/cloudkeeper/one/errors/opennebula/stub_error.rb +9 -0
- data/lib/cloudkeeper/one/errors/opennebula/user_not_authorized_error.rb +9 -0
- data/lib/cloudkeeper/one/errors/opennebula.rb +17 -0
- data/lib/cloudkeeper/one/errors/standard_error.rb +7 -0
- data/lib/cloudkeeper/one/errors.rb +14 -0
- data/lib/cloudkeeper/one/opennebula/appliance_handler.rb +91 -0
- data/lib/cloudkeeper/one/opennebula/datastore_handler.rb +16 -0
- data/lib/cloudkeeper/one/opennebula/group_handler.rb +12 -0
- data/lib/cloudkeeper/one/opennebula/handler.rb +59 -0
- data/lib/cloudkeeper/one/opennebula/helper.rb +27 -0
- data/lib/cloudkeeper/one/opennebula/image_handler.rb +133 -0
- data/lib/cloudkeeper/one/opennebula/tags.rb +34 -0
- data/lib/cloudkeeper/one/opennebula/template_handler.rb +24 -0
- data/lib/cloudkeeper/one/opennebula.rb +14 -0
- data/lib/cloudkeeper/one/settings.rb +21 -0
- data/lib/cloudkeeper/one/version.rb +5 -0
- data/lib/cloudkeeper/one.rb +19 -0
- data/lib/cloudkeeper_grpc.rb +5 -0
- metadata +385 -0
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
module Cloudkeeper
|
4
|
+
module One
|
5
|
+
module ApplianceActions
|
6
|
+
module Utils
|
7
|
+
module ImageDownload
|
8
|
+
def download_image(uri, username, password)
|
9
|
+
logger.debug "Downloading image from #{uri.inspect} (username: #{username}, password: #{password})"
|
10
|
+
filename = generate_filename
|
11
|
+
retrieve_image URI.parse(uri), username, password, filename
|
12
|
+
|
13
|
+
logger.debug "Image stored into #{filename}"
|
14
|
+
filename
|
15
|
+
rescue URI::InvalidURIError => ex
|
16
|
+
raise Cloudkeeper::One::Errors::NetworkConnectionError, ex
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def retrieve_image(uri, username, password, filename)
|
22
|
+
Net::HTTP.start(uri.host, uri.port) do |http|
|
23
|
+
request = Net::HTTP::Get.new(uri)
|
24
|
+
request.basic_auth username, password
|
25
|
+
|
26
|
+
http.request(request) do |response|
|
27
|
+
response.value
|
28
|
+
open(filename, 'w') { |file| response.read_body { |chunk| file.write(chunk) } }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, Errno::ECONNREFUSED, EOFError, Net::HTTPBadResponse,
|
32
|
+
Net::HTTPServerException, Net::HTTPHeaderSyntaxError, Net::ProtocolError => ex
|
33
|
+
raise Cloudkeeper::One::Errors::NetworkConnectionError, ex
|
34
|
+
end
|
35
|
+
|
36
|
+
def generate_filename
|
37
|
+
File.join(Cloudkeeper::One::Settings[:'appliances-tmp-dir'], SecureRandom.uuid)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'tilt/erb'
|
3
|
+
|
4
|
+
module Cloudkeeper
|
5
|
+
module One
|
6
|
+
module ApplianceActions
|
7
|
+
module Utils
|
8
|
+
module TemplatePreparation
|
9
|
+
def prepare_template(filename, data)
|
10
|
+
template_file = File.join(Cloudkeeper::One::Settings[:'appliances-template-dir'], filename)
|
11
|
+
raise Cloudkeeper::One::Errors::ArgumentError, "Missing file #{filename.inspect} in template directory" \
|
12
|
+
unless File.exist?(template_file)
|
13
|
+
|
14
|
+
logger.debug "Populating template from #{template_file}"
|
15
|
+
templates = [template_file, File.join(File.dirname(__FILE__), 'templates', 'attributes.erb')]
|
16
|
+
|
17
|
+
data[:image] ||= nil
|
18
|
+
rendered = render_templates templates, data
|
19
|
+
logger.debug "Template:\n#{rendered}"
|
20
|
+
rendered
|
21
|
+
end
|
22
|
+
|
23
|
+
def render_templates(templates, data)
|
24
|
+
Tempfile.open 'cloudkeeper-template' do |tmp|
|
25
|
+
templates.each { |template| tmp.write(File.read(template)) }
|
26
|
+
tmp.flush
|
27
|
+
|
28
|
+
template = Tilt::ERBTemplate.new tmp
|
29
|
+
template.render Object.new, data
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<%= Cloudkeeper::One::Opennebula::Tags::ID %> = "<%= Cloudkeeper::One::Settings[:identifier] %>"
|
2
|
+
<%= Cloudkeeper::One::Opennebula::Tags::APPLIANCE_ID %> = "<%= appliance.identifier %>"
|
3
|
+
<%= Cloudkeeper::One::Opennebula::Tags::APPLIANCE_TITLE %> = "<%= appliance.title %>"
|
4
|
+
<%= Cloudkeeper::One::Opennebula::Tags::APPLIANCE_DESCRIPTION %> = "<%= appliance.description %>"
|
5
|
+
<%= Cloudkeeper::One::Opennebula::Tags::APPLIANCE_MPURI %> = "<%= appliance.mpuri %>"
|
6
|
+
<%= Cloudkeeper::One::Opennebula::Tags::APPLIANCE_GROUP %> = "<%= appliance.group %>"
|
7
|
+
<%= Cloudkeeper::One::Opennebula::Tags::APPLIANCE_RAM %> = "<%= appliance.ram %>"
|
8
|
+
<%= Cloudkeeper::One::Opennebula::Tags::APPLIANCE_CORE %> = "<%= appliance.core %>"
|
9
|
+
<%= Cloudkeeper::One::Opennebula::Tags::APPLIANCE_VERSION %> = "<%= appliance.version %>"
|
10
|
+
<%= Cloudkeeper::One::Opennebula::Tags::APPLIANCE_ARCHITECTURE %> = "<%= appliance.architecture %>"
|
11
|
+
<%= Cloudkeeper::One::Opennebula::Tags::APPLIANCE_OPERATING_SYSTEM %> = "<%= appliance.operating_system %>"
|
12
|
+
<%= Cloudkeeper::One::Opennebula::Tags::APPLIANCE_VO %> = "<%= appliance.vo %>"
|
13
|
+
<%= Cloudkeeper::One::Opennebula::Tags::APPLIANCE_EXPIRATION_DATE %> = "<%= appliance.expiration_date %>"
|
14
|
+
<%= Cloudkeeper::One::Opennebula::Tags::APPLIANCE_IMAGE_LIST_ID %> = "<%= appliance.image_list_identifier %>"
|
15
|
+
|
16
|
+
<% if image %>
|
17
|
+
<%= Cloudkeeper::One::Opennebula::Tags::IMAGE_URI %> = "<%= image.uri %>"
|
18
|
+
<%= Cloudkeeper::One::Opennebula::Tags::IMAGE_CHECKSUM %> = "<%= image.checksum %>"
|
19
|
+
<%= Cloudkeeper::One::Opennebula::Tags::IMAGE_SIZE %> = "<%= image.size %>"
|
20
|
+
<%= Cloudkeeper::One::Opennebula::Tags::IMAGE_FORMAT %> = "<%= image.format %>"
|
21
|
+
<% end %>
|
22
|
+
|
23
|
+
<%= Cloudkeeper::One::Opennebula::Tags::APPLIANCE_ATTRIBUTES %> = "<%= Base64.strict_encode64 appliance.attributes.to_h.to_json %>"
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Cloudkeeper
|
2
|
+
module One
|
3
|
+
module ApplianceActions
|
4
|
+
module Utils
|
5
|
+
autoload :ImageDownload, 'cloudkeeper/one/appliance_actions/utils/image_download'
|
6
|
+
autoload :TemplatePreparation, 'cloudkeeper/one/appliance_actions/utils/template_preparation'
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Cloudkeeper
|
2
|
+
module One
|
3
|
+
module ApplianceActions
|
4
|
+
autoload :Registration, 'cloudkeeper/one/appliance_actions/registration'
|
5
|
+
autoload :Removal, 'cloudkeeper/one/appliance_actions/removal'
|
6
|
+
autoload :Update, 'cloudkeeper/one/appliance_actions/update'
|
7
|
+
autoload :List, 'cloudkeeper/one/appliance_actions/list'
|
8
|
+
autoload :Utils, 'cloudkeeper/one/appliance_actions/utils'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,185 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'yell'
|
3
|
+
require 'chronic_duration'
|
4
|
+
|
5
|
+
module Cloudkeeper
|
6
|
+
module One
|
7
|
+
class CLI < Thor
|
8
|
+
class_option :'logging-level',
|
9
|
+
required: true,
|
10
|
+
default: Cloudkeeper::One::Settings['logging']['level'],
|
11
|
+
type: :string,
|
12
|
+
enum: Yell::Severities
|
13
|
+
class_option :'logging-file',
|
14
|
+
default: Cloudkeeper::One::Settings['logging']['file'],
|
15
|
+
type: :string,
|
16
|
+
desc: 'File to write logs to'
|
17
|
+
class_option :debug,
|
18
|
+
default: Cloudkeeper::One::Settings['debug'],
|
19
|
+
type: :boolean,
|
20
|
+
desc: 'Runs cloudkeeper in debug mode'
|
21
|
+
|
22
|
+
method_option :'listen-address',
|
23
|
+
required: true,
|
24
|
+
default: Cloudkeeper::One::Settings['listen-address'],
|
25
|
+
type: :string,
|
26
|
+
desc: 'IP address gRPC server will listen on'
|
27
|
+
method_option :authentication,
|
28
|
+
default: Cloudkeeper::One::Settings['authentication'],
|
29
|
+
type: :boolean,
|
30
|
+
desc: 'Client <-> server authentication'
|
31
|
+
method_option :certificate,
|
32
|
+
required: false,
|
33
|
+
default: Cloudkeeper::One::Settings['certificate'],
|
34
|
+
type: :string,
|
35
|
+
desc: "Backend's host certificate"
|
36
|
+
method_option :key,
|
37
|
+
required: false,
|
38
|
+
default: Cloudkeeper::One::Settings['key'],
|
39
|
+
type: :string,
|
40
|
+
desc: "Backend's host key"
|
41
|
+
method_option :identifier,
|
42
|
+
required: true,
|
43
|
+
default: Cloudkeeper::One::Settings['identifier'],
|
44
|
+
type: :string,
|
45
|
+
desc: 'Instance identifier'
|
46
|
+
method_option :'core-certificate',
|
47
|
+
required: false,
|
48
|
+
default: Cloudkeeper::One::Settings['core']['certificate'],
|
49
|
+
type: :string,
|
50
|
+
desc: "Core's certificate"
|
51
|
+
method_option :'appliances-tmp-dir',
|
52
|
+
required: true,
|
53
|
+
default: Cloudkeeper::One::Settings['appliances']['tmp-dir'],
|
54
|
+
type: :string,
|
55
|
+
desc: 'Directory where to temporarily store appliances'
|
56
|
+
method_option :'appliances-template-dir',
|
57
|
+
required: false,
|
58
|
+
default: Cloudkeeper::One::Settings['appliances']['template-dir'],
|
59
|
+
type: :string,
|
60
|
+
desc: 'If set, templates within this directory are used to construct images and templates in OpenNebula'
|
61
|
+
method_option :'appliances-permissions',
|
62
|
+
required: true,
|
63
|
+
default: Cloudkeeper::One::Settings['appliances']['permissions'],
|
64
|
+
type: :string,
|
65
|
+
desc: 'UNIX-like permissions appliances will have within OpenNebula'
|
66
|
+
method_option :'opennebula-secret',
|
67
|
+
required: true,
|
68
|
+
default: Cloudkeeper::One::Settings['opennebula']['secret'],
|
69
|
+
type: :string,
|
70
|
+
desc: 'OpenNebula authentication secret'
|
71
|
+
method_option :'opennebula-endpoint',
|
72
|
+
required: true,
|
73
|
+
default: Cloudkeeper::One::Settings['opennebula']['endpoint'],
|
74
|
+
type: :string,
|
75
|
+
desc: 'OpenNebula XML-RPC endpoint'
|
76
|
+
method_option :'opennebula-datastores',
|
77
|
+
required: true,
|
78
|
+
default: Cloudkeeper::One::Settings['opennebula']['datastores'],
|
79
|
+
type: :array,
|
80
|
+
desc: 'OpenNebula datastores images will be uploaded to'
|
81
|
+
method_option :'opennebula-users',
|
82
|
+
required: false,
|
83
|
+
default: Cloudkeeper::One::Settings['opennebula']['users'],
|
84
|
+
type: :array,
|
85
|
+
desc: 'Handle only images/templates of specified users'
|
86
|
+
method_option :'opennebula-api-call-timeout',
|
87
|
+
required: true,
|
88
|
+
default: Cloudkeeper::One::Settings['opennebula']['api-call-timeout'],
|
89
|
+
type: :string,
|
90
|
+
desc: 'How long will cloudkeeper-one wait for image/template operations to finish in OpenNebula'
|
91
|
+
|
92
|
+
desc 'sync', 'Runs synchronization process'
|
93
|
+
def sync
|
94
|
+
initialize_sync options
|
95
|
+
grpc_server = GRPC::RpcServer.new
|
96
|
+
grpc_server.add_http2_port Cloudkeeper::One::Settings[:'listen-address'], credentials
|
97
|
+
grpc_server.handle Cloudkeeper::One::CoreConnector
|
98
|
+
grpc_server.run_till_terminated
|
99
|
+
rescue Interrupt
|
100
|
+
grpc_server.stop
|
101
|
+
rescue Cloudkeeper::One::Errors::InvalidConfigurationError => ex
|
102
|
+
abort ex.message
|
103
|
+
end
|
104
|
+
|
105
|
+
desc 'version', 'Prints cloudkeeper version'
|
106
|
+
def version
|
107
|
+
$stdout.puts Cloudkeeper::One::VERSION
|
108
|
+
end
|
109
|
+
|
110
|
+
default_task :sync
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def initialize_sync(options)
|
115
|
+
initialize_configuration options
|
116
|
+
validate_configuration!
|
117
|
+
initialize_logger
|
118
|
+
logger.debug "cloudkeeper-one 'sync' called with parameters: #{Cloudkeeper::One::Settings.to_hash.inspect}"
|
119
|
+
end
|
120
|
+
|
121
|
+
def validate_configuration!
|
122
|
+
validate_configuration_group! :authentication,
|
123
|
+
[:certificate, :key, :'core-certificate'],
|
124
|
+
'Authentication configuration missing'
|
125
|
+
end
|
126
|
+
|
127
|
+
def validate_configuration_group!(flag, required_options, error_message)
|
128
|
+
return unless Cloudkeeper::One::Settings[flag]
|
129
|
+
|
130
|
+
raise Cloudkeeper::One::Errors::InvalidConfigurationError, error_message unless all_options_available(required_options)
|
131
|
+
end
|
132
|
+
|
133
|
+
def all_options_available(required_options)
|
134
|
+
required_options.reduce(true) { |acc, elem| Cloudkeeper::One::Settings[elem] && acc }
|
135
|
+
end
|
136
|
+
|
137
|
+
def credentials
|
138
|
+
return :this_port_is_insecure unless Cloudkeeper::One::Settings[:authentication]
|
139
|
+
|
140
|
+
GRPC::Core::ServerCredentials.new(
|
141
|
+
File.read(Cloudkeeper::One::Settings[:'core-certificate']),
|
142
|
+
[
|
143
|
+
private_key: File.read(Cloudkeeper::One::Settings[:key]),
|
144
|
+
cert_chain: File.read(Cloudkeeper::One::Settings[:certificate])
|
145
|
+
],
|
146
|
+
true
|
147
|
+
)
|
148
|
+
end
|
149
|
+
|
150
|
+
def initialize_configuration(options)
|
151
|
+
Cloudkeeper::One::Settings.clear
|
152
|
+
Cloudkeeper::One::Settings.merge! options.to_hash
|
153
|
+
|
154
|
+
gem_dir = File.realdirpath(File.join(File.dirname(__FILE__), '..', '..', '..'))
|
155
|
+
Cloudkeeper::One::Settings[:'appliances-template-dir'] = File.join(gem_dir, 'config', 'templates') \
|
156
|
+
unless Cloudkeeper::One::Settings[:'appliances-template-dir']
|
157
|
+
Cloudkeeper::One::Settings[:'opennebula-api-call-timeout'] = \
|
158
|
+
ChronicDuration.parse Cloudkeeper::One::Settings[:'opennebula-api-call-timeout'], keep_zero: true
|
159
|
+
end
|
160
|
+
|
161
|
+
def initialize_logger
|
162
|
+
Cloudkeeper::One::Settings[:'logging-level'] = 'DEBUG' if Cloudkeeper::One::Settings[:debug]
|
163
|
+
|
164
|
+
logging_file = Cloudkeeper::One::Settings[:'logging-file']
|
165
|
+
logging_level = Cloudkeeper::One::Settings[:'logging-level']
|
166
|
+
|
167
|
+
Yell.new :stdout, name: Object, level: logging_level.downcase, format: Yell::DefaultFormat
|
168
|
+
Object.send :include, Yell::Loggable
|
169
|
+
|
170
|
+
setup_file_logger(logging_file) if logging_file
|
171
|
+
|
172
|
+
logger.debug 'Running in debug mode...'
|
173
|
+
end
|
174
|
+
|
175
|
+
def setup_file_logger(logging_file)
|
176
|
+
unless (File.exist?(logging_file) && File.writable?(logging_file)) || File.writable?(File.dirname(logging_file))
|
177
|
+
logger.error "File #{logging_file} isn't writable"
|
178
|
+
return
|
179
|
+
end
|
180
|
+
|
181
|
+
logger.adapter :file, logging_file
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module Cloudkeeper
|
2
|
+
module One
|
3
|
+
class CoreConnector < CloudkeeperGrpc::Communicator::Service
|
4
|
+
attr_reader :image_handler, :template_handler, :datastore_handler, :group_handler
|
5
|
+
|
6
|
+
include Cloudkeeper::One::ApplianceActions::Registration
|
7
|
+
include Cloudkeeper::One::ApplianceActions::Removal
|
8
|
+
include Cloudkeeper::One::ApplianceActions::Update
|
9
|
+
include Cloudkeeper::One::ApplianceActions::List
|
10
|
+
|
11
|
+
ERRORS = Hash.new(CloudkeeperGrpc::Constants::STATUS_ERROR).update(
|
12
|
+
Cloudkeeper::One::Errors::Actions::ListingError => CloudkeeperGrpc::Constants::STATUS_ERROR_APPLIANCE_NOT_FOUND,
|
13
|
+
Cloudkeeper::One::Errors::Actions::UpdateError => CloudkeeperGrpc::Constants::STATUS_ERROR_APPLIANCE_NOT_FOUND,
|
14
|
+
Cloudkeeper::One::Errors::NetworkConnectionError => CloudkeeperGrpc::Constants::STATUS_ERROR_APPLIANCE_TRANSFER,
|
15
|
+
Cloudkeeper::One::Errors::Opennebula::AuthenticationError => CloudkeeperGrpc::Constants::STATUS_ERROR_AUTHENTICATION,
|
16
|
+
Cloudkeeper::One::Errors::Opennebula::UserNotAuthorizedError => CloudkeeperGrpc::Constants::STATUS_ERROR_USER_NOT_AUTHORIZED,
|
17
|
+
Cloudkeeper::One::Errors::Opennebula::ResourceNotFoundError => CloudkeeperGrpc::Constants::STATUS_ERROR_RESOURCE_NOT_FOUND,
|
18
|
+
Cloudkeeper::One::Errors::Actions::RegistrationError => CloudkeeperGrpc::Constants::STATUS_ERROR_RESOURCE_NOT_FOUND,
|
19
|
+
Cloudkeeper::One::Errors::Opennebula::ResourceRetrievalError => CloudkeeperGrpc::Constants::STATUS_ERROR_RESOURCE_RETRIEVAL,
|
20
|
+
Cloudkeeper::One::Errors::Opennebula::ResourceStateError => CloudkeeperGrpc::Constants::STATUS_ERROR_RESOURCE_STATE,
|
21
|
+
Cloudkeeper::One::Errors::Opennebula::ApiCallTimeoutError => CloudkeeperGrpc::Constants::STATUS_ERROR_RESOURCE_STATE
|
22
|
+
).freeze
|
23
|
+
|
24
|
+
def initialize
|
25
|
+
super
|
26
|
+
|
27
|
+
@image_handler = Cloudkeeper::One::Opennebula::ImageHandler.new
|
28
|
+
@template_handler = Cloudkeeper::One::Opennebula::TemplateHandler.new
|
29
|
+
@datastore_handler = Cloudkeeper::One::Opennebula::DatastoreHandler.new
|
30
|
+
@group_handler = Cloudkeeper::One::Opennebula::GroupHandler.new
|
31
|
+
end
|
32
|
+
|
33
|
+
def pre_action(_empty, call)
|
34
|
+
logger.debug 'Running \'pre-action\'...'
|
35
|
+
call_backend(call) { remove_expired }
|
36
|
+
end
|
37
|
+
|
38
|
+
def post_action(_empty, call)
|
39
|
+
logger.debug 'Running \'post-action\'...'
|
40
|
+
call.output_metadata['status'] = 'SUCCESS'
|
41
|
+
Google::Protobuf::Empty.new
|
42
|
+
end
|
43
|
+
|
44
|
+
def add_appliance(appliance, call)
|
45
|
+
logger.debug "Registering appliance #{appliance.identifier.inspect}"
|
46
|
+
call_backend(call) { register_or_update_appliance appliance }
|
47
|
+
end
|
48
|
+
|
49
|
+
def update_appliance(appliance, call)
|
50
|
+
logger.debug "Updating appliance #{appliance.identifier.inspect}"
|
51
|
+
call_backend(call) { appliance.image ? register_or_update_appliance(appliance) : update_appliance_metadata(appliance) }
|
52
|
+
end
|
53
|
+
|
54
|
+
def remove_appliance(appliance, call)
|
55
|
+
logger.debug "Removing appliance #{appliance.identifier.inspect}"
|
56
|
+
call_backend(call) { remove_appliance appliance }
|
57
|
+
end
|
58
|
+
|
59
|
+
def remove_image_list(image_list_identifier, call)
|
60
|
+
logger.debug "Removing appliances from image list #{image_list_identifier.image_list_identifier.inspect}"
|
61
|
+
call_backend(call) { remove_image_list image_list_identifier.image_list_identifier }
|
62
|
+
end
|
63
|
+
|
64
|
+
def image_lists(_empty, call)
|
65
|
+
logger.debug 'Retrieving image lists registered in OpenNebula'
|
66
|
+
call_backend(call, default_return_value: [], use_return_value: true) { list_image_lists.each }
|
67
|
+
end
|
68
|
+
|
69
|
+
def appliances(image_list_identifier, call)
|
70
|
+
logger.debug "Retrieving appliances from image list #{image_list_identifier.image_list_identifier.inspect} " \
|
71
|
+
'registered in OpenNebula'
|
72
|
+
call_backend(call, default_return_value: [], use_return_value: true) do
|
73
|
+
list_appliances(image_list_identifier.image_list_identifier).each
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def call_backend(call, default_return_value: Google::Protobuf::Empty.new, use_return_value: false)
|
80
|
+
raise Cloudkeeper::One::Errors::ArgumentError, 'Error handler was called without a block!' unless block_given?
|
81
|
+
|
82
|
+
return_value = handle_errors(call) { yield }
|
83
|
+
finalize_return_value(return_value, default_return_value, use_return_value)
|
84
|
+
end
|
85
|
+
|
86
|
+
def handle_errors(call)
|
87
|
+
return_value = yield
|
88
|
+
call.output_metadata[CloudkeeperGrpc::Constants::KEY_STATUS] = CloudkeeperGrpc::Constants::STATUS_SUCCESS
|
89
|
+
|
90
|
+
return_value
|
91
|
+
rescue Cloudkeeper::One::Errors::StandardError => ex
|
92
|
+
logger.error "#{ex.class.inspect}: #{ex.message}"
|
93
|
+
call.output_metadata[CloudkeeperGrpc::Constants::KEY_STATUS] = ERRORS[ex.class]
|
94
|
+
call.output_metadata[CloudkeeperGrpc::Constants::KEY_MESSAGE] = ex.message
|
95
|
+
|
96
|
+
return_value
|
97
|
+
end
|
98
|
+
|
99
|
+
def finalize_return_value(return_value, default_return_value, use_return_value)
|
100
|
+
return_value = use_return_value ? return_value : default_return_value
|
101
|
+
|
102
|
+
return_value
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Cloudkeeper
|
2
|
+
module One
|
3
|
+
module Errors
|
4
|
+
module Actions
|
5
|
+
autoload :ActionError, 'cloudkeeper/one/errors/actions/action_error'
|
6
|
+
autoload :RegistrationError, 'cloudkeeper/one/errors/actions/registration_error'
|
7
|
+
autoload :ListingError, 'cloudkeeper/one/errors/actions/listing_error'
|
8
|
+
autoload :UpdateError, 'cloudkeeper/one/errors/actions/update_error'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Cloudkeeper
|
2
|
+
module One
|
3
|
+
module Errors
|
4
|
+
class MultiError < StandardError
|
5
|
+
attr_accessor :errors
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@errors = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def <<(error)
|
12
|
+
@errors << error
|
13
|
+
end
|
14
|
+
|
15
|
+
def message
|
16
|
+
errors.map(&:message).join('|')
|
17
|
+
end
|
18
|
+
|
19
|
+
def count
|
20
|
+
errors.count
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Cloudkeeper
|
2
|
+
module One
|
3
|
+
module Errors
|
4
|
+
module Opennebula
|
5
|
+
autoload :OpennebulaError, 'cloudkeeper/one/errors/opennebula/opennebula_error'
|
6
|
+
autoload :StubError, 'cloudkeeper/one/errors/opennebula/stub_error'
|
7
|
+
autoload :MissingPoolError, 'cloudkeeper/one/errors/opennebula/missing_pool_error'
|
8
|
+
autoload :ApiCallTimeoutError, 'cloudkeeper/one/errors/opennebula/api_call_timeout_error'
|
9
|
+
autoload :AuthenticationError, 'cloudkeeper/one/errors/opennebula/authentication_error'
|
10
|
+
autoload :ResourceNotFoundError, 'cloudkeeper/one/errors/opennebula/resource_not_found_error'
|
11
|
+
autoload :ResourceRetrievalError, 'cloudkeeper/one/errors/opennebula/resource_retrieval_error'
|
12
|
+
autoload :ResourceStateError, 'cloudkeeper/one/errors/opennebula/resource_state_error'
|
13
|
+
autoload :UserNotAuthorizedError, 'cloudkeeper/one/errors/opennebula/user_not_authorized_error'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|