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.
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