cloudkeeper 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 +12 -0
- data/.gitmodules +3 -0
- data/.rspec +2 -0
- data/.rubocop.yml +61 -0
- data/.travis.yml +21 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +17 -0
- data/README.md +122 -0
- data/Rakefile +17 -0
- data/bin/cloudkeeper +5 -0
- data/cloudkeeper.gemspec +45 -0
- data/config/cloudkeeper.yml +27 -0
- data/lib/cloudkeeper.rb +16 -0
- data/lib/cloudkeeper/backend_connector.rb +123 -0
- data/lib/cloudkeeper/cli.rb +174 -0
- data/lib/cloudkeeper/command_executioner.rb +22 -0
- data/lib/cloudkeeper/entities.rb +11 -0
- data/lib/cloudkeeper/entities/appliance.rb +84 -0
- data/lib/cloudkeeper/entities/conversions.rb +48 -0
- data/lib/cloudkeeper/entities/convertables.rb +8 -0
- data/lib/cloudkeeper/entities/convertables/convertable.rb +63 -0
- data/lib/cloudkeeper/entities/convertables/ova.rb +54 -0
- data/lib/cloudkeeper/entities/image.rb +40 -0
- data/lib/cloudkeeper/entities/image_file.rb +23 -0
- data/lib/cloudkeeper/entities/image_formats.rb +7 -0
- data/lib/cloudkeeper/entities/image_formats/ova.rb +41 -0
- data/lib/cloudkeeper/entities/image_list.rb +84 -0
- data/lib/cloudkeeper/errors.rb +20 -0
- data/lib/cloudkeeper/errors/appliance.rb +7 -0
- data/lib/cloudkeeper/errors/appliance/propagation_error.rb +7 -0
- data/lib/cloudkeeper/errors/argument_error.rb +5 -0
- data/lib/cloudkeeper/errors/backend_error.rb +5 -0
- data/lib/cloudkeeper/errors/command_execution_error.rb +5 -0
- data/lib/cloudkeeper/errors/convertables.rb +7 -0
- data/lib/cloudkeeper/errors/convertables/convertability_error.rb +7 -0
- data/lib/cloudkeeper/errors/image.rb +9 -0
- data/lib/cloudkeeper/errors/image/conversion_error.rb +7 -0
- data/lib/cloudkeeper/errors/image/download_error.rb +7 -0
- data/lib/cloudkeeper/errors/image/format.rb +12 -0
- data/lib/cloudkeeper/errors/image/format/no_format_recognized_error.rb +9 -0
- data/lib/cloudkeeper/errors/image/format/no_required_format_available_error.rb +9 -0
- data/lib/cloudkeeper/errors/image/format/ova.rb +12 -0
- data/lib/cloudkeeper/errors/image/format/ova/invalid_archive_error.rb +11 -0
- data/lib/cloudkeeper/errors/image/format/ova/ova_format_error.rb +11 -0
- data/lib/cloudkeeper/errors/image/format/recognition_error.rb +9 -0
- data/lib/cloudkeeper/errors/image_list.rb +9 -0
- data/lib/cloudkeeper/errors/image_list/download_error.rb +7 -0
- data/lib/cloudkeeper/errors/image_list/retrieval_error.rb +7 -0
- data/lib/cloudkeeper/errors/image_list/verification_error.rb +7 -0
- data/lib/cloudkeeper/errors/invalid_configuration_error.rb +5 -0
- data/lib/cloudkeeper/errors/invalid_url_error.rb +5 -0
- data/lib/cloudkeeper/errors/network_connection_error.rb +5 -0
- data/lib/cloudkeeper/errors/nginx_error.rb +5 -0
- data/lib/cloudkeeper/errors/no_such_file_error.rb +5 -0
- data/lib/cloudkeeper/errors/not_implemented_error.rb +5 -0
- data/lib/cloudkeeper/errors/parsing.rb +10 -0
- data/lib/cloudkeeper/errors/parsing/invalid_appliance_hash_error.rb +7 -0
- data/lib/cloudkeeper/errors/parsing/invalid_image_hash_error.rb +7 -0
- data/lib/cloudkeeper/errors/parsing/invalid_image_list_hash_error.rb +7 -0
- data/lib/cloudkeeper/errors/parsing/parsing_error.rb +7 -0
- data/lib/cloudkeeper/errors/permission_denied_error.rb +5 -0
- data/lib/cloudkeeper/errors/standard_error.rb +5 -0
- data/lib/cloudkeeper/managers.rb +7 -0
- data/lib/cloudkeeper/managers/appliance_manager.rb +152 -0
- data/lib/cloudkeeper/managers/image_list_manager.rb +88 -0
- data/lib/cloudkeeper/managers/image_manager.rb +82 -0
- data/lib/cloudkeeper/nginx.rb +5 -0
- data/lib/cloudkeeper/nginx/http_server.rb +113 -0
- data/lib/cloudkeeper/nginx/templates/nginx.conf.erb +32 -0
- data/lib/cloudkeeper/settings.rb +19 -0
- data/lib/cloudkeeper/utils.rb +7 -0
- data/lib/cloudkeeper/utils/checksum.rb +9 -0
- data/lib/cloudkeeper/utils/hash.rb +9 -0
- data/lib/cloudkeeper/utils/url.rb +11 -0
- data/lib/cloudkeeper/version.rb +3 -0
- data/lib/cloudkeeper_grpc.rb +5 -0
- metadata +416 -0
@@ -0,0 +1,10 @@
|
|
1
|
+
module Cloudkeeper
|
2
|
+
module Errors
|
3
|
+
module Parsing
|
4
|
+
autoload :ParsingError, 'cloudkeeper/errors/parsing/parsing_error'
|
5
|
+
autoload :InvalidApplianceHashError, 'cloudkeeper/errors/parsing/invalid_appliance_hash_error'
|
6
|
+
autoload :InvalidImageHashError, 'cloudkeeper/errors/parsing/invalid_image_hash_error'
|
7
|
+
autoload :InvalidImageListHashError, 'cloudkeeper/errors/parsing/invalid_image_list_hash_error'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
module Cloudkeeper
|
2
|
+
module Managers
|
3
|
+
class ApplianceManager
|
4
|
+
attr_reader :backend_connector, :image_list_manager, :acceptable_formats
|
5
|
+
|
6
|
+
IMAGE_UPDATE_ATTRIBUTES = ['hv:uri', 'sl:checksum:sha512', 'hv:size'].freeze
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@backend_connector = Cloudkeeper::BackendConnector.new
|
10
|
+
@image_list_manager = Cloudkeeper::Managers::ImageListManager.new
|
11
|
+
@acceptable_formats = Cloudkeeper::Settings[:formats].map(&:to_sym)
|
12
|
+
end
|
13
|
+
|
14
|
+
def synchronize_appliances
|
15
|
+
logger.debug 'Running appliance synchronization...'
|
16
|
+
backend_connector.pre_action
|
17
|
+
|
18
|
+
backend_image_lists = backend_connector.image_lists
|
19
|
+
image_list_manager.download_image_lists
|
20
|
+
|
21
|
+
sync_expired_image_lists
|
22
|
+
sync_new_image_lists(backend_image_lists)
|
23
|
+
sync_old_image_lists(backend_image_lists)
|
24
|
+
|
25
|
+
backend_connector.post_action
|
26
|
+
rescue Cloudkeeper::Errors::BackendError => ex
|
27
|
+
abort ex.message
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def sync_expired_image_lists
|
33
|
+
logger.debug 'Removing appliances from expired image lists...'
|
34
|
+
image_list_manager.image_lists.each_value do |image_list|
|
35
|
+
backend_connector.remove_image_list image_list if image_list.expired?
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def sync_new_image_lists(backend_image_lists)
|
40
|
+
logger.debug 'Registering appliances from new image lists...'
|
41
|
+
add_list = image_list_manager.image_lists.keys - backend_image_lists
|
42
|
+
add_list.each do |image_list_identifier|
|
43
|
+
image_list_manager.image_lists[image_list_identifier].appliances.each_value { |appliance| add_appliance appliance }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def sync_old_image_lists(backend_image_lists)
|
48
|
+
logger.debug 'Synchronizing registered appliances...'
|
49
|
+
sync_list = image_list_manager.image_lists.keys & backend_image_lists
|
50
|
+
sync_list.each { |image_list_identifier| sync_image_list image_list_identifier }
|
51
|
+
end
|
52
|
+
|
53
|
+
def sync_image_list(image_list_identifier)
|
54
|
+
backend_appliances = backend_connector.appliances image_list_identifier
|
55
|
+
image_list_appliances = image_list_manager.image_lists[image_list_identifier].appliances
|
56
|
+
|
57
|
+
remove_appliances backend_appliances, image_list_appliances
|
58
|
+
add_appliances backend_appliances, image_list_appliances
|
59
|
+
update_appliances backend_appliances, image_list_appliances
|
60
|
+
end
|
61
|
+
|
62
|
+
def remove_appliances(backend_appliances, image_list_appliances)
|
63
|
+
logger.debug 'Removing previously registered appliances...'
|
64
|
+
remove_list = backend_appliances.keys - image_list_appliances.keys
|
65
|
+
remove_list.each { |appliance_identifier| backend_connector.remove_appliance image_list_appliances[appliance_identifier] }
|
66
|
+
end
|
67
|
+
|
68
|
+
def add_appliances(backend_appliances, image_list_appliances)
|
69
|
+
logger.debug 'Registering new appliances...'
|
70
|
+
add_list = image_list_appliances.keys - backend_appliances.keys
|
71
|
+
add_list.each { |appliance_identifier| add_appliance image_list_appliances[appliance_identifier] }
|
72
|
+
end
|
73
|
+
|
74
|
+
def update_appliances(backend_appliances, image_list_appliances)
|
75
|
+
logger.debug 'Updating appliances...'
|
76
|
+
update_list = backend_appliances.keys & image_list_appliances.keys
|
77
|
+
update_list.each do |appliance_identifier|
|
78
|
+
image_list_appliance = image_list_appliances[appliance_identifier]
|
79
|
+
backend_appliance = backend_appliances[appliance_identifier]
|
80
|
+
|
81
|
+
image_update = update_image?(image_list_appliance, backend_appliance)
|
82
|
+
image_list_appliance.image = nil unless image_update
|
83
|
+
update_appliance image_list_appliance if image_update || update_metadata?(image_list_appliance, backend_appliance)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def clean_image_files(appliance)
|
88
|
+
return unless appliance && appliance.image
|
89
|
+
|
90
|
+
logger.debug "Cleaning downloaded image files for appliance #{appliance.identifier.inspect}"
|
91
|
+
appliance.image.image_files.each { |image_file| clean_image_file image_file.file }
|
92
|
+
rescue ::IOError => ex
|
93
|
+
logger.warn "Appliance cleanup error: #{ex.message}"
|
94
|
+
end
|
95
|
+
|
96
|
+
def clean_image_file(filename)
|
97
|
+
File.delete(filename) if File.exist?(filename)
|
98
|
+
end
|
99
|
+
|
100
|
+
def update_image?(image_list_appliance, backend_appliance)
|
101
|
+
image_list_attributes = image_list_appliance.attributes
|
102
|
+
backend_attributes = backend_appliance.attributes
|
103
|
+
|
104
|
+
IMAGE_UPDATE_ATTRIBUTES.reduce(false) { |red, elem| red || (image_list_attributes[elem] != backend_attributes[elem]) }
|
105
|
+
end
|
106
|
+
|
107
|
+
def update_metadata?(image_list_appliance, backend_appliance)
|
108
|
+
image_list_appliance.attributes != backend_appliance.attributes
|
109
|
+
end
|
110
|
+
|
111
|
+
def update_appliance(appliance)
|
112
|
+
modify_appliance :update_appliance, appliance
|
113
|
+
end
|
114
|
+
|
115
|
+
def add_appliance(appliance)
|
116
|
+
modify_appliance :add_appliance, appliance
|
117
|
+
end
|
118
|
+
|
119
|
+
def modify_appliance(method, appliance)
|
120
|
+
prepare_image!(appliance) if appliance.image
|
121
|
+
backend_connector.send method, appliance
|
122
|
+
rescue Cloudkeeper::Errors::Image::DownloadError, Cloudkeeper::Errors::Image::ConversionError => ex
|
123
|
+
logger.error "Image preparation error: #{ex.message}"
|
124
|
+
rescue Cloudkeeper::Errors::Appliance::PropagationError => ex
|
125
|
+
logger.error "Appliance propagation error: #{ex.message}"
|
126
|
+
ensure
|
127
|
+
clean_image_files appliance
|
128
|
+
end
|
129
|
+
|
130
|
+
def prepare_image!(appliance)
|
131
|
+
image_file = Cloudkeeper::Managers::ImageManager.download_image(appliance.image.uri)
|
132
|
+
appliance.image.add_image_file image_file
|
133
|
+
return if acceptable_formats.include? image_file.format
|
134
|
+
|
135
|
+
convert_image! appliance, image_file
|
136
|
+
end
|
137
|
+
|
138
|
+
def convert_image!(appliance, image_file)
|
139
|
+
format = acceptable_formats.find { |acceptable_format| image_file.respond_to? "to_#{acceptable_format}".to_sym }
|
140
|
+
unless format
|
141
|
+
raise Cloudkeeper::Errors::Image::Format::NoRequiredFormatAvailableError,
|
142
|
+
"image #{image.inspect} cannot be converted to any acceptable format"
|
143
|
+
end
|
144
|
+
|
145
|
+
appliance.image.add_image_file image_file.send("to_#{format}".to_sym)
|
146
|
+
rescue Cloudkeeper::Errors::Image::Format::NoRequiredFormatAvailableError, Cloudkeeper::Errors::CommandExecutionError,
|
147
|
+
Cloudkeeper::Errors::ArgumentError, ::IOError => ex
|
148
|
+
raise Cloudkeeper::Errors::Image::ConversionError, ex
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'tmpdir'
|
2
|
+
require 'faraday'
|
3
|
+
require 'zaru'
|
4
|
+
require 'openssl'
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
module Cloudkeeper
|
8
|
+
module Managers
|
9
|
+
class ImageListManager
|
10
|
+
attr_reader :image_lists, :openssl_store
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@image_lists = {}
|
14
|
+
|
15
|
+
@openssl_store = OpenSSL::X509::Store.new
|
16
|
+
@openssl_store.add_path Cloudkeeper::Settings[:'ca-dir'] if Cloudkeeper::Settings[:'ca-dir']
|
17
|
+
end
|
18
|
+
|
19
|
+
def download_image_lists
|
20
|
+
logger.debug 'Downloading fresh image lists...'
|
21
|
+
Dir.mktmpdir('cloudkeeper') do |dir|
|
22
|
+
urls = Cloudkeeper::Settings[:'image-lists']
|
23
|
+
retrieve_image_lists urls, dir
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def retrieve_image_lists(urls, dir)
|
30
|
+
urls.each do |url|
|
31
|
+
begin
|
32
|
+
image_list = convert_image_list(load_image_list(download_image_list(url, dir)))
|
33
|
+
image_lists[image_list.identifier] = image_list
|
34
|
+
rescue Cloudkeeper::Errors::ImageList::DownloadError, Cloudkeeper::Errors::ImageList::VerificationError,
|
35
|
+
Cloudkeeper::Errors::Parsing::ParsingError => ex
|
36
|
+
logger.warn "Image list #{url} couldn't be donwloaded\n#{ex.message}"
|
37
|
+
next
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def download_image_list(url, dir)
|
43
|
+
logger.debug "Downloading image list from #{url.inspect}"
|
44
|
+
Cloudkeeper::Utils::URL.check!(url)
|
45
|
+
uri = URI.parse url
|
46
|
+
|
47
|
+
filename = generate_filename(uri, dir)
|
48
|
+
response = make_request uri
|
49
|
+
|
50
|
+
if response.success?
|
51
|
+
File.write filename, response.body
|
52
|
+
return filename
|
53
|
+
end
|
54
|
+
|
55
|
+
raise Cloudkeeper::Errors::ImageList::RetrievalError,
|
56
|
+
"couldn't download image list from url #{url.inspect}\n#{response.to_hash.inspect}"
|
57
|
+
rescue Cloudkeeper::Errors::ImageList::RetrievalError, Cloudkeeper::Errors::InvalidURLError, ::IOError,
|
58
|
+
::Faraday::ConnectionFailed => ex
|
59
|
+
raise Cloudkeeper::Errors::ImageList::DownloadError, ex
|
60
|
+
end
|
61
|
+
|
62
|
+
def make_request(uri)
|
63
|
+
conn = Faraday.new url: uri
|
64
|
+
conn.get
|
65
|
+
end
|
66
|
+
|
67
|
+
def generate_filename(uri, dir)
|
68
|
+
File.join(dir, Zaru.sanitize!("#{uri.host}#{uri.path}"))
|
69
|
+
end
|
70
|
+
|
71
|
+
def convert_image_list(image_list_hash)
|
72
|
+
Cloudkeeper::Entities::ImageList.from_hash image_list_hash
|
73
|
+
end
|
74
|
+
|
75
|
+
def load_image_list(file)
|
76
|
+
pkcs7 = OpenSSL::PKCS7.read_smime(File.read(file))
|
77
|
+
verify_image_list!(pkcs7, file)
|
78
|
+
|
79
|
+
JSON.parse pkcs7.data
|
80
|
+
end
|
81
|
+
|
82
|
+
def verify_image_list!(pkcs7, file)
|
83
|
+
raise Cloudkeeper::Errors::ImageList::VerificationError, "image list #{file.inspect} cannot be verified" \
|
84
|
+
unless pkcs7.verify([], openssl_store)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module Cloudkeeper
|
4
|
+
module Managers
|
5
|
+
class ImageManager
|
6
|
+
extend Cloudkeeper::Entities::ImageFormats::Ova
|
7
|
+
|
8
|
+
FORMATS = {
|
9
|
+
qcow2: /qemu qcow image/i,
|
10
|
+
ova: /posix tar archive/i,
|
11
|
+
vmdk: /vmware4 disk image/i,
|
12
|
+
raw: /boot sector/i
|
13
|
+
}.freeze
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def format(file)
|
17
|
+
check_file!(file)
|
18
|
+
recognize_format(file)
|
19
|
+
rescue Cloudkeeper::Errors::CommandExecutionError, Cloudkeeper::Errors::NoSuchFileError,
|
20
|
+
Cloudkeeper::Errors::PermissionDeniedError, Cloudkeeper::Errors::Image::Format::NoFormatRecognizedError,
|
21
|
+
Cloudkeeper::Errors::Image::Format::Ova::OvaFormatError => ex
|
22
|
+
raise Cloudkeeper::Errors::Image::Format::RecognitionError, ex, "Cannot recognize image format for file #{file.inspect}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def file_description(file)
|
26
|
+
Cloudkeeper::CommandExecutioner.execute('file', '-b', file)
|
27
|
+
end
|
28
|
+
|
29
|
+
def check_file!(file)
|
30
|
+
raise Cloudkeeper::Errors::NoSuchFileError, "No such file #{file.inspect}" unless File.exist?(file)
|
31
|
+
raise Cloudkeeper::Errors::PermissionDeniedError, "Cannot read file #{file.inspect}" unless File.readable?(file)
|
32
|
+
end
|
33
|
+
|
34
|
+
def recognize_format(file)
|
35
|
+
file_format_string = file_description(file)
|
36
|
+
FORMATS.each do |format, regex|
|
37
|
+
next unless regex =~ file_format_string
|
38
|
+
|
39
|
+
format_test_method = "#{format}?".to_sym
|
40
|
+
additional_test_result = respond_to?(format_test_method) ? send(format_test_method, file) : true
|
41
|
+
|
42
|
+
return format if additional_test_result
|
43
|
+
end
|
44
|
+
|
45
|
+
raise Cloudkeeper::Errors::Image::Format::NoFormatRecognizedError, "No image format recognized for file #{file.inspect}"
|
46
|
+
end
|
47
|
+
|
48
|
+
def download_image(url)
|
49
|
+
logger.debug "Downloading image from #{url.inspect}"
|
50
|
+
Cloudkeeper::Utils::URL.check!(url)
|
51
|
+
|
52
|
+
uri = URI.parse url
|
53
|
+
filename = generate_filename(uri)
|
54
|
+
retrieve_image(uri, filename)
|
55
|
+
|
56
|
+
Cloudkeeper::Entities::ImageFile.new filename, format(filename), Cloudkeeper::Utils::Checksum.compute(filename), true
|
57
|
+
rescue Cloudkeeper::Errors::InvalidURLError, Cloudkeeper::Errors::Image::Format::RecognitionError,
|
58
|
+
Cloudkeeper::Errors::ArgumentError, Cloudkeeper::Errors::NetworkConnectionError, ::IOError => ex
|
59
|
+
raise Cloudkeeper::Errors::Image::DownloadError, ex
|
60
|
+
end
|
61
|
+
|
62
|
+
def retrieve_image(uri, filename)
|
63
|
+
Net::HTTP.start(uri.host, uri.port) do |http|
|
64
|
+
request = Net::HTTP::Get.new(uri)
|
65
|
+
|
66
|
+
http.request(request) do |response|
|
67
|
+
response.value
|
68
|
+
open(filename, 'w') { |file| response.read_body { |chunk| file.write(chunk) } }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, Errno::ECONNREFUSED, EOFError, Net::HTTPBadResponse,
|
72
|
+
Net::HTTPServerException, Net::HTTPHeaderSyntaxError, Net::ProtocolError => ex
|
73
|
+
raise Cloudkeeper::Errors::NetworkConnectionError, ex
|
74
|
+
end
|
75
|
+
|
76
|
+
def generate_filename(uri)
|
77
|
+
File.join(Cloudkeeper::Settings[:'image-dir'], Zaru.sanitize!(File.basename(uri.path)))
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'webrick'
|
2
|
+
require 'tempfile'
|
3
|
+
require 'securerandom'
|
4
|
+
require 'erb'
|
5
|
+
require 'tilt/erb'
|
6
|
+
|
7
|
+
module Cloudkeeper
|
8
|
+
module Nginx
|
9
|
+
class HttpServer
|
10
|
+
attr_reader :auth_file, :conf_file, :access_data
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@access_data = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def start(image_file)
|
17
|
+
logger.debug 'Starting NGINX server'
|
18
|
+
@access_data = {}
|
19
|
+
credentials = prepare_credentials
|
20
|
+
configuration = prepare_configuration File.dirname(image_file), File.basename(image_file)
|
21
|
+
prepare_configuration_file configuration
|
22
|
+
fill_access_data credentials, configuration
|
23
|
+
|
24
|
+
Cloudkeeper::CommandExecutioner.execute Cloudkeeper::Settings[:'nginx-binary'], '-c', conf_file.path
|
25
|
+
rescue Cloudkeeper::Errors::CommandExecutionError, ::IOError => ex
|
26
|
+
stop
|
27
|
+
raise Cloudkeeper::Errors::NginxError, ex
|
28
|
+
end
|
29
|
+
|
30
|
+
def stop
|
31
|
+
logger.debug 'Stopping NGINX server'
|
32
|
+
if conf_file
|
33
|
+
Cloudkeeper::CommandExecutioner.execute Cloudkeeper::Settings[:'nginx-binary'], '-s', 'stop', '-c', conf_file.path
|
34
|
+
conf_file.unlink
|
35
|
+
end
|
36
|
+
|
37
|
+
auth_file.unlink if auth_file
|
38
|
+
@access_data = {}
|
39
|
+
rescue Cloudkeeper::Errors::CommandExecutionError, ::IOError => ex
|
40
|
+
raise Cloudkeeper::Errors::NginxError, ex
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def fill_access_data(credentials, configuration)
|
46
|
+
access_data.merge! credentials
|
47
|
+
access_data[:url] = "http://#{configuration[:ip_address]}:#{configuration[:port]}/#{configuration[:image_file]}"
|
48
|
+
end
|
49
|
+
|
50
|
+
def prepare_credentials
|
51
|
+
username = random_string
|
52
|
+
password = random_string
|
53
|
+
|
54
|
+
write_auth_file username, password
|
55
|
+
|
56
|
+
logger.debug("Prepared NGINX authentication file #{auth_file.path.inspect}: "\
|
57
|
+
"username: #{username.inspect}, password: #{password.inspect}")
|
58
|
+
|
59
|
+
{ username: username, password: password }
|
60
|
+
end
|
61
|
+
|
62
|
+
def write_auth_file(username, password)
|
63
|
+
@auth_file = Tempfile.new('cloudkeeper-nginx-auth')
|
64
|
+
passwd = WEBrick::HTTPAuth::Htpasswd.new(auth_file.path)
|
65
|
+
passwd.set_passwd(nil, username, password)
|
66
|
+
passwd.flush
|
67
|
+
auth_file.close
|
68
|
+
end
|
69
|
+
|
70
|
+
def prepare_configuration_file(configuration)
|
71
|
+
conf_content = prepare_configuration_file_content configuration
|
72
|
+
write_configuration_file conf_content
|
73
|
+
|
74
|
+
logger.debug("Prepared NGINX configuration file #{conf_file.path.inspect}:\n#{conf_content}")
|
75
|
+
end
|
76
|
+
|
77
|
+
def write_configuration_file(content)
|
78
|
+
@conf_file = Tempfile.new('cloudkeeper-nginx-conf')
|
79
|
+
|
80
|
+
conf_file.write content
|
81
|
+
conf_file.close
|
82
|
+
end
|
83
|
+
|
84
|
+
def prepare_configuration_file_content(configuration)
|
85
|
+
conf_template = Tilt::ERBTemplate.new(File.join(File.expand_path(File.dirname(__FILE__)), 'templates', 'nginx.conf.erb'))
|
86
|
+
conf_template.render(Object.new, configuration)
|
87
|
+
end
|
88
|
+
|
89
|
+
def prepare_configuration(root_dir, image_file)
|
90
|
+
nginx_configuration = {}
|
91
|
+
nginx_configuration[:error_log_file] = Cloudkeeper::Settings[:'nginx-error-log-file']
|
92
|
+
nginx_configuration[:access_log_file] = Cloudkeeper::Settings[:'nginx-access-log-file']
|
93
|
+
nginx_configuration[:pid_file] = Cloudkeeper::Settings[:'nginx-pid-file']
|
94
|
+
nginx_configuration[:auth_file] = auth_file.path
|
95
|
+
nginx_configuration[:root_dir] = root_dir
|
96
|
+
nginx_configuration[:image_file] = image_file
|
97
|
+
nginx_configuration[:ip_address] = Cloudkeeper::Settings[:'nginx-ip-address']
|
98
|
+
nginx_configuration[:port] = choose_port
|
99
|
+
|
100
|
+
logger.debug("NGINX configuration: #{nginx_configuration.inspect}")
|
101
|
+
nginx_configuration
|
102
|
+
end
|
103
|
+
|
104
|
+
def choose_port
|
105
|
+
rand(Cloudkeeper::Settings[:'nginx-min-port']..Cloudkeeper::Settings[:'nginx-max-port'])
|
106
|
+
end
|
107
|
+
|
108
|
+
def random_string
|
109
|
+
SecureRandom.uuid
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|