cloudkeeper 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 +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
|