cloudkeeper 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.gitmodules +3 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +61 -0
  6. data/.travis.yml +21 -0
  7. data/CODE_OF_CONDUCT.md +49 -0
  8. data/Gemfile +4 -0
  9. data/LICENSE.txt +17 -0
  10. data/README.md +122 -0
  11. data/Rakefile +17 -0
  12. data/bin/cloudkeeper +5 -0
  13. data/cloudkeeper.gemspec +45 -0
  14. data/config/cloudkeeper.yml +27 -0
  15. data/lib/cloudkeeper.rb +16 -0
  16. data/lib/cloudkeeper/backend_connector.rb +123 -0
  17. data/lib/cloudkeeper/cli.rb +174 -0
  18. data/lib/cloudkeeper/command_executioner.rb +22 -0
  19. data/lib/cloudkeeper/entities.rb +11 -0
  20. data/lib/cloudkeeper/entities/appliance.rb +84 -0
  21. data/lib/cloudkeeper/entities/conversions.rb +48 -0
  22. data/lib/cloudkeeper/entities/convertables.rb +8 -0
  23. data/lib/cloudkeeper/entities/convertables/convertable.rb +63 -0
  24. data/lib/cloudkeeper/entities/convertables/ova.rb +54 -0
  25. data/lib/cloudkeeper/entities/image.rb +40 -0
  26. data/lib/cloudkeeper/entities/image_file.rb +23 -0
  27. data/lib/cloudkeeper/entities/image_formats.rb +7 -0
  28. data/lib/cloudkeeper/entities/image_formats/ova.rb +41 -0
  29. data/lib/cloudkeeper/entities/image_list.rb +84 -0
  30. data/lib/cloudkeeper/errors.rb +20 -0
  31. data/lib/cloudkeeper/errors/appliance.rb +7 -0
  32. data/lib/cloudkeeper/errors/appliance/propagation_error.rb +7 -0
  33. data/lib/cloudkeeper/errors/argument_error.rb +5 -0
  34. data/lib/cloudkeeper/errors/backend_error.rb +5 -0
  35. data/lib/cloudkeeper/errors/command_execution_error.rb +5 -0
  36. data/lib/cloudkeeper/errors/convertables.rb +7 -0
  37. data/lib/cloudkeeper/errors/convertables/convertability_error.rb +7 -0
  38. data/lib/cloudkeeper/errors/image.rb +9 -0
  39. data/lib/cloudkeeper/errors/image/conversion_error.rb +7 -0
  40. data/lib/cloudkeeper/errors/image/download_error.rb +7 -0
  41. data/lib/cloudkeeper/errors/image/format.rb +12 -0
  42. data/lib/cloudkeeper/errors/image/format/no_format_recognized_error.rb +9 -0
  43. data/lib/cloudkeeper/errors/image/format/no_required_format_available_error.rb +9 -0
  44. data/lib/cloudkeeper/errors/image/format/ova.rb +12 -0
  45. data/lib/cloudkeeper/errors/image/format/ova/invalid_archive_error.rb +11 -0
  46. data/lib/cloudkeeper/errors/image/format/ova/ova_format_error.rb +11 -0
  47. data/lib/cloudkeeper/errors/image/format/recognition_error.rb +9 -0
  48. data/lib/cloudkeeper/errors/image_list.rb +9 -0
  49. data/lib/cloudkeeper/errors/image_list/download_error.rb +7 -0
  50. data/lib/cloudkeeper/errors/image_list/retrieval_error.rb +7 -0
  51. data/lib/cloudkeeper/errors/image_list/verification_error.rb +7 -0
  52. data/lib/cloudkeeper/errors/invalid_configuration_error.rb +5 -0
  53. data/lib/cloudkeeper/errors/invalid_url_error.rb +5 -0
  54. data/lib/cloudkeeper/errors/network_connection_error.rb +5 -0
  55. data/lib/cloudkeeper/errors/nginx_error.rb +5 -0
  56. data/lib/cloudkeeper/errors/no_such_file_error.rb +5 -0
  57. data/lib/cloudkeeper/errors/not_implemented_error.rb +5 -0
  58. data/lib/cloudkeeper/errors/parsing.rb +10 -0
  59. data/lib/cloudkeeper/errors/parsing/invalid_appliance_hash_error.rb +7 -0
  60. data/lib/cloudkeeper/errors/parsing/invalid_image_hash_error.rb +7 -0
  61. data/lib/cloudkeeper/errors/parsing/invalid_image_list_hash_error.rb +7 -0
  62. data/lib/cloudkeeper/errors/parsing/parsing_error.rb +7 -0
  63. data/lib/cloudkeeper/errors/permission_denied_error.rb +5 -0
  64. data/lib/cloudkeeper/errors/standard_error.rb +5 -0
  65. data/lib/cloudkeeper/managers.rb +7 -0
  66. data/lib/cloudkeeper/managers/appliance_manager.rb +152 -0
  67. data/lib/cloudkeeper/managers/image_list_manager.rb +88 -0
  68. data/lib/cloudkeeper/managers/image_manager.rb +82 -0
  69. data/lib/cloudkeeper/nginx.rb +5 -0
  70. data/lib/cloudkeeper/nginx/http_server.rb +113 -0
  71. data/lib/cloudkeeper/nginx/templates/nginx.conf.erb +32 -0
  72. data/lib/cloudkeeper/settings.rb +19 -0
  73. data/lib/cloudkeeper/utils.rb +7 -0
  74. data/lib/cloudkeeper/utils/checksum.rb +9 -0
  75. data/lib/cloudkeeper/utils/hash.rb +9 -0
  76. data/lib/cloudkeeper/utils/url.rb +11 -0
  77. data/lib/cloudkeeper/version.rb +3 -0
  78. data/lib/cloudkeeper_grpc.rb +5 -0
  79. metadata +416 -0
@@ -0,0 +1,5 @@
1
+ module Cloudkeeper
2
+ module Errors
3
+ class NetworkConnectionError < StandardError; end
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Cloudkeeper
2
+ module Errors
3
+ class NginxError < StandardError; end
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Cloudkeeper
2
+ module Errors
3
+ class NoSuchFileError < StandardError; end
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Cloudkeeper
2
+ module Errors
3
+ class NotImplementedError < StandardError; end
4
+ end
5
+ end
@@ -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,7 @@
1
+ module Cloudkeeper
2
+ module Errors
3
+ module Parsing
4
+ class InvalidApplianceHashError < ParsingError; end
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Cloudkeeper
2
+ module Errors
3
+ module Parsing
4
+ class InvalidImageHashError < ParsingError; end
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Cloudkeeper
2
+ module Errors
3
+ module Parsing
4
+ class InvalidImageListHashError < ParsingError; end
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Cloudkeeper
2
+ module Errors
3
+ module Parsing
4
+ class ParsingError < StandardError; end
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ module Cloudkeeper
2
+ module Errors
3
+ class PermissionDeniedError < StandardError; end
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Cloudkeeper
2
+ module Errors
3
+ class StandardError < ::StandardError; end
4
+ end
5
+ end
@@ -0,0 +1,7 @@
1
+ module Cloudkeeper
2
+ module Managers
3
+ autoload :ImageListManager, 'cloudkeeper/managers/image_list_manager'
4
+ autoload :ImageManager, 'cloudkeeper/managers/image_manager'
5
+ autoload :ApplianceManager, 'cloudkeeper/managers/appliance_manager'
6
+ end
7
+ 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,5 @@
1
+ module Cloudkeeper
2
+ module Nginx
3
+ autoload :HttpServer, 'cloudkeeper/nginx/http_server'
4
+ end
5
+ 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