cloudkeeper-one 1.0.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.
- 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
|